cache.h: allow oid_object_info to handle arbitrary repositories

This involves also adapting oid_object_info_extended and a some internal functions that are used to implement these. It all has to happen in one patch, because of a single recursive chain of calls visits all these functions. oid_object_info_extended is also used in partial clones, which allow fetching missing objects. As this series will not add the repository struct to the transport code and fetch_object(), add a TODO note and omit fetching if a user tries to use a partial clone in a repository other than the_repository. Among the functions modified to handle arbitrary repositories, unpack_entry() is one of them. Note that it still references the globals "delta_base_cache" and "delta_base_cached", but those are safe to be referenced (the former is indexed partly by "struct packed_git *", which is repo-specific, and the latter is only used to limit the size of the former as an optimization). Helped-by: Brandon Williams <bmwill@google.com> Helped-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Stefan Beller <sbeller@google.com> Reviewed-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Apr 25, 2018 at 11:21 UTC 9d98354f48997faf8251c566d909957f6ae427d5
4 files changed +54 -52
cache.h
+4 -5
@@ -1192,8 +1192,7 @@ static inline void *read_object_file(const struct object_id *oid, enum object_ty
1192 }
1193
1194 /* Read and unpack an object file into memory, write memory to an object file */
1195 -#define oid_object_info(r, o, f) oid_object_info_##r(o, f)
1196 -int oid_object_info_the_repository(const struct object_id *, unsigned long *);
1195 +int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
1196
1197 extern int hash_object_file(const void *buf, unsigned long len,
1198 const char *type, struct object_id *oid);
@@ -1675,9 +1674,9 @@ struct object_info {
1674 /* Do not check loose object */
1675 #define OBJECT_INFO_IGNORE_LOOSE 16
1676
1678 -#define oid_object_info_extended(r, oid, oi, flags) \
1679 - oid_object_info_extended_##r(oid, oi, flags)
1680 -int oid_object_info_extended_the_repository(const struct object_id *, struct object_info *, unsigned flags);
1677 +int oid_object_info_extended(struct repository *r,
1678 + const struct object_id *,
1679 + struct object_info *, unsigned flags);
1680
1681 /*
1682 * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
packfile.c
+28 -30
@@ -1104,9 +1104,9 @@ static const unsigned char *get_delta_base_sha1(struct packed_git *p,
1104 return NULL;
1105 }
1106
1107 -#define retry_bad_packed_offset(r, p, o) \
1108 - retry_bad_packed_offset_##r(p, o)
1109 -static int retry_bad_packed_offset_the_repository(struct packed_git *p, off_t obj_offset)
1107 +static int retry_bad_packed_offset(struct repository *r,
1108 + struct packed_git *p,
1109 + off_t obj_offset)
1110 {
1111 int type;
1112 struct revindex_entry *revidx;
@@ -1116,7 +1116,7 @@ static int retry_bad_packed_offset_the_repository(struct packed_git *p, off_t ob
1116 return OBJ_BAD;
1117 nth_packed_object_oid(&oid, p, revidx->nr);
1118 mark_bad_packed_object(p, oid.hash);
1119 - type = oid_object_info(the_repository, &oid, NULL);
1119 + type = oid_object_info(r, &oid, NULL);
1120 if (type <= OBJ_NONE)
1121 return OBJ_BAD;
1122 return type;
@@ -1124,13 +1124,12 @@ static int retry_bad_packed_offset_the_repository(struct packed_git *p, off_t ob
1124
1125 #define POI_STACK_PREALLOC 64
1126
1127 -#define packed_to_object_type(r, p, o, t, w, c) \
1128 - packed_to_object_type_##r(p, o, t, w, c)
1129 -static enum object_type packed_to_object_type_the_repository(struct packed_git *p,
1130 - off_t obj_offset,
1131 - enum object_type type,
1132 - struct pack_window **w_curs,
1133 - off_t curpos)
1127 +static enum object_type packed_to_object_type(struct repository *r,
1128 + struct packed_git *p,
1129 + off_t obj_offset,
1130 + enum object_type type,
1131 + struct pack_window **w_curs,
1132 + off_t curpos)
1133 {
1134 off_t small_poi_stack[POI_STACK_PREALLOC];
1135 off_t *poi_stack = small_poi_stack;
@@ -1157,7 +1156,7 @@ static enum object_type packed_to_object_type_the_repository(struct packed_git *
1156 if (type <= OBJ_NONE) {
1157 /* If getting the base itself fails, we first
1158 * retry the base, otherwise unwind */
1160 - type = retry_bad_packed_offset(the_repository, p, base_offset);
1159 + type = retry_bad_packed_offset(r, p, base_offset);
1160 if (type > OBJ_NONE)
1161 goto out;
1162 goto unwind;
@@ -1185,7 +1184,7 @@ out:
1184 unwind:
1185 while (poi_stack_nr) {
1186 obj_offset = poi_stack[--poi_stack_nr];
1188 - type = retry_bad_packed_offset(the_repository, p, obj_offset);
1187 + type = retry_bad_packed_offset(r, p, obj_offset);
1188 if (type > OBJ_NONE)
1189 goto out;
1190 }
@@ -1272,15 +1271,15 @@ static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)
1271 free(ent);
1272 }
1273
1275 -#define cache_or_unpack_entry(r, p, bo, bs, t) cache_or_unpack_entry_##r(p, bo, bs, t)
1276 -static void *cache_or_unpack_entry_the_repository(struct packed_git *p, off_t base_offset,
1277 - unsigned long *base_size, enum object_type *type)
1274 +static void *cache_or_unpack_entry(struct repository *r, struct packed_git *p,
1275 + off_t base_offset, unsigned long *base_size,
1276 + enum object_type *type)
1277 {
1278 struct delta_base_cache_entry *ent;
1279
1280 ent = get_delta_base_cache_entry(p, base_offset);
1281 if (!ent)
1283 - return unpack_entry(the_repository, p, base_offset, type, base_size);
1282 + return unpack_entry(r, p, base_offset, type, base_size);
1283
1284 if (type)
1285 *type = ent->type;
@@ -1334,8 +1333,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
1333 hashmap_add(&delta_base_cache, ent);
1334 }
1335
1337 -int packed_object_info_the_repository(struct packed_git *p, off_t obj_offset,
1338 - struct object_info *oi)
1336 +int packed_object_info(struct repository *r, struct packed_git *p,
1337 + off_t obj_offset, struct object_info *oi)
1338 {
1339 struct pack_window *w_curs = NULL;
1340 unsigned long size;
@@ -1347,7 +1346,7 @@ int packed_object_info_the_repository(struct packed_git *p, off_t obj_offset,
1346 * a "real" type later if the caller is interested.
1347 */
1348 if (oi->contentp) {
1350 - *oi->contentp = cache_or_unpack_entry(the_repository, p, obj_offset, oi->sizep,
1349 + *oi->contentp = cache_or_unpack_entry(r, p, obj_offset, oi->sizep,
1350 &type);
1351 if (!*oi->contentp)
1352 type = OBJ_BAD;
@@ -1381,7 +1380,7 @@ int packed_object_info_the_repository(struct packed_git *p, off_t obj_offset,
1380
1381 if (oi->typep || oi->type_name) {
1382 enum object_type ptot;
1384 - ptot = packed_to_object_type(the_repository, p, obj_offset,
1383 + ptot = packed_to_object_type(r, p, obj_offset,
1384 type, &w_curs, curpos);
1385 if (oi->typep)
1386 *oi->typep = ptot;
@@ -1470,10 +1469,10 @@ struct unpack_entry_stack_ent {
1469 unsigned long size;
1470 };
1471
1473 -#define read_object(r, o, t, s) read_object_##r(o, t, s)
1474 -static void *read_object_the_repository(const struct object_id *oid,
1475 - enum object_type *type,
1476 - unsigned long *size)
1472 +static void *read_object(struct repository *r,
1473 + const struct object_id *oid,
1474 + enum object_type *type,
1475 + unsigned long *size)
1476 {
1477 struct object_info oi = OBJECT_INFO_INIT;
1478 void *content;
@@ -1481,14 +1480,13 @@ static void *read_object_the_repository(const struct object_id *oid,
1480 oi.sizep = size;
1481 oi.contentp = &content;
1482
1484 - if (oid_object_info_extended(the_repository, oid, &oi, 0) < 0)
1483 + if (oid_object_info_extended(r, oid, &oi, 0) < 0)
1484 return NULL;
1485 return content;
1486 }
1487
1489 -void *unpack_entry_the_repository(struct packed_git *p, off_t obj_offset,
1490 - enum object_type *final_type,
1491 - unsigned long *final_size)
1488 +void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
1489 + enum object_type *final_type, unsigned long *final_size)
1490 {
1491 struct pack_window *w_curs = NULL;
1492 off_t curpos = obj_offset;
@@ -1618,7 +1616,7 @@ void *unpack_entry_the_repository(struct packed_git *p, off_t obj_offset,
1616 oid_to_hex(&base_oid), (uintmax_t)obj_offset,
1617 p->pack_name);
1618 mark_bad_packed_object(p, base_oid.hash);
1621 - base = read_object(the_repository, &base_oid, &type, &base_size);
1619 + base = read_object(r, &base_oid, &type, &base_size);
1620 external_base = base;
1621 }
1622 }
packfile.h
+4 -4
@@ -115,8 +115,7 @@ extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
115 extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
116
117 extern int is_pack_valid(struct packed_git *);
118 -#define unpack_entry(r, p, of, ot, s) unpack_entry_##r(p, of, ot, s)
119 -extern void *unpack_entry_the_repository(struct packed_git *, off_t, enum object_type *, unsigned long *);
118 +extern void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *);
119 extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
120 extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
121 extern int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *);
@@ -126,8 +125,9 @@ extern void release_pack_memory(size_t);
125 /* global flag to enable extra checks when accessing packed objects */
126 extern int do_check_packed_object_crc;
127
129 -#define packed_object_info(r, p, o, oi) packed_object_info_##r(p, o, oi)
130 -extern int packed_object_info_the_repository(struct packed_git *pack, off_t offset, struct object_info *);
128 +extern int packed_object_info(struct repository *r,
129 + struct packed_git *pack,
130 + off_t offset, struct object_info *);
131
132 extern void mark_bad_packed_object(struct packed_git *p, const unsigned char *sha1);
133 extern const struct packed_git *has_packed_and_bad(const unsigned char *sha1);
sha1_file.c
+18 -13
@@ -1231,7 +1231,8 @@ static int sha1_loose_object_info(struct repository *r,
1231
1232 int fetch_if_missing = 1;
1233
1234 -int oid_object_info_extended_the_repository(const struct object_id *oid, struct object_info *oi, unsigned flags)
1234 +int oid_object_info_extended(struct repository *r, const struct object_id *oid,
1235 + struct object_info *oi, unsigned flags)
1236 {
1237 static struct object_info blank_oi = OBJECT_INFO_INIT;
1238 struct pack_entry e;
@@ -1240,7 +1241,7 @@ int oid_object_info_extended_the_repository(const struct object_id *oid, struct
1241 int already_retried = 0;
1242
1243 if (flags & OBJECT_INFO_LOOKUP_REPLACE)
1243 - real = lookup_replace_object(the_repository, oid);
1244 + real = lookup_replace_object(r, oid);
1245
1246 if (is_null_oid(real))
1247 return -1;
@@ -1269,29 +1270,31 @@ int oid_object_info_extended_the_repository(const struct object_id *oid, struct
1270 }
1271
1272 while (1) {
1272 - if (find_pack_entry(the_repository, real->hash, &e))
1273 + if (find_pack_entry(r, real->hash, &e))
1274 break;
1275
1276 if (flags & OBJECT_INFO_IGNORE_LOOSE)
1277 return -1;
1278
1279 /* Most likely it's a loose object. */
1279 - if (!sha1_loose_object_info(the_repository, real->hash, oi, flags))
1280 + if (!sha1_loose_object_info(r, real->hash, oi, flags))
1281 return 0;
1282
1283 /* Not a loose object; someone else may have just packed it. */
1284 if (!(flags & OBJECT_INFO_QUICK)) {
1284 - reprepare_packed_git(the_repository);
1285 - if (find_pack_entry(the_repository, real->hash, &e))
1285 + reprepare_packed_git(r);
1286 + if (find_pack_entry(r, real->hash, &e))
1287 break;
1288 }
1289
1290 /* Check if it is a missing object */
1291 if (fetch_if_missing && repository_format_partial_clone &&
1291 - !already_retried) {
1292 + !already_retried && r == the_repository) {
1293 /*
1293 - * TODO Investigate haveing fetch_object() return
1294 + * TODO Investigate having fetch_object() return
1295 * TODO error/success and stopping the music here.
1296 + * TODO Pass a repository struct through fetch_object,
1297 + * such that arbitrary repositories work.
1298 */
1299 fetch_object(repository_format_partial_clone, real->hash);
1300 already_retried = 1;
@@ -1307,10 +1310,10 @@ int oid_object_info_extended_the_repository(const struct object_id *oid, struct
1310 * information below, so return early.
1311 */
1312 return 0;
1310 - rtype = packed_object_info(the_repository, e.p, e.offset, oi);
1313 + rtype = packed_object_info(r, e.p, e.offset, oi);
1314 if (rtype < 0) {
1315 mark_bad_packed_object(e.p, real->hash);
1313 - return oid_object_info_extended(the_repository, real, oi, 0);
1316 + return oid_object_info_extended(r, real, oi, 0);
1317 } else if (oi->whence == OI_PACKED) {
1318 oi->u.packed.offset = e.offset;
1319 oi->u.packed.pack = e.p;
@@ -1322,15 +1325,17 @@ int oid_object_info_extended_the_repository(const struct object_id *oid, struct
1325 }
1326
1327 /* returns enum object_type or negative */
1325 -int oid_object_info_the_repository(const struct object_id *oid, unsigned long *sizep)
1328 +int oid_object_info(struct repository *r,
1329 + const struct object_id *oid,
1330 + unsigned long *sizep)
1331 {
1332 enum object_type type;
1333 struct object_info oi = OBJECT_INFO_INIT;
1334
1335 oi.typep = &type;
1336 oi.sizep = sizep;
1332 - if (oid_object_info_extended(the_repository, oid, &oi,
1333 - OBJECT_INFO_LOOKUP_REPLACE) < 0)
1337 + if (oid_object_info_extended(r, oid, &oi,
1338 + OBJECT_INFO_LOOKUP_REPLACE) < 0)
1339 return -1;
1340 return type;
1341 }