Skip to content

Commit 9da5c99

Browse files
pks-tgitster
authored andcommitted
reftable/block: avoid copying block iterators on seek
When seeking a reftable record in a block we need to position the iterator _before_ the sought-after record so that the next call to `block_iter_next()` would yield that record. To achieve this, the loop that performs the linear seeks to restore the previous position once it has found the record. This is done by advancing two `block_iter`s: one to check whether the next record is our sought-after record, and one that we update after every iteration. This of course involves quite a lot of copying and also leads to needless memory allocations. Refactor the code to get rid of the `next` iterator and the copying this involves. Instead, we can restore the previous offset such that the call to `next` will return the correct record. Next to being simpler conceptually this also leads to a nice speedup. The following benchmark parser 10k refs out of 100k existing refs via `git-rev-list --no-walk`: Benchmark 1: rev-list: print many refs (HEAD~) Time (mean ± σ): 170.2 ms ± 1.7 ms [User: 86.1 ms, System: 83.6 ms] Range (min … max): 166.4 ms … 180.3 ms 500 runs Benchmark 2: rev-list: print many refs (HEAD~) Time (mean ± σ): 161.6 ms ± 1.6 ms [User: 78.1 ms, System: 83.0 ms] Range (min … max): 158.4 ms … 172.3 ms 500 runs Summary rev-list: print many refs (HEAD) ran 1.05 ± 0.01 times faster than rev-list: print many refs (HEAD~) Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ce1f213 commit 9da5c99

File tree

2 files changed

+14
-20
lines changed

2 files changed

+14
-20
lines changed

reftable/block.c

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -365,16 +365,6 @@ static int restart_needle_less(size_t idx, void *_args)
365365
return args->needle.len < suffix_len;
366366
}
367367

368-
void block_iter_copy_from(struct block_iter *dest, const struct block_iter *src)
369-
{
370-
dest->block = src->block;
371-
dest->block_len = src->block_len;
372-
dest->hash_size = src->hash_size;
373-
dest->next_off = src->next_off;
374-
strbuf_reset(&dest->last_key);
375-
strbuf_addbuf(&dest->last_key, &src->last_key);
376-
}
377-
378368
int block_iter_next(struct block_iter *it, struct reftable_record *rec)
379369
{
380370
struct string_view in = {
@@ -427,7 +417,6 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
427417
.needle = *want,
428418
.reader = br,
429419
};
430-
struct block_iter next = BLOCK_ITER_INIT;
431420
struct reftable_record rec;
432421
int err = 0;
433422
size_t i;
@@ -486,11 +475,13 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
486475
* far and then back up.
487476
*/
488477
while (1) {
489-
block_iter_copy_from(&next, it);
490-
err = block_iter_next(&next, &rec);
478+
size_t prev_off = it->next_off;
479+
480+
err = block_iter_next(it, &rec);
491481
if (err < 0)
492482
goto done;
493483
if (err > 0) {
484+
it->next_off = prev_off;
494485
err = 0;
495486
goto done;
496487
}
@@ -501,18 +492,23 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
501492
* record does not exist in the block and can thus abort early.
502493
* In case it is equal to the sought-after key we have found
503494
* the desired record.
495+
*
496+
* Note that we store the next record's key record directly in
497+
* `last_key` without restoring the key of the preceding record
498+
* in case we need to go one record back. This is safe to do as
499+
* `block_iter_next()` would return the ref whose key is equal
500+
* to `last_key` now, and naturally all keys share a prefix
501+
* with themselves.
504502
*/
505503
reftable_record_key(&rec, &it->last_key);
506-
if (strbuf_cmp(&it->last_key, want) >= 0)
504+
if (strbuf_cmp(&it->last_key, want) >= 0) {
505+
it->next_off = prev_off;
507506
goto done;
508-
509-
block_iter_copy_from(it, &next);
507+
}
510508
}
511509

512510
done:
513-
block_iter_close(&next);
514511
reftable_record_release(&rec);
515-
516512
return err;
517513
}
518514

reftable/block.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ void block_iter_seek_start(struct block_iter *it, const struct block_reader *br)
121121
int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
122122
struct strbuf *want);
123123

124-
void block_iter_copy_from(struct block_iter *dest, const struct block_iter *src);
125-
126124
/* return < 0 for error, 0 for OK, > 0 for EOF. */
127125
int block_iter_next(struct block_iter *it, struct reftable_record *rec);
128126

0 commit comments

Comments
 (0)