refs/iterator: implement seeking for packed-ref iterators
Implement seeking of `packed-ref` iterators. The implementation is again straight forward, except that we cannot continue to use the prefix iterator as we would otherwise not be able to reseek the iterator anymore in case one first asks for an empty and then for a non-empty prefix. Instead, we open-code the logic to in `advance()`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Mar 12, 2025 at 16:56 UTC
22600c045298f4f3664f94f6cbbf337903c72e82
1 file changed
+43
-22
refs/packed-backend.c
+43
-22
@@ -819,6 +819,8 @@ struct packed_ref_iterator {
819
820
struct snapshot *snapshot;
821
822
+ char *prefix;
823
+
824
/* The current position in the snapshot's buffer: */
825
const char *pos;
826
@@ -841,11 +843,9 @@ struct packed_ref_iterator {
843
};
844
845
/*
844
- * Move the iterator to the next record in the snapshot, without
845
- * respect for whether the record is actually required by the current
846
- * iteration. Adjust the fields in `iter` and return `ITER_OK` or
847
- * `ITER_DONE`. This function does not free the iterator in the case
848
- * of `ITER_DONE`.
846
+ * Move the iterator to the next record in the snapshot. Adjust the fields in
847
+ * `iter` and return `ITER_OK` or `ITER_DONE`. This function does not free the
848
+ * iterator in the case of `ITER_DONE`.
849
*/
850
static int next_record(struct packed_ref_iterator *iter)
851
{
@@ -942,6 +942,9 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
942
int ok;
943
944
while ((ok = next_record(iter)) == ITER_OK) {
945
+ const char *refname = iter->base.refname;
946
+ const char *prefix = iter->prefix;
947
+
948
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
949
!is_per_worktree_ref(iter->base.refname))
950
continue;
@@ -951,12 +954,41 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
954
&iter->oid, iter->flags))
955
continue;
956
957
+ while (prefix && *prefix) {
958
+ if (*refname < *prefix)
959
+ BUG("packed-refs backend yielded reference preceding its prefix");
960
+ else if (*refname > *prefix)
961
+ return ITER_DONE;
962
+ prefix++;
963
+ refname++;
964
+ }
965
+
966
return ITER_OK;
967
}
968
969
return ok;
970
}
971
972
+static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator,
973
+ const char *prefix)
974
+{
975
+ struct packed_ref_iterator *iter =
976
+ (struct packed_ref_iterator *)ref_iterator;
977
+ const char *start;
978
+
979
+ if (prefix && *prefix)
980
+ start = find_reference_location(iter->snapshot, prefix, 0);
981
+ else
982
+ start = iter->snapshot->start;
983
+
984
+ free(iter->prefix);
985
+ iter->prefix = xstrdup_or_null(prefix);
986
+ iter->pos = start;
987
+ iter->eof = iter->snapshot->eof;
988
+
989
+ return 0;
990
+}
991
+
992
static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
993
struct object_id *peeled)
994
{
@@ -979,11 +1011,13 @@ static void packed_ref_iterator_release(struct ref_iterator *ref_iterator)
1011
(struct packed_ref_iterator *)ref_iterator;
1012
strbuf_release(&iter->refname_buf);
1013
free(iter->jump);
1014
+ free(iter->prefix);
1015
release_snapshot(iter->snapshot);
1016
}
1017
1018
static struct ref_iterator_vtable packed_ref_iterator_vtable = {
1019
.advance = packed_ref_iterator_advance,
1020
+ .seek = packed_ref_iterator_seek,
1021
.peel = packed_ref_iterator_peel,
1022
.release = packed_ref_iterator_release,
1023
};
@@ -1097,7 +1131,6 @@ static struct ref_iterator *packed_ref_iterator_begin(
1131
{
1132
struct packed_ref_store *refs;
1133
struct snapshot *snapshot;
1100
- const char *start;
1134
struct packed_ref_iterator *iter;
1135
struct ref_iterator *ref_iterator;
1136
unsigned int required_flags = REF_STORE_READ;
@@ -1113,14 +1146,6 @@ static struct ref_iterator *packed_ref_iterator_begin(
1146
*/
1147
snapshot = get_snapshot(refs);
1148
1116
- if (prefix && *prefix)
1117
- start = find_reference_location(snapshot, prefix, 0);
1118
- else
1119
- start = snapshot->start;
1120
-
1121
- if (start == snapshot->eof)
1122
- return empty_ref_iterator_begin();
1123
-
1149
CALLOC_ARRAY(iter, 1);
1150
ref_iterator = &iter->base;
1151
base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable);
@@ -1130,19 +1155,15 @@ static struct ref_iterator *packed_ref_iterator_begin(
1155
1156
iter->snapshot = snapshot;
1157
acquire_snapshot(snapshot);
1133
-
1134
- iter->pos = start;
1135
- iter->eof = snapshot->eof;
1158
strbuf_init(&iter->refname_buf, 0);
1137
-
1159
iter->base.oid = &iter->oid;
1139
-
1160
iter->repo = ref_store->repo;
1161
iter->flags = flags;
1162
1143
- if (prefix && *prefix)
1144
- /* Stop iteration after we've gone *past* prefix: */
1145
- ref_iterator = prefix_ref_iterator_begin(ref_iterator, prefix, 0);
1163
+ if (packed_ref_iterator_seek(&iter->base, prefix) < 0) {
1164
+ ref_iterator_free(&iter->base);
1165
+ return NULL;
1166
+ }
1167
1168
return ref_iterator;
1169
}