Fossil SCM

Performance improvements to the bid= query parameter of /timeline.

drh 2026-10-17 13:14 UTC trunk
Commit 912711f044b83f4083ceda7b5f0927a35bb4ef6ffb48cf0c03bfaf062b9ab0ce
2 files changed +29 -9 +4
+29 -9
--- src/bisect.c
+++ src/bisect.c
@@ -214,10 +214,20 @@
214214
}else{
215215
blob_append_sql(pSql, "(NULL,NULL,%d)", iRid);
216216
}
217217
}
218218
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
+
219229
/*
220230
** Create a TEMP table named "bilog" that contains the complete history
221231
** of the current bisect.
222232
**
223233
** If iCurrent>0 then it is the RID of the current check-out and is included
@@ -227,38 +237,46 @@
227237
** that describes a bisect. Use the information in zDesc rather than in
228238
** the bisect-log variable.
229239
**
230240
** If bDetail is true, then also include information about every node
231241
** 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.
232245
*/
233246
int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){
234
- char *zLog;
247
+ char *zLog = 0;
235248
Blob log, id;
236249
int cnt = 0;
237250
int lastGood = -1;
238251
int lastBad = -1;
239252
Blob ins = BLOB_INITIALIZER;
240253
241254
if( zDesc!=0 ){
255
+ int nTerm = 0;
242256
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
+ ){
244260
int i;
245261
char c;
246262
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);
250263
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 */
252266
rid = db_int(0,
253267
"SELECT rid FROM blob"
254
- " WHERE uuid LIKE '%.*q%%'"
268
+ " WHERE uuid GLOB '%.*q*'"
255269
" AND EXISTS(SELECT 1 FROM plink WHERE cid=rid)",
256270
i-1, zDesc+1
257271
);
258272
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);
259276
blob_appendf(&log, "%d", rid);
277
+ nTerm++;
260278
zDesc += i;
261279
while( zDesc[0]=='-' ) zDesc++;
262280
}
263281
}else{
264282
zLog = db_lget("bisect-log","");
@@ -299,13 +317,15 @@
299317
bisect_log_append(&ins, ++cnt, 0, p->rid);
300318
p = p->u.pTo;
301319
}
302320
path_reset();
303321
}
304
- db_exec_sql(blob_sql_text(&ins));
322
+ if( cnt>0 ) db_exec_sql(blob_sql_text(&ins));
305323
blob_reset(&ins);
306
- return 1;
324
+ blob_reset(&log);
325
+ fossil_free(zLog);
326
+ return cnt>0;
307327
}
308328
309329
/* Return a permalink description of a bisect. Space is obtained from
310330
** fossil_malloc() and should be freed by the caller.
311331
**
312332
--- 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
--- src/timeline.c
+++ src/timeline.c
@@ -2188,10 +2188,14 @@
21882188
style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm);
21892189
}
21902190
}else{
21912191
bisectLocal = 0;
21922192
}
2193
+ if( zBisect!=0 && bisectLocal ){
2194
+ zBisect = 0; /* bisect=1 takes precedence over bid= */
2195
+ }
2196
+ if( zBisect!=0 && robot_restrict("timelineX") ) return;
21932197
if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){
21942198
tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
21952199
zType = "ci";
21962200
disableY = 1;
21972201
}else{
21982202
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button