reftable: generic interface to tables

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Han-Wen Nienhuys committed Oct 7, 2021 at 20:25 UTC 17df8dbeba18c8c36f14c58815a03091ba61f895
6 files changed +405
Makefile
+3
@@ -2462,6 +2462,9 @@ REFTABLE_OBJS += reftable/block.o
2462 REFTABLE_OBJS += reftable/blocksource.o
2463 REFTABLE_OBJS += reftable/publicbasics.o
2464 REFTABLE_OBJS += reftable/record.o
2465 +REFTABLE_OBJS += reftable/refname.o
2466 +REFTABLE_OBJS += reftable/generic.o
2467 +REFTABLE_OBJS += reftable/stack.o
2468 REFTABLE_OBJS += reftable/tree.o
2469 REFTABLE_OBJS += reftable/writer.o
2470
reftable/generic.c new
+169
@@ -0,0 +1,169 @@
1 +/*
2 +Copyright 2020 Google LLC
3 +
4 +Use of this source code is governed by a BSD-style
5 +license that can be found in the LICENSE file or at
6 +https://developers.google.com/open-source/licenses/bsd
7 +*/
8 +
9 +#include "basics.h"
10 +#include "record.h"
11 +#include "generic.h"
12 +#include "reftable-iterator.h"
13 +#include "reftable-generic.h"
14 +
15 +int reftable_table_seek_ref(struct reftable_table *tab,
16 + struct reftable_iterator *it, const char *name)
17 +{
18 + struct reftable_ref_record ref = {
19 + .refname = (char *)name,
20 + };
21 + struct reftable_record rec = { NULL };
22 + reftable_record_from_ref(&rec, &ref);
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);
35 + return tab->ops->seek_record(tab->table_arg, it, &rec);
36 +}
37 +
38 +int reftable_table_read_ref(struct reftable_table *tab, const char *name,
39 + struct reftable_ref_record *ref)
40 +{
41 + struct reftable_iterator it = { NULL };
42 + int err = reftable_table_seek_ref(tab, &it, name);
43 + if (err)
44 + goto done;
45 +
46 + err = reftable_iterator_next_ref(&it, ref);
47 + if (err)
48 + goto done;
49 +
50 + if (strcmp(ref->refname, name) ||
51 + reftable_ref_record_is_deletion(ref)) {
52 + reftable_ref_record_release(ref);
53 + err = 1;
54 + goto done;
55 + }
56 +
57 +done:
58 + reftable_iterator_destroy(&it);
59 + return err;
60 +}
61 +
62 +int reftable_table_print(struct reftable_table *tab) {
63 + struct reftable_iterator it = { NULL };
64 + struct reftable_ref_record ref = { NULL };
65 + struct reftable_log_record log = { NULL };
66 + uint32_t hash_id = reftable_table_hash_id(tab);
67 + int err = reftable_table_seek_ref(tab, &it, "");
68 + if (err < 0) {
69 + return err;
70 + }
71 +
72 + while (1) {
73 + err = reftable_iterator_next_ref(&it, &ref);
74 + if (err > 0) {
75 + break;
76 + }
77 + if (err < 0) {
78 + return err;
79 + }
80 + reftable_ref_record_print(&ref, hash_id);
81 + }
82 + reftable_iterator_destroy(&it);
83 + reftable_ref_record_release(&ref);
84 +
85 + err = reftable_table_seek_log(tab, &it, "");
86 + if (err < 0) {
87 + return err;
88 + }
89 + while (1) {
90 + err = reftable_iterator_next_log(&it, &log);
91 + if (err > 0) {
92 + break;
93 + }
94 + if (err < 0) {
95 + return err;
96 + }
97 + reftable_log_record_print(&log, hash_id);
98 + }
99 + reftable_iterator_destroy(&it);
100 + reftable_log_record_release(&log);
101 + return 0;
102 +}
103 +
104 +uint64_t reftable_table_max_update_index(struct reftable_table *tab)
105 +{
106 + return tab->ops->max_update_index(tab->table_arg);
107 +}
108 +
109 +uint64_t reftable_table_min_update_index(struct reftable_table *tab)
110 +{
111 + return tab->ops->min_update_index(tab->table_arg);
112 +}
113 +
114 +uint32_t reftable_table_hash_id(struct reftable_table *tab)
115 +{
116 + return tab->ops->hash_id(tab->table_arg);
117 +}
118 +
119 +void reftable_iterator_destroy(struct reftable_iterator *it)
120 +{
121 + if (!it->ops) {
122 + return;
123 + }
124 + it->ops->close(it->iter_arg);
125 + it->ops = NULL;
126 + FREE_AND_NULL(it->iter_arg);
127 +}
128 +
129 +int reftable_iterator_next_ref(struct reftable_iterator *it,
130 + struct reftable_ref_record *ref)
131 +{
132 + struct reftable_record rec = { NULL };
133 + reftable_record_from_ref(&rec, ref);
134 + return iterator_next(it, &rec);
135 +}
136 +
137 +int reftable_iterator_next_log(struct reftable_iterator *it,
138 + struct reftable_log_record *log)
139 +{
140 + struct reftable_record rec = { NULL };
141 + reftable_record_from_log(&rec, log);
142 + return iterator_next(it, &rec);
143 +}
144 +
145 +int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
146 +{
147 + return it->ops->next(it->iter_arg, rec);
148 +}
149 +
150 +static int empty_iterator_next(void *arg, struct reftable_record *rec)
151 +{
152 + return 1;
153 +}
154 +
155 +static void empty_iterator_close(void *arg)
156 +{
157 +}
158 +
159 +static struct reftable_iterator_vtable empty_vtable = {
160 + .next = &empty_iterator_next,
161 + .close = &empty_iterator_close,
162 +};
163 +
164 +void iterator_set_empty(struct reftable_iterator *it)
165 +{
166 + assert(!it->ops);
167 + it->iter_arg = NULL;
168 + it->ops = &empty_vtable;
169 +}
reftable/generic.h new
+32
@@ -0,0 +1,32 @@
1 +/*
2 +Copyright 2020 Google LLC
3 +
4 +Use of this source code is governed by a BSD-style
5 +license that can be found in the LICENSE file or at
6 +https://developers.google.com/open-source/licenses/bsd
7 +*/
8 +
9 +#ifndef GENERIC_H
10 +#define GENERIC_H
11 +
12 +#include "record.h"
13 +#include "reftable-generic.h"
14 +
15 +/* generic interface to reftables */
16 +struct reftable_table_vtable {
17 + int (*seek_record)(void *tab, struct reftable_iterator *it,
18 + struct reftable_record *);
19 + uint32_t (*hash_id)(void *tab);
20 + uint64_t (*min_update_index)(void *tab);
21 + uint64_t (*max_update_index)(void *tab);
22 +};
23 +
24 +struct reftable_iterator_vtable {
25 + int (*next)(void *iter_arg, struct reftable_record *rec);
26 + void (*close)(void *iter_arg);
27 +};
28 +
29 +void iterator_set_empty(struct reftable_iterator *it);
30 +int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
31 +
32 +#endif
reftable/reftable-generic.h new
+47
@@ -0,0 +1,47 @@
1 +/*
2 +Copyright 2020 Google LLC
3 +
4 +Use of this source code is governed by a BSD-style
5 +license that can be found in the LICENSE file or at
6 +https://developers.google.com/open-source/licenses/bsd
7 +*/
8 +
9 +#ifndef REFTABLE_GENERIC_H
10 +#define REFTABLE_GENERIC_H
11 +
12 +#include "reftable-iterator.h"
13 +
14 +struct reftable_table_vtable;
15 +
16 +/*
17 + * Provides a unified API for reading tables, either merged tables, or single
18 + * readers. */
19 +struct reftable_table {
20 + struct reftable_table_vtable *ops;
21 + void *table_arg;
22 +};
23 +
24 +int reftable_table_seek_log(struct reftable_table *tab,
25 + struct reftable_iterator *it, const char *name);
26 +
27 +int reftable_table_seek_ref(struct reftable_table *tab,
28 + struct reftable_iterator *it, const char *name);
29 +
30 +/* returns the hash ID from a generic reftable_table */
31 +uint32_t reftable_table_hash_id(struct reftable_table *tab);
32 +
33 +/* returns the max update_index covered by this table. */
34 +uint64_t reftable_table_max_update_index(struct reftable_table *tab);
35 +
36 +/* returns the min update_index covered by this table. */
37 +uint64_t reftable_table_min_update_index(struct reftable_table *tab);
38 +
39 +/* convenience function to read a single ref. Returns < 0 for error, 0
40 + for success, and 1 if ref not found. */
41 +int reftable_table_read_ref(struct reftable_table *tab, const char *name,
42 + struct reftable_ref_record *ref);
43 +
44 +/* dump table contents onto stdout for debugging */
45 +int reftable_table_print(struct reftable_table *tab);
46 +
47 +#endif
reftable/reftable-iterator.h new
+39
@@ -0,0 +1,39 @@
1 +/*
2 +Copyright 2020 Google LLC
3 +
4 +Use of this source code is governed by a BSD-style
5 +license that can be found in the LICENSE file or at
6 +https://developers.google.com/open-source/licenses/bsd
7 +*/
8 +
9 +#ifndef REFTABLE_ITERATOR_H
10 +#define REFTABLE_ITERATOR_H
11 +
12 +#include "reftable-record.h"
13 +
14 +struct reftable_iterator_vtable;
15 +
16 +/* iterator is the generic interface for walking over data stored in a
17 + * reftable.
18 + */
19 +struct reftable_iterator {
20 + struct reftable_iterator_vtable *ops;
21 + void *iter_arg;
22 +};
23 +
24 +/* reads the next reftable_ref_record. Returns < 0 for error, 0 for OK and > 0:
25 + * end of iteration.
26 + */
27 +int reftable_iterator_next_ref(struct reftable_iterator *it,
28 + struct reftable_ref_record *ref);
29 +
30 +/* reads the next reftable_log_record. Returns < 0 for error, 0 for OK and > 0:
31 + * end of iteration.
32 + */
33 +int reftable_iterator_next_log(struct reftable_iterator *it,
34 + struct reftable_log_record *log);
35 +
36 +/* releases resources associated with an iterator. */
37 +void reftable_iterator_destroy(struct reftable_iterator *it);
38 +
39 +#endif
reftable/reftable.c new
+115
@@ -0,0 +1,115 @@
1 +/*
2 +Copyright 2020 Google LLC
3 +
4 +Use of this source code is governed by a BSD-style
5 +license that can be found in the LICENSE file or at
6 +https://developers.google.com/open-source/licenses/bsd
7 +*/
8 +
9 +#include "basics.h"
10 +#include "record.h"
11 +#include "generic.h"
12 +#include "reftable-iterator.h"
13 +#include "reftable-generic.h"
14 +
15 +int reftable_table_seek_ref(struct reftable_table *tab,
16 + struct reftable_iterator *it, const char *name)
17 +{
18 + struct reftable_ref_record ref = {
19 + .refname = (char *)name,
20 + };
21 + struct reftable_record rec = { NULL };
22 + reftable_record_from_ref(&rec, &ref);
23 + return tab->ops->seek_record(tab->table_arg, it, &rec);
24 +}
25 +
26 +int reftable_table_read_ref(struct reftable_table *tab, const char *name,
27 + struct reftable_ref_record *ref)
28 +{
29 + struct reftable_iterator it = { NULL };
30 + int err = reftable_table_seek_ref(tab, &it, name);
31 + if (err)
32 + goto done;
33 +
34 + err = reftable_iterator_next_ref(&it, ref);
35 + if (err)
36 + goto done;
37 +
38 + if (strcmp(ref->refname, name) ||
39 + reftable_ref_record_is_deletion(ref)) {
40 + reftable_ref_record_release(ref);
41 + err = 1;
42 + goto done;
43 + }
44 +
45 +done:
46 + reftable_iterator_destroy(&it);
47 + return err;
48 +}
49 +
50 +uint64_t reftable_table_max_update_index(struct reftable_table *tab)
51 +{
52 + return tab->ops->max_update_index(tab->table_arg);
53 +}
54 +
55 +uint64_t reftable_table_min_update_index(struct reftable_table *tab)
56 +{
57 + return tab->ops->min_update_index(tab->table_arg);
58 +}
59 +
60 +uint32_t reftable_table_hash_id(struct reftable_table *tab)
61 +{
62 + return tab->ops->hash_id(tab->table_arg);
63 +}
64 +
65 +void reftable_iterator_destroy(struct reftable_iterator *it)
66 +{
67 + if (!it->ops) {
68 + return;
69 + }
70 + it->ops->close(it->iter_arg);
71 + it->ops = NULL;
72 + FREE_AND_NULL(it->iter_arg);
73 +}
74 +
75 +int reftable_iterator_next_ref(struct reftable_iterator *it,
76 + struct reftable_ref_record *ref)
77 +{
78 + struct reftable_record rec = { NULL };
79 + reftable_record_from_ref(&rec, ref);
80 + return iterator_next(it, &rec);
81 +}
82 +
83 +int reftable_iterator_next_log(struct reftable_iterator *it,
84 + struct reftable_log_record *log)
85 +{
86 + struct reftable_record rec = { NULL };
87 + reftable_record_from_log(&rec, log);
88 + return iterator_next(it, &rec);
89 +}
90 +
91 +int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
92 +{
93 + return it->ops->next(it->iter_arg, rec);
94 +}
95 +
96 +static int empty_iterator_next(void *arg, struct reftable_record *rec)
97 +{
98 + return 1;
99 +}
100 +
101 +static void empty_iterator_close(void *arg)
102 +{
103 +}
104 +
105 +static struct reftable_iterator_vtable empty_vtable = {
106 + .next = &empty_iterator_next,
107 + .close = &empty_iterator_close,
108 +};
109 +
110 +void iterator_set_empty(struct reftable_iterator *it)
111 +{
112 + assert(!it->ops);
113 + it->iter_arg = NULL;
114 + it->ops = &empty_vtable;
115 +}