reftable/reader: keep readers alive during iteration
The lifetime of a table iterator may survive the lifetime of a reader when the stack gets reloaded. Keep the reader from being released by increasing its refcount while the iterator is still being used. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
d857469d85
commit
89eada4ea1
@ -175,6 +175,7 @@ static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
|
||||
{
|
||||
struct block_iter bi = BLOCK_ITER_INIT;
|
||||
memset(ti, 0, sizeof(*ti));
|
||||
reftable_reader_incref(r);
|
||||
ti->r = r;
|
||||
ti->bi = bi;
|
||||
return 0;
|
||||
@ -262,6 +263,7 @@ static void table_iter_close(struct table_iter *ti)
|
||||
{
|
||||
table_iter_block_done(ti);
|
||||
block_iter_close(&ti->bi);
|
||||
reftable_reader_decref(ti->r);
|
||||
}
|
||||
|
||||
static int table_iter_next_block(struct table_iter *ti)
|
||||
|
@ -1076,6 +1076,55 @@ static void test_reftable_stack_compaction_concurrent_clean(void)
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static void test_reftable_stack_read_across_reload(void)
|
||||
{
|
||||
struct reftable_write_options opts = { 0 };
|
||||
struct reftable_stack *st1 = NULL, *st2 = NULL;
|
||||
struct reftable_ref_record rec = { 0 };
|
||||
struct reftable_iterator it = { 0 };
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
int err;
|
||||
|
||||
/* Create a first stack and set up an iterator for it. */
|
||||
err = reftable_new_stack(&st1, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
write_n_ref_tables(st1, 2);
|
||||
EXPECT(st1->merged->readers_len == 2);
|
||||
reftable_stack_init_ref_iterator(st1, &it);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
EXPECT_ERR(err);
|
||||
|
||||
/* Set up a second stack for the same directory and compact it. */
|
||||
err = reftable_new_stack(&st2, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st2->merged->readers_len == 2);
|
||||
err = reftable_stack_compact_all(st2, NULL);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st2->merged->readers_len == 1);
|
||||
|
||||
/*
|
||||
* Verify that we can continue to use the old iterator even after we
|
||||
* have reloaded its stack.
|
||||
*/
|
||||
err = reftable_stack_reload(st1);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st1->merged->readers_len == 1);
|
||||
err = reftable_iterator_next_ref(&it, &rec);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(!strcmp(rec.refname, "refs/heads/branch-0000"));
|
||||
err = reftable_iterator_next_ref(&it, &rec);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(!strcmp(rec.refname, "refs/heads/branch-0001"));
|
||||
err = reftable_iterator_next_ref(&it, &rec);
|
||||
EXPECT(err > 0);
|
||||
|
||||
reftable_ref_record_release(&rec);
|
||||
reftable_iterator_destroy(&it);
|
||||
reftable_stack_destroy(st1);
|
||||
reftable_stack_destroy(st2);
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
int stack_test_main(int argc, const char *argv[])
|
||||
{
|
||||
RUN_TEST(test_empty_add);
|
||||
@ -1098,6 +1147,7 @@ int stack_test_main(int argc, const char *argv[])
|
||||
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
|
||||
RUN_TEST(test_reftable_stack_update_index_check);
|
||||
RUN_TEST(test_reftable_stack_uptodate);
|
||||
RUN_TEST(test_reftable_stack_read_across_reload);
|
||||
RUN_TEST(test_suggest_compaction_segment);
|
||||
RUN_TEST(test_suggest_compaction_segment_nothing);
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user