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>

Michael Haggerty committed Jun 23, 2017 at 09:01 UTC 38b86e81ae9d3fff3ce300e867f6cd2d1732c998
1 file changed +110 -9
refs/files-backend.c
+110 -9
@@ -1062,10 +1062,102 @@ static int files_peel_ref(struct ref_store *ref_store,
1062 return peel_object(base, sha1);
1063 }
1064
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 +
1158 struct files_ref_iterator {
1159 struct ref_iterator base;
1160
1068 - struct packed_ref_cache *packed_ref_cache;
1161 struct ref_iterator *iter0;
1162 unsigned int flags;
1163 };
@@ -1118,7 +1210,6 @@ static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
1210 if (iter->iter0)
1211 ok = ref_iterator_abort(iter->iter0);
1212
1121 - release_packed_ref_cache(iter->packed_ref_cache);
1213 base_ref_iterator_free(ref_iterator);
1214 return ok;
1215 }
@@ -1160,18 +1251,28 @@ static struct ref_iterator *files_ref_iterator_begin(
1251 * (If they've already been read, that's OK; we only need to
1252 * guarantee that they're read before the packed refs, not
1253 * *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.
1257 */
1258
1259 loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
1260 prefix, 1);
1261
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);
1276
1277 iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
1278 iter->flags = flags;