Fossil SCM
Performance improvements to the bid= query parameter of /timeline.
Commit
912711f044b83f4083ceda7b5f0927a35bb4ef6ffb48cf0c03bfaf062b9ab0ce
Parent
c5bdd31304b92ee…
2 files changed
+29
-9
+4
+29
-9
| --- src/bisect.c | ||
| +++ src/bisect.c | ||
| @@ -214,10 +214,20 @@ | ||
| 214 | 214 | }else{ |
| 215 | 215 | blob_append_sql(pSql, "(NULL,NULL,%d)", iRid); |
| 216 | 216 | } |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | +/* | |
| 220 | +** Limits on the bid= query parameter to /timeline. BISECT_MAX_TERM is | |
| 221 | +** the maximum number of terms and BISECT_MIN_PREFIX is the minimum number | |
| 222 | +** of hash prefix characters in each term. Permalinks generated by | |
| 223 | +** bisect_permalink() use 10-character prefixes, and a real bisect needs | |
| 224 | +** only about log2(N) steps, so these limits do not affect legitimate use. | |
| 225 | +*/ | |
| 226 | +#define BISECT_MAX_TERM 100 | |
| 227 | +#define BISECT_MIN_PREFIX 4 | |
| 228 | + | |
| 219 | 229 | /* |
| 220 | 230 | ** Create a TEMP table named "bilog" that contains the complete history |
| 221 | 231 | ** of the current bisect. |
| 222 | 232 | ** |
| 223 | 233 | ** If iCurrent>0 then it is the RID of the current check-out and is included |
| @@ -227,38 +237,46 @@ | ||
| 227 | 237 | ** that describes a bisect. Use the information in zDesc rather than in |
| 228 | 238 | ** the bisect-log variable. |
| 229 | 239 | ** |
| 230 | 240 | ** If bDetail is true, then also include information about every node |
| 231 | 241 | ** in between the inner-most GOOD and BAD nodes. |
| 242 | +** | |
| 243 | +** The bilog table is always created. Return true if at least one row | |
| 244 | +** was inserted into it, or false if the bilog table is empty. | |
| 232 | 245 | */ |
| 233 | 246 | int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){ |
| 234 | - char *zLog; | |
| 247 | + char *zLog = 0; | |
| 235 | 248 | Blob log, id; |
| 236 | 249 | int cnt = 0; |
| 237 | 250 | int lastGood = -1; |
| 238 | 251 | int lastBad = -1; |
| 239 | 252 | Blob ins = BLOB_INITIALIZER; |
| 240 | 253 | |
| 241 | 254 | if( zDesc!=0 ){ |
| 255 | + int nTerm = 0; | |
| 242 | 256 | blob_init(&log, 0, 0); |
| 243 | - while( zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s' ){ | |
| 257 | + while( (zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s') | |
| 258 | + && nTerm<BISECT_MAX_TERM | |
| 259 | + ){ | |
| 244 | 260 | int i; |
| 245 | 261 | char c; |
| 246 | 262 | int rid; |
| 247 | - if( blob_size(&log) ) blob_append(&log, " ", 1); | |
| 248 | - if( zDesc[0]=='n' ) blob_append(&log, "-", 1); | |
| 249 | - if( zDesc[0]=='s' ) blob_append(&log, "s", 1); | |
| 250 | 263 | for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){} |
| 251 | - if( i==1 ) break; | |
| 264 | + if( i-1<BISECT_MIN_PREFIX ) break; | |
| 265 | + /* Use GLOB, not LIKE, so that the lookup can use the blob.uuid index */ | |
| 252 | 266 | rid = db_int(0, |
| 253 | 267 | "SELECT rid FROM blob" |
| 254 | - " WHERE uuid LIKE '%.*q%%'" | |
| 268 | + " WHERE uuid GLOB '%.*q*'" | |
| 255 | 269 | " AND EXISTS(SELECT 1 FROM plink WHERE cid=rid)", |
| 256 | 270 | i-1, zDesc+1 |
| 257 | 271 | ); |
| 258 | 272 | if( rid==0 ) break; |
| 273 | + if( blob_size(&log) ) blob_append(&log, " ", 1); | |
| 274 | + if( zDesc[0]=='n' ) blob_append(&log, "-", 1); | |
| 275 | + if( zDesc[0]=='s' ) blob_append(&log, "s", 1); | |
| 259 | 276 | blob_appendf(&log, "%d", rid); |
| 277 | + nTerm++; | |
| 260 | 278 | zDesc += i; |
| 261 | 279 | while( zDesc[0]=='-' ) zDesc++; |
| 262 | 280 | } |
| 263 | 281 | }else{ |
| 264 | 282 | zLog = db_lget("bisect-log",""); |
| @@ -299,13 +317,15 @@ | ||
| 299 | 317 | bisect_log_append(&ins, ++cnt, 0, p->rid); |
| 300 | 318 | p = p->u.pTo; |
| 301 | 319 | } |
| 302 | 320 | path_reset(); |
| 303 | 321 | } |
| 304 | - db_exec_sql(blob_sql_text(&ins)); | |
| 322 | + if( cnt>0 ) db_exec_sql(blob_sql_text(&ins)); | |
| 305 | 323 | blob_reset(&ins); |
| 306 | - return 1; | |
| 324 | + blob_reset(&log); | |
| 325 | + fossil_free(zLog); | |
| 326 | + return cnt>0; | |
| 307 | 327 | } |
| 308 | 328 | |
| 309 | 329 | /* Return a permalink description of a bisect. Space is obtained from |
| 310 | 330 | ** fossil_malloc() and should be freed by the caller. |
| 311 | 331 | ** |
| 312 | 332 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -214,10 +214,20 @@ | |
| 214 | }else{ |
| 215 | blob_append_sql(pSql, "(NULL,NULL,%d)", iRid); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | /* |
| 220 | ** Create a TEMP table named "bilog" that contains the complete history |
| 221 | ** of the current bisect. |
| 222 | ** |
| 223 | ** If iCurrent>0 then it is the RID of the current check-out and is included |
| @@ -227,38 +237,46 @@ | |
| 227 | ** that describes a bisect. Use the information in zDesc rather than in |
| 228 | ** the bisect-log variable. |
| 229 | ** |
| 230 | ** If bDetail is true, then also include information about every node |
| 231 | ** in between the inner-most GOOD and BAD nodes. |
| 232 | */ |
| 233 | int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){ |
| 234 | char *zLog; |
| 235 | Blob log, id; |
| 236 | int cnt = 0; |
| 237 | int lastGood = -1; |
| 238 | int lastBad = -1; |
| 239 | Blob ins = BLOB_INITIALIZER; |
| 240 | |
| 241 | if( zDesc!=0 ){ |
| 242 | blob_init(&log, 0, 0); |
| 243 | while( zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s' ){ |
| 244 | int i; |
| 245 | char c; |
| 246 | int rid; |
| 247 | if( blob_size(&log) ) blob_append(&log, " ", 1); |
| 248 | if( zDesc[0]=='n' ) blob_append(&log, "-", 1); |
| 249 | if( zDesc[0]=='s' ) blob_append(&log, "s", 1); |
| 250 | for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){} |
| 251 | if( i==1 ) break; |
| 252 | rid = db_int(0, |
| 253 | "SELECT rid FROM blob" |
| 254 | " WHERE uuid LIKE '%.*q%%'" |
| 255 | " AND EXISTS(SELECT 1 FROM plink WHERE cid=rid)", |
| 256 | i-1, zDesc+1 |
| 257 | ); |
| 258 | if( rid==0 ) break; |
| 259 | blob_appendf(&log, "%d", rid); |
| 260 | zDesc += i; |
| 261 | while( zDesc[0]=='-' ) zDesc++; |
| 262 | } |
| 263 | }else{ |
| 264 | zLog = db_lget("bisect-log",""); |
| @@ -299,13 +317,15 @@ | |
| 299 | bisect_log_append(&ins, ++cnt, 0, p->rid); |
| 300 | p = p->u.pTo; |
| 301 | } |
| 302 | path_reset(); |
| 303 | } |
| 304 | db_exec_sql(blob_sql_text(&ins)); |
| 305 | blob_reset(&ins); |
| 306 | return 1; |
| 307 | } |
| 308 | |
| 309 | /* Return a permalink description of a bisect. Space is obtained from |
| 310 | ** fossil_malloc() and should be freed by the caller. |
| 311 | ** |
| 312 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -214,10 +214,20 @@ | |
| 214 | }else{ |
| 215 | blob_append_sql(pSql, "(NULL,NULL,%d)", iRid); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | /* |
| 220 | ** Limits on the bid= query parameter to /timeline. BISECT_MAX_TERM is |
| 221 | ** the maximum number of terms and BISECT_MIN_PREFIX is the minimum number |
| 222 | ** of hash prefix characters in each term. Permalinks generated by |
| 223 | ** bisect_permalink() use 10-character prefixes, and a real bisect needs |
| 224 | ** only about log2(N) steps, so these limits do not affect legitimate use. |
| 225 | */ |
| 226 | #define BISECT_MAX_TERM 100 |
| 227 | #define BISECT_MIN_PREFIX 4 |
| 228 | |
| 229 | /* |
| 230 | ** Create a TEMP table named "bilog" that contains the complete history |
| 231 | ** of the current bisect. |
| 232 | ** |
| 233 | ** If iCurrent>0 then it is the RID of the current check-out and is included |
| @@ -227,38 +237,46 @@ | |
| 237 | ** that describes a bisect. Use the information in zDesc rather than in |
| 238 | ** the bisect-log variable. |
| 239 | ** |
| 240 | ** If bDetail is true, then also include information about every node |
| 241 | ** in between the inner-most GOOD and BAD nodes. |
| 242 | ** |
| 243 | ** The bilog table is always created. Return true if at least one row |
| 244 | ** was inserted into it, or false if the bilog table is empty. |
| 245 | */ |
| 246 | int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){ |
| 247 | char *zLog = 0; |
| 248 | Blob log, id; |
| 249 | int cnt = 0; |
| 250 | int lastGood = -1; |
| 251 | int lastBad = -1; |
| 252 | Blob ins = BLOB_INITIALIZER; |
| 253 | |
| 254 | if( zDesc!=0 ){ |
| 255 | int nTerm = 0; |
| 256 | blob_init(&log, 0, 0); |
| 257 | while( (zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s') |
| 258 | && nTerm<BISECT_MAX_TERM |
| 259 | ){ |
| 260 | int i; |
| 261 | char c; |
| 262 | int rid; |
| 263 | for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){} |
| 264 | if( i-1<BISECT_MIN_PREFIX ) break; |
| 265 | /* Use GLOB, not LIKE, so that the lookup can use the blob.uuid index */ |
| 266 | rid = db_int(0, |
| 267 | "SELECT rid FROM blob" |
| 268 | " WHERE uuid GLOB '%.*q*'" |
| 269 | " AND EXISTS(SELECT 1 FROM plink WHERE cid=rid)", |
| 270 | i-1, zDesc+1 |
| 271 | ); |
| 272 | if( rid==0 ) break; |
| 273 | if( blob_size(&log) ) blob_append(&log, " ", 1); |
| 274 | if( zDesc[0]=='n' ) blob_append(&log, "-", 1); |
| 275 | if( zDesc[0]=='s' ) blob_append(&log, "s", 1); |
| 276 | blob_appendf(&log, "%d", rid); |
| 277 | nTerm++; |
| 278 | zDesc += i; |
| 279 | while( zDesc[0]=='-' ) zDesc++; |
| 280 | } |
| 281 | }else{ |
| 282 | zLog = db_lget("bisect-log",""); |
| @@ -299,13 +317,15 @@ | |
| 317 | bisect_log_append(&ins, ++cnt, 0, p->rid); |
| 318 | p = p->u.pTo; |
| 319 | } |
| 320 | path_reset(); |
| 321 | } |
| 322 | if( cnt>0 ) db_exec_sql(blob_sql_text(&ins)); |
| 323 | blob_reset(&ins); |
| 324 | blob_reset(&log); |
| 325 | fossil_free(zLog); |
| 326 | return cnt>0; |
| 327 | } |
| 328 | |
| 329 | /* Return a permalink description of a bisect. Space is obtained from |
| 330 | ** fossil_malloc() and should be freed by the caller. |
| 331 | ** |
| 332 |
+4
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -2188,10 +2188,14 @@ | ||
| 2188 | 2188 | style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm); |
| 2189 | 2189 | } |
| 2190 | 2190 | }else{ |
| 2191 | 2191 | bisectLocal = 0; |
| 2192 | 2192 | } |
| 2193 | + if( zBisect!=0 && bisectLocal ){ | |
| 2194 | + zBisect = 0; /* bisect=1 takes precedence over bid= */ | |
| 2195 | + } | |
| 2196 | + if( zBisect!=0 && robot_restrict("timelineX") ) return; | |
| 2193 | 2197 | if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){ |
| 2194 | 2198 | tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS; |
| 2195 | 2199 | zType = "ci"; |
| 2196 | 2200 | disableY = 1; |
| 2197 | 2201 | }else{ |
| 2198 | 2202 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -2188,10 +2188,14 @@ | |
| 2188 | style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm); |
| 2189 | } |
| 2190 | }else{ |
| 2191 | bisectLocal = 0; |
| 2192 | } |
| 2193 | if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){ |
| 2194 | tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS; |
| 2195 | zType = "ci"; |
| 2196 | disableY = 1; |
| 2197 | }else{ |
| 2198 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -2188,10 +2188,14 @@ | |
| 2188 | style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm); |
| 2189 | } |
| 2190 | }else{ |
| 2191 | bisectLocal = 0; |
| 2192 | } |
| 2193 | if( zBisect!=0 && bisectLocal ){ |
| 2194 | zBisect = 0; /* bisect=1 takes precedence over bid= */ |
| 2195 | } |
| 2196 | if( zBisect!=0 && robot_restrict("timelineX") ) return; |
| 2197 | if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){ |
| 2198 | tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS; |
| 2199 | zType = "ci"; |
| 2200 | disableY = 1; |
| 2201 | }else{ |
| 2202 |