Skip to content

Commit 89eada4

Browse files
pks-tgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d857469 commit 89eada4

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

reftable/reader.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
175175
{
176176
struct block_iter bi = BLOCK_ITER_INIT;
177177
memset(ti, 0, sizeof(*ti));
178+
reftable_reader_incref(r);
178179
ti->r = r;
179180
ti->bi = bi;
180181
return 0;
@@ -262,6 +263,7 @@ static void table_iter_close(struct table_iter *ti)
262263
{
263264
table_iter_block_done(ti);
264265
block_iter_close(&ti->bi);
266+
reftable_reader_decref(ti->r);
265267
}
266268

267269
static int table_iter_next_block(struct table_iter *ti)

reftable/stack_test.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,55 @@ static void test_reftable_stack_compaction_concurrent_clean(void)
10761076
clear_dir(dir);
10771077
}
10781078

1079+
static void test_reftable_stack_read_across_reload(void)
1080+
{
1081+
struct reftable_write_options opts = { 0 };
1082+
struct reftable_stack *st1 = NULL, *st2 = NULL;
1083+
struct reftable_ref_record rec = { 0 };
1084+
struct reftable_iterator it = { 0 };
1085+
char *dir = get_tmp_dir(__LINE__);
1086+
int err;
1087+
1088+
/* Create a first stack and set up an iterator for it. */
1089+
err = reftable_new_stack(&st1, dir, &opts);
1090+
EXPECT_ERR(err);
1091+
write_n_ref_tables(st1, 2);
1092+
EXPECT(st1->merged->readers_len == 2);
1093+
reftable_stack_init_ref_iterator(st1, &it);
1094+
err = reftable_iterator_seek_ref(&it, "");
1095+
EXPECT_ERR(err);
1096+
1097+
/* Set up a second stack for the same directory and compact it. */
1098+
err = reftable_new_stack(&st2, dir, &opts);
1099+
EXPECT_ERR(err);
1100+
EXPECT(st2->merged->readers_len == 2);
1101+
err = reftable_stack_compact_all(st2, NULL);
1102+
EXPECT_ERR(err);
1103+
EXPECT(st2->merged->readers_len == 1);
1104+
1105+
/*
1106+
* Verify that we can continue to use the old iterator even after we
1107+
* have reloaded its stack.
1108+
*/
1109+
err = reftable_stack_reload(st1);
1110+
EXPECT_ERR(err);
1111+
EXPECT(st1->merged->readers_len == 1);
1112+
err = reftable_iterator_next_ref(&it, &rec);
1113+
EXPECT_ERR(err);
1114+
EXPECT(!strcmp(rec.refname, "refs/heads/branch-0000"));
1115+
err = reftable_iterator_next_ref(&it, &rec);
1116+
EXPECT_ERR(err);
1117+
EXPECT(!strcmp(rec.refname, "refs/heads/branch-0001"));
1118+
err = reftable_iterator_next_ref(&it, &rec);
1119+
EXPECT(err > 0);
1120+
1121+
reftable_ref_record_release(&rec);
1122+
reftable_iterator_destroy(&it);
1123+
reftable_stack_destroy(st1);
1124+
reftable_stack_destroy(st2);
1125+
clear_dir(dir);
1126+
}
1127+
10791128
int stack_test_main(int argc, const char *argv[])
10801129
{
10811130
RUN_TEST(test_empty_add);
@@ -1098,6 +1147,7 @@ int stack_test_main(int argc, const char *argv[])
10981147
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
10991148
RUN_TEST(test_reftable_stack_update_index_check);
11001149
RUN_TEST(test_reftable_stack_uptodate);
1150+
RUN_TEST(test_reftable_stack_read_across_reload);
11011151
RUN_TEST(test_suggest_compaction_segment);
11021152
RUN_TEST(test_suggest_compaction_segment_nothing);
11031153
return 0;

0 commit comments

Comments
 (0)