git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/2] core.fsyncobjectfiles: batch disk flushes

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Aug 25, 2021, 16:11 UTC
Message-ID
<87mtp5cwpn.fsf@evledraar.gmail.com>
In-Reply-To
<d1e68d4a2afc1d0ba74af64680bea09f412f21cc.1629856293.git.gitgitgadget@gmail.com>
On Wed, Aug 25 2021, Neeraj Singh via GitGitGadget wrote:
Show 38 quoted lines
> From: Neeraj Singh <neerajsi@microsoft.com>
>
> When adding many objects to a repo with core.fsyncObjectFiles set to
> true, the cost of fsync'ing each object file can become prohibitive.
>
> One major source of the cost of fsync is the implied flush of the
> hardware writeback cache within the disk drive. Fortunately, Windows,
> MacOS, and Linux each offer mechanisms to write data from the filesystem
> page cache without initiating a hardware flush.
>
> This patch introduces a new 'core.fsyncObjectFiles = 2' option that
> takes advantage of the bulk-checkin infrastructure to batch up hardware
> flushes.
>
> When the new mode is enabled we do the following for new objects:
>
> 1. Create a tmp_obj_XXXX file and write the object data to it.
> 2. Issue a pagecache writeback request and wait for it to complete.
> 3. Record the tmp name and the final name in the bulk-checkin state for
>    later name.
>
> At the end of the entire transaction we:
> 1. Issue a fsync against the lock file to flush the hardware writeback
>    cache, which should by now have processed the tmp file writes.
> 2. Rename all of the temp files to their final names.
> 3. When updating the index and/or refs, we will issue another fsync
>    internal to that operation.
>
> On a filesystem with a singular journal that is updated during name
> operations (e.g. create, link, rename, etc), such as NTFS and HFS+, we
> would expect the fsync to trigger a journal writeout so that this
> sequence is enough to ensure that the user's data is durable by the time
> the git command returns.
>
> This change also updates the MacOS code to trigger a real hardware flush
> via fnctl(fd, F_FULLFSYNC) when fsync_or_die is called. Previously, on
> MacOS there was no guarantee of durability since a simple fsync(2) call
> does not flush any hardware caches.

Thanks for working on this, good to see fsck issues picked up after some on-list pause.

Show 25 quoted lines
> diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
> index c04f62a54a1..3b672c2db67 100644
> --- a/Documentation/config/core.txt
> +++ b/Documentation/config/core.txt
> @@ -548,12 +548,17 @@ core.whitespace::
>    errors. The default tab width is 8. Allowed values are 1 to 63.
>  
>  core.fsyncObjectFiles::
> -	This boolean will enable 'fsync()' when writing object files.
> -+
> -This is a total waste of time and effort on a filesystem that orders
> -data writes properly, but can be useful for filesystems that do not use
> -journalling (traditional UNIX filesystems) or that only journal metadata
> -and not file contents (OS X's HFS+, or Linux ext3 with "data=writeback").
> +	A boolean value or the number '2', indicating the level of durability
> +	applied to object files.
> ++
> +This setting controls how much effort Git makes to ensure that data added to
> +the object store are durable in the case of an unclean system shutdown. If
> +'false', Git allows data to remain in file system caches according to operating
> +system policy, whence they may be lost if the system loses power or crashes. A
> +value of 'true' instructs Git to force objects to stable storage immediately
> +when they are added to the object store. The number '2' is an experimental
> +value that also preserves durability but tries to perform hardware flushes in a
> +batch.
Some feedback/thoughts:
0) Let's not expose "2" to users, but give it some friendly config name
and just translate this to the enum internally.
1) Your commit message says "When updating the index and/or refs[...]"
but we're changing core.fsyncObjectFiles here, I assume that's
summarizing existing behavior then
2) You say "when adding many [loose] objects to a repo[...]", and the
test-case is "git stash push", but for e.g. accepting pushes we have
transfer.unpackLimit.

It would be interesting to see if/how this impacts performance there, and also if not that should at least be called out in documentation. I.e. users might want to set this differently on servers v.s. checkouts.

But also, is this sort of thing something we could mitigate even more in commands like "git stash push" by just writing a pack instead of N loose objects?

I don't think such questions should preclude changing the fsync approach, or offering more options, but they should inform our longer-term goals.

