Instead of using 8 bytes (on 64 bit arch) to store a pointer to a pack. Use an index isntead since the number of packs should be relatively small. This limits the number of packs we can handle to 256 (still unreasonably high for a repo to work well). If you have more than 256 packs, you'll need an older version of Git to repack first. This technically saves 7 bytes. But we don't see any of that in practice due to padding. The saving becomes real when we pack this struct tighter later. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- builtin/pack-objects.c | 48 ++++++++++++++++++++++++++++++++---------- pack-objects.h | 12 +++++++++-- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 7bb5544883..d0d371714a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -367,7 +367,7 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry, unsigned long limit, int usable_delta) { - struct packed_git *p = entry->in_pack; + struct packed_git *p = IN_PACK(&to_pack, entry); struct pack_window *w_curs = NULL; struct revindex_entry *revidx; off_t offset; @@ -478,7 +478,7 @@ static off_t write_object(struct hashfile *f, if (!reuse_object) to_reuse = 0; /* explicit */ - else if (!entry->in_pack) + else if (!IN_PACK(&to_pack, entry)) to_reuse = 0; /* can't reuse what we don't have */ else if (entry->type == OBJ_REF_DELTA || entry->type == OBJ_OFS_DELTA) /* check_object() decided it for us ... */ @@ -1074,7 +1074,15 @@ static void create_object_entry(const struct object_id *oid, else nr_result++; if (found_pack) { - entry->in_pack = found_pack; + int i; + + for (i = 0; i < (1 << OE_IN_PACK_BITS); i++) + if (to_pack.in_pack[i] == found_pack) { + entry->in_pack_idx = i; + break; + } + if (i == (1 << OE_IN_PACK_BITS)) + die("BUG: pack not found!"); entry->in_pack_offset = found_offset; } @@ -1399,8 +1407,8 @@ static void cleanup_preferred_base(void) static void check_object(struct object_entry *entry) { - if (entry->in_pack) { - struct packed_git *p = entry->in_pack; + if (IN_PACK(&to_pack, entry)) { + struct packed_git *p = IN_PACK(&to_pack, entry); struct pack_window *w_curs = NULL; const unsigned char *base_ref = NULL; struct object_entry *base_entry; @@ -1535,14 +1543,16 @@ static int pack_offset_sort(const void *_a, const void *_b) { const struct object_entry *a = *(struct object_entry **)_a; const struct object_entry *b = *(struct object_entry **)_b; + const struct packed_git *a_in_pack = IN_PACK(&to_pack, a); + const struct packed_git *b_in_pack = IN_PACK(&to_pack, b); /* avoid filesystem trashing with loose objects */ - if (!a->in_pack && !b->in_pack) + if (!a_in_pack && !b_in_pack) return oidcmp(&a->idx.oid, &b->idx.oid); - if (a->in_pack < b->in_pack) + if (a_in_pack < b_in_pack) return -1; - if (a->in_pack > b->in_pack) + if (a_in_pack > b_in_pack) return 1; return a->in_pack_offset < b->in_pack_offset ? -1 : (a->in_pack_offset > b->in_pack_offset); @@ -1578,7 +1588,7 @@ static void drop_reused_delta(struct object_entry *entry) oi.sizep = &entry->size; oi.typep = &type; - if (packed_object_info(entry->in_pack, entry->in_pack_offset, &oi) < 0) { + if (packed_object_info(IN_PACK(&to_pack, entry), entry->in_pack_offset, &oi) < 0) { /* * We failed to get the info from this pack for some reason; * fall back to sha1_object_info, which may find another copy. @@ -1848,8 +1858,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * it, we will still save the transfer cost, as we already know * the other side has it and we won't send src_entry at all. */ - if (reuse_delta && trg_entry->in_pack && - trg_entry->in_pack == src_entry->in_pack && + if (reuse_delta && IN_PACK(&to_pack, trg_entry) && + IN_PACK(&to_pack, trg_entry) == IN_PACK(&to_pack, src_entry) && !src_entry->preferred_base && trg_entry->in_pack_type != OBJ_REF_DELTA && trg_entry->in_pack_type != OBJ_OFS_DELTA) @@ -2958,6 +2968,21 @@ static int option_parse_unpack_unreachable(const struct option *opt, return 0; } +static void init_in_pack_mapping(struct packing_data *to_pack) +{ + struct packed_git *p; + int i = 0; + + /* let IN_PACK() return NULL if in_pack_idx is zero */ + to_pack->in_pack[i++] = NULL; + + for (p = packed_git; p; p = p->next, i++) { + if (i >= (1 << OE_IN_PACK_BITS)) + die("BUG: too many packs to handle!"); + to_pack->in_pack[i] = p; + } +} + int cmd_pack_objects(int argc, const char **argv, const char *prefix) { int use_internal_rev_list = 0; @@ -3190,6 +3215,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) } } } + init_in_pack_mapping(&to_pack); if (progress) progress_state = start_progress(_("Counting objects"), 0); diff --git a/pack-objects.h b/pack-objects.h index 3bef28196c..839d5dc4fd 100644 --- a/pack-objects.h +++ b/pack-objects.h @@ -3,10 +3,14 @@ #define OE_DFS_STATE_BITS 2 #define OE_DEPTH_BITS 12 +#define OE_IN_PACK_BITS 8 #define IN_PACK_POS(to_pack, obj) \ (to_pack)->in_pack_pos[(struct object_entry *)(obj) - (to_pack)->objects] +#define IN_PACK(to_pack, obj) \ + (to_pack)->in_pack[(obj)->in_pack_idx] + /* * State flags for depth-first search used for analyzing delta cycles. * @@ -23,7 +27,6 @@ enum dfs_state { struct object_entry { struct pack_idx_entry idx; unsigned long size; /* uncompressed size */ - struct packed_git *in_pack; /* already in pack */ off_t in_pack_offset; struct object_entry *delta; /* delta base object */ struct object_entry *delta_child; /* deltified objects who bases me */ @@ -35,6 +38,7 @@ struct object_entry { unsigned long z_delta_size; /* delta data size (compressed) */ uint32_t hash; /* name hint hash */ unsigned char in_pack_header_size; /* note: spare bits available! */ + unsigned in_pack_idx:OE_IN_PACK_BITS; /* already in pack */ unsigned type:TYPE_BITS; unsigned in_pack_type:TYPE_BITS; /* could be delta */ unsigned preferred_base:1; /* @@ -46,9 +50,12 @@ struct object_entry { unsigned tagged:1; /* near the very tip of refs */ unsigned filled:1; /* assigned write-order */ unsigned dfs_state:OE_DFS_STATE_BITS; + + /* XXX 12 bits hole, try to pack */ + unsigned depth:OE_DEPTH_BITS; - /* size: 112 */ + /* size: 112, padding: 4 */ }; struct packing_data { @@ -59,6 +66,7 @@ struct packing_data { uint32_t index_size; unsigned int *in_pack_pos; + struct packed_git *in_pack[1 << OE_IN_PACK_BITS]; }; struct object_entry *packlist_alloc(struct packing_data *pdata, -- 2.16.1.435.g8f24da2e1a