@@ -280,6 +280,7 @@ struct expand_data {
280280 off_t disk_size ;
281281 const char * rest ;
282282 struct object_id delta_base_oid ;
283+ struct git_iovec iov [3 ];
283284
284285 /*
285286 * If mark_query is true, we do not expand anything, but rather
@@ -368,7 +369,7 @@ static void expand_format(struct strbuf *sb, const char *start,
368369 }
369370}
370371
371- static void batch_write (struct batch_options * opt , const void * data , int len )
372+ static void batch_write (struct batch_options * opt , const void * data , size_t len )
372373{
373374 if (opt -> buffer_output ) {
374375 if (fwrite (data , 1 , len , stdout ) != len )
@@ -377,15 +378,72 @@ static void batch_write(struct batch_options *opt, const void *data, int len)
377378 write_or_die (1 , data , len );
378379}
379380
380- static void print_object_or_die (struct batch_options * opt , struct expand_data * data )
381+ static void batch_writev (struct batch_options * opt , struct expand_data * data ,
382+ const struct strbuf * hdr , size_t size )
383+ {
384+ data -> iov [0 ].iov_base = hdr -> buf ;
385+ data -> iov [0 ].iov_len = hdr -> len ;
386+ data -> iov [1 ].iov_len = size ;
387+
388+ /*
389+ * Copying a (8|16)-byte iovec for a single byte is gross, but my
390+ * attempt to stuff output_delim into the trailing NUL byte of
391+ * iov[1].iov_base (and restoring it after writev(2) for the
392+ * OI_DBCACHED case) to drop iovcnt from 3->2 wasn't faster.
393+ */
394+ data -> iov [2 ].iov_base = & opt -> output_delim ;
395+ data -> iov [2 ].iov_len = 1 ;
396+
397+ if (opt -> buffer_output )
398+ fwritev_or_die (stdout , data -> iov , 3 );
399+ else
400+ writev_or_die (1 , data -> iov , 3 );
401+
402+ /* writev_or_die may move iov[1].iov_base, so it's invalid */
403+ data -> iov [1 ].iov_base = NULL ;
404+ }
405+
406+ static void print_object_or_die (struct batch_options * opt ,
407+ struct expand_data * data , struct strbuf * hdr )
381408{
382409 const struct object_id * oid = & data -> oid ;
383410
384411 assert (data -> info .typep );
385412
386- if (data -> type == OBJ_BLOB ) {
387- if (opt -> buffer_output )
388- fflush (stdout );
413+ if (data -> iov [1 ].iov_base ) {
414+ void * content = data -> iov [1 ].iov_base ;
415+ unsigned long size = data -> size ;
416+
417+ if (use_mailmap && (data -> type == OBJ_COMMIT ||
418+ data -> type == OBJ_TAG )) {
419+ size_t s = size ;
420+
421+ if (data -> info .whence == OI_DBCACHED ) {
422+ content = xmemdupz (content , s );
423+ data -> info .whence = OI_PACKED ;
424+ }
425+
426+ content = replace_idents_using_mailmap (content , & s );
427+ data -> iov [1 ].iov_base = content ;
428+ size = cast_size_t_to_ulong (s );
429+ }
430+ batch_writev (opt , data , hdr , size );
431+ switch (data -> info .whence ) {
432+ case OI_CACHED :
433+ /*
434+ * only blame uses OI_CACHED atm, so it's unlikely
435+ * we'll ever hit this path
436+ */
437+ BUG ("TODO OI_CACHED support not done" );
438+ case OI_LOOSE :
439+ case OI_PACKED :
440+ free (content );
441+ break ;
442+ case OI_DBCACHED :
443+ unlock_delta_base_cache ();
444+ }
445+ } else {
446+ assert (data -> type == OBJ_BLOB );
389447 if (opt -> transform_mode ) {
390448 char * contents ;
391449 unsigned long size ;
@@ -412,36 +470,17 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
412470 oid_to_hex (oid ), data -> rest );
413471 } else
414472 BUG ("invalid transform_mode: %c" , opt -> transform_mode );
415- batch_write (opt , contents , size );
473+ data -> iov [1 ].iov_base = contents ;
474+ batch_writev (opt , data , hdr , size );
416475 free (contents );
417476 } else {
477+ batch_write (opt , hdr -> buf , hdr -> len );
478+ if (opt -> buffer_output )
479+ fflush (stdout );
418480 stream_blob (oid );
481+ batch_write (opt , & opt -> output_delim , 1 );
419482 }
420483 }
421- else {
422- enum object_type type ;
423- unsigned long size ;
424- void * contents ;
425-
426- contents = repo_read_object_file (the_repository , oid , & type ,
427- & size );
428- if (!contents )
429- die ("object %s disappeared" , oid_to_hex (oid ));
430-
431- if (use_mailmap ) {
432- size_t s = size ;
433- contents = replace_idents_using_mailmap (contents , & s );
434- size = cast_size_t_to_ulong (s );
435- }
436-
437- if (type != data -> type )
438- die ("object %s changed type!?" , oid_to_hex (oid ));
439- if (data -> info .sizep && size != data -> size && !use_mailmap )
440- die ("object %s changed size!?" , oid_to_hex (oid ));
441-
442- batch_write (opt , contents , size );
443- free (contents );
444- }
445484}
446485
447486static void print_default_format (struct strbuf * scratch , struct expand_data * data ,
@@ -508,12 +547,10 @@ static void batch_object_write(const char *obj_name,
508547 strbuf_addch (scratch , opt -> output_delim );
509548 }
510549
511- batch_write (opt , scratch -> buf , scratch -> len );
512-
513- if (opt -> batch_mode == BATCH_MODE_CONTENTS ) {
514- print_object_or_die (opt , data );
515- batch_write (opt , & opt -> output_delim , 1 );
516- }
550+ if (opt -> batch_mode == BATCH_MODE_CONTENTS )
551+ print_object_or_die (opt , data , scratch );
552+ else
553+ batch_write (opt , scratch -> buf , scratch -> len );
517554}
518555
519556static void batch_one_object (const char * obj_name ,
@@ -655,6 +692,7 @@ static void parse_cmd_contents(struct batch_options *opt,
655692 struct expand_data * data )
656693{
657694 opt -> batch_mode = BATCH_MODE_CONTENTS ;
695+ data -> info .contentp = & data -> iov [1 ].iov_base ;
658696 batch_one_object (line , output , opt , data );
659697}
660698
@@ -664,6 +702,7 @@ static void parse_cmd_info(struct batch_options *opt,
664702 struct expand_data * data )
665703{
666704 opt -> batch_mode = BATCH_MODE_INFO ;
705+ data -> info .contentp = NULL ;
667706 batch_one_object (line , output , opt , data );
668707}
669708
@@ -801,9 +840,20 @@ static int batch_objects(struct batch_options *opt)
801840 /*
802841 * If we are printing out the object, then always fill in the type,
803842 * since we will want to decide whether or not to stream.
843+ *
844+ * Likewise, grab the content in the initial request if it's small
845+ * and we're not planning to filter it.
804846 */
805- if (opt -> batch_mode == BATCH_MODE_CONTENTS )
847+ if ((opt -> batch_mode == BATCH_MODE_CONTENTS ) ||
848+ (opt -> batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH )) {
806849 data .info .typep = & data .type ;
850+ if (!opt -> transform_mode ) {
851+ data .info .sizep = & data .size ;
852+ data .info .contentp = & data .iov [1 ].iov_base ;
853+ data .info .content_limit = big_file_threshold ;
854+ data .info .direct_cache = 1 ;
855+ }
856+ }
807857
808858 if (opt -> all_objects ) {
809859 struct object_cb_data cb ;
0 commit comments