blob: f2a433885ac80ec9cbadfd3e5e7553655237c924 [file] [log] [blame]
Vicent Marti2834bc22013-10-24 14:01:06 -04001#include "cache.h"
2#include "object.h"
3#include "pack.h"
4#include "pack-objects.h"
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +02005#include "packfile.h"
6#include "config.h"
Vicent Marti2834bc22013-10-24 14:01:06 -04007
8static uint32_t locate_object_entry_hash(struct packing_data *pdata,
Jeff King5e7ac682019-06-20 03:41:07 -04009 const struct object_id *oid,
Vicent Marti2834bc22013-10-24 14:01:06 -040010 int *found)
11{
Karsten Blees039dc712014-07-03 00:20:20 +020012 uint32_t i, mask = (pdata->index_size - 1);
Vicent Marti2834bc22013-10-24 14:01:06 -040013
Jeff Kingd40abc82019-06-20 03:41:49 -040014 i = oidhash(oid) & mask;
Vicent Marti2834bc22013-10-24 14:01:06 -040015
16 while (pdata->index[i] > 0) {
17 uint32_t pos = pdata->index[i] - 1;
18
Jeff King5e7ac682019-06-20 03:41:07 -040019 if (oideq(oid, &pdata->objects[pos].idx.oid)) {
Vicent Marti2834bc22013-10-24 14:01:06 -040020 *found = 1;
21 return i;
22 }
23
24 i = (i + 1) & mask;
25 }
26
27 *found = 0;
28 return i;
29}
30
31static inline uint32_t closest_pow2(uint32_t v)
32{
33 v = v - 1;
34 v |= v >> 1;
35 v |= v >> 2;
36 v |= v >> 4;
37 v |= v >> 8;
38 v |= v >> 16;
39 return v + 1;
40}
41
42static void rehash_objects(struct packing_data *pdata)
43{
44 uint32_t i;
45 struct object_entry *entry;
46
47 pdata->index_size = closest_pow2(pdata->nr_objects * 3);
48 if (pdata->index_size < 1024)
49 pdata->index_size = 1024;
50
René Scharfefb799472014-06-01 13:07:21 +020051 free(pdata->index);
52 pdata->index = xcalloc(pdata->index_size, sizeof(*pdata->index));
Vicent Marti2834bc22013-10-24 14:01:06 -040053
54 entry = pdata->objects;
55
56 for (i = 0; i < pdata->nr_objects; i++) {
57 int found;
brian m. carlsone6a492b2017-05-06 22:10:11 +000058 uint32_t ix = locate_object_entry_hash(pdata,
Jeff King5e7ac682019-06-20 03:41:07 -040059 &entry->idx.oid,
brian m. carlsone6a492b2017-05-06 22:10:11 +000060 &found);
Vicent Marti2834bc22013-10-24 14:01:06 -040061
62 if (found)
Johannes Schindelin033abf92018-05-02 11:38:39 +020063 BUG("Duplicate object in hash");
Vicent Marti2834bc22013-10-24 14:01:06 -040064
65 pdata->index[ix] = i + 1;
66 entry++;
67 }
68}
69
70struct object_entry *packlist_find(struct packing_data *pdata,
Jeff King3a378762019-09-05 21:36:05 -040071 const struct object_id *oid)
Vicent Marti2834bc22013-10-24 14:01:06 -040072{
73 uint32_t i;
74 int found;
75
76 if (!pdata->index_size)
77 return NULL;
78
Jeff King5e7ac682019-06-20 03:41:07 -040079 i = locate_object_entry_hash(pdata, oid, &found);
Vicent Marti2834bc22013-10-24 14:01:06 -040080
Vicent Marti2834bc22013-10-24 14:01:06 -040081 if (!found)
82 return NULL;
83
84 return &pdata->objects[pdata->index[i] - 1];
85}
86
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +020087static void prepare_in_pack_by_idx(struct packing_data *pdata)
88{
89 struct packed_git **mapping, *p;
90 int cnt = 0, nr = 1U << OE_IN_PACK_BITS;
91
92 ALLOC_ARRAY(mapping, nr);
93 /*
94 * oe_in_pack() on an all-zero'd object_entry
95 * (i.e. in_pack_idx also zero) should return NULL.
96 */
97 mapping[cnt++] = NULL;
Nguyễn Thái Ngọc Duy7c141122018-11-10 06:49:08 +010098 for (p = get_all_packs(pdata->repo); p; p = p->next, cnt++) {
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +020099 if (cnt == nr) {
100 free(mapping);
101 return;
102 }
103 p->index = cnt;
104 mapping[cnt] = p;
105 }
106 pdata->in_pack_by_idx = mapping;
107}
108
109/*
110 * A new pack appears after prepare_in_pack_by_idx() has been
111 * run. This is likely a race.
112 *
113 * We could map this new pack to in_pack_by_idx[] array, but then we
114 * have to deal with full array anyway. And since it's hard to test
115 * this fall back code, just stay simple and fall back to using
116 * in_pack[] array.
117 */
Jeff Kingc409d102019-02-14 00:50:32 -0500118void oe_map_new_pack(struct packing_data *pack)
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200119{
120 uint32_t i;
121
Jeff Kingf66e0402019-11-11 06:12:49 -0500122 if (pack->in_pack)
123 BUG("packing_data has already been converted to pack array");
124
125 ALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200126
127 for (i = 0; i < pack->nr_objects; i++)
128 pack->in_pack[i] = oe_in_pack(pack, pack->objects + i);
129
130 FREE_AND_NULL(pack->in_pack_by_idx);
131}
132
133/* assume pdata is already zero'd by caller */
Nguyễn Thái Ngọc Duy7c141122018-11-10 06:49:08 +0100134void prepare_packing_data(struct repository *r, struct packing_data *pdata)
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200135{
Nguyễn Thái Ngọc Duy7c141122018-11-10 06:49:08 +0100136 pdata->repo = r;
137
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200138 if (git_env_bool("GIT_TEST_FULL_IN_PACK_ARRAY", 0)) {
139 /*
140 * do not initialize in_pack_by_idx[] to force the
141 * slow path in oe_in_pack()
142 */
143 } else {
144 prepare_in_pack_by_idx(pdata);
145 }
Nguyễn Thái Ngọc Duyac77d0c2018-04-14 17:35:10 +0200146
147 pdata->oe_size_limit = git_env_ulong("GIT_TEST_OE_SIZE",
148 1U << OE_SIZE_BITS);
Nguyễn Thái Ngọc Duy9ac3f0e2018-07-22 10:04:21 +0200149 pdata->oe_delta_size_limit = git_env_ulong("GIT_TEST_OE_DELTA_SIZE",
150 1UL << OE_DELTA_SIZE_BITS);
Patrick Hoggedb673c2019-01-24 19:22:05 -0500151 init_recursive_mutex(&pdata->odb_lock);
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200152}
153
Vicent Marti2834bc22013-10-24 14:01:06 -0400154struct object_entry *packlist_alloc(struct packing_data *pdata,
Jeff King3a378762019-09-05 21:36:05 -0400155 const struct object_id *oid)
Vicent Marti2834bc22013-10-24 14:01:06 -0400156{
157 struct object_entry *new_entry;
158
159 if (pdata->nr_objects >= pdata->nr_alloc) {
160 pdata->nr_alloc = (pdata->nr_alloc + 1024) * 3 / 2;
René Scharfe2756ca42014-09-16 20:56:57 +0200161 REALLOC_ARRAY(pdata->objects, pdata->nr_alloc);
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200162
163 if (!pdata->in_pack_by_idx)
164 REALLOC_ARRAY(pdata->in_pack, pdata->nr_alloc);
Nguyễn Thái Ngọc Duy9ac3f0e2018-07-22 10:04:21 +0200165 if (pdata->delta_size)
166 REALLOC_ARRAY(pdata->delta_size, pdata->nr_alloc);
Christian Couder108f5302018-08-16 08:13:12 +0200167
168 if (pdata->tree_depth)
169 REALLOC_ARRAY(pdata->tree_depth, pdata->nr_alloc);
Christian Couderfe0ac2f2018-08-16 08:13:13 +0200170
171 if (pdata->layer)
172 REALLOC_ARRAY(pdata->layer, pdata->nr_alloc);
Vicent Marti2834bc22013-10-24 14:01:06 -0400173 }
174
175 new_entry = pdata->objects + pdata->nr_objects++;
176
177 memset(new_entry, 0, sizeof(*new_entry));
Jeff Kingf1cbd032019-09-05 18:52:25 -0400178 oidcpy(&new_entry->idx.oid, oid);
Vicent Marti2834bc22013-10-24 14:01:06 -0400179
180 if (pdata->index_size * 3 <= pdata->nr_objects * 4)
181 rehash_objects(pdata);
Jeff King3a378762019-09-05 21:36:05 -0400182 else {
183 int found;
184 uint32_t pos = locate_object_entry_hash(pdata,
185 &new_entry->idx.oid,
186 &found);
187 if (found)
188 BUG("duplicate object inserted into hash");
189 pdata->index[pos] = pdata->nr_objects;
190 }
Vicent Marti2834bc22013-10-24 14:01:06 -0400191
Nguyễn Thái Ngọc Duy43fa44f2018-04-14 17:35:05 +0200192 if (pdata->in_pack)
193 pdata->in_pack[pdata->nr_objects - 1] = NULL;
194
Christian Couder108f5302018-08-16 08:13:12 +0200195 if (pdata->tree_depth)
196 pdata->tree_depth[pdata->nr_objects - 1] = 0;
197
Christian Couderfe0ac2f2018-08-16 08:13:13 +0200198 if (pdata->layer)
199 pdata->layer[pdata->nr_objects - 1] = 0;
200
Vicent Marti2834bc22013-10-24 14:01:06 -0400201 return new_entry;
202}
Jeff King6a1e32d2018-08-21 15:07:05 -0400203
204void oe_set_delta_ext(struct packing_data *pdata,
205 struct object_entry *delta,
Jeff Kinga93c1412020-02-23 23:30:07 -0500206 const struct object_id *oid)
Jeff King6a1e32d2018-08-21 15:07:05 -0400207{
208 struct object_entry *base;
209
210 ALLOC_GROW(pdata->ext_bases, pdata->nr_ext + 1, pdata->alloc_ext);
211 base = &pdata->ext_bases[pdata->nr_ext++];
212 memset(base, 0, sizeof(*base));
Jeff Kinga93c1412020-02-23 23:30:07 -0500213 oidcpy(&base->idx.oid, oid);
Jeff King6a1e32d2018-08-21 15:07:05 -0400214
215 /* These flags mark that we are not part of the actual pack output. */
216 base->preferred_base = 1;
217 base->filled = 1;
218
219 delta->ext_base = 1;
220 delta->delta_idx = base - pdata->ext_bases + 1;
221}