Merge branch 'jk/http-leakfixes' into ps/leakfixes-part-8
[git/gitster.git] / reftable / iter.c
blob416a9f6996bac0701d3d47b9bd71327b732d1b28
1 /*
2 Copyright 2020 Google LLC
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 */
9 #include "iter.h"
11 #include "system.h"
13 #include "block.h"
14 #include "constants.h"
15 #include "reader.h"
16 #include "reftable-error.h"
18 int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
20 return it->ops->seek(it->iter_arg, want);
23 int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
25 return it->ops->next(it->iter_arg, rec);
28 static int empty_iterator_seek(void *arg UNUSED, struct reftable_record *want UNUSED)
30 return 0;
33 static int empty_iterator_next(void *arg UNUSED, struct reftable_record *rec UNUSED)
35 return 1;
38 static void empty_iterator_close(void *arg UNUSED)
42 static struct reftable_iterator_vtable empty_vtable = {
43 .seek = &empty_iterator_seek,
44 .next = &empty_iterator_next,
45 .close = &empty_iterator_close,
48 void iterator_set_empty(struct reftable_iterator *it)
50 assert(!it->ops);
51 it->iter_arg = NULL;
52 it->ops = &empty_vtable;
55 static void filtering_ref_iterator_close(void *iter_arg)
57 struct filtering_ref_iterator *fri = iter_arg;
58 strbuf_release(&fri->oid);
59 reftable_iterator_destroy(&fri->it);
62 static int filtering_ref_iterator_seek(void *iter_arg,
63 struct reftable_record *want)
65 struct filtering_ref_iterator *fri = iter_arg;
66 return iterator_seek(&fri->it, want);
69 static int filtering_ref_iterator_next(void *iter_arg,
70 struct reftable_record *rec)
72 struct filtering_ref_iterator *fri = iter_arg;
73 struct reftable_ref_record *ref = &rec->u.ref;
74 int err = 0;
75 while (1) {
76 err = reftable_iterator_next_ref(&fri->it, ref);
77 if (err != 0) {
78 break;
81 if (ref->value_type == REFTABLE_REF_VAL2 &&
82 (!memcmp(fri->oid.buf, ref->value.val2.target_value,
83 fri->oid.len) ||
84 !memcmp(fri->oid.buf, ref->value.val2.value,
85 fri->oid.len)))
86 return 0;
88 if (ref->value_type == REFTABLE_REF_VAL1 &&
89 !memcmp(fri->oid.buf, ref->value.val1, fri->oid.len)) {
90 return 0;
94 reftable_ref_record_release(ref);
95 return err;
98 static struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
99 .seek = &filtering_ref_iterator_seek,
100 .next = &filtering_ref_iterator_next,
101 .close = &filtering_ref_iterator_close,
104 void iterator_from_filtering_ref_iterator(struct reftable_iterator *it,
105 struct filtering_ref_iterator *fri)
107 assert(!it->ops);
108 it->iter_arg = fri;
109 it->ops = &filtering_ref_iterator_vtable;
112 static void indexed_table_ref_iter_close(void *p)
114 struct indexed_table_ref_iter *it = p;
115 block_iter_close(&it->cur);
116 reftable_block_done(&it->block_reader.block);
117 reftable_free(it->offsets);
118 strbuf_release(&it->oid);
121 static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
123 uint64_t off;
124 int err = 0;
125 if (it->offset_idx == it->offset_len) {
126 it->is_finished = 1;
127 return 1;
130 reftable_block_done(&it->block_reader.block);
132 off = it->offsets[it->offset_idx++];
133 err = reader_init_block_reader(it->r, &it->block_reader, off,
134 BLOCK_TYPE_REF);
135 if (err < 0) {
136 return err;
138 if (err > 0) {
139 /* indexed block does not exist. */
140 return REFTABLE_FORMAT_ERROR;
142 block_iter_seek_start(&it->cur, &it->block_reader);
143 return 0;
146 static int indexed_table_ref_iter_seek(void *p UNUSED,
147 struct reftable_record *want UNUSED)
149 BUG("seeking indexed table is not supported");
150 return -1;
153 static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
155 struct indexed_table_ref_iter *it = p;
156 struct reftable_ref_record *ref = &rec->u.ref;
158 while (1) {
159 int err = block_iter_next(&it->cur, rec);
160 if (err < 0) {
161 return err;
164 if (err > 0) {
165 err = indexed_table_ref_iter_next_block(it);
166 if (err < 0) {
167 return err;
170 if (it->is_finished) {
171 return 1;
173 continue;
175 /* BUG */
176 if (!memcmp(it->oid.buf, ref->value.val2.target_value,
177 it->oid.len) ||
178 !memcmp(it->oid.buf, ref->value.val2.value, it->oid.len)) {
179 return 0;
184 int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
185 struct reftable_reader *r, uint8_t *oid,
186 int oid_len, uint64_t *offsets, int offset_len)
188 struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
189 struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
190 int err = 0;
192 *itr = empty;
193 itr->r = r;
194 strbuf_add(&itr->oid, oid, oid_len);
196 itr->offsets = offsets;
197 itr->offset_len = offset_len;
199 err = indexed_table_ref_iter_next_block(itr);
200 if (err < 0) {
201 reftable_free(itr);
202 } else {
203 *dest = itr;
205 return err;
208 static struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
209 .seek = &indexed_table_ref_iter_seek,
210 .next = &indexed_table_ref_iter_next,
211 .close = &indexed_table_ref_iter_close,
214 void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
215 struct indexed_table_ref_iter *itr)
217 assert(!it->ops);
218 it->iter_arg = itr;
219 it->ops = &indexed_table_ref_iter_vtable;
222 void reftable_iterator_destroy(struct reftable_iterator *it)
224 if (!it->ops)
225 return;
226 it->ops->close(it->iter_arg);
227 it->ops = NULL;
228 FREE_AND_NULL(it->iter_arg);
231 int reftable_iterator_seek_ref(struct reftable_iterator *it,
232 const char *name)
234 struct reftable_record want = {
235 .type = BLOCK_TYPE_REF,
236 .u.ref = {
237 .refname = (char *)name,
240 return it->ops->seek(it->iter_arg, &want);
243 int reftable_iterator_next_ref(struct reftable_iterator *it,
244 struct reftable_ref_record *ref)
246 struct reftable_record rec = {
247 .type = BLOCK_TYPE_REF,
248 .u = {
249 .ref = *ref
252 int err = iterator_next(it, &rec);
253 *ref = rec.u.ref;
254 return err;
257 int reftable_iterator_seek_log_at(struct reftable_iterator *it,
258 const char *name, uint64_t update_index)
260 struct reftable_record want = {
261 .type = BLOCK_TYPE_LOG,
262 .u.log = {
263 .refname = (char *)name,
264 .update_index = update_index,
267 return it->ops->seek(it->iter_arg, &want);
270 int reftable_iterator_seek_log(struct reftable_iterator *it,
271 const char *name)
273 return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
276 int reftable_iterator_next_log(struct reftable_iterator *it,
277 struct reftable_log_record *log)
279 struct reftable_record rec = {
280 .type = BLOCK_TYPE_LOG,
281 .u = {
282 .log = *log,
285 int err = iterator_next(it, &rec);
286 *log = rec.u.log;
287 return err;