Coverage Report

Created: 2024-09-08 06:23

/src/git/pack-objects.c
Line
Count
Source (jump to first uncovered line)
1
#include "git-compat-util.h"
2
#include "object.h"
3
#include "pack.h"
4
#include "pack-objects.h"
5
#include "packfile.h"
6
#include "parse.h"
7
8
static uint32_t locate_object_entry_hash(struct packing_data *pdata,
9
           const struct object_id *oid,
10
           int *found)
11
0
{
12
0
  uint32_t i, mask = (pdata->index_size - 1);
13
14
0
  i = oidhash(oid) & mask;
15
16
0
  while (pdata->index[i] > 0) {
17
0
    uint32_t pos = pdata->index[i] - 1;
18
19
0
    if (oideq(oid, &pdata->objects[pos].idx.oid)) {
20
0
      *found = 1;
21
0
      return i;
22
0
    }
23
24
0
    i = (i + 1) & mask;
25
0
  }
26
27
0
  *found = 0;
28
0
  return i;
29
0
}
30
31
static inline uint32_t closest_pow2(uint32_t v)
32
0
{
33
0
  v = v - 1;
34
0
  v |= v >> 1;
35
0
  v |= v >> 2;
36
0
  v |= v >> 4;
37
0
  v |= v >> 8;
38
0
  v |= v >> 16;
39
0
  return v + 1;
40
0
}
41
42
static void rehash_objects(struct packing_data *pdata)
43
0
{
44
0
  uint32_t i;
45
0
  struct object_entry *entry;
46
47
0
  pdata->index_size = closest_pow2(pdata->nr_objects * 3);
48
0
  if (pdata->index_size < 1024)
49
0
    pdata->index_size = 1024;
50
51
0
  free(pdata->index);
52
0
  CALLOC_ARRAY(pdata->index, pdata->index_size);
53
54
0
  entry = pdata->objects;
55
56
0
  for (i = 0; i < pdata->nr_objects; i++) {
57
0
    int found;
58
0
    uint32_t ix = locate_object_entry_hash(pdata,
59
0
                   &entry->idx.oid,
60
0
                   &found);
61
62
0
    if (found)
63
0
      BUG("Duplicate object in hash");
64
65
0
    pdata->index[ix] = i + 1;
66
0
    entry++;
67
0
  }
68
0
}
69
70
struct object_entry *packlist_find(struct packing_data *pdata,
71
           const struct object_id *oid)
72
0
{
73
0
  uint32_t i;
74
0
  int found;
75
76
0
  if (!pdata->index_size)
77
0
    return NULL;
78
79
0
  i = locate_object_entry_hash(pdata, oid, &found);
80
81
0
  if (!found)
82
0
    return NULL;
83
84
0
  return &pdata->objects[pdata->index[i] - 1];
85
0
}
86
87
static void prepare_in_pack_by_idx(struct packing_data *pdata)
88
0
{
89
0
  struct packed_git **mapping, *p;
90
0
  int cnt = 0, nr = 1U << OE_IN_PACK_BITS;
91
92
0
  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
0
  mapping[cnt++] = NULL;
98
0
  for (p = get_all_packs(pdata->repo); p; p = p->next, cnt++) {
99
0
    if (cnt == nr) {
100
0
      free(mapping);
101
0
      return;
102
0
    }
103
0
    p->index = cnt;
104
0
    mapping[cnt] = p;
105
0
  }
106
0
  pdata->in_pack_by_idx = mapping;
107
0
}
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
 */
118
void oe_map_new_pack(struct packing_data *pack)
119
0
{
120
0
  uint32_t i;
121
122
0
  if (pack->in_pack)
123
0
    BUG("packing_data has already been converted to pack array");
124
125
0
  ALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
126
127
0
  for (i = 0; i < pack->nr_objects; i++)
128
0
    pack->in_pack[i] = oe_in_pack(pack, pack->objects + i);
129
130
0
  FREE_AND_NULL(pack->in_pack_by_idx);
131
0
}
132
133
/* assume pdata is already zero'd by caller */
134
void prepare_packing_data(struct repository *r, struct packing_data *pdata)
135
0
{
136
0
  pdata->repo = r;
137
138
0
  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
0
  } else {
144
0
    prepare_in_pack_by_idx(pdata);
145
0
  }
