Skip to content

Commit 38b86e8

Browse files
mhaggergitster
authored andcommitted
packed_ref_store: support iteration
Add the infrastructure to iterate over a `packed_ref_store`. It's a lot of boilerplate, but it's all part of a campaign to make `packed_ref_store` implement `ref_store`. In the future, this iterator will work much differently. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 6dc6ba7 commit 38b86e8

File tree

1 file changed

+110
-9
lines changed

1 file changed

+110
-9
lines changed

refs/files-backend.c

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,10 +1062,102 @@ static int files_peel_ref(struct ref_store *ref_store,
10621062
return peel_object(base, sha1);
10631063
}
10641064

1065+
struct packed_ref_iterator {
1066+
struct ref_iterator base;
1067+
1068+
struct packed_ref_cache *cache;
1069+
struct ref_iterator *iter0;
1070+
unsigned int flags;
1071+
};
1072+
1073+
static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
1074+
{
1075+
struct packed_ref_iterator *iter =
1076+
(struct packed_ref_iterator *)ref_iterator;
1077+
int ok;
1078+
1079+
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
1080+
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
1081+
ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
1082+
continue;
1083+
1084+
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
1085+
!ref_resolves_to_object(iter->iter0->refname,
1086+
iter->iter0->oid,
1087+
iter->iter0->flags))
1088+
continue;
1089+
1090+
iter->base.refname = iter->iter0->refname;
1091+
iter->base.oid = iter->iter0->oid;
1092+
iter->base.flags = iter->iter0->flags;
1093+
return ITER_OK;
1094+
}
1095+
1096+
iter->iter0 = NULL;
1097+
if (ref_iterator_abort(ref_iterator) != ITER_DONE)
1098+
ok = ITER_ERROR;
1099+
1100+
return ok;
1101+
}
1102+
1103+
static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
1104+
struct object_id *peeled)
1105+
{
1106+
struct packed_ref_iterator *iter =
1107+
(struct packed_ref_iterator *)ref_iterator;
1108+
1109+
return ref_iterator_peel(iter->iter0, peeled);
1110+
}
1111+
1112+
static int packed_ref_iterator_abort(struct ref_iterator *ref_iterator)
1113+
{
1114+
struct packed_ref_iterator *iter =
1115+
(struct packed_ref_iterator *)ref_iterator;
1116+
int ok = ITER_DONE;
1117+
1118+
if (iter->iter0)
1119+
ok = ref_iterator_abort(iter->iter0);
1120+
1121+
release_packed_ref_cache(iter->cache);
1122+
base_ref_iterator_free(ref_iterator);
1123+
return ok;
1124+
}
1125+
1126+
static struct ref_iterator_vtable packed_ref_iterator_vtable = {
1127+
packed_ref_iterator_advance,
1128+
packed_ref_iterator_peel,
1129+
packed_ref_iterator_abort
1130+
};
1131+
1132+
static struct ref_iterator *packed_ref_iterator_begin(
1133+
struct packed_ref_store *refs,
1134+
const char *prefix, unsigned int flags)
1135+
{
1136+
struct packed_ref_iterator *iter;
1137+
struct ref_iterator *ref_iterator;
1138+
1139+
iter = xcalloc(1, sizeof(*iter));
1140+
ref_iterator = &iter->base;
1141+
base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable);
1142+
1143+
/*
1144+
* Note that get_packed_ref_cache() internally checks whether
1145+
* the packed-ref cache is up to date with what is on disk,
1146+
* and re-reads it if not.
1147+
*/
1148+
1149+
iter->cache = get_packed_ref_cache(refs);
1150+
acquire_packed_ref_cache(iter->cache);
1151+
iter->iter0 = cache_ref_iterator_begin(iter->cache->cache, prefix, 0);
1152+
1153+
iter->flags = flags;
1154+
1155+
return ref_iterator;
1156+
}
1157+
10651158
struct files_ref_iterator {
10661159
struct ref_iterator base;
10671160

1068-
struct packed_ref_cache *packed_ref_cache;
10691161
struct ref_iterator *iter0;
10701162
unsigned int flags;
10711163
};
@@ -1118,7 +1210,6 @@ static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
11181210
if (iter->iter0)
11191211
ok = ref_iterator_abort(iter->iter0);
11201212

1121-
release_packed_ref_cache(iter->packed_ref_cache);
11221213
base_ref_iterator_free(ref_iterator);
11231214
return ok;
11241215
}
@@ -1160,18 +1251,28 @@ static struct ref_iterator *files_ref_iterator_begin(
11601251
* (If they've already been read, that's OK; we only need to
11611252
* guarantee that they're read before the packed refs, not
11621253
* *how much* before.) After that, we call
1163-
* get_packed_ref_cache(), which internally checks whether the
1164-
* packed-ref cache is up to date with what is on disk, and
1165-
* re-reads it if not.
1254+
* packed_ref_iterator_begin(), which internally checks
1255+
* whether the packed-ref cache is up to date with what is on
1256+
* disk, and re-reads it if not.
11661257
*/
11671258

11681259
loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
11691260
prefix, 1);
11701261

1171-
iter->packed_ref_cache = get_packed_ref_cache(refs->packed_ref_store);
1172-
acquire_packed_ref_cache(iter->packed_ref_cache);
1173-
packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,
1174-
prefix, 0);
1262+
/*
1263+
* The packed-refs file might contain broken references, for
1264+
* example an old version of a reference that points at an
1265+
* object that has since been garbage-collected. This is OK as
1266+
* long as there is a corresponding loose reference that
1267+
* overrides it, and we don't want to emit an error message in
1268+
* this case. So ask the packed_ref_store for all of its
1269+
* references, and (if needed) do our own check for broken
1270+
* ones in files_ref_iterator_advance(), after we have merged
1271+
* the packed and loose references.
1272+
*/
1273+
packed_iter = packed_ref_iterator_begin(
1274+
refs->packed_ref_store, prefix,
1275+
DO_FOR_EACH_INCLUDE_BROKEN);
11751276

11761277
iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
11771278
iter->flags = flags;

0 commit comments

Comments
 (0)