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;