indexer: inject one base at a time There may be multiple deltas referencing the same base as well as OFS deltas which rely on a thin delta. Deal with both at the same time by injecting a single object and going back up to the main delta-resolving loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
diff --git a/src/indexer.c b/src/indexer.c
index 21b993a..2cda1a6 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -683,50 +683,58 @@ cleanup:
static int fix_thin_pack(git_indexer_stream *idx, git_transfer_progress *stats)
{
- int error;
+ int error, found_ref_delta = 0;
unsigned int i;
struct delta_info *delta;
+ size_t size;
+ git_otype type;
+ git_mwindow *w = NULL;
+ git_off_t curpos;
+ unsigned char *base_info;
+ unsigned int left = 0;
+ git_oid base;
+
+ assert(git_vector_length(&idx->deltas) > 0);
if (idx->odb == NULL) {
giterr_set(GITERR_INDEXER, "cannot fix a thin pack without an ODB");
return -1;
}
+ /* Loop until we find the first REF delta */
git_vector_foreach(&idx->deltas, i, delta) {
- size_t size;
- git_otype type;
- git_mwindow *w = NULL;
- git_off_t curpos = delta->delta_off;
- unsigned char *base_info;
- unsigned int left = 0;
- git_oid base;
-
+ curpos = delta->delta_off;
error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos);
git_mwindow_close(&w);
if (error < 0)
return error;
- if (type != GIT_OBJ_REF_DELTA) {
- giterr_set(GITERR_INDEXER, "delta with missing base is not REF_DELTA");
- return -1;
+ if (type == GIT_OBJ_REF_DELTA) {
+ found_ref_delta = 1;
+ break;
}
+ }
- /* curpos now points to the base information, which is an OID */
- base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, GIT_OID_RAWSZ, &left);
- if (base_info == NULL) {
- giterr_set(GITERR_INDEXER, "failed to map delta information");
- return -1;
- }
+ if (!found_ref_delta) {
+ giterr_set(GITERR_INDEXER, "no REF_DELTA found, cannot inject object");
+ return -1;
+ }
- git_oid_fromraw(&base, base_info);
- git_mwindow_close(&w);
+ /* curpos now points to the base information, which is an OID */
+ base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, GIT_OID_RAWSZ, &left);
+ if (base_info == NULL) {
+ giterr_set(GITERR_INDEXER, "failed to map delta information");
+ return -1;
+ }
- if (inject_object(idx, &base) < 0)
- return -1;
+ git_oid_fromraw(&base, base_info);
+ git_mwindow_close(&w);
- stats->total_objects++;
- stats->local_objects++;
- }
+ if (inject_object(idx, &base) < 0)
+ return -1;
+
+ stats->total_objects++;
+ stats->local_objects++;
return 0;
}
@@ -764,8 +772,10 @@ static int resolve_deltas(git_indexer_stream *idx, git_transfer_progress *stats)
i--;
}
- if (!progressed && (fix_thin_pack(idx, stats) < 0))
- return -1;
+ if (!progressed && (fix_thin_pack(idx, stats) < 0)) {
+ giterr_set(GITERR_INDEXER, "missing delta bases");
+ return -1;
+ }
}
return 0;