Skip to content

Commit cec2b6f

Browse files
pks-tgitster
authored andcommitted
refs/iterator: separate lifecycle from iteration
The ref and reflog iterators have their lifecycle attached to iteration: once the iterator reaches its end, it is automatically released and the caller doesn't have to care about that anymore. When the iterator should be released before it has been exhausted, callers must explicitly abort the iterator via `ref_iterator_abort()`. This lifecycle is somewhat unusual in the Git codebase and creates two problems: - Callsites need to be very careful about when exactly they call `ref_iterator_abort()`, as calling the function is only valid when the iterator itself still is. This leads to somewhat awkward calling patterns in some situations. - It is impossible to reuse iterators and re-seek them to a different prefix. This feature isn't supported by any iterator implementation except for the reftable iterators anyway, but if it was implemented it would allow us to optimize cases where we need to search for specific references repeatedly by reusing internal state. Detangle the lifecycle from iteration so that we don't deallocate the iterator anymore once it is exhausted. Instead, callers are now expected to always call a newly introduce `ref_iterator_free()` function that deallocates the iterator and its internal state. Note that the `dir_iterator` is somewhat special because it does not implement the `ref_iterator` interface, but is only used to implement other iterators. Consequently, we have to provide `dir_iterator_free()` instead of `dir_iterator_release()` as the allocated structure itself is managed by the `dir_iterator` interfaces, as well, and not freed by `ref_iterator_free()` like in all the other cases. While at it, drop the return value of `ref_iterator_abort()`, which wasn't really required by any of the iterator implementations anyway. Furthermore, stop calling `base_ref_iterator_free()` in any of the backends, but instead call it in `ref_iterator_free()`. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9e39a96 commit cec2b6f

File tree

13 files changed

+105
-186
lines changed

13 files changed

+105
-186
lines changed

builtin/clone.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
342342
strbuf_setlen(src, src_len);
343343
die(_("failed to iterate over '%s'"), src->buf);
344344
}
345+
346+
dir_iterator_free(iter);
345347
}
346348

347349
static void clone_local(const char *src_repo, const char *dest_repo)

dir-iterator.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,9 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
193193

194194
if (S_ISDIR(iter->base.st.st_mode) && push_level(iter)) {
195195
if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
196-
goto error_out;
196+
return ITER_ERROR;
197197
if (iter->levels_nr == 0)
198-
goto error_out;
198+
return ITER_ERROR;
199199
}
200200

201201
/* Loop until we find an entry that we can give back to the caller. */
@@ -211,19 +211,19 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
211211
int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
212212
if (ret < 0) {
213213
if (iter->flags & DIR_ITERATOR_PEDANTIC)
214-
goto error_out;
214+
return ITER_ERROR;
215215
continue;
216216
} else if (ret > 0) {
217217
if (pop_level(iter) == 0)
218-
return dir_iterator_abort(dir_iterator);
218+
return ITER_DONE;
219219
continue;
220220
}
221221

222222
name = de->d_name;
223223
} else {
224224
if (level->entries_idx >= level->entries.nr) {
225225
if (pop_level(iter) == 0)
226-
return dir_iterator_abort(dir_iterator);
226+
return ITER_DONE;
227227
continue;
228228
}
229229

@@ -232,22 +232,21 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
232232

233233
if (prepare_next_entry_data(iter, name)) {
234234
if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
235-
goto error_out;
235+
return ITER_ERROR;
236236
continue;
237237
}
238238

239239
return ITER_OK;
240240
}
241-
242-
error_out:
243-
dir_iterator_abort(dir_iterator);
244-
return ITER_ERROR;
245241
}
246242

247-
int dir_iterator_abort(struct dir_iterator *dir_iterator)
243+
void dir_iterator_free(struct dir_iterator *dir_iterator)
248244
{
249245
struct dir_iterator_int *iter = (struct dir_iterator_int *)dir_iterator;
250246

247+
if (!iter)
248+
return;
249+
251250
for (; iter->levels_nr; iter->levels_nr--) {
252251
struct dir_iterator_level *level =
253252
&iter->levels[iter->levels_nr - 1];
@@ -266,7 +265,6 @@ int dir_iterator_abort(struct dir_iterator *dir_iterator)
266265
free(iter->levels);
267266
strbuf_release(&iter->base.path);
268267
free(iter);
269-
return ITER_DONE;
270268
}
271269

272270
struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
@@ -301,7 +299,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
301299
return dir_iterator;
302300

303301
error_out:
304-
dir_iterator_abort(dir_iterator);
302+
dir_iterator_free(dir_iterator);
305303
errno = saved_errno;
306304
return NULL;
307305
}