146
147
0
  pdata->oe_size_limit = git_env_ulong("GIT_TEST_OE_SIZE",
148
0
               1U << OE_SIZE_BITS);
149
0
  pdata->oe_delta_size_limit = git_env_ulong("GIT_TEST_OE_DELTA_SIZE",
150
0
               1UL << OE_DELTA_SIZE_BITS);
151
0
  init_recursive_mutex(&pdata->odb_lock);
152
0
}
153
154
void clear_packing_data(struct packing_data *pdata)
155
0
{
156
0
  if (!pdata)
157
0
    return;
158
159
0
  free(pdata->cruft_mtime);
160
0
  free(pdata->in_pack);
161
0
  free(pdata->in_pack_by_idx);
162
0
  free(pdata->in_pack_pos);
163
0
  free(pdata->index);
164
0
  free(pdata->layer);
165
0
  free(pdata->objects);
166
0
  free(pdata->tree_depth);
167
0
}
168
169
struct object_entry *packlist_alloc(struct packing_data *pdata,
170
            const struct object_id *oid)
171
0
{
172
0
  struct object_entry *new_entry;
173
174
0
  if (pdata->nr_objects >= pdata->nr_alloc) {
175
0
    pdata->nr_alloc = (pdata->nr_alloc  + 1024) * 3 / 2;
176
0
    REALLOC_ARRAY(pdata->objects, pdata->nr_alloc);
177
178
0
    if (!pdata->in_pack_by_idx)
179
0
      REALLOC_ARRAY(pdata->in_pack, pdata->nr_alloc);
180
0
    if (pdata->delta_size)
181
0
      REALLOC_ARRAY(pdata->delta_size, pdata->nr_alloc);
182
183
0
    if (pdata->tree_depth)
184
0
      REALLOC_ARRAY(pdata->tree_depth, pdata->nr_alloc);
185
186
0
    if (pdata->layer)
187
0
      REALLOC_ARRAY(pdata->layer, pdata->nr_alloc);
188
189
0
    if (pdata->cruft_mtime)
190
0
      REALLOC_ARRAY(pdata->cruft_mtime, pdata->nr_alloc);
191
0
  }
192
193
0
  new_entry = pdata->objects + pdata->nr_objects++;
194
195
0
  memset(new_entry, 0, sizeof(*new_entry));
196
0
  oidcpy(&new_entry->idx.oid, oid);
197
198
0
  if (pdata->index_size * 3 <= pdata->nr_objects * 4)
199
0
    rehash_objects(pdata);
200
0
  else {
201
0
    int found;
202
0
    uint32_t pos = locate_object_entry_hash(pdata,
203
0
              &new_entry->idx.oid,
204
0
              &found);
205
0
    if (found)
206
0
      BUG("duplicate object inserted into hash");
207
0
    pdata->index[pos] = pdata->nr_objects;
208
0
  }
209
210
0
  if (pdata->in_pack)
211
0
    pdata->in_pack[pdata->nr_objects - 1] = NULL;
212
213
0
  if (pdata->tree_depth)
214
0
    pdata->tree_depth[pdata->nr_objects - 1] = 0;
215
216
0
  if (pdata->layer)
217
0
    pdata->layer[pdata->nr_objects - 1] = 0;
218
219
0
  if (pdata->cruft_mtime)
220
0
    pdata->cruft_mtime[pdata->nr_objects - 1] = 0;
221
222
0
  return new_entry;
223
0
}
224
225
void oe_set_delta_ext(struct packing_data *pdata,
226
          struct object_entry *delta,
227
          const struct object_id *oid)
228
0
{
229
0
  struct object_entry *base;
230
231
0
  ALLOC_GROW(pdata->ext_bases, pdata->nr_ext + 1, pdata->alloc_ext);
232
0
  base = &pdata->ext_bases[pdata->nr_ext++];
233
0
  memset(base, 0, sizeof(*base));
234
0
  oidcpy(&base->idx.oid, oid);
235
236
  /* These flags mark that we are not part of the actual pack output. */
237
0
  base->preferred_base = 1;
238
0
  base->filled = 1;
239
240
0
  delta->ext_base = 1;
241
0
  delta->delta_idx = base - pdata->ext_bases + 1;
242
0
}