Skip to content

Commit 0aca34e

Browse files
pcloudsgitster
authored andcommitted
pack-objects: shrink delta_size field in struct object_entry
Allowing a delta size of 64 bits is crazy. Shrink this field down to 20 bits with one overflow bit. If we find an existing delta larger than 1MB, we do not cache delta_size at all and will get the value from oe_size(), potentially from disk if it's larger than 4GB. Note, since DELTA_SIZE() is used in try_delta() code, it must be thread-safe. Luckily oe_size() does guarantee this so we it is thread-safe. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ac77d0c commit 0aca34e

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

builtin/pack-objects.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
3535
#define SIZE(obj) oe_size(&to_pack, obj)
3636
#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
37+
#define DELTA_SIZE(obj) oe_delta_size(&to_pack, obj)
3738
#define DELTA(obj) oe_delta(&to_pack, obj)
3839
#define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
3940
#define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
4041
#define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
42+
#define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
4143
#define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
4244
#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
4345

@@ -144,7 +146,7 @@ static void *get_delta(struct object_entry *entry)
144146
oid_to_hex(&DELTA(entry)->idx.oid));
145147
delta_buf = diff_delta(base_buf, base_size,
146148
buf, size, &delta_size, 0);
147-
if (!delta_buf || delta_size != entry->delta_size)
149+
if (!delta_buf || delta_size != DELTA_SIZE(entry))
148150
die("delta size changed");
149151
free(buf);
150152
free(base_buf);
@@ -294,14 +296,14 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
294296
FREE_AND_NULL(entry->delta_data);
295297
entry->z_delta_size = 0;
296298
} else if (entry->delta_data) {
297-
size = entry->delta_size;
299+
size = DELTA_SIZE(entry);
298300
buf = entry->delta_data;
299301
entry->delta_data = NULL;
300302
type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
301303
OBJ_OFS_DELTA : OBJ_REF_DELTA;
302304
} else {
303305
buf = get_delta(entry);
304-
size = entry->delta_size;
306+
size = DELTA_SIZE(entry);
305307
type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
306308
OBJ_OFS_DELTA : OBJ_REF_DELTA;
307309
}
@@ -1509,7 +1511,7 @@ static void check_object(struct object_entry *entry)
15091511
oe_set_type(entry, entry->in_pack_type);
15101512
SET_SIZE(entry, in_pack_size); /* delta size */
15111513
SET_DELTA(entry, base_entry);
1512-
entry->delta_size = in_pack_size;
1514+
SET_DELTA_SIZE(entry, in_pack_size);
15131515
entry->delta_sibling_idx = base_entry->delta_child_idx;
15141516
SET_DELTA_CHILD(base_entry, entry);
15151517
unuse_pack(&w_curs);
@@ -1937,7 +1939,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
19371939
max_size = trg_size/2 - 20;
19381940
ref_depth = 1;
19391941
} else {
1940-
max_size = trg_entry->delta_size;
1942+
max_size = DELTA_SIZE(trg_entry);
19411943
ref_depth = trg->depth;
19421944
}
19431945
max_size = (uint64_t)max_size * (max_depth - src->depth) /
@@ -2006,10 +2008,14 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
20062008
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
20072009
if (!delta_buf)
20082010
return 0;
2011+
if (delta_size >= (1U << OE_DELTA_SIZE_BITS)) {
2012+
free(delta_buf);
2013+
return 0;
2014+
}
20092015

20102016
if (DELTA(trg_entry)) {
20112017
/* Prefer only shallower same-sized deltas. */
2012-
if (delta_size == trg_entry->delta_size &&
2018+
if (delta_size == DELTA_SIZE(trg_entry) &&
20132019
src->depth + 1 >= trg->depth) {
20142020
free(delta_buf);
20152021
return 0;
@@ -2024,7 +2030,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
20242030
free(trg_entry->delta_data);
20252031
cache_lock();
20262032
if (trg_entry->delta_data) {
2027-
delta_cache_size -= trg_entry->delta_size;
2033+
delta_cache_size -= DELTA_SIZE(trg_entry);
20282034
trg_entry->delta_data = NULL;
20292035
}
20302036
if (delta_cacheable(src_size, trg_size, delta_size)) {
@@ -2037,7 +2043,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
20372043
}
20382044

20392045
SET_DELTA(trg_entry, src_entry);
2040-
trg_entry->delta_size = delta_size;
2046+
SET_DELTA_SIZE(trg_entry, delta_size);
20412047
trg->depth = src->depth + 1;
20422048

20432049
return 1;
@@ -2160,11 +2166,11 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
21602166
if (entry->delta_data && !pack_to_stdout) {
21612167
unsigned long size;
21622168

2163-
size = do_compress(&entry->delta_data, entry->delta_size);
2169+
size = do_compress(&entry->delta_data, DELTA_SIZE(entry));
21642170
if (size < (1U << OE_Z_DELTA_BITS)) {
21652171
entry->z_delta_size = size;
21662172
cache_lock();
2167-
delta_cache_size -= entry->delta_size;
2173+
delta_cache_size -= DELTA_SIZE(entry);
21682174
delta_cache_size += entry->z_delta_size;
21692175
cache_unlock();
21702176
} else {

pack-objects.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* above this limit. Don't lower it too much.
1313
*/
1414
#define OE_SIZE_BITS 31
15+
#define OE_DELTA_SIZE_BITS 20
1516

1617
/*
1718
* State flags for depth-first search used for analyzing delta cycles.
@@ -85,7 +86,8 @@ struct object_entry {
8586
* uses the same base as me
8687
*/
8788
void *delta_data; /* cached delta (uncompressed) */
88-
unsigned long delta_size; /* delta data size (uncompressed) */
89+
unsigned delta_size_:OE_DELTA_SIZE_BITS; /* delta data size (uncompressed) */
90+
unsigned delta_size_valid:1;
8991
unsigned z_delta_size:OE_Z_DELTA_BITS;
9092
unsigned type_:TYPE_BITS;
9193
unsigned in_pack_type:TYPE_BITS; /* could be delta */
@@ -309,4 +311,23 @@ static inline void oe_set_size(struct packing_data *pack,
309311
}
310312
}
311313

314+
static inline unsigned long oe_delta_size(struct packing_data *pack,
315+
const struct object_entry *e)
316+
{
317+
if (e->delta_size_valid)
318+
return e->delta_size_;
319+
return oe_size(pack, e);
320+
}
321+
322+
static inline void oe_set_delta_size(struct packing_data *pack,
323+
struct object_entry *e,
324+
unsigned long size)
325+
{
326+
e->delta_size_ = size;
327+
e->delta_size_valid = e->delta_size_ == size;
328+
if (!e->delta_size_valid && size != oe_size(pack, e))
329+
BUG("this can only happen in check_object() "
330+
"where delta size is the same as entry size");
331+
}
332+
312333
#endif

0 commit comments

Comments
 (0)