dir-iterator.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
* while ((ok = dir_iterator_advance(iter)) == ITER_OK) {
3030
* if (want_to_stop_iteration()) {
31-
* ok = dir_iterator_abort(iter);
31+
* ok = ITER_DONE;
3232
* break;
3333
* }
3434
*
@@ -39,6 +39,7 @@
3939
*
4040
* if (ok != ITER_DONE)
4141
* handle_error();
42+
* dir_iterator_free(iter);
4243
*
4344
* Callers are allowed to modify iter->path while they are working,
4445
* but they must restore it to its original contents before calling
@@ -107,11 +108,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags);
107108
*/
108109
int dir_iterator_advance(struct dir_iterator *iterator);
109110

110-
/*
111-
* End the iteration before it has been exhausted. Free the
112-
* dir_iterator and any associated resources and return ITER_DONE. On
113-
* error, free the dir_iterator and return ITER_ERROR.
114-
*/
115-
int dir_iterator_abort(struct dir_iterator *iterator);
111+
/* Free the dir_iterator and any associated resources. */
112+
void dir_iterator_free(struct dir_iterator *iterator);
116113

117114
#endif

iterator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#define ITER_OK 0
1313

1414
/*
15-
* The iterator is exhausted and has been freed.
15+
* The iterator is exhausted.
1616
*/
1717
#define ITER_DONE -1
1818

refs.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,7 @@ int refs_verify_refnames_available(struct ref_store *refs,
24852485
struct strbuf dirname = STRBUF_INIT;
24862486
struct strbuf referent = STRBUF_INIT;
24872487
struct string_list_item *item;
2488+
struct ref_iterator *iter = NULL;
24882489
struct strset dirnames;
24892490
int ret = -1;
24902491

@@ -2561,7 +2562,6 @@ int refs_verify_refnames_available(struct ref_store *refs,
25612562
strbuf_addch(&dirname, '/');
25622563

25632564
if (!initial_transaction) {
2564-
struct ref_iterator *iter;
25652565
int ok;
25662566

25672567
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
@@ -2573,12 +2573,14 @@ int refs_verify_refnames_available(struct ref_store *refs,
25732573

25742574
strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
25752575
iter->refname, refname);
2576-
ref_iterator_abort(iter);
25772576
goto cleanup;
25782577
}
25792578

25802579
if (ok != ITER_DONE)
25812580
BUG("error while iterating over references");
2581+
2582+
ref_iterator_free(iter);
2583+
iter = NULL;
25822584
}
25832585

25842586
extra_refname = find_descendant_ref(dirname.buf, extras, skip);
@@ -2595,6 +2597,7 @@ int refs_verify_refnames_available(struct ref_store *refs,
25952597
strbuf_release(&referent);
25962598
strbuf_release(&dirname);
25972599
strset_clear(&dirnames);
2600+
ref_iterator_free(iter);
25982601
return ret;
25992602
}
26002603

refs/debug.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,19 +179,18 @@ static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator,
179179
return res;
180180
}
181181

182-
static int debug_ref_iterator_abort(struct ref_iterator *ref_iterator)
182+
static void debug_ref_iterator_release(struct ref_iterator *ref_iterator)
183183
{
184184
struct debug_ref_iterator *diter =
185185
(struct debug_ref_iterator *)ref_iterator;
186-
int res = diter->iter->vtable->abort(diter->iter);
187-
trace_printf_key(&trace_refs, "iterator_abort: %d\n", res);
188-
return res;
186+
diter->iter->vtable->release(diter->iter);
187+
trace_printf_key(&trace_refs, "iterator_abort\n");
189188
}
190189

