Line | Count | Source (jump to first uncovered line) |
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 "iter.h" |
10 | | |
11 | | #include "system.h" |
12 | | |
13 | | #include "block.h" |
14 | | #include "constants.h" |
15 | | #include "reader.h" |
16 | | #include "reftable.h" |
17 | | |
18 | | bool iterator_is_null(struct reftable_iterator it) |
19 | 670 | { |
20 | 670 | return it.ops == NULL; |
21 | 670 | } |
22 | | |
23 | | static int empty_iterator_next(void *arg, struct record rec) |
24 | 215 | { |
25 | 215 | return 1; |
26 | 215 | } |
27 | | |
28 | | static void empty_iterator_close(void *arg) |
29 | 215 | { |
30 | 215 | } |
31 | | |
32 | | struct reftable_iterator_vtable empty_vtable = { |
33 | | .next = &empty_iterator_next, |
34 | | .close = &empty_iterator_close, |
35 | | }; |
36 | | |
37 | | void iterator_set_empty(struct reftable_iterator *it) |
38 | 215 | { |
39 | 215 | assert(it->ops == NULL); |
40 | 215 | it->iter_arg = NULL; |
41 | 215 | it->ops = &empty_vtable; |
42 | 215 | } |
43 | | |
44 | | int iterator_next(struct reftable_iterator it, struct record rec) |
45 | 3.11k | { |
46 | 3.11k | return it.ops->next(it.iter_arg, rec); |
47 | 3.11k | } |
48 | | |
49 | | void reftable_iterator_destroy(struct reftable_iterator *it) |
50 | 2.37k | { |
51 | 2.37k | if (it->ops == NULL) { |
52 | 699 | return; |
53 | 699 | } |
54 | 1.67k | it->ops->close(it->iter_arg); |
55 | 1.67k | it->ops = NULL; |
56 | 1.67k | FREE_AND_NULL(it->iter_arg); |
57 | 1.67k | } |
58 | | |
59 | | int reftable_iterator_next_ref(struct reftable_iterator it, |
60 | | struct reftable_ref_record *ref) |
61 | 1.25k | { |
62 | 1.25k | struct record rec = { 0 }; |
63 | 1.25k | record_from_ref(&rec, ref); |
64 | 1.25k | return iterator_next(it, rec); |
65 | 1.25k | } |
66 | | |
67 | | int reftable_iterator_next_log(struct reftable_iterator it, |
68 | | struct reftable_log_record *log) |
69 | 187 | { |
70 | 187 | struct record rec = { 0 }; |
71 | 187 | record_from_log(&rec, log); |
72 | 187 | return iterator_next(it, rec); |
73 | 187 | } |
74 | | |
75 | | static void filtering_ref_iterator_close(void *iter_arg) |
76 | 1 | { |
77 | 1 | struct filtering_ref_iterator *fri = |
78 | 1 | (struct filtering_ref_iterator *)iter_arg; |
79 | 1 | slice_clear(&fri->oid); |
80 | 1 | reftable_iterator_destroy(&fri->it); |
81 | 1 | } |
82 | | |
83 | | static int filtering_ref_iterator_next(void *iter_arg, struct record rec) |
84 | 9 | { |
85 | 9 | struct filtering_ref_iterator *fri = |
86 | 9 | (struct filtering_ref_iterator *)iter_arg; |
87 | 9 | struct reftable_ref_record *ref = |
88 | 9 | (struct reftable_ref_record *)rec.data; |
89 | 9 | int err = 0; |
90 | 51 | while (true) { |
91 | 51 | err = reftable_iterator_next_ref(fri->it, ref); |
92 | 51 | if (err != 0) { |
93 | 1 | break; |
94 | 1 | } |
95 | 50 | |
96 | 50 | if (fri->double_check) { |
97 | 0 | struct reftable_iterator it = { 0 }; |
98 | 0 |
|
99 | 0 | err = reftable_table_seek_ref(fri->tab, &it, |
100 | 0 | ref->ref_name); |
101 | 0 | if (err == 0) { |
102 | 0 | err = reftable_iterator_next_ref(it, ref); |
103 | 0 | } |
104 | 0 |
|
105 | 0 | reftable_iterator_destroy(&it); |
106 | 0 |
|
107 | 0 | if (err < 0) { |
108 | 0 | break; |
109 | 0 | } |
110 | 0 | |
111 | 0 | if (err > 0) { |
112 | 0 | continue; |
113 | 0 | } |
114 | 50 | } |
115 | 50 | |
116 | 50 | if ((ref->target_value != NULL && |
117 | 50 | !memcmp(fri->oid.buf, ref->target_value, fri->oid.len)) || |
118 | 50 | (ref->value != NULL && |
119 | 46 | !memcmp(fri->oid.buf, ref->value, fri->oid.len))) { |
120 | 8 | return 0; |
121 | 8 | } |
122 | 50 | } |
123 | 9 | |
124 | 9 | reftable_ref_record_clear(ref); |
125 | 1 | return err; |
126 | 9 | } |
127 | | |
128 | | struct reftable_iterator_vtable filtering_ref_iterator_vtable = { |
129 | | .next = &filtering_ref_iterator_next, |
130 | | .close = &filtering_ref_iterator_close, |
131 | | }; |
132 | | |
133 | | void iterator_from_filtering_ref_iterator(struct reftable_iterator *it, |
134 | | struct filtering_ref_iterator *fri) |
135 | 1 | { |
136 | 1 | assert(it->ops == NULL); |
137 | 1 | it->iter_arg = fri; |
138 | 1 | it->ops = &filtering_ref_iterator_vtable; |
139 | 1 | } |
140 | | |
141 | | static void indexed_table_ref_iter_close(void *p) |
142 | 1 | { |
143 | 1 | struct indexed_table_ref_iter *it = (struct indexed_table_ref_iter *)p; |
144 | 1 | block_iter_close(&it->cur); |
145 | 1 | reftable_block_done(&it->block_reader.block); |
146 | 1 | slice_clear(&it->oid); |
147 | 1 | } |
148 | | |
149 | | static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it) |
150 | 5 | { |
151 | 5 | if (it->offset_idx == it->offset_len) { |
152 | 1 | it->finished = true; |
153 | 1 | return 1; |
154 | 1 | } |
155 | 4 | |
156 | 4 | reftable_block_done(&it->block_reader.block); |
157 | 4 | |
158 | 4 | { |
159 | 4 | uint64_t off = it->offsets[it->offset_idx++]; |
160 | 4 | int err = reader_init_block_reader(it->r, &it->block_reader, |
161 | 4 | off, BLOCK_TYPE_REF); |
162 | 4 | if (err < 0) { |
163 | 0 | return err; |
164 | 0 | } |
165 | 4 | if (err > 0) { |
166 | 0 | /* indexed block does not exist. */ |
167 | 0 | return REFTABLE_FORMAT_ERROR; |
168 | 0 | } |
169 | 4 | } |
170 | 4 | block_reader_start(&it->block_reader, &it->cur); |
171 | 4 | return 0; |
172 | 4 | } |
173 | | |
174 | | static int indexed_table_ref_iter_next(void *p, struct record rec) |
175 | 9 | { |
176 | 9 | struct indexed_table_ref_iter *it = (struct indexed_table_ref_iter *)p; |
177 | 9 | struct reftable_ref_record *ref = |
178 | 9 | (struct reftable_ref_record *)rec.data; |
179 | 9 | |
180 | 16 | while (true) { |
181 | 16 | int err = block_iter_next(&it->cur, rec); |
182 | 16 | if (err < 0) { |
183 | 0 | return err; |
184 | 0 | } |
185 | 16 | |
186 | 16 | if (err > 0) { |
187 | 4 | err = indexed_table_ref_iter_next_block(it); |
188 | 4 | if (err < 0) { |
189 | 0 | return err; |
190 | 0 | } |
191 | 4 | |
192 | 4 | if (it->finished) { |
193 | 1 | return 1; |
194 | 1 | } |
195 | 3 | continue; |
196 | 3 | } |
197 | 12 | |
198 | 12 | if (!memcmp(it->oid.buf, ref->target_value, it->oid.len) || |
199 | 12 | !memcmp(it->oid.buf, ref->value, it->oid.len)) { |
200 | 8 | return 0; |
201 | 8 | } |
202 | 12 | } |
203 | 9 | } |
204 | | |
205 | | int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest, |
206 | | struct reftable_reader *r, byte *oid, |
207 | | int oid_len, uint64_t *offsets, int offset_len) |
208 | 1 | { |
209 | 1 | struct indexed_table_ref_iter *itr = |
210 | 1 | reftable_calloc(sizeof(struct indexed_table_ref_iter)); |
211 | 1 | int err = 0; |
212 | 1 | |
213 | 1 | itr->r = r; |
214 | 1 | slice_resize(&itr->oid, oid_len); |
215 | 1 | memcpy(itr->oid.buf, oid, oid_len); |
216 | 1 | |
217 | 1 | itr->offsets = offsets; |
218 | 1 | itr->offset_len = offset_len; |
219 | 1 | |
220 | 1 | err = indexed_table_ref_iter_next_block(itr); |
221 | 1 | if (err < 0) { |
222 | 0 | reftable_free(itr); |
223 | 1 | } else { |
224 | 1 | *dest = itr; |
225 | 1 | } |
226 | 1 | return err; |
227 | 1 | } |
228 | | |
229 | | struct reftable_iterator_vtable indexed_table_ref_iter_vtable = { |
230 | | .next = &indexed_table_ref_iter_next, |
231 | | .close = &indexed_table_ref_iter_close, |
232 | | }; |
233 | | |
234 | | void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it, |
235 | | struct indexed_table_ref_iter *itr) |
236 | 1 | { |
237 | 1 | assert(it->ops == NULL); |
238 | 1 | it->iter_arg = itr; |
239 | 1 | it->ops = &indexed_table_ref_iter_vtable; |
240 | 1 | } |