Skip to content

Commit 17636cd

Browse files
committed
Merge branch 'ps/reftable-concurrent-compaction'
The code path for compacting reftable files saw some bugfixes against concurrent operation. * ps/reftable-concurrent-compaction: reftable/stack: fix segfault when reload with reused readers fails reftable/stack: reorder swapping in the reloaded stack contents reftable/reader: keep readers alive during iteration reftable/reader: introduce refcounting reftable/stack: fix broken refnames in `write_n_ref_tables()` reftable/reader: inline `reader_close()` reftable/reader: inline `init_reader()` reftable/reader: rename `reftable_new_reader()` reftable/stack: inline `stack_compact_range_stats()` reftable/blocksource: drop malloc block source
2 parents dd90365 + 85da2a2 commit 17636cd

File tree

11 files changed

+316
-194
lines changed

11 files changed

+316
-194
lines changed

reftable/blocksource.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,6 @@ void block_source_from_strbuf(struct reftable_block_source *bs,
5555
bs->arg = buf;
5656
}
5757

58-
static void malloc_return_block(void *b UNUSED, struct reftable_block *dest)
59-
{
60-
if (dest->len)
61-
memset(dest->data, 0xff, dest->len);
62-
reftable_free(dest->data);
63-
}
64-
65-
static struct reftable_block_source_vtable malloc_vtable = {
66-
.return_block = &malloc_return_block,
67-
};
68-
69-
static struct reftable_block_source malloc_block_source_instance = {
70-
.ops = &malloc_vtable,
71-
};
72-
73-
struct reftable_block_source malloc_block_source(void)
74-
{
75-
return malloc_block_source_instance;
76-
}
77-
7858
struct file_block_source {
7959
uint64_t size;
8060
unsigned char *data;

reftable/blocksource.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,4 @@ struct reftable_block_source;
1717
void block_source_from_strbuf(struct reftable_block_source *bs,
1818
struct strbuf *buf);
1919

20-
struct reftable_block_source malloc_block_source(void);
21-
2220
#endif

reftable/reader.c

Lines changed: 79 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -162,58 +162,6 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
162162
return err;
163163
}
164164

165-
int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
166-
const char *name)
167-
{
168-
struct reftable_block footer = { NULL };
169-
struct reftable_block header = { NULL };
170-
int err = 0;
171-
uint64_t file_size = block_source_size(source);
172-
173-
/* Need +1 to read type of first block. */
174-
uint32_t read_size = header_size(2) + 1; /* read v2 because it's larger. */
175-
memset(r, 0, sizeof(struct reftable_reader));
176-
177-
if (read_size > file_size) {
178-
err = REFTABLE_FORMAT_ERROR;
179-
goto done;
180-
}
181-
182-
err = block_source_read_block(source, &header, 0, read_size);
183-
if (err != read_size) {
184-
err = REFTABLE_IO_ERROR;
185-
goto done;
186-
}
187-
188-
if (memcmp(header.data, "REFT", 4)) {
189-
err = REFTABLE_FORMAT_ERROR;
190-
goto done;
191-
}
192-
r->version = header.data[4];
193-
if (r->version != 1 && r->version != 2) {
194-
err = REFTABLE_FORMAT_ERROR;
195-
goto done;
196-
}
197-
198-
r->size = file_size - footer_size(r->version);
199-
r->source = *source;
200-
r->name = xstrdup(name);
201-
r->hash_id = 0;
202-
203-
err = block_source_read_block(source, &footer, r->size,
204-
footer_size(r->version));
205-
if (err != footer_size(r->version)) {
206-
err = REFTABLE_IO_ERROR;
207-
goto done;
208-
}
209-
210-
err = parse_footer(r, footer.data, header.data);
211-
done:
212-
reftable_block_done(&footer);
213-
reftable_block_done(&header);
214-
return err;
215-
}
216-
217165
struct table_iter {
218166
struct reftable_reader *r;
219167
uint8_t typ;
@@ -227,6 +175,7 @@ static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
227175
{
228176
struct block_iter bi = BLOCK_ITER_INIT;
229177
memset(ti, 0, sizeof(*ti));
178+
reftable_reader_incref(r);
230179
ti->r = r;
231180
ti->bi = bi;
232181
return 0;
@@ -314,6 +263,7 @@ static void table_iter_close(struct table_iter *ti)
314263
{
315264
table_iter_block_done(ti);
316265
block_iter_close(&ti->bi);
266+
reftable_reader_decref(ti->r);
317267
}
318268

319269
static int table_iter_next_block(struct table_iter *ti)
@@ -631,31 +581,90 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
631581
reader_init_iter(r, it, BLOCK_TYPE_LOG);
632582
}
633583

634-
void reader_close(struct reftable_reader *r)
584+
int reftable_reader_new(struct reftable_reader **out,
585+
struct reftable_block_source *source, char const *name)
635586
{
636-
block_source_close(&r->source);
637-
FREE_AND_NULL(r->name);
638-
}
587+
struct reftable_block footer = { 0 };
588+
struct reftable_block header = { 0 };
589+
struct reftable_reader *r;
590+
uint64_t file_size = block_source_size(source);
591+
uint32_t read_size;
592+
int err;
639593

640-
int reftable_new_reader(struct reftable_reader **p,
641-
struct reftable_block_source *src, char const *name)
642-
{
643-
struct reftable_reader *rd = reftable_calloc(1, sizeof(*rd));
644-
int err = init_reader(rd, src, name);
645-
if (err == 0) {
646-
*p = rd;
647-
} else {
648-
block_source_close(src);
649-
reftable_free(rd);
594+
REFTABLE_CALLOC_ARRAY(r, 1);
595+
596+
/*
597+
* We need one extra byte to read the type of first block. We also
598+
* pretend to always be reading v2 of the format because it is larger.
599+
*/
600+
read_size = header_size(2) + 1;
601+
if (read_size > file_size) {
602+
err = REFTABLE_FORMAT_ERROR;
603+
goto done;
604+
}
605+
606+
err = block_source_read_block(source, &header, 0, read_size);
607+
if (err != read_size) {
608+
err = REFTABLE_IO_ERROR;
609+
goto done;
610+
}
611+
612+
if (memcmp(header.data, "REFT", 4)) {
613+
err = REFTABLE_FORMAT_ERROR;
614+
goto done;
615+
}
616+
r->version = header.data[4];
617+
if (r->version != 1 && r->version != 2) {
618+
err = REFTABLE_FORMAT_ERROR;
619+
goto done;
620+
}
621+
622+
r->size = file_size - footer_size(r->version);
623+
r->source = *source;
624+
r->name = xstrdup(name);
625+
r->hash_id = 0;
626+
r->refcount = 1;
627+
628+
err = block_source_read_block(source, &footer, r->size,
629+
footer_size(r->version));
630+
if (err != footer_size(r->version)) {
631+
err = REFTABLE_IO_ERROR;
632+
goto done;
633+
}
634+
635+
err = parse_footer(r, footer.data, header.data);
636+
if (err)
637+
goto done;
638+
639+
*out = r;
640+
641+
done:
642+
reftable_block_done(&footer);
643+
reftable_block_done(&header);
644+
if (err) {
645+
reftable_free(r);
646+
block_source_close(source);
650647
}
651648
return err;
652649
}
653650

654-
void reftable_reader_free(struct reftable_reader *r)
651+
void reftable_reader_incref(struct reftable_reader *r)
652+
{
653+
if (!r->refcount)
654+
BUG("cannot increment ref counter of dead reader");
655+
r->refcount++;
656+
}
657+
658+
void reftable_reader_decref(struct reftable_reader *r)
655659
{
656660
if (!r)
657661
return;
658-
reader_close(r);
662+
if (!r->refcount)
663+
BUG("cannot decrement ref counter of dead reader");
664+
if (--r->refcount)
665+
return;
666+
block_source_close(&r->source);
667+
FREE_AND_NULL(r->name);
659668
reftable_free(r);
660669
}
661670

@@ -786,7 +795,7 @@ int reftable_reader_print_blocks(const char *tablename)
786795
if (err < 0)
787796
goto done;
788797

789-
err = reftable_new_reader(&r, &src, tablename);
798+
err = reftable_reader_new(&r, &src, tablename);
790799
if (err < 0)
791800
goto done;
792801

@@ -817,7 +826,7 @@ int reftable_reader_print_blocks(const char *tablename)
817826
}
818827

819828
done:
820-
reftable_reader_free(r);
829+
reftable_reader_decref(r);
821830
table_iter_close(&ti);
822831
return err;
823832
}

