pack-objects: refactor write_object() into helper functions
The function first decides if we want to copy data taken from existing pack verbatim or we want to encode the data ourselves for the packfile we are creating and then carries out the decision. Separate the latter phase into two helper functions, one for the case the data is reused, the other for the case the data is produced anew. A little twist is that it can later turn out that we cannot reuse the data after we initially decide to do so; in such a case, the "reuse" helper makes a call to "generate" helper. It is easier to follow than the current fallback code that uses "goto" inside a single large function. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
May 16, 2012 at 19:02 UTC
c9018b0305a56436c85b292edbeacff04b0ebb5d
1 file changed
+172
-150
builtin/pack-objects.c
+172
-150
@@ -200,22 +200,178 @@ static void copy_pack_data(struct sha1file *f,
200
}
201
202
/* Return 0 if we will bust the pack-size limit */
203
-static unsigned long write_object(struct sha1file *f,
204
- struct object_entry *entry,
205
- off_t write_offset)
203
+static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
204
+ unsigned long limit, int usable_delta)
205
{
207
- unsigned long size, limit, datalen;
208
- void *buf;
206
+ unsigned long size, datalen;
207
unsigned char header[10], dheader[10];
208
unsigned hdrlen;
209
enum object_type type;
210
+ void *buf;
211
+
212
+ if (!usable_delta) {
213
+ buf = read_sha1_file(entry->idx.sha1, &type, &size);
214
+ if (!buf)
215
+ die("unable to read %s", sha1_to_hex(entry->idx.sha1));
216
+ /*
217
+ * make sure no cached delta data remains from a
218
+ * previous attempt before a pack split occurred.
219
+ */
220
+ free(entry->delta_data);
221
+ entry->delta_data = NULL;
222
+ entry->z_delta_size = 0;
223
+ } else if (entry->delta_data) {
224
+ size = entry->delta_size;
225
+ buf = entry->delta_data;
226
+ entry->delta_data = NULL;
227
+ type = (allow_ofs_delta && entry->delta->idx.offset) ?
228
+ OBJ_OFS_DELTA : OBJ_REF_DELTA;
229
+ } else {
230
+ buf = get_delta(entry);
231
+ size = entry->delta_size;
232
+ type = (allow_ofs_delta && entry->delta->idx.offset) ?
233
+ OBJ_OFS_DELTA : OBJ_REF_DELTA;
234
+ }
235
+
236
+ if (entry->z_delta_size)
237
+ datalen = entry->z_delta_size;
238
+ else
239
+ datalen = do_compress(&buf, size);
240
+
241
+ /*
242
+ * The object header is a byte of 'type' followed by zero or
243
+ * more bytes of length.
244
+ */
245
+ hdrlen = encode_in_pack_object_header(type, size, header);
246
+
247
+ if (type == OBJ_OFS_DELTA) {
248
+ /*
249
+ * Deltas with relative base contain an additional
250
+ * encoding of the relative offset for the delta
251
+ * base from this object's position in the pack.
252
+ */
253
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
254
+ unsigned pos = sizeof(dheader) - 1;
255
+ dheader[pos] = ofs & 127;
256
+ while (ofs >>= 7)
257
+ dheader[--pos] = 128 | (--ofs & 127);
258
+ if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
259
+ free(buf);
260
+ return 0;
261
+ }
262
+ sha1write(f, header, hdrlen);
263
+ sha1write(f, dheader + pos, sizeof(dheader) - pos);
264
+ hdrlen += sizeof(dheader) - pos;
265
+ } else if (type == OBJ_REF_DELTA) {
266
+ /*
267
+ * Deltas with a base reference contain
268
+ * an additional 20 bytes for the base sha1.
269
+ */
270
+ if (limit && hdrlen + 20 + datalen + 20 >= limit) {
271
+ free(buf);
272
+ return 0;
273
+ }
274
+ sha1write(f, header, hdrlen);
275
+ sha1write(f, entry->delta->idx.sha1, 20);
276
+ hdrlen += 20;
277
+ } else {
278
+ if (limit && hdrlen + datalen + 20 >= limit) {
279
+ free(buf);
280
+ return 0;
281
+ }
282
+ sha1write(f, header, hdrlen);
283
+ }
284
+ sha1write(f, buf, datalen);
285
+ free(buf);
286
+
287
+ return hdrlen + datalen;
288
+}
289
+
290
+/* Return 0 if we will bust the pack-size limit */
291
+static unsigned long write_reuse_object(struct sha1file *f, struct object_entry *entry,
292
+ unsigned long limit, int usable_delta)
293
+{
294
+ struct packed_git *p = entry->in_pack;
295
+ struct pack_window *w_curs = NULL;
296
+ struct revindex_entry *revidx;
297
+ off_t offset;
298
+ enum object_type type = entry->type;
299
+ unsigned long datalen;
300
+ unsigned char header[10], dheader[10];
301
+ unsigned hdrlen;
302
+
303
+ if (entry->delta)
304
+ type = (allow_ofs_delta && entry->delta->idx.offset) ?
305
+ OBJ_OFS_DELTA : OBJ_REF_DELTA;
306
+ hdrlen = encode_in_pack_object_header(type, entry->size, header);
307
+
308
+ offset = entry->in_pack_offset;
309
+ revidx = find_pack_revindex(p, offset);
310
+ datalen = revidx[1].offset - offset;
311
+ if (!pack_to_stdout && p->index_version > 1 &&
312
+ check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
313
+ error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
314
+ unuse_pack(&w_curs);
315
+ return write_no_reuse_object(f, entry, limit, usable_delta);
316
+ }
317
+
318
+ offset += entry->in_pack_header_size;
319
+ datalen -= entry->in_pack_header_size;
320
+
321
+ if (!pack_to_stdout && p->index_version == 1 &&
322
+ check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
323
+ error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
324
+ unuse_pack(&w_curs);
325
+ return write_no_reuse_object(f, entry, limit, usable_delta);
326
+ }
327
+
328
+ if (type == OBJ_OFS_DELTA) {
329
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
330
+ unsigned pos = sizeof(dheader) - 1;
331
+ dheader[pos] = ofs & 127;
332
+ while (ofs >>= 7)
333
+ dheader[--pos] = 128 | (--ofs & 127);
334
+ if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
335
+ unuse_pack(&w_curs);
336
+ return 0;
337
+ }
338
+ sha1write(f, header, hdrlen);
339
+ sha1write(f, dheader + pos, sizeof(dheader) - pos);
340
+ hdrlen += sizeof(dheader) - pos;
341
+ reused_delta++;
342
+ } else if (type == OBJ_REF_DELTA) {
343
+ if (limit && hdrlen + 20 + datalen + 20 >= limit) {
344
+ unuse_pack(&w_curs);
345
+ return 0;
346
+ }
347
+ sha1write(f, header, hdrlen);
348
+ sha1write(f, entry->delta->idx.sha1, 20);
349
+ hdrlen += 20;
350
+ reused_delta++;
351
+ } else {
352
+ if (limit && hdrlen + datalen + 20 >= limit) {
353
+ unuse_pack(&w_curs);
354
+ return 0;
355
+ }
356
+ sha1write(f, header, hdrlen);
357
+ }
358
+ copy_pack_data(f, p, &w_curs, offset, datalen);
359
+ unuse_pack(&w_curs);
360
+ reused++;
361
+ return hdrlen + datalen;
362
+}
363
+
364
+/* Return 0 if we will bust the pack-size limit */
365
+static unsigned long write_object(struct sha1file *f,
366
+ struct object_entry *entry,
367
+ off_t write_offset)
368
+{
369
+ unsigned long limit, len;
370
int usable_delta, to_reuse;
371
372
if (!pack_to_stdout)
373
crc32_begin(f);
374
217
- type = entry->type;
218
-
375
/* apply size limit if limited packsize and not first object */
376
if (!pack_size_limit || !nr_written)
377
limit = 0;
@@ -243,11 +399,11 @@ static unsigned long write_object(struct sha1file *f,
399
to_reuse = 0; /* explicit */
400
else if (!entry->in_pack)
401
to_reuse = 0; /* can't reuse what we don't have */
246
- else if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA)
402
+ else if (entry->type == OBJ_REF_DELTA || entry->type == OBJ_OFS_DELTA)
403
/* check_object() decided it for us ... */
404
to_reuse = usable_delta;
405
/* ... but pack split may override that */
250
- else if (type != entry->in_pack_type)
406
+ else if (entry->type != entry->in_pack_type)
407
to_reuse = 0; /* pack has delta which is unusable */
408
else if (entry->delta)
409
to_reuse = 0; /* we want to pack afresh */
@@ -256,153 +412,19 @@ static unsigned long write_object(struct sha1file *f,
412
* and we do not need to deltify it.
413
*/
414
259
- if (!to_reuse) {
260
- no_reuse:
261
- if (!usable_delta) {
262
- buf = read_sha1_file(entry->idx.sha1, &type, &size);
263
- if (!buf)
264
- die("unable to read %s", sha1_to_hex(entry->idx.sha1));
265
- /*
266
- * make sure no cached delta data remains from a
267
- * previous attempt before a pack split occurred.
268
- */
269
- free(entry->delta_data);
270
- entry->delta_data = NULL;
271
- entry->z_delta_size = 0;
272
- } else if (entry->delta_data) {
273
- size = entry->delta_size;
274
- buf = entry->delta_data;
275
- entry->delta_data = NULL;
276
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
277
- OBJ_OFS_DELTA : OBJ_REF_DELTA;
278
- } else {
279
- buf = get_delta(entry);
280
- size = entry->delta_size;
281
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
282
- OBJ_OFS_DELTA : OBJ_REF_DELTA;
283
- }
284
-
285
- if (entry->z_delta_size)
286
- datalen = entry->z_delta_size;
287
- else
288
- datalen = do_compress(&buf, size);
289
-
290
- /*
291
- * The object header is a byte of 'type' followed by zero or
292
- * more bytes of length.
293
- */
294
- hdrlen = encode_in_pack_object_header(type, size, header);
295
-
296
- if (type == OBJ_OFS_DELTA) {
297
- /*
298
- * Deltas with relative base contain an additional
299
- * encoding of the relative offset for the delta
300
- * base from this object's position in the pack.
301
- */
302
- off_t ofs = entry->idx.offset - entry->delta->idx.offset;
303
- unsigned pos = sizeof(dheader) - 1;
304
- dheader[pos] = ofs & 127;
305
- while (ofs >>= 7)
306
- dheader[--pos] = 128 | (--ofs & 127);
307
- if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
308
- free(buf);
309
- return 0;
310
- }
311
- sha1write(f, header, hdrlen);
312
- sha1write(f, dheader + pos, sizeof(dheader) - pos);
313
- hdrlen += sizeof(dheader) - pos;
314
- } else if (type == OBJ_REF_DELTA) {
315
- /*
316
- * Deltas with a base reference contain
317
- * an additional 20 bytes for the base sha1.
318
- */
319
- if (limit && hdrlen + 20 + datalen + 20 >= limit) {
320
- free(buf);
321
- return 0;
322
- }
323
- sha1write(f, header, hdrlen);
324
- sha1write(f, entry->delta->idx.sha1, 20);
325
- hdrlen += 20;
326
- } else {
327
- if (limit && hdrlen + datalen + 20 >= limit) {
328
- free(buf);
329
- return 0;
330
- }
331
- sha1write(f, header, hdrlen);
332
- }
333
- sha1write(f, buf, datalen);
334
- free(buf);
335
- }
336
- else {
337
- struct packed_git *p = entry->in_pack;
338
- struct pack_window *w_curs = NULL;
339
- struct revindex_entry *revidx;
340
- off_t offset;
341
-
342
- if (entry->delta)
343
- type = (allow_ofs_delta && entry->delta->idx.offset) ?
344
- OBJ_OFS_DELTA : OBJ_REF_DELTA;
345
- hdrlen = encode_in_pack_object_header(type, entry->size, header);
346
-
347
- offset = entry->in_pack_offset;
348
- revidx = find_pack_revindex(p, offset);
349
- datalen = revidx[1].offset - offset;
350
- if (!pack_to_stdout && p->index_version > 1 &&
351
- check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
352
- error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
353
- unuse_pack(&w_curs);
354
- goto no_reuse;
355
- }
356
-
357
- offset += entry->in_pack_header_size;
358
- datalen -= entry->in_pack_header_size;
359
- if (!pack_to_stdout && p->index_version == 1 &&
360
- check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
361
- error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
362
- unuse_pack(&w_curs);
363
- goto no_reuse;
364
- }
415
+ if (!to_reuse)
416
+ len = write_no_reuse_object(f, entry, limit, usable_delta);
417
+ else
418
+ len = write_reuse_object(f, entry, limit, usable_delta);
419
+ if (!len)
420
+ return 0;
421
366
- if (type == OBJ_OFS_DELTA) {
367
- off_t ofs = entry->idx.offset - entry->delta->idx.offset;
368
- unsigned pos = sizeof(dheader) - 1;
369
- dheader[pos] = ofs & 127;
370
- while (ofs >>= 7)
371
- dheader[--pos] = 128 | (--ofs & 127);
372
- if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
373
- unuse_pack(&w_curs);
374
- return 0;
375
- }
376
- sha1write(f, header, hdrlen);
377
- sha1write(f, dheader + pos, sizeof(dheader) - pos);
378
- hdrlen += sizeof(dheader) - pos;
379
- reused_delta++;
380
- } else if (type == OBJ_REF_DELTA) {
381
- if (limit && hdrlen + 20 + datalen + 20 >= limit) {
382
- unuse_pack(&w_curs);
383
- return 0;
384
- }
385
- sha1write(f, header, hdrlen);
386
- sha1write(f, entry->delta->idx.sha1, 20);
387
- hdrlen += 20;
388
- reused_delta++;
389
- } else {
390
- if (limit && hdrlen + datalen + 20 >= limit) {
391
- unuse_pack(&w_curs);
392
- return 0;
393
- }
394
- sha1write(f, header, hdrlen);
395
- }
396
- copy_pack_data(f, p, &w_curs, offset, datalen);
397
- unuse_pack(&w_curs);
398
- reused++;
399
- }
422
if (usable_delta)
423
written_delta++;
424
written++;
425
if (!pack_to_stdout)
426
entry->idx.crc32 = crc32_end(f);
405
- return hdrlen + datalen;
427
+ return len;
428
}
429
430
enum write_one_status {