reftable: make reftable_record a tagged union
This reduces the amount of glue code, because we don't need a void pointer or vtable within the structure. The only snag is that reftable_index_record contain a strbuf, so it cannot be zero-initialized. To address this, use reftable_new_record() to return fresh instance, given a record type. Since reftable_new_record() doesn't cause heap allocation anymore, it should be balanced with reftable_record_release() rather than reftable_record_destroy(). Thanks to Peff for the suggestion. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Han-Wen Nienhuys committed
Jan 20, 2022 at 15:12 UTC
66c0dabab5e15f78d0505be36cac4a383e14cf88
12 files changed
+334
-337
reftable/block.c
+1
-1
@@ -421,7 +421,7 @@ int block_reader_seek(struct block_reader *br, struct block_iter *it,
421
done:
422
strbuf_release(&key);
423
strbuf_release(&next.last_key);
424
- reftable_record_destroy(&rec);
424
+ reftable_record_release(&rec);
425
426
return err;
427
}
reftable/block_test.c
+11
-11
@@ -26,8 +26,9 @@ static void test_block_read_write(void)
26
struct block_writer bw = {
27
.last_key = STRBUF_INIT,
28
};
29
- struct reftable_ref_record ref = { NULL };
30
- struct reftable_record rec = { NULL };
29
+ struct reftable_record rec = {
30
+ .type = BLOCK_TYPE_REF,
31
+ };
32
int i = 0;
33
int n;
34
struct block_reader br = { 0 };
@@ -40,7 +41,6 @@ static void test_block_read_write(void)
41
block.source = malloc_block_source();
42
block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
43
header_off, hash_size(GIT_SHA1_FORMAT_ID));
43
- reftable_record_from_ref(&rec, &ref);
44
45
for (i = 0; i < N; i++) {
46
char name[100];
@@ -48,14 +48,14 @@ static void test_block_read_write(void)
48
snprintf(name, sizeof(name), "branch%02d", i);
49
memset(hash, i, sizeof(hash));
50
51
- ref.refname = name;
52
- ref.value_type = REFTABLE_REF_VAL1;
53
- ref.value.val1 = hash;
51
+ rec.u.ref.refname = name;
52
+ rec.u.ref.value_type = REFTABLE_REF_VAL1;
53
+ rec.u.ref.value.val1 = hash;
54
55
names[i] = xstrdup(name);
56
n = block_writer_add(&bw, &rec);
57
- ref.refname = NULL;
58
- ref.value_type = REFTABLE_REF_DELETION;
57
+ rec.u.ref.refname = NULL;
58
+ rec.u.ref.value_type = REFTABLE_REF_DELETION;
59
EXPECT(n == 0);
60
}
61
@@ -74,7 +74,7 @@ static void test_block_read_write(void)
74
if (r > 0) {
75
break;
76
}
77
- EXPECT_STREQ(names[j], ref.refname);
77
+ EXPECT_STREQ(names[j], rec.u.ref.refname);
78
j++;
79
}
80
@@ -92,7 +92,7 @@ static void test_block_read_write(void)
92
n = block_iter_next(&it, &rec);
93
EXPECT(n == 0);
94
95
- EXPECT_STREQ(names[i], ref.refname);
95
+ EXPECT_STREQ(names[i], rec.u.ref.refname);
96
97
want.len--;
98
n = block_reader_seek(&br, &it, &want);
@@ -100,7 +100,7 @@ static void test_block_read_write(void)
100
101
n = block_iter_next(&it, &rec);
102
EXPECT(n == 0);
103
- EXPECT_STREQ(names[10 * (i / 10)], ref.refname);
103
+ EXPECT_STREQ(names[10 * (i / 10)], rec.u.ref.refname);
104
105
block_iter_close(&it);
106
}
reftable/generic.c
+24
-17
@@ -7,6 +7,7 @@ https://developers.google.com/open-source/licenses/bsd
7
*/
8
9
#include "basics.h"
10
+#include "constants.h"
11
#include "record.h"
12
#include "generic.h"
13
#include "reftable-iterator.h"
@@ -15,23 +16,21 @@ https://developers.google.com/open-source/licenses/bsd
16
int reftable_table_seek_ref(struct reftable_table *tab,
17
struct reftable_iterator *it, const char *name)
18
{
18
- struct reftable_ref_record ref = {
19
- .refname = (char *)name,
20
- };
21
- struct reftable_record rec = { NULL };
22
- reftable_record_from_ref(&rec, &ref);
19
+ struct reftable_record rec = { .type = BLOCK_TYPE_REF,
20
+ .u.ref = {
21
+ .refname = (char *)name,
22
+ } };
23
return tab->ops->seek_record(tab->table_arg, it, &rec);
24
}
25
26
int reftable_table_seek_log(struct reftable_table *tab,
27
struct reftable_iterator *it, const char *name)
28
{
29
- struct reftable_log_record log = {
30
- .refname = (char *)name,
31
- .update_index = ~((uint64_t)0),
32
- };
33
- struct reftable_record rec = { NULL };
34
- reftable_record_from_log(&rec, &log);
29
+ struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
30
+ .u.log = {
31
+ .refname = (char *)name,
32
+ .update_index = ~((uint64_t)0),
33
+ } };
34
return tab->ops->seek_record(tab->table_arg, it, &rec);
35
}
36
@@ -129,17 +128,25 @@ void reftable_iterator_destroy(struct reftable_iterator *it)
128
int reftable_iterator_next_ref(struct reftable_iterator *it,
129
struct reftable_ref_record *ref)
130
{
132
- struct reftable_record rec = { NULL };
133
- reftable_record_from_ref(&rec, ref);
134
- return iterator_next(it, &rec);
131
+ struct reftable_record rec = {
132
+ .type = BLOCK_TYPE_REF,
133
+ .u.ref = *ref,
134
+ };
135
+ int err = iterator_next(it, &rec);
136
+ *ref = rec.u.ref;
137
+ return err;
138
}
139
140
int reftable_iterator_next_log(struct reftable_iterator *it,
141
struct reftable_log_record *log)
142
{
140
- struct reftable_record rec = { NULL };
141
- reftable_record_from_log(&rec, log);
142
- return iterator_next(it, &rec);
143
+ struct reftable_record rec = {
144
+ .type = BLOCK_TYPE_LOG,
145
+ .u.log = *log,
146
+ };
147
+ int err = iterator_next(it, &rec);
148
+ *log = rec.u.log;
149
+ return err;
150
}
151
152
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
reftable/iter.c
+2
-2
@@ -32,7 +32,7 @@ static int filtering_ref_iterator_next(void *iter_arg,
32
struct reftable_record *rec)
33
{
34
struct filtering_ref_iterator *fri = iter_arg;
35
- struct reftable_ref_record *ref = rec->data;
35
+ struct reftable_ref_record *ref = &rec->u.ref;
36
int err = 0;
37
while (1) {
38
err = reftable_iterator_next_ref(&fri->it, ref);
@@ -127,7 +127,7 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
127
static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
128
{
129
struct indexed_table_ref_iter *it = p;
130
- struct reftable_ref_record *ref = rec->data;
130
+ struct reftable_ref_record *ref = &rec->u.ref;
131
132
while (1) {
133
int err = block_iter_next(&it->cur, rec);
reftable/merged.c
+16
-17
@@ -30,7 +30,7 @@ static int merged_iter_init(struct merged_iter *mi)
30
31
if (err > 0) {
32
reftable_iterator_destroy(&mi->stack[i]);
33
- reftable_record_destroy(&rec);
33
+ reftable_record_release(&rec);
34
} else {
35
struct pq_entry e = {
36
.rec = rec,
@@ -57,18 +57,17 @@ static void merged_iter_close(void *p)
57
static int merged_iter_advance_nonnull_subiter(struct merged_iter *mi,
58
size_t idx)
59
{
60
- struct reftable_record rec = reftable_new_record(mi->typ);
60
struct pq_entry e = {
62
- .rec = rec,
61
+ .rec = reftable_new_record(mi->typ),
62
.index = idx,
63
};
65
- int err = iterator_next(&mi->stack[idx], &rec);
64
+ int err = iterator_next(&mi->stack[idx], &e.rec);
65
if (err < 0)
66
return err;
67
68
if (err > 0) {
69
reftable_iterator_destroy(&mi->stack[idx]);
71
- reftable_record_destroy(&rec);
70
+ reftable_record_release(&e.rec);
71
return 0;
72
}
73
@@ -126,11 +125,11 @@ static int merged_iter_next_entry(struct merged_iter *mi,
125
if (err < 0) {
126
return err;
127
}
129
- reftable_record_destroy(&top.rec);
128
+ reftable_record_release(&top.rec);
129
}
130
131
reftable_record_copy_from(rec, &entry.rec, hash_size(mi->hash_id));
133
- reftable_record_destroy(&entry.rec);
132
+ reftable_record_release(&entry.rec);
133
strbuf_release(&entry_key);
134
return 0;
135
}
@@ -290,11 +289,12 @@ int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
289
struct reftable_iterator *it,
290
const char *name)
291
{
293
- struct reftable_ref_record ref = {
294
- .refname = (char *)name,
292
+ struct reftable_record rec = {
293
+ .type = BLOCK_TYPE_REF,
294
+ .u.ref = {
295
+ .refname = (char *)name,
296
+ },
297
};
296
- struct reftable_record rec = { NULL };
297
- reftable_record_from_ref(&rec, &ref);
298
return merged_table_seek_record(mt, it, &rec);
299
}
300
@@ -302,12 +302,11 @@ int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
302
struct reftable_iterator *it,
303
const char *name, uint64_t update_index)
304
{
305
- struct reftable_log_record log = {
306
- .refname = (char *)name,
307
- .update_index = update_index,
308
- };
309
- struct reftable_record rec = { NULL };
310
- reftable_record_from_log(&rec, &log);
305
+ struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
306
+ .u.log = {
307
+ .refname = (char *)name,
308
+ .update_index = update_index,
309
+ } };
310
return merged_table_seek_record(mt, it, &rec);
311
}
312
reftable/pq.c
+2
-1
@@ -74,6 +74,7 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
74
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e)
75
{
76
int i = 0;
77
+
78
if (pq->len == pq->cap) {
79
pq->cap = 2 * pq->cap + 1;
80
pq->heap = reftable_realloc(pq->heap,
@@ -98,7 +99,7 @@ void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
99
{
100
int i = 0;
101
for (i = 0; i < pq->len; i++) {
101
- reftable_record_destroy(&pq->heap[i].rec);
102
+ reftable_record_release(&pq->heap[i].rec);
103
}
104
FREE_AND_NULL(pq->heap);
105
pq->len = pq->cap = 0;
reftable/pq_test.c
+12
-15
@@ -31,7 +31,7 @@ static void test_pq(void)
31
int N = ARRAY_SIZE(names) - 1;
32
33
struct merged_iter_pqueue pq = { NULL };
34
- const char *last = NULL;
34
+ char *last = NULL;
35
36
int i = 0;
37
for (i = 0; i < N; i++) {
@@ -42,12 +42,10 @@ static void test_pq(void)
42
43
i = 1;
44
do {
45
- struct reftable_record rec =
46
- reftable_new_record(BLOCK_TYPE_REF);
47
- struct pq_entry e = { 0 };
48
-
49
- reftable_record_as_ref(&rec)->refname = names[i];
50
- e.rec = rec;
45
+ struct pq_entry e = { .rec = { .type = BLOCK_TYPE_REF,
46
+ .u.ref = {
47
+ .refname = names[i],
48
+ } } };
49
merged_iter_pqueue_add(&pq, e);
50
merged_iter_pqueue_check(pq);
51
i = (i * 7) % N;
@@ -55,19 +53,18 @@ static void test_pq(void)
53
54
while (!merged_iter_pqueue_is_empty(pq)) {
55
struct pq_entry e = merged_iter_pqueue_remove(&pq);
58
- struct reftable_ref_record *ref =
59
- reftable_record_as_ref(&e.rec);
60
-
56
+ struct reftable_record *rec = &e.rec;
57
merged_iter_pqueue_check(pq);
58
59
+ EXPECT(reftable_record_type(rec) == BLOCK_TYPE_REF);
60
if (last) {
64
- EXPECT(strcmp(last, ref->refname) < 0);
61
+ EXPECT(strcmp(last, rec->u.ref.refname) < 0);
62
}
66
- last = ref->refname;
67
- ref->refname = NULL;
68
- reftable_free(ref);
63
+ // this is names[i], so don't dealloc.
64
+ last = rec->u.ref.refname;
65
+ rec->u.ref.refname = NULL;
66
+ reftable_record_release(rec);
67
}
70
-
68
for (i = 0; i < N; i++) {
69
reftable_free(names[i]);
70
}
reftable/reader.c
+45
-42
@@ -239,8 +239,7 @@ static int table_iter_next_in_block(struct table_iter *ti,
239
{
240
int res = block_iter_next(&ti->bi, rec);
241
if (res == 0 && reftable_record_type(rec) == BLOCK_TYPE_REF) {
242
- ((struct reftable_ref_record *)rec->data)->update_index +=
243
- ti->r->min_update_index;
242
+ rec->u.ref.update_index += ti->r->min_update_index;
243
}
244
245
return res;
@@ -480,7 +479,7 @@ static int reader_seek_linear(struct reftable_reader *r, struct table_iter *ti,
479
480
done:
481
block_iter_close(&next.bi);
483
- reftable_record_destroy(&rec);
482
+ reftable_record_release(&rec);
483
strbuf_release(&want_key);
484
strbuf_release(&got_key);
485
return err;
@@ -490,34 +489,35 @@ static int reader_seek_indexed(struct reftable_reader *r,
489
struct reftable_iterator *it,
490
struct reftable_record *rec)
491
{
493
- struct reftable_index_record want_index = { .last_key = STRBUF_INIT };
494
- struct reftable_record want_index_rec = { NULL };
495
- struct reftable_index_record index_result = { .last_key = STRBUF_INIT };
496
- struct reftable_record index_result_rec = { NULL };
492
+ struct reftable_record want_index = {
493
+ .type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = STRBUF_INIT }
494
+ };
495
+ struct reftable_record index_result = {
496
+ .type = BLOCK_TYPE_INDEX,
497
+ .u.idx = { .last_key = STRBUF_INIT },
498
+ };
499
struct table_iter index_iter = TABLE_ITER_INIT;
500
struct table_iter next = TABLE_ITER_INIT;
501
int err = 0;
502
501
- reftable_record_key(rec, &want_index.last_key);
502
- reftable_record_from_index(&want_index_rec, &want_index);
503
- reftable_record_from_index(&index_result_rec, &index_result);
504
-
503
+ reftable_record_key(rec, &want_index.u.idx.last_key);
504
err = reader_start(r, &index_iter, reftable_record_type(rec), 1);
505
if (err < 0)
506
goto done;
507
509
- err = reader_seek_linear(r, &index_iter, &want_index_rec);
508
+ err = reader_seek_linear(r, &index_iter, &want_index);
509
while (1) {
511
- err = table_iter_next(&index_iter, &index_result_rec);
510
+ err = table_iter_next(&index_iter, &index_result);
511
table_iter_block_done(&index_iter);
512
if (err != 0)
513
goto done;
514
516
- err = reader_table_iter_at(r, &next, index_result.offset, 0);
515
+ err = reader_table_iter_at(r, &next, index_result.u.idx.offset,
516
+ 0);
517
if (err != 0)
518
goto done;
519
520
- err = block_iter_seek(&next.bi, &want_index.last_key);
520
+ err = block_iter_seek(&next.bi, &want_index.u.idx.last_key);
521
if (err < 0)
522
goto done;
523
@@ -545,8 +545,8 @@ static int reader_seek_indexed(struct reftable_reader *r,
545
done:
546
block_iter_close(&next.bi);
547
table_iter_close(&index_iter);
548
- reftable_record_release(&want_index_rec);
549
- reftable_record_release(&index_result_rec);
548
+ reftable_record_release(&want_index);
549
+ reftable_record_release(&index_result);
550
return err;
551
}
552
@@ -595,11 +595,12 @@ static int reader_seek(struct reftable_reader *r, struct reftable_iterator *it,
595
int reftable_reader_seek_ref(struct reftable_reader *r,
596
struct reftable_iterator *it, const char *name)
597
{
598
- struct reftable_ref_record ref = {
599
- .refname = (char *)name,
598
+ struct reftable_record rec = {
599
+ .type = BLOCK_TYPE_REF,
600
+ .u.ref = {
601
+ .refname = (char *)name,
602
+ },
603
};
601
- struct reftable_record rec = { NULL };
602
- reftable_record_from_ref(&rec, &ref);
604
return reader_seek(r, it, &rec);
605
}
606
@@ -607,12 +608,11 @@ int reftable_reader_seek_log_at(struct reftable_reader *r,
608
struct reftable_iterator *it, const char *name,
609
uint64_t update_index)
610
{
610
- struct reftable_log_record log = {
611
- .refname = (char *)name,
612
- .update_index = update_index,
613
- };
614
- struct reftable_record rec = { NULL };
615
- reftable_record_from_log(&rec, &log);
611
+ struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
612
+ .u.log = {
613
+ .refname = (char *)name,
614
+ .update_index = update_index,
615
+ } };
616
return reader_seek(r, it, &rec);
617
}
618
@@ -656,31 +656,33 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
656
struct reftable_iterator *it,
657
uint8_t *oid)
658
{
659
- struct reftable_obj_record want = {
660
- .hash_prefix = oid,
661
- .hash_prefix_len = r->object_id_len,
659
+ struct reftable_record want = {
660
+ .type = BLOCK_TYPE_OBJ,
661
+ .u.obj = {
662
+ .hash_prefix = oid,
663
+ .hash_prefix_len = r->object_id_len,
664
+ },
665
};
663
- struct reftable_record want_rec = { NULL };
666
struct reftable_iterator oit = { NULL };
665
- struct reftable_obj_record got = { NULL };
666
- struct reftable_record got_rec = { NULL };
667
+ struct reftable_record got = {
668
+ .type = BLOCK_TYPE_OBJ,
669
+ .u.obj = { 0 },
670
+ };
671
int err = 0;
672
struct indexed_table_ref_iter *itr = NULL;
673
674
/* Look through the reverse index. */
671
- reftable_record_from_obj(&want_rec, &want);
672
- err = reader_seek(r, &oit, &want_rec);
675
+ err = reader_seek(r, &oit, &want);
676
if (err != 0)
677
goto done;
678
679
/* read out the reftable_obj_record */
677
- reftable_record_from_obj(&got_rec, &got);
678
- err = iterator_next(&oit, &got_rec);
680
+ err = iterator_next(&oit, &got);
681
if (err < 0)
682
goto done;
683
682
- if (err > 0 ||
683
- memcmp(want.hash_prefix, got.hash_prefix, r->object_id_len)) {
684
+ if (err > 0 || memcmp(want.u.obj.hash_prefix, got.u.obj.hash_prefix,
685
+ r->object_id_len)) {
686
/* didn't find it; return empty iterator */
687
iterator_set_empty(it);
688
err = 0;
@@ -688,15 +690,16 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
690
}
691
692
err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
691
- got.offsets, got.offset_len);
693
+ got.u.obj.offsets,
694
+ got.u.obj.offset_len);
695
if (err < 0)
696
goto done;
694
- got.offsets = NULL;
697
+ got.u.obj.offsets = NULL;
698
iterator_from_indexed_table_ref_iter(it, itr);
699
700
done:
701
reftable_iterator_destroy(&oit);
699
- reftable_record_release(&got_rec);
702
+ reftable_record_release(&got);
703
return err;
704
}
705
reftable/record.c
+100
-112
@@ -15,6 +15,10 @@ https://developers.google.com/open-source/licenses/bsd
15
#include "reftable-error.h"
16
#include "basics.h"
17
18
+static struct reftable_record_vtable *
19
+reftable_record_vtable(struct reftable_record *rec);
20
+static void *reftable_record_data(struct reftable_record *rec);
21
+
22
int get_var_int(uint64_t *dest, struct string_view *in)
23
{
24
int ptr = 0;
@@ -475,12 +479,14 @@ static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
479
(const struct reftable_obj_record *)src_rec;
480
481
reftable_obj_record_release(obj);
478
- *obj = *src;
479
- obj->hash_prefix = reftable_malloc(obj->hash_prefix_len);
480
- memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
482
+ obj->hash_prefix = reftable_malloc(src->hash_prefix_len);
483
+ obj->hash_prefix_len = src->hash_prefix_len;
484
+ if (src->hash_prefix_len)
485
+ memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
486
482
- obj->offsets = reftable_malloc(obj->offset_len * sizeof(uint64_t));
483
- COPY_ARRAY(obj->offsets, src->offsets, obj->offset_len);
487
+ obj->offsets = reftable_malloc(src->offset_len * sizeof(uint64_t));
488
+ obj->offset_len = src->offset_len;
489
+ COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
490
}
491
492
static uint8_t reftable_obj_record_val_type(const void *rec)
@@ -965,58 +971,6 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
971
.equal = &reftable_log_record_equal_void
972
};
973
968
-struct reftable_record reftable_new_record(uint8_t typ)
969
-{
970
- struct reftable_record rec = { NULL };
971
- switch (typ) {
972
- case BLOCK_TYPE_REF: {
973
- struct reftable_ref_record *r =
974
- reftable_calloc(sizeof(struct reftable_ref_record));
975
- reftable_record_from_ref(&rec, r);
976
- return rec;
977
- }
978
-
979
- case BLOCK_TYPE_OBJ: {
980
- struct reftable_obj_record *r =
981
- reftable_calloc(sizeof(struct reftable_obj_record));
982
- reftable_record_from_obj(&rec, r);
983
- return rec;
984
- }
985
- case BLOCK_TYPE_LOG: {
986
- struct reftable_log_record *r =
987
- reftable_calloc(sizeof(struct reftable_log_record));
988
- reftable_record_from_log(&rec, r);
989
- return rec;
990
- }
991
- case BLOCK_TYPE_INDEX: {
992
- struct reftable_index_record empty = { .last_key =
993
- STRBUF_INIT };
994
- struct reftable_index_record *r =
995
- reftable_calloc(sizeof(struct reftable_index_record));
996
- *r = empty;
997
- reftable_record_from_index(&rec, r);
998
- return rec;
999
- }
1000
- }
1001
- abort();
1002
- return rec;
1003
-}
1004
-
1005
-/* clear out the record, yielding the reftable_record data that was
1006
- * encapsulated. */
1007
-static void *reftable_record_yield(struct reftable_record *rec)
1008
-{
1009
- void *p = rec->data;
1010
- rec->data = NULL;
1011
- return p;
1012
-}
1013
-
1014
-void reftable_record_destroy(struct reftable_record *rec)
1015
-{
1016
- reftable_record_release(rec);
1017
- reftable_free(reftable_record_yield(rec));
1018
-}
1019
-
974
static void reftable_index_record_key(const void *r, struct strbuf *dest)
975
{
976
const struct reftable_index_record *rec = r;
@@ -1103,98 +1057,60 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
1057
1058
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
1059
{
1106
- rec->ops->key(rec->data, dest);
1060
+ reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
1061
}
1062
1063
uint8_t reftable_record_type(struct reftable_record *rec)
1064
{
1111
- return rec->ops->type;
1065
+ return rec->type;
1066
}
1067
1068
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
1069
int hash_size)
1070
{
1117
- return rec->ops->encode(rec->data, dest, hash_size);
1071
+ return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
1072
+ dest, hash_size);
1073
}
1074
1075
void reftable_record_copy_from(struct reftable_record *rec,
1076
struct reftable_record *src, int hash_size)
1077
{
1123
- assert(src->ops->type == rec->ops->type);
1078
+ assert(src->type == rec->type);
1079
1125
- rec->ops->copy_from(rec->data, src->data, hash_size);
1080
+ reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
1081
+ reftable_record_data(src),
1082
+ hash_size);
1083
}
1084
1085
uint8_t reftable_record_val_type(struct reftable_record *rec)
1086
{
1130
- return rec->ops->val_type(rec->data);
1087
+ return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
1088
}
1089
1090
int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
1091
uint8_t extra, struct string_view src, int hash_size)
1092
{
1136
- return rec->ops->decode(rec->data, key, extra, src, hash_size);
1093
+ return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
1094
+ key, extra, src, hash_size);
1095
}
1096
1097
void reftable_record_release(struct reftable_record *rec)
1098
{
1141
- rec->ops->release(rec->data);
1099
+ reftable_record_vtable(rec)->release(reftable_record_data(rec));
1100
}
1101
1102
int reftable_record_is_deletion(struct reftable_record *rec)
1103
{
1146
- return rec->ops->is_deletion(rec->data);
1104
+ return reftable_record_vtable(rec)->is_deletion(
1105
+ reftable_record_data(rec));
1106
}
1107
1108
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
1109
{
1151
- if (a->ops != b->ops)
1110
+ if (a->type != b->type)
1111
return 0;
1153
- return a->ops->equal(a->data, b->data, hash_size);
1154
-}
1155
-
1156
-void reftable_record_from_ref(struct reftable_record *rec,
1157
- struct reftable_ref_record *ref_rec)
1158
-{
1159
- assert(!rec->ops);
1160
- rec->data = ref_rec;
1161
- rec->ops = &reftable_ref_record_vtable;
1162
-}
1163
-
1164
-void reftable_record_from_obj(struct reftable_record *rec,
1165
- struct reftable_obj_record *obj_rec)
1166
-{
1167
- assert(!rec->ops);
1168
- rec->data = obj_rec;
1169
- rec->ops = &reftable_obj_record_vtable;
1170
-}
1171
-
1172
-void reftable_record_from_index(struct reftable_record *rec,
1173
- struct reftable_index_record *index_rec)
1174
-{
1175
- assert(!rec->ops);
1176
- rec->data = index_rec;
1177
- rec->ops = &reftable_index_record_vtable;
1178
-}
1179
-
1180
-void reftable_record_from_log(struct reftable_record *rec,
1181
- struct reftable_log_record *log_rec)
1182
-{
1183
- assert(!rec->ops);
1184
- rec->data = log_rec;
1185
- rec->ops = &reftable_log_record_vtable;
1186
-}
1187
-
1188
-struct reftable_ref_record *reftable_record_as_ref(struct reftable_record *rec)
1189
-{
1190
- assert(reftable_record_type(rec) == BLOCK_TYPE_REF);
1191
- return rec->data;
1192
-}
1193
-
1194
-struct reftable_log_record *reftable_record_as_log(struct reftable_record *rec)
1195
-{
1196
- assert(reftable_record_type(rec) == BLOCK_TYPE_LOG);
1197
- return rec->data;
1112
+ return reftable_record_vtable(a)->equal(
1113
+ reftable_record_data(a), reftable_record_data(b), hash_size);
1114
}
1115
1116
static int hash_equal(uint8_t *a, uint8_t *b, int hash_size)
@@ -1267,3 +1183,75 @@ void string_view_consume(struct string_view *s, int n)
1183
s->buf += n;
1184
s->len -= n;
1185
}
1186
+
1187
+static void *reftable_record_data(struct reftable_record *rec)
1188
+{
1189
+ switch (rec->type) {
1190
+ case BLOCK_TYPE_REF:
1191
+ return &rec->u.ref;
1192
+ case BLOCK_TYPE_LOG:
1193
+ return &rec->u.log;
1194
+ case BLOCK_TYPE_INDEX:
1195
+ return &rec->u.idx;
1196
+ case BLOCK_TYPE_OBJ:
1197
+ return &rec->u.obj;
1198
+ }
1199
+ abort();
1200
+}
1201
+
1202
+static struct reftable_record_vtable *
1203
+reftable_record_vtable(struct reftable_record *rec)
1204
+{
1205
+ switch (rec->type) {
1206
+ case BLOCK_TYPE_REF:
1207
+ return &reftable_ref_record_vtable;
1208
+ case BLOCK_TYPE_LOG:
1209
+ return &reftable_log_record_vtable;
1210
+ case BLOCK_TYPE_INDEX:
1211
+ return &reftable_index_record_vtable;
1212
+ case BLOCK_TYPE_OBJ:
1213
+ return &reftable_obj_record_vtable;
1214
+ }
1215
+ abort();
1216
+}
1217
+
1218
+struct reftable_record reftable_new_record(uint8_t typ)
1219
+{
1220
+ struct reftable_record clean = {
1221
+ .type = typ,
1222
+ };
1223
+
1224
+ /* the following is involved, but the naive solution (just return
1225
+ * `clean` as is, except for BLOCK_TYPE_INDEX), returns a garbage
1226
+ * clean.u.obj.offsets pointer on Windows VS CI. Go figure.
1227
+ */
1228
+ switch (typ) {
1229
+ case BLOCK_TYPE_OBJ:
1230
+ {
1231
+ struct reftable_obj_record obj = { 0 };
1232
+ clean.u.obj = obj;
1233
+ break;
1234
+ }
1235
+ case BLOCK_TYPE_INDEX:
1236
+ {
1237
+ struct reftable_index_record idx = {
1238
+ .last_key = STRBUF_INIT,
1239
+ };
1240
+ clean.u.idx = idx;
1241
+ break;
1242
+ }
1243
+ case BLOCK_TYPE_REF:
1244
+ {
1245
+ struct reftable_ref_record ref = { 0 };
1246
+ clean.u.ref = ref;
1247
+ break;
1248
+ }
1249
+ case BLOCK_TYPE_LOG:
1250
+ {
1251
+ struct reftable_log_record log = { 0 };
1252
+ clean.u.log = log;
1253
+ break;
1254
+ }
1255
+ }
1256
+ return clean;
1257
+}
reftable/record.h
+18
-24
@@ -63,16 +63,10 @@ struct reftable_record_vtable {
63
int (*equal)(const void *a, const void *b, int hash_size);
64
};
65
66
-/* record is a generic wrapper for different types of records. */
67
-struct reftable_record {
68
- void *data;
69
- struct reftable_record_vtable *ops;
70
-};
71
-
66
/* returns true for recognized block types. Block start with the block type. */
67
int reftable_is_block_type(uint8_t typ);
68
75
-/* creates a malloced record of the given type. Dispose with record_destroy */
69
+/* return an initialized record for the given type */
70
struct reftable_record reftable_new_record(uint8_t typ);
71
72
/* Encode `key` into `dest`. Sets `is_restart` to indicate a restart. Returns
@@ -100,6 +94,22 @@ struct reftable_obj_record {
94
int offset_len;
95
};
96
97
+/* record is a generic wrapper for different types of records. It is normally
98
+ * created on the stack, or embedded within another struct. If the type is
99
+ * known, a fresh instance can be initialized explicitly. Otherwise, use
100
+ * reftable_new_record() to initialize generically (as the index_record is not
101
+ * valid as 0-initialized structure)
102
+ */
103
+struct reftable_record {
104
+ uint8_t type;
105
+ union {
106
+ struct reftable_ref_record ref;
107
+ struct reftable_log_record log;
108
+ struct reftable_obj_record obj;
109
+ struct reftable_index_record idx;
110
+ } u;
111
+};
112
+
113
/* see struct record_vtable */
114
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
115
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
@@ -114,25 +124,9 @@ int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
124
int hash_size);
125
int reftable_record_is_deletion(struct reftable_record *rec);
126
117
-/* zeroes out the embedded record */
127
+/* frees and zeroes out the embedded record */
128
void reftable_record_release(struct reftable_record *rec);
129
120
-/* clear and deallocate embedded record, and zero `rec`. */
121
-void reftable_record_destroy(struct reftable_record *rec);
122
-
123
-/* initialize generic records from concrete records. The generic record should
124
- * be zeroed out. */
125
-void reftable_record_from_obj(struct reftable_record *rec,
126
- struct reftable_obj_record *objrec);
127
-void reftable_record_from_index(struct reftable_record *rec,
128
- struct reftable_index_record *idxrec);
129
-void reftable_record_from_ref(struct reftable_record *rec,
130
- struct reftable_ref_record *refrec);
131
-void reftable_record_from_log(struct reftable_record *rec,
132
- struct reftable_log_record *logrec);
133
-struct reftable_ref_record *reftable_record_as_ref(struct reftable_record *ref);
134
-struct reftable_log_record *reftable_record_as_log(struct reftable_record *ref);
135
-
130
/* for qsort. */
131
int reftable_ref_record_compare_name(const void *a, const void *b);
132
reftable/record_test.c
+80
-77
@@ -16,13 +16,16 @@
16
17
static void test_copy(struct reftable_record *rec)
18
{
19
- struct reftable_record copy =
20
- reftable_new_record(reftable_record_type(rec));
19
+ struct reftable_record copy = { 0 };
20
+ uint8_t typ;
21
+
22
+ typ = reftable_record_type(rec);
23
+ copy = reftable_new_record(typ);
24
reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ);
25
/* do it twice to catch memory leaks */
26
reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ);
27
EXPECT(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ));
25
- reftable_record_destroy(©);
28
+ reftable_record_release(©);
29
}
30
31
static void test_varint_roundtrip(void)
@@ -95,61 +98,58 @@ static void test_reftable_ref_record_roundtrip(void)
98
int i = 0;
99
100
for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
98
- struct reftable_ref_record in = { NULL };
99
- struct reftable_ref_record out = { NULL };
100
- struct reftable_record rec_out = { NULL };
101
+ struct reftable_record in = {
102
+ .type = BLOCK_TYPE_REF,
103
+ };
104
+ struct reftable_record out = { .type = BLOCK_TYPE_REF };
105
struct strbuf key = STRBUF_INIT;
102
- struct reftable_record rec = { NULL };
106
uint8_t buffer[1024] = { 0 };
107
struct string_view dest = {
108
.buf = buffer,
109
.len = sizeof(buffer),
110
};
108
-
111
int n, m;
112
111
- in.value_type = i;
113
+ in.u.ref.value_type = i;
114
switch (i) {
115
case REFTABLE_REF_DELETION:
116
break;
117
case REFTABLE_REF_VAL1:
116
- in.value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
117
- set_hash(in.value.val1, 1);
118
+ in.u.ref.value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
119
+ set_hash(in.u.ref.value.val1, 1);
120
break;
121
case REFTABLE_REF_VAL2:
120
- in.value.val2.value = reftable_malloc(GIT_SHA1_RAWSZ);
121
- set_hash(in.value.val2.value, 1);
122
- in.value.val2.target_value =
122
+ in.u.ref.value.val2.value =
123
reftable_malloc(GIT_SHA1_RAWSZ);
124
- set_hash(in.value.val2.target_value, 2);
124
+ set_hash(in.u.ref.value.val2.value, 1);
125
+ in.u.ref.value.val2.target_value =
126
+ reftable_malloc(GIT_SHA1_RAWSZ);
127
+ set_hash(in.u.ref.value.val2.target_value, 2);
128
break;
129
case REFTABLE_REF_SYMREF:
127
- in.value.symref = xstrdup("target");
130
+ in.u.ref.value.symref = xstrdup("target");
131
break;
132
}
130
- in.refname = xstrdup("refs/heads/master");
133
+ in.u.ref.refname = xstrdup("refs/heads/master");
134
132
- reftable_record_from_ref(&rec, &in);
133
- test_copy(&rec);
135
+ test_copy(&in);
136
135
- EXPECT(reftable_record_val_type(&rec) == i);
137
+ EXPECT(reftable_record_val_type(&in) == i);
138
137
- reftable_record_key(&rec, &key);
138
- n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
139
+ reftable_record_key(&in, &key);
140
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
141
EXPECT(n > 0);
142
143
/* decode into a non-zero reftable_record to test for leaks. */
142
-
143
- reftable_record_from_ref(&rec_out, &out);
144
- m = reftable_record_decode(&rec_out, key, i, dest,
145
- GIT_SHA1_RAWSZ);
144
+ m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ);
145
EXPECT(n == m);
146
148
- EXPECT(reftable_ref_record_equal(&in, &out, GIT_SHA1_RAWSZ));
149
- reftable_record_release(&rec_out);
147
+ EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref,
148
+ GIT_SHA1_RAWSZ));
149
+ reftable_record_release(&in);
150
151
strbuf_release(&key);
152
- reftable_ref_record_release(&in);
152
+ reftable_record_release(&out);
153
}
154
}
155
@@ -202,7 +202,7 @@ static void test_reftable_log_record_roundtrip(void)
202
set_test_hash(in[0].value.update.new_hash, 1);
203
set_test_hash(in[0].value.update.old_hash, 2);
204
for (i = 0; i < ARRAY_SIZE(in); i++) {
205
- struct reftable_record rec = { NULL };
205
+ struct reftable_record rec = { .type = BLOCK_TYPE_LOG };
206
struct strbuf key = STRBUF_INIT;
207
uint8_t buffer[1024] = { 0 };
208
struct string_view dest = {
@@ -210,23 +210,25 @@ static void test_reftable_log_record_roundtrip(void)
210
.len = sizeof(buffer),
211
};
212
/* populate out, to check for leaks. */
213
- struct reftable_log_record out = {
214
- .refname = xstrdup("old name"),
215
- .value_type = REFTABLE_LOG_UPDATE,
216
- .value = {
217
- .update = {
218
- .new_hash = reftable_calloc(GIT_SHA1_RAWSZ),
219
- .old_hash = reftable_calloc(GIT_SHA1_RAWSZ),
220
- .name = xstrdup("old name"),
221
- .email = xstrdup("old@email"),
222
- .message = xstrdup("old message"),
213
+ struct reftable_record out = {
214
+ .type = BLOCK_TYPE_LOG,
215
+ .u.log = {
216
+ .refname = xstrdup("old name"),
217
+ .value_type = REFTABLE_LOG_UPDATE,
218
+ .value = {
219
+ .update = {
220
+ .new_hash = reftable_calloc(GIT_SHA1_RAWSZ),
221
+ .old_hash = reftable_calloc(GIT_SHA1_RAWSZ),
222
+ .name = xstrdup("old name"),
223
+ .email = xstrdup("old@email"),
224
+ .message = xstrdup("old message"),
225
+ },
226
},
227
},
228
};
226
- struct reftable_record rec_out = { NULL };
229
int n, m, valtype;
230
229
- reftable_record_from_log(&rec, &in[i]);
231
+ rec.u.log = in[i];
232
233
test_copy(&rec);
234
@@ -234,16 +236,16 @@ static void test_reftable_log_record_roundtrip(void)
236
237
n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
238
EXPECT(n >= 0);
237
- reftable_record_from_log(&rec_out, &out);
239
valtype = reftable_record_val_type(&rec);
239
- m = reftable_record_decode(&rec_out, key, valtype, dest,
240
+ m = reftable_record_decode(&out, key, valtype, dest,
241
GIT_SHA1_RAWSZ);
242
EXPECT(n == m);
243
243
- EXPECT(reftable_log_record_equal(&in[i], &out, GIT_SHA1_RAWSZ));
244
+ EXPECT(reftable_log_record_equal(&in[i], &out.u.log,
245
+ GIT_SHA1_RAWSZ));
246
reftable_log_record_release(&in[i]);
247
strbuf_release(&key);
246
- reftable_record_release(&rec_out);
248
+ reftable_record_release(&out);
249
}
250
}
251
@@ -311,41 +313,43 @@ static void test_reftable_obj_record_roundtrip(void)
313
} };
314
int i = 0;
315
for (i = 0; i < ARRAY_SIZE(recs); i++) {
314
- struct reftable_obj_record in = recs[i];
316
uint8_t buffer[1024] = { 0 };
317
struct string_view dest = {
318
.buf = buffer,
319
.len = sizeof(buffer),
320
};
320
- struct reftable_record rec = { NULL };
321
+ struct reftable_record in = {
322
+ .type = BLOCK_TYPE_OBJ,
323
+ .u.obj = recs[i],
324
+ };
325
struct strbuf key = STRBUF_INIT;
322
- struct reftable_obj_record out = { NULL };
323
- struct reftable_record rec_out = { NULL };
326
+ struct reftable_record out = { .type = BLOCK_TYPE_OBJ };
327
int n, m;
328
uint8_t extra;
329
327
- reftable_record_from_obj(&rec, &in);
328
- test_copy(&rec);
329
- reftable_record_key(&rec, &key);
330
- n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
330
+ test_copy(&in);
331
+ reftable_record_key(&in, &key);
332
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
333
EXPECT(n > 0);
332
- extra = reftable_record_val_type(&rec);
333
- reftable_record_from_obj(&rec_out, &out);
334
- m = reftable_record_decode(&rec_out, key, extra, dest,
334
+ extra = reftable_record_val_type(&in);
335
+ m = reftable_record_decode(&out, key, extra, dest,
336
GIT_SHA1_RAWSZ);
337
EXPECT(n == m);
338
338
- EXPECT(reftable_record_equal(&rec, &rec_out, GIT_SHA1_RAWSZ));
339
+ EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
340
strbuf_release(&key);
340
- reftable_record_release(&rec_out);
341
+ reftable_record_release(&out);
342
}
343
}
344
345
static void test_reftable_index_record_roundtrip(void)
346
{
346
- struct reftable_index_record in = {
347
- .offset = 42,
348
- .last_key = STRBUF_INIT,
347
+ struct reftable_record in = {
348
+ .type = BLOCK_TYPE_INDEX,
349
+ .u.idx = {
350
+ .offset = 42,
351
+ .last_key = STRBUF_INIT,
352
+ },
353
};
354
uint8_t buffer[1024] = { 0 };
355
struct string_view dest = {
@@ -353,31 +357,30 @@ static void test_reftable_index_record_roundtrip(void)
357
.len = sizeof(buffer),
358
};
359
struct strbuf key = STRBUF_INIT;
356
- struct reftable_record rec = { NULL };
357
- struct reftable_index_record out = { .last_key = STRBUF_INIT };
358
- struct reftable_record out_rec = { NULL };
360
+ struct reftable_record out = {
361
+ .type = BLOCK_TYPE_INDEX,
362
+ .u.idx = { .last_key = STRBUF_INIT },
363
+ };
364
int n, m;
365
uint8_t extra;
366
362
- strbuf_addstr(&in.last_key, "refs/heads/master");
363
- reftable_record_from_index(&rec, &in);
364
- reftable_record_key(&rec, &key);
365
- test_copy(&rec);
367
+ strbuf_addstr(&in.u.idx.last_key, "refs/heads/master");
368
+ reftable_record_key(&in, &key);
369
+ test_copy(&in);
370
367
- EXPECT(0 == strbuf_cmp(&key, &in.last_key));
368
- n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
371
+ EXPECT(0 == strbuf_cmp(&key, &in.u.idx.last_key));
372
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
373
EXPECT(n > 0);
374
371
- extra = reftable_record_val_type(&rec);
372
- reftable_record_from_index(&out_rec, &out);
373
- m = reftable_record_decode(&out_rec, key, extra, dest, GIT_SHA1_RAWSZ);
375
+ extra = reftable_record_val_type(&in);
376
+ m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ);
377
EXPECT(m == n);
378
376
- EXPECT(reftable_record_equal(&rec, &out_rec, GIT_SHA1_RAWSZ));
379
+ EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
380
378
- reftable_record_release(&out_rec);
381
+ reftable_record_release(&out);
382
strbuf_release(&key);
380
- strbuf_release(&in.last_key);
383
+ strbuf_release(&in.u.idx.last_key);
384
}
385
386
int record_test_main(int argc, const char *argv[])
reftable/writer.c
+23
-18
@@ -253,8 +253,10 @@ done:
253
int reftable_writer_add_ref(struct reftable_writer *w,
254
struct reftable_ref_record *ref)
255
{
256
- struct reftable_record rec = { NULL };
257
- struct reftable_ref_record copy = *ref;
256
+ struct reftable_record rec = {
257
+ .type = BLOCK_TYPE_REF,
258
+ .u.ref = *ref,
259
+ };
260
int err = 0;
261
262
if (ref->refname == NULL)
@@ -263,8 +265,7 @@ int reftable_writer_add_ref(struct reftable_writer *w,
265
ref->update_index > w->max_update_index)
266
return REFTABLE_API_ERROR;
267
266
- reftable_record_from_ref(&rec, ©);
267
- copy.update_index -= w->min_update_index;
268
+ rec.u.ref.update_index -= w->min_update_index;
269
270
err = writer_add_record(w, &rec);
271
if (err < 0)
@@ -303,7 +304,10 @@ int reftable_writer_add_refs(struct reftable_writer *w,
304
static int reftable_writer_add_log_verbatim(struct reftable_writer *w,
305
struct reftable_log_record *log)
306
{
306
- struct reftable_record rec = { NULL };
307
+ struct reftable_record rec = {
308
+ .type = BLOCK_TYPE_LOG,
309
+ .u.log = *log,
310
+ };
311
if (w->block_writer &&
312
block_writer_type(w->block_writer) == BLOCK_TYPE_REF) {
313
int err = writer_finish_public_section(w);
@@ -313,8 +317,6 @@ static int reftable_writer_add_log_verbatim(struct reftable_writer *w,
317
318
w->next -= w->pending_padding;
319
w->pending_padding = 0;
316
-
317
- reftable_record_from_log(&rec, log);
320
return writer_add_record(w, &rec);
321
}
322
@@ -395,8 +397,10 @@ static int writer_finish_section(struct reftable_writer *w)
397
w->index_len = 0;
398
w->index_cap = 0;
399
for (i = 0; i < idx_len; i++) {
398
- struct reftable_record rec = { NULL };
399
- reftable_record_from_index(&rec, idx + i);
400
+ struct reftable_record rec = {
401
+ .type = BLOCK_TYPE_INDEX,
402
+ .u.idx = idx[i],
403
+ };
404
if (block_writer_add(w->block_writer, &rec) == 0) {
405
continue;
406
}
@@ -464,17 +468,17 @@ static void write_object_record(void *void_arg, void *key)
468
{
469
struct write_record_arg *arg = void_arg;
470
struct obj_index_tree_node *entry = key;
467
- struct reftable_obj_record obj_rec = {
468
- .hash_prefix = (uint8_t *)entry->hash.buf,
469
- .hash_prefix_len = arg->w->stats.object_id_len,
470
- .offsets = entry->offsets,
471
- .offset_len = entry->offset_len,
472
- };
473
- struct reftable_record rec = { NULL };
471
+ struct reftable_record
472
+ rec = { .type = BLOCK_TYPE_OBJ,
473
+ .u.obj = {
474
+ .hash_prefix = (uint8_t *)entry->hash.buf,
475
+ .hash_prefix_len = arg->w->stats.object_id_len,
476
+ .offsets = entry->offsets,
477
+ .offset_len = entry->offset_len,
478
+ } };
479
if (arg->err < 0)
480
goto done;
481
477
- reftable_record_from_obj(&rec, &obj_rec);
482
arg->err = block_writer_add(arg->w->block_writer, &rec);
483
if (arg->err == 0)
484
goto done;
@@ -487,7 +491,8 @@ static void write_object_record(void *void_arg, void *key)
491
arg->err = block_writer_add(arg->w->block_writer, &rec);
492
if (arg->err == 0)
493
goto done;
490
- obj_rec.offset_len = 0;
494
+
495
+ rec.u.obj.offset_len = 0;
496
arg->err = block_writer_add(arg->w->block_writer, &rec);
497
498
/* Should be able to write into a fresh block. */