3) Re some of the musings about fsync() recently in
https://lore.kernel.org/git/877dhs20x3.fsf@evledraar.gmail.com/; is this
method of doing not-quite-an-fsync guaranteed by some OS's / POSIX etc,
or is it more like the initial approach before core.fsyncObjectFiles,
i.e. the happy-go-lucky approach described in the "[...]that orders data
writes properly[...]" documentation you're removing.
4) While that documentation written by Linus long ago is rather
flippant, I think just removing it and not replacing it with some
discussion about how this is a trade-off v.s. real-world filesystem
semantics isn't a good change.
5) On a similar thought as transfer.unpackLimit in #2, I wonder if this
fsync() setting shouldn't really be something we should be splitting
up. I.e. maybe handle batch loose object writes one way, ref updates
another way etc. I think moving core.fsync* to a setting like what we
have for fsck.* and <cmd>.fsck.* is probably a better thing to do in the
longer term.
I.e. being able to do things like:
    fsync.objectFiles = none
    fsync.refFiles = cache # or "hardware"
    receive.fsync.objectFiles = hardware
    receive.fsync.refFiles = hardware

Or whatever, i.e. we're using one hammer for all of these now, but I suspect most users who care about fsync care about /some/ fsync, not everything.

6) Inline comments below.
Show 10 quoted lines
> +struct object_rename {
> +	char *src;
> +	char *dst;
> +};
> +
> +static struct bulk_rename_state {
> +	struct object_rename *renames;
> +	uint32_t alloc_renames;
> +	uint32_t nr_renames;
> +} bulk_rename_state;

In a crash of git itself it seems we're going to leave some litter behind in the object dir now, and "git gc" won't know how to clean it up. I think this is going to want to just use the tmp-objdir.[ch] API, which might or might not need to be extended for loose objects / some oddities of this use-case.

Also, if you have a pair of things like this the string-list API is much more pleasing to use than coming up with your own encapsulation.