191190
static struct ref_iterator_vtable debug_ref_iterator_vtable = {
192191
.advance = debug_ref_iterator_advance,
193192
.peel = debug_ref_iterator_peel,
194-
.abort = debug_ref_iterator_abort,
193+
.release = debug_ref_iterator_release,
195194
};
196195

197196
static struct ref_iterator *

refs/files-backend.c

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -915,10 +915,6 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
915915
return ITER_OK;
916916
}
917917

918-
iter->iter0 = NULL;
919-
if (ref_iterator_abort(ref_iterator) != ITER_DONE)
920-
ok = ITER_ERROR;
921-
922918
return ok;
923919
}
924920

@@ -931,23 +927,17 @@ static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
931927
return ref_iterator_peel(iter->iter0, peeled);
932928
}
933929

934-
static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
930+
static void files_ref_iterator_release(struct ref_iterator *ref_iterator)
935931
{
936932
struct files_ref_iterator *iter =
937933
(struct files_ref_iterator *)ref_iterator;
938-
int ok = ITER_DONE;
939-
940-
if (iter->iter0)
941-
ok = ref_iterator_abort(iter->iter0);
942-
943-
base_ref_iterator_free(ref_iterator);
944-
return ok;
934+
ref_iterator_free(iter->iter0);
945935
}
946936

947937
static struct ref_iterator_vtable files_ref_iterator_vtable = {
948938
.advance = files_ref_iterator_advance,
949939
.peel = files_ref_iterator_peel,
950-
.abort = files_ref_iterator_abort,
940+
.release = files_ref_iterator_release,
951941
};
952942

953943
static struct ref_iterator *files_ref_iterator_begin(
@@ -1378,14 +1368,15 @@ static int should_pack_refs(struct files_ref_store *refs,
13781368
iter->flags, opts))
13791369
refcount++;
13801370
if (refcount >= limit) {
1381-
ref_iterator_abort(iter);
1371+
ref_iterator_free(iter);
13821372
return 1;
13831373
}
13841374
}
13851375

13861376
if (ret != ITER_DONE)
13871377
die("error while iterating over references");
13881378

1379+
ref_iterator_free(iter);
13891380
return 0;
13901381
}
13911382

@@ -1452,6 +1443,7 @@ static int files_pack_refs(struct ref_store *ref_store,
14521443
packed_refs_unlock(refs->packed_ref_store);
14531444

14541445
prune_refs(refs, &refs_to_prune);
1446+
ref_iterator_free(iter);
14551447
strbuf_release(&err);
14561448
return 0;
14571449
}
@@ -2299,9 +2291,6 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
22992291
return ITER_OK;
23002292
}
23012293

2302-
iter->dir_iterator = NULL;
2303-
if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
2304-
ok = ITER_ERROR;
23052294
return ok;
23062295
}
23072296

@@ -2311,23 +2300,17 @@ static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
23112300
BUG("ref_iterator_peel() called for reflog_iterator");
23122301
}
23132302

2314-
static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
2303+
static void files_reflog_iterator_release(struct ref_iterator *ref_iterator)
23152304
{
23162305
struct files_reflog_iterator *iter =
23172306
(struct files_reflog_iterator *)ref_iterator;
2318-
int ok = ITER_DONE;
2319-
2320-
if (iter->dir_iterator)
2321-
ok = dir_iterator_abort(iter->dir_iterator);
2322-
2323-
base_ref_iterator_free(ref_iterator);
2324-
return ok;
2307+
dir_iterator_free(iter->dir_iterator);
23252308
}
23262309

23272310
static struct ref_iterator_vtable files_reflog_iterator_vtable = {
23282311
.advance = files_reflog_iterator_advance,
23292312
.peel = files_reflog_iterator_peel,
2330-
.abort = files_reflog_iterator_abort,
2313+
.release = files_reflog_iterator_release,
23312314
};
23322315

23332316
static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
@@ -3837,6 +3820,7 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
38373820
ret = error(_("failed to iterate over '%s'"), sb.buf);
38383821

38393822
out:
3823+
dir_iterator_free(iter);
38403824
strbuf_release(&sb);
38413825
strbuf_release(&refname);
38423826
return ret;

0 commit comments

Comments
 (0)