reftable/reader.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ struct reftable_reader {
5050
struct reftable_reader_offsets ref_offsets;
5151
struct reftable_reader_offsets obj_offsets;
5252
struct reftable_reader_offsets log_offsets;
53+
54+
uint64_t refcount;
5355
};
5456

55-
int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
56-
const char *name);
57-
void reader_close(struct reftable_reader *r);
5857
const char *reader_name(struct reftable_reader *r);
5958

6059
void reader_init_iter(struct reftable_reader *r,

reftable/reftable-reader.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,28 @@
2323
/* The reader struct is a handle to an open reftable file. */
2424
struct reftable_reader;
2525

26-
/* reftable_new_reader opens a reftable for reading. If successful,
26+
/* reftable_reader_new opens a reftable for reading. If successful,
2727
* returns 0 code and sets pp. The name is used for creating a
2828
* stack. Typically, it is the basename of the file. The block source
2929
* `src` is owned by the reader, and is closed on calling
3030
* reftable_reader_destroy(). On error, the block source `src` is
3131
* closed as well.
3232
*/
33-
int reftable_new_reader(struct reftable_reader **pp,
33+
int reftable_reader_new(struct reftable_reader **pp,
3434
struct reftable_block_source *src, const char *name);
3535

36+
/*
37+
* Manage the reference count of the reftable reader. A newly initialized
38+
* reader starts with a refcount of 1 and will be deleted once the refcount has
39+
* reached 0.
40+
*
41+
* This is required because readers may have longer lifetimes than the stack
42+
* they belong to. The stack may for example be reloaded while the old tables
43+
* are still being accessed by an iterator.
44+
*/
45+
void reftable_reader_incref(struct reftable_reader *reader);
46+
void reftable_reader_decref(struct reftable_reader *reader);
47+
3648
/* Initialize a reftable iterator for reading refs. */
3749
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
3850
struct reftable_iterator *it);
@@ -44,9 +56,6 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
4456
/* returns the hash ID used in this table. */
4557
uint32_t reftable_reader_hash_id(struct reftable_reader *r);
4658

47-
/* closes and deallocates a reader. */
48-
void reftable_reader_free(struct reftable_reader *);
49-
5059
/* return an iterator for the refs pointing to `oid`. */
5160
int reftable_reader_refs_for(struct reftable_reader *r,
5261
struct reftable_iterator *it, uint8_t *oid);

0 commit comments

Comments
 (0)