Show 8 quoted lines
>  static struct bulk_checkin_state {
>  	unsigned plugged:1;
>  
> @@ -21,13 +33,15 @@ static struct bulk_checkin_state {
>  	struct pack_idx_entry **written;
>  	uint32_t alloc_written;
>  	uint32_t nr_written;
> -} state;
> +
> +		free(state->renames);
> +		memset(state, 0, sizeof(*state));

So with this and other use of the "state" variable is this part of bulk-checkin going to become thread-unsafe, was that already the case?

Show 11 quoted lines
> +static void add_rename_bulk_checkin(struct bulk_rename_state *state,
> +				    const char *src, const char *dst)
> +{
> +	struct object_rename *rename;
> +
> +	ALLOC_GROW(state->renames, state->nr_renames + 1, state->alloc_renames);
> +
> +	rename = &state->renames[state->nr_renames++];
> +	rename->src = xstrdup(src);
> +	rename->dst = xstrdup(dst);
> +}
All boilerplate duplicating things you'd get with a string-list for free...
Show 6 quoted lines
> +		/*
> +		 * If we have a plugged bulk checkin, we issue a call that
> +		 * cleans the filesystem page cache but avoids a hardware flush
> +		 * command. Later on we will issue a single hardware flush
> +		 * before renaming files as part of do_sync_and_rename.
> +		 */

So this is the sort of thing I meant by extending Linus's docs, I know some FS's work this way, but not all do.

Also there's no guarantee in git that your .git is on one FS, so I think even for the FS's you have in mind this might not be an absolute guarantee...

Previous: Christoph HellwigNext: Neeraj Singh
Message 9 of 160 in “[RFC] Implement a bulk-checkin option for core.fsyncObjectFiles”
  1. 0/2 [RFC] Implement a bulk-checkin option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Aug 25, 2021
  2. 1/2 object-file: use futimes rather than utimeNeeraj Singh via GitGitGadget, Aug 25, 2021
  3. Johannes SchindelinAug 25, 2021
  4. Neeraj SinghAug 25, 2021
  5. 2/2 core.fsyncobjectfiles: batch disk flushesNeeraj Singh via GitGitGadget, Aug 25, 2021
  6. Christoph HellwigAug 25, 2021
  7. Neeraj SinghAug 25, 2021
  8. Christoph HellwigAug 26, 2021
  9. Ævar Arnfjörð BjarmasonAug 25, 2021
  10. Neeraj SinghAug 26, 2021
  11. Christoph HellwigAug 26, 2021
  12. Neeraj SinghAug 28, 2021
  13. Christoph HellwigAug 28, 2021
  14. Neeraj SinghAug 31, 2021
  15. Christoph HellwigSep 1, 2021
  16. Christoph HellwigAug 26, 2021
  17. Johannes SchindelinAug 25, 2021
  18. Junio C HamanoAug 25, 2021
  19. Neeraj SinghAug 26, 2021
  20. Neeraj SinghAug 25, 2021
  21. 0/6 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Aug 27, 2021
  22. 1/6 object-file: use futimens rather than utimeNeeraj Singh via GitGitGadget, Aug 27, 2021
  23. 2/6 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Aug 27, 2021
  24. 3/6 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Aug 27, 2021
  25. 5/6 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Aug 27, 2021
  26. 6/6 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Aug 27, 2021
  27. 4/6 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Aug 27, 2021
  28. Neeraj SinghSep 7, 2021
  29. Ævar Arnfjörð BjarmasonSep 7, 2021
  30. Randall S. BeckerSep 7, 2021
  31. Neeraj SinghSep 8, 2021
  32. Ævar Arnfjörð BjarmasonSep 8, 2021
  33. Randall S. BeckerSep 8, 2021
  34. Neeraj SinghSep 8, 2021
  35. Neeraj SinghSep 8, 2021
  36. Junio C HamanoSep 8, 2021
  37. Christoph HellwigSep 8, 2021
  38. Randall S. BeckerSep 8, 2021
  39. 'Christoph Hellwig'Sep 8, 2021
  40. Randall S. BeckerSep 8, 2021
  41. Neeraj SinghSep 8, 2021
  42. Junio C HamanoSep 8, 2021
  43. Neeraj SinghSep 8, 2021
  44. Ævar Arnfjörð BjarmasonSep 8, 2021
  45. 0/6 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Sep 14, 2021
  46. 1/6 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Sep 14, 2021
  47. 2/6 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Sep 14, 2021
  48. Bagas SanjayaSep 14, 2021
  49. Neeraj SinghSep 14, 2021
  50. Junio C HamanoSep 14, 2021
  51. Junio C HamanoSep 14, 2021
  52. Neeraj SinghSep 15, 2021
  53. 3/6 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Sep 14, 2021
  54. 4/6 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 14, 2021
  55. Junio C HamanoSep 14, 2021
  56. 5/6 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Sep 14, 2021
  57. 6/6 core.fsyncobjectfiles: enable batch mode for testingNeeraj Singh via GitGitGadget, Sep 14, 2021
  58. Junio C HamanoSep 15, 2021
  59. Neeraj SinghSep 15, 2021
  60. Junio C HamanoSep 15, 2021
  61. Junio C HamanoSep 16, 2021
  62. Christoph HellwigSep 14, 2021
  63. 0/6 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Sep 20, 2021
  64. 5/6 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Sep 20, 2021
  65. Ævar Arnfjörð BjarmasonSep 21, 2021
  66. Neeraj SinghSep 22, 2021
  67. Ævar Arnfjörð BjarmasonSep 22, 2021
  68. Neeraj SinghSep 22, 2021
  69. Ævar Arnfjörð BjarmasonSep 22, 2021
  70. 2/6 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Sep 20, 2021
  71. Ævar Arnfjörð BjarmasonSep 21, 2021
  72. Neeraj SinghSep 22, 2021
  73. Ævar Arnfjörð BjarmasonSep 22, 2021
  74. Neeraj SinghSep 22, 2021
  75. 1/6 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Sep 20, 2021
  76. 4/6 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 20, 2021
  77. Ævar Arnfjörð BjarmasonSep 21, 2021
  78. Neeraj SinghSep 22, 2021
  79. Neeraj SinghSep 23, 2021
  80. 3/6 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Sep 20, 2021
  81. Ævar Arnfjörð BjarmasonSep 21, 2021
  82. Neeraj SinghSep 22, 2021
  83. 6/6 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Sep 20, 2021
  84. 0/7 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Sep 24, 2021
  85. 1/7 object-file.c: do not rename in a temp odbNeeraj Singh via GitGitGadget, Sep 24, 2021
  86. 2/7 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Sep 24, 2021
  87. 3/7 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Sep 24, 2021
  88. Neeraj SinghSep 24, 2021
  89. 4/7 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 24, 2021
  90. Neeraj SinghSep 24, 2021
  91. 5/7 unpack-objects: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 24, 2021
  92. 6/7 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Sep 24, 2021
  93. 7/7 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Sep 24, 2021
  94. Neeraj SinghSep 24, 2021
  95. 0/8 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Sep 24, 2021
  96. 1/8 object-file.c: do not rename in a temp odbNeeraj Singh via GitGitGadget, Sep 24, 2021
  97. 2/8 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Sep 24, 2021
  98. 3/8 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Sep 24, 2021
  99. Bagas SanjayaSep 25, 2021
  100. Neeraj SinghSep 27, 2021
  101. 5/8 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 24, 2021
  102. 4/8 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Sep 24, 2021
  103. Junio C HamanoSep 27, 2021
  104. Neeraj SinghSep 27, 2021
  105. Neeraj SinghSep 27, 2021
  106. Junio C HamanoSep 27, 2021
  107. 6/8 unpack-objects: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 24, 2021
  108. 8/8 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Sep 24, 2021
  109. 7/8 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Sep 24, 2021
  110. 0/9 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Sep 28, 2021
  111. 1/9 object-file.c: do not rename in a temp odbNeeraj Singh via GitGitGadget, Sep 28, 2021
  112. Jeff KingSep 28, 2021
  113. Neeraj SinghSep 29, 2021
  114. 3/9 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Sep 28, 2021
  115. 2/9 tmp-objdir: new API for creating temporary writable databasesNeeraj Singh via GitGitGadget, Sep 28, 2021
  116. Elijah NewrenSep 29, 2021
  117. Neeraj SinghSep 29, 2021
  118. 4/9 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Sep 28, 2021
  119. 5/9 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Sep 28, 2021
  120. 6/9 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 28, 2021
  121. 8/9 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Sep 28, 2021
  122. 7/9 unpack-objects: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Sep 28, 2021
  123. 9/9 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Sep 28, 2021
  124. 0/9 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Oct 4, 2021
  125. 1/9 tmp-objdir: new API for creating temporary writable databasesNeeraj Singh via GitGitGadget, Oct 4, 2021
  126. 2/9 tmp-objdir: disable ref updates when replacing the primary odbNeeraj Singh via GitGitGadget, Oct 4, 2021
  127. 3/9 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Oct 4, 2021
  128. 4/9 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Oct 4, 2021
  129. 5/9 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Oct 4, 2021
  130. 6/9 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Oct 4, 2021
  131. 7/9 unpack-objects: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Oct 4, 2021
  132. 8/9 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Oct 4, 2021
  133. 9/9 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Oct 4, 2021
  134. 0/9 Implement a batched fsync option for core.fsyncObjectFilesNeeraj K. Singh via GitGitGadget, Nov 15, 2021
  135. 2/9 tmp-objdir: disable ref updates when replacing the primary odbNeeraj Singh via GitGitGadget, Nov 15, 2021
  136. Ævar Arnfjörð BjarmasonNov 16, 2021
  137. Neeraj SinghNov 16, 2021
  138. 1/9 tmp-objdir: new API for creating temporary writable databasesNeeraj Singh via GitGitGadget, Nov 15, 2021
  139. Elijah NewrenNov 30, 2021
  140. Neeraj SinghNov 30, 2021
  141. Elijah NewrenNov 30, 2021
  142. 3/9 bulk-checkin: rename 'state' variable and separate 'plugged' booleanNeeraj Singh via GitGitGadget, Nov 15, 2021
  143. 4/9 core.fsyncobjectfiles: batched disk flushesNeeraj Singh via GitGitGadget, Nov 15, 2021
  144. 5/9 core.fsyncobjectfiles: add windows support for batch modeNeeraj Singh via GitGitGadget, Nov 15, 2021
  145. 6/9 update-index: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Nov 15, 2021
  146. 7/9 unpack-objects: use the bulk-checkin infrastructureNeeraj Singh via GitGitGadget, Nov 15, 2021
  147. 8/9 core.fsyncobjectfiles: tests for batch modeNeeraj Singh via GitGitGadget, Nov 15, 2021
  148. 9/9 core.fsyncobjectfiles: performance tests for add and stashNeeraj Singh via GitGitGadget, Nov 15, 2021
  149. Ævar Arnfjörð BjarmasonNov 16, 2021
  150. Neeraj SinghNov 17, 2021
  151. Ævar Arnfjörð BjarmasonNov 17, 2021
  152. Neeraj SinghNov 18, 2021
  153. Ævar Arnfjörð BjarmasonDec 1, 2021
  154. Ævar Arnfjörð BjarmasonMar 9, 2022
  155. Neeraj SinghMar 10, 2022
  156. Ævar Arnfjörð BjarmasonMar 10, 2022
  157. Neeraj SinghMar 10, 2022
  158. rsbecker@nexbridge.comMar 10, 2022
  159. Neeraj SinghMar 10, 2022
  160. rsbecker@nexbridge.comMar 10, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.