Git fork

reftable/block: make block iterators reseekable

Refactor the block iterators so that initialization and seeking are
different from one another. This makes the iterator trivially reseekable
by storing the pointer to the block at initialization time, which we can
then reuse on every seek.

This refactoring prepares the code for exposing a `reftable_iterator`
interface for blocks in a subsequent commit. Callsites are adjusted
accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
6da48a5e 156d79ce

+48 -35
+13 -10
reftable/block.c
··· 381 381 return reftable_get_be24(b->block_data.data + b->restart_off + 3 * idx); 382 382 } 383 383 384 - void block_iter_seek_start(struct block_iter *it, const struct reftable_block *block) 384 + void block_iter_init(struct block_iter *it, const struct reftable_block *block) 385 385 { 386 386 it->block = block; 387 + block_iter_seek_start(it); 388 + } 389 + 390 + void block_iter_seek_start(struct block_iter *it) 391 + { 387 392 reftable_buf_reset(&it->last_key); 388 - it->next_off = block->header_off + 4; 393 + it->next_off = it->block->header_off + 4; 389 394 } 390 395 391 396 struct restart_needle_less_args { ··· 473 478 reftable_buf_release(&it->scratch); 474 479 } 475 480 476 - int block_iter_seek_key(struct block_iter *it, const struct reftable_block *block, 477 - struct reftable_buf *want) 481 + int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want) 478 482 { 479 483 struct restart_needle_less_args args = { 480 484 .needle = *want, 481 - .block = block, 485 + .block = it->block, 482 486 }; 483 487 struct reftable_record rec; 484 488 int err = 0; ··· 496 500 * restart point. While that works alright, we would end up scanning 497 501 * too many record. 498 502 */ 499 - i = binsearch(block->restart_count, &restart_needle_less, &args); 503 + i = binsearch(it->block->restart_count, &restart_needle_less, &args); 500 504 if (args.error) { 501 505 err = REFTABLE_FORMAT_ERROR; 502 506 goto done; ··· 521 525 * starting from the preceding restart point. 522 526 */ 523 527 if (i > 0) 524 - it->next_off = block_restart_offset(block, i - 1); 528 + it->next_off = block_restart_offset(it->block, i - 1); 525 529 else 526 - it->next_off = block->header_off + 4; 527 - it->block = block; 530 + it->next_off = it->block->header_off + 4; 528 531 529 - err = reftable_record_init(&rec, reftable_block_type(block)); 532 + err = reftable_record_init(&rec, reftable_block_type(it->block)); 530 533 if (err < 0) 531 534 goto done; 532 535
+16 -5
reftable/block.h
··· 79 79 .scratch = REFTABLE_BUF_INIT, \ 80 80 } 81 81 82 - /* Position `it` at start of the block */ 83 - void block_iter_seek_start(struct block_iter *it, const struct reftable_block *block); 82 + /* 83 + * Initialize the block iterator with the given block. The iterator will be 84 + * positioned at the first record contained in the block. The block must remain 85 + * valid until the end of the iterator's lifetime. It is valid to re-initialize 86 + * iterators multiple times. 87 + */ 88 + void block_iter_init(struct block_iter *it, const struct reftable_block *block); 89 + 90 + /* Position the initialized iterator at the first record of its block. */ 91 + void block_iter_seek_start(struct block_iter *it); 84 92 85 - /* Position `it` to the `want` key in the block */ 86 - int block_iter_seek_key(struct block_iter *it, const struct reftable_block *block, 87 - struct reftable_buf *want); 93 + /* 94 + * Position the initialized iterator at the desired record key. It is not an 95 + * error in case the record cannot be found. If so, a subsequent call to 96 + * `block_iter_next()` will indicate that the iterator is exhausted. 97 + */ 98 + int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want); 88 99 89 100 /* return < 0 for error, 0 for OK, > 0 for EOF. */ 90 101 int block_iter_next(struct block_iter *it, struct reftable_record *rec);
+1 -1
reftable/iter.c
··· 139 139 /* indexed block does not exist. */ 140 140 return REFTABLE_FORMAT_ERROR; 141 141 } 142 - block_iter_seek_start(&it->cur, &it->block); 142 + block_iter_init(&it->cur, &it->block); 143 143 return 0; 144 144 } 145 145
+7 -4
reftable/table.c
··· 208 208 209 209 ti->block_off = next_block_off; 210 210 ti->is_finished = 0; 211 - block_iter_seek_start(&ti->bi, &ti->block); 211 + block_iter_init(&ti->bi, &ti->block); 212 212 213 213 return 0; 214 214 } ··· 256 256 257 257 ti->typ = reftable_block_type(&ti->block); 258 258 ti->block_off = off; 259 - block_iter_seek_start(&ti->bi, &ti->block); 259 + block_iter_init(&ti->bi, &ti->block); 260 260 ti->is_finished = 0; 261 261 return 0; 262 262 } ··· 349 349 * the wanted key inside of it. If the block does not contain our key 350 350 * we know that the corresponding record does not exist. 351 351 */ 352 - err = block_iter_seek_key(&ti->bi, &ti->block, &want_key); 352 + block_iter_init(&ti->bi, &ti->block); 353 + err = block_iter_seek_key(&ti->bi, &want_key); 353 354 if (err < 0) 354 355 goto done; 355 356 err = 0; ··· 417 418 if (err != 0) 418 419 goto done; 419 420 420 - err = block_iter_seek_key(&ti->bi, &ti->block, &want_index.u.idx.last_key); 421 + block_iter_init(&ti->bi, &ti->block); 422 + 423 + err = block_iter_seek_key(&ti->bi, &want_index.u.idx.last_key); 421 424 if (err < 0) 422 425 goto done; 423 426
+11 -15
t/unit-tests/t-reftable-block.c
··· 66 66 block_source_from_buf(&source ,&block_data); 67 67 reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); 68 68 69 - block_iter_seek_start(&it, &block); 69 + block_iter_init(&it, &block); 70 70 71 71 for (i = 0; ; i++) { 72 72 ret = block_iter_next(&it, &rec); ··· 79 79 } 80 80 81 81 for (i = 0; i < N; i++) { 82 - block_iter_reset(&it); 83 82 reftable_record_key(&recs[i], &want); 84 83 85 - ret = block_iter_seek_key(&it, &block, &want); 84 + ret = block_iter_seek_key(&it, &want); 86 85 check_int(ret, ==, 0); 87 86 88 87 ret = block_iter_next(&it, &rec); ··· 91 90 check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); 92 91 93 92 want.len--; 94 - ret = block_iter_seek_key(&it, &block, &want); 93 + ret = block_iter_seek_key(&it, &want); 95 94 check_int(ret, ==, 0); 96 95 97 96 ret = block_iter_next(&it, &rec); ··· 156 155 block_source_from_buf(&source, &block_data); 157 156 reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); 158 157 159 - block_iter_seek_start(&it, &block); 158 + block_iter_init(&it, &block); 160 159 161 160 for (i = 0; ; i++) { 162 161 ret = block_iter_next(&it, &rec); ··· 169 168 } 170 169 171 170 for (i = 0; i < N; i++) { 172 - block_iter_reset(&it); 173 171 reftable_buf_reset(&want); 174 172 check(!reftable_buf_addstr(&want, recs[i].u.log.refname)); 175 173 176 - ret = block_iter_seek_key(&it, &block, &want); 174 + ret = block_iter_seek_key(&it, &want); 177 175 check_int(ret, ==, 0); 178 176 179 177 ret = block_iter_next(&it, &rec); ··· 182 180 check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); 183 181 184 182 want.len--; 185 - ret = block_iter_seek_key(&it, &block, &want); 183 + ret = block_iter_seek_key(&it, &want); 186 184 check_int(ret, ==, 0); 187 185 188 186 ret = block_iter_next(&it, &rec); ··· 249 247 block_source_from_buf(&source, &block_data); 250 248 reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); 251 249 252 - block_iter_seek_start(&it, &block); 250 + block_iter_init(&it, &block); 253 251 254 252 for (i = 0; ; i++) { 255 253 ret = block_iter_next(&it, &rec); ··· 262 260 } 263 261 264 262 for (i = 0; i < N; i++) { 265 - block_iter_reset(&it); 266 263 reftable_record_key(&recs[i], &want); 267 264 268 - ret = block_iter_seek_key(&it, &block, &want); 265 + ret = block_iter_seek_key(&it, &want); 269 266 check_int(ret, ==, 0); 270 267 271 268 ret = block_iter_next(&it, &rec); ··· 334 331 block_source_from_buf(&source, &block_data); 335 332 reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); 336 333 337 - block_iter_seek_start(&it, &block); 334 + block_iter_init(&it, &block); 338 335 339 336 for (i = 0; ; i++) { 340 337 ret = block_iter_next(&it, &rec); ··· 347 344 } 348 345 349 346 for (i = 0; i < N; i++) { 350 - block_iter_reset(&it); 351 347 reftable_record_key(&recs[i], &want); 352 348 353 - ret = block_iter_seek_key(&it, &block, &want); 349 + ret = block_iter_seek_key(&it, &want); 354 350 check_int(ret, ==, 0); 355 351 356 352 ret = block_iter_next(&it, &rec); ··· 359 355 check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); 360 356 361 357 want.len--; 362 - ret = block_iter_seek_key(&it, &block, &want); 358 + ret = block_iter_seek_key(&it, &want); 363 359 check_int(ret, ==, 0); 364 360 365 361 ret = block_iter_next(&it, &rec);