cat-file: use a single strbuf for all output

When we're in batch mode, we end up in batch_object_write() for each object, which allocates its own strbuf for each call. Instead, we can provide a single "scratch" buffer that gets reused for each output. When running: git cat-file --batch-all-objects --batch-check='%(objectname)' on git.git, my best-of-five time drops from: real 0m0.171s user 0m0.159s sys 0m0.012s to: real 0m0.133s user 0m0.121s sys 0m0.012s Note that we could do this just by putting the "scratch" pointer into "struct expand_data", but I chose instead to add an extra parameter to the callstack. That's more verbose, but it makes it a bit more obvious what is going on, which in turn makes it easy to see where we need to be releasing the string in the caller (right after the loop which uses it in each case). Based-on-a-patch-by: René Scharfe <l.s.r@web.de> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Aug 14, 2018 at 14:20 UTC 79ed0a5e2627a0e1eab0448e6f32d781e80bfafa
1 file changed +17 -11
builtin/cat-file.c
+17 -11
@@ -338,11 +338,11 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
338 }
339 }
340
341 -static void batch_object_write(const char *obj_name, struct batch_options *opt,
341 +static void batch_object_write(const char *obj_name,
342 + struct strbuf *scratch,
343 + struct batch_options *opt,
344 struct expand_data *data)
345 {
344 - struct strbuf buf = STRBUF_INIT;
345 -
346 if (!data->skip_object_info &&
347 oid_object_info_extended(the_repository, &data->oid, &data->info,
348 OBJECT_INFO_LOOKUP_REPLACE) < 0) {
@@ -352,10 +352,10 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
352 return;
353 }
354
355 - strbuf_expand(&buf, opt->format, expand_format, data);
356 - strbuf_addch(&buf, '\n');
357 - batch_write(opt, buf.buf, buf.len);
358 - strbuf_release(&buf);
355 + strbuf_reset(scratch);
356 + strbuf_expand(scratch, opt->format, expand_format, data);
357 + strbuf_addch(scratch, '\n');
358 + batch_write(opt, scratch->buf, scratch->len);
359
360 if (opt->print_contents) {
361 print_object_or_die(opt, data);
@@ -363,7 +363,9 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
363 }
364 }
365
366 -static void batch_one_object(const char *obj_name, struct batch_options *opt,
366 +static void batch_one_object(const char *obj_name,
367 + struct strbuf *scratch,
368 + struct batch_options *opt,
369 struct expand_data *data)
370 {
371 struct object_context ctx;
@@ -405,20 +407,21 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
407 return;
408 }
409
408 - batch_object_write(obj_name, opt, data);
410 + batch_object_write(obj_name, scratch, opt, data);
411 }
412
413 struct object_cb_data {
414 struct batch_options *opt;
415 struct expand_data *expand;
416 struct oidset *seen;
417 + struct strbuf *scratch;
418 };
419
420 static int batch_object_cb(const struct object_id *oid, void *vdata)
421 {
422 struct object_cb_data *data = vdata;
423 oidcpy(&data->expand->oid, oid);
421 - batch_object_write(NULL, data->opt, data->expand);
424 + batch_object_write(NULL, data->scratch, data->opt, data->expand);
425 return 0;
426 }
427
@@ -509,6 +512,7 @@ static int batch_objects(struct batch_options *opt)
512
513 cb.opt = opt;
514 cb.expand = &data;
515 + cb.scratch = &output;
516
517 if (opt->unordered) {
518 struct oidset seen = OIDSET_INIT;
@@ -531,6 +535,7 @@ static int batch_objects(struct batch_options *opt)
535 oid_array_clear(&sa);
536 }
537
538 + strbuf_release(&output);
539 return 0;
540 }
541
@@ -559,10 +564,11 @@ static int batch_objects(struct batch_options *opt)
564 data.rest = p;
565 }
566
562 - batch_one_object(input.buf, opt, &data);
567 + batch_one_object(input.buf, &output, opt, &data);
568 }
569
570 strbuf_release(&input);
571 + strbuf_release(&output);
572 warn_on_object_refname_ambiguity = save_warning;
573 return retval;
574 }