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 {