pack: iterate objects in offset order Compute the ordering on demand and persist until the index is freed.
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
diff --git a/src/pack.c b/src/pack.c
index e1fa085..9346ace 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -54,6 +54,10 @@ static int packfile_error(const char *message)
static void pack_index_free(struct git_pack_file *p)
{
+ if (p->oids) {
+ git__free(p->oids);
+ p->oids = NULL;
+ }
if (p->index_map.data) {
git_futils_mmap_free(&p->index_map);
p->index_map.data = NULL;
@@ -686,13 +690,16 @@ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_
}
}
+static int git__memcmp4(const void *a, const void *b) {
+ return memcmp(a, b, 4);
+}
+
int git_pack_foreach_entry(
struct git_pack_file *p,
int (*cb)(git_oid *oid, void *data),
void *data)
{
const unsigned char *index = p->index_map.data, *current;
- unsigned stride;
uint32_t i;
if (index == NULL) {
@@ -712,21 +719,38 @@ int git_pack_foreach_entry(
index += 4 * 256;
- if (p->index_version > 1) {
- stride = 20;
- } else {
- stride = 24;
- index += 4;
- }
+ if (p->oids == NULL) {
+ git_vector offsets, oids;
+ int error;
- current = index;
- for (i = 0; i < p->num_objects; i++) {
- if (cb((git_oid *)current, data))
- return GIT_EUSER;
+ if ((error = git_vector_init(&oids, p->num_objects, NULL)))
+ return error;
+
+ if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4)))
+ return error;
- current += stride;
+ if (p->index_version > 1) {
+ const unsigned char *off = index + 24 * p->num_objects;
+ for (i = 0; i < p->num_objects; i++)
+ git_vector_insert(&offsets, (void*)&off[4 * i]);
+ git_vector_sort(&offsets);
+ git_vector_foreach(&offsets, i, current)
+ git_vector_insert(&oids, (void*)&index[5 * (current - off)]);
+ } else {
+ for (i = 0; i < p->num_objects; i++)
+ git_vector_insert(&offsets, (void*)&index[24 * i]);
+ git_vector_sort(&offsets);
+ git_vector_foreach(&offsets, i, current)
+ git_vector_insert(&oids, (void*)¤t[4]);
+ }
+ git_vector_free(&offsets);
+ p->oids = (git_oid **)oids.contents;
}
+ for (i = 0; i < p->num_objects; i++)
+ if (cb(p->oids[i], data))
+ return GIT_EUSER;
+
return 0;
}
diff --git a/src/pack.h b/src/pack.h
index 1785456..af87b7c 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -64,6 +64,7 @@ struct git_pack_file {
unsigned pack_local:1, pack_keep:1, has_cache:1;
git_oid sha1;
git_vector cache;
+ git_oid **oids;
/* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[GIT_FLEX_ARRAY]; /* more */