33 */
44#include "cache.h"
55#include "bulk-checkin.h"
6+ #include "lockfile.h"
67#include "repository.h"
78#include "csum-file.h"
89#include "pack.h"
910#include "strbuf.h"
11+ #include "string-list.h"
12+ #include "tmp-objdir.h"
1013#include "packfile.h"
1114#include "object-store.h"
1215
13- static struct bulk_checkin_state {
14- unsigned plugged :1 ;
16+ static int bulk_checkin_plugged ;
17+ static int needs_batch_fsync ;
18+
19+ static struct tmp_objdir * bulk_fsync_objdir ;
1520
21+ static struct bulk_checkin_state {
1622 char * pack_tmp_name ;
1723 struct hashfile * f ;
1824 off_t offset ;
@@ -21,7 +27,7 @@ static struct bulk_checkin_state {
2127 struct pack_idx_entry * * written ;
2228 uint32_t alloc_written ;
2329 uint32_t nr_written ;
24- } state ;
30+ } bulk_checkin_state ;
2531
2632static void finish_tmp_packfile (struct strbuf * basename ,
2733 const char * pack_tmp_name ,
@@ -79,6 +85,34 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state)
7985 reprepare_packed_git (the_repository );
8086}
8187
88+ /*
89+ * Cleanup after batch-mode fsync_object_files.
90+ */
91+ static void do_batch_fsync (void )
92+ {
93+ /*
94+ * Issue a full hardware flush against a temporary file to ensure
95+ * that all objects are durable before any renames occur. The code in
96+ * fsync_loose_object_bulk_checkin has already issued a writeout
97+ * request, but it has not flushed any writeback cache in the storage
98+ * hardware.
99+ */
100+
101+ if (needs_batch_fsync ) {
102+ struct strbuf temp_path = STRBUF_INIT ;
103+ struct tempfile * temp ;
104+
105+ strbuf_addf (& temp_path , "%s/bulk_fsync_XXXXXX" , get_object_directory ());
106+ temp = xmks_tempfile (temp_path .buf );
107+ fsync_or_die (get_tempfile_fd (temp ), get_tempfile_path (temp ));
108+ delete_tempfile (& temp );
109+ strbuf_release (& temp_path );
110+ }
111+
112+ if (bulk_fsync_objdir )
113+ tmp_objdir_migrate (bulk_fsync_objdir );
114+ }
115+
82116static int already_written (struct bulk_checkin_state * state , struct object_id * oid )
83117{
84118 int i ;
@@ -273,25 +307,61 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
273307 return 0 ;
274308}
275309
310+ void fsync_loose_object_bulk_checkin (int fd )
311+ {
312+ assert (fsync_object_files == FSYNC_OBJECT_FILES_BATCH );
313+
314+ /*
315+ * If we have a plugged bulk checkin, we issue a call that
316+ * cleans the filesystem page cache but avoids a hardware flush
317+ * command. Later on we will issue a single hardware flush
318+ * before as part of do_batch_fsync.
319+ */
320+ if (bulk_checkin_plugged &&
321+ git_fsync (fd , FSYNC_WRITEOUT_ONLY ) >= 0 ) {
322+ if (!needs_batch_fsync )
323+ needs_batch_fsync = 1 ;
324+ } else {
325+ fsync_or_die (fd , "loose object file" );
326+ }
327+ }
328+
276329int index_bulk_checkin (struct object_id * oid ,
277330 int fd , size_t size , enum object_type type ,
278331 const char * path , unsigned flags )
279332{
280- int status = deflate_to_pack (& state , oid , fd , size , type ,
333+ int status = deflate_to_pack (& bulk_checkin_state , oid , fd , size , type ,
281334 path , flags );
282- if (!state . plugged )
283- finish_bulk_checkin (& state );
335+ if (!bulk_checkin_plugged )
336+ finish_bulk_checkin (& bulk_checkin_state );
284337 return status ;
285338}
286339
287340void plug_bulk_checkin (void )
288341{
289- state .plugged = 1 ;
342+ assert (!bulk_checkin_plugged );
343+
344+ /*
345+ * A temporary object directory is used to hold the files
346+ * while they are not fsynced.
347+ */
348+ if (fsync_object_files == FSYNC_OBJECT_FILES_BATCH ) {
349+ bulk_fsync_objdir = tmp_objdir_create ("bulk-fsync" );
350+ if (!bulk_fsync_objdir )
351+ die (_ ("Could not create temporary object directory for core.fsyncobjectfiles=batch" ));
352+
353+ tmp_objdir_replace_primary_odb (bulk_fsync_objdir , 0 );
354+ }
355+
356+ bulk_checkin_plugged = 1 ;
290357}
291358
292359void unplug_bulk_checkin (void )
293360{
294- state .plugged = 0 ;
295- if (state .f )
296- finish_bulk_checkin (& state );
361+ assert (bulk_checkin_plugged );
362+ bulk_checkin_plugged = 0 ;
363+ if (bulk_checkin_state .f )
364+ finish_bulk_checkin (& bulk_checkin_state );
365+
366+ do_batch_fsync ();
297367}
0 commit comments