From 2ee6012b3faaf12710ec63626795148caeef0f6a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 2 Jan 2023 10:00:41 -0800 Subject: [PATCH] Improve interactive file-saving performance * src/fileio.c (init_fileio): No longer any need to set write-region-inhibit-fsync here. (syms_of_fileio): Default write-region-inhibit-fsync to t (Bug#60474). --- doc/emacs/files.texi | 13 ++++++------- doc/lispref/files.texi | 27 ++++++++++++++++++--------- etc/NEWS | 4 ++++ src/fileio.c | 37 ++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 37 deletions(-) diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 6d666831612..6a9103d3a09 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -801,22 +801,21 @@ Customize Save @vindex write-region-inhibit-fsync Normally, when a program writes a file, the operating system briefly caches the file's data in main memory before committing the data to -disk. This can greatly improve performance; for example, when running -on laptops, it can avoid a disk spin-up each time a file is written. -However, it risks data loss if the operating system crashes before -committing the cache to disk. +secondary storage. Although this can greatly improve performance, it +risks data loss if the system loses power before committing the cache, +and on some platforms other processes might not immediately notice the +file's change. To lessen this risk, Emacs can invoke the @code{fsync} system call after saving a file. Using @code{fsync} does not eliminate the risk -of data loss, partly because many systems do not implement +of data loss or slow notification, partly because many systems do not support @code{fsync} properly, and partly because Emacs's file-saving procedure typically relies also on directory updates that might not survive a crash even if @code{fsync} works properly. The @code{write-region-inhibit-fsync} variable controls whether Emacs invokes @code{fsync} after saving a file. The variable's -default value is @code{nil} when Emacs is interactive, and @code{t} -when Emacs runs in batch mode (@pxref{Initial Options, Batch Mode}). +default value is @code{t}. Emacs never uses @code{fsync} when writing auto-save files, as these files might lose data anyway. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 707af6ee64c..91643530f7f 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -692,11 +692,9 @@ Writing to Files @defvar write-region-inhibit-fsync If this variable's value is @code{nil}, @code{write-region} uses the -@code{fsync} system call after writing a file. Although this slows -Emacs down, it lessens the risk of data loss after power failure. If -the value is @code{t}, Emacs does not use @code{fsync}. The default -value is @code{nil} when Emacs is interactive, and @code{t} when Emacs -runs in batch mode. @xref{Files and Storage}. +@code{fsync} system call after writing a file. If the value is +@code{t}, Emacs does not use @code{fsync}. The default value is +@code{t}. @xref{Files and Storage}. @end defvar @defmac with-temp-file file body@dots{} @@ -2038,17 +2036,28 @@ Files and Storage the other is later modified; this will lose both files if the only copy on secondary storage is lost due to media failure. Second, the operating system might not write data to secondary storage -immediately, which will lose the data if power is lost. +immediately, which will lose the data if power is lost +or if there is a media failure. @findex write-region Although both sorts of failures can largely be avoided by a suitably -configured file system, such systems are typically more expensive or -less efficient. In more-typical systems, to survive media failure you +configured system, such systems are typically more expensive or +less efficient. In lower-end systems, to survive media failure you can copy the file to a different device, and to survive a power -failure you can use the @code{write-region} function with the +failure (or be immediately notified of a media failure) you can use +the @code{write-region} function with the @code{write-region-inhibit-fsync} variable set to @code{nil}. +Although this variable is ordinarily @code{t} because that can +significantly improve performance, it may make sense to temporarily +bind it to @code{nil} if using Emacs to implement database-like +transactions that survive power failure on lower-end systems. @xref{Writing to Files}. +On some platforms when Emacs changes a file other processes might not +be notified of the change immediately. Setting +@code{write-region-inhibit-fsync} to @code{nil} may improve +notification speed in this case, though there are no guarantees. + @node File Names @section File Names @cindex file names diff --git a/etc/NEWS b/etc/NEWS index eb68ce434b3..1ab6822da3f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -41,6 +41,10 @@ compositing manager, Emacs will now redisplay such a frame even though 'frame-visible-' returns nil or 'icon' for it. This can happen, for example, as part of preview for iconified frames. ++++ +** 'write-region-inhibit-fsync' now defaults to t in interactive mode, +as it has in batch mode since Emacs 24. + * Editing Changes in Emacs 30.1 diff --git a/src/fileio.c b/src/fileio.c index 7fb7f5ddc5e..c672e0f7baf 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -6334,24 +6334,6 @@ init_fileio (void) umask (realmask); valid_timestamp_file_system = 0; - - /* fsync can be a significant performance hit. Often it doesn't - suffice to make the file-save operation survive a crash. For - batch scripts, which are typically part of larger shell commands - that don't fsync other files, its effect on performance can be - significant so its utility is particularly questionable. - Hence, for now by default fsync is used only when interactive. - - For more on why fsync often fails to work on today's hardware, see: - Zheng M et al. Understanding the robustness of SSDs under power fault. - 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 - https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf - - For more on why fsync does not suffice even if it works properly, see: - Roche X. Necessary step(s) to synchronize filename operations on disk. - Austin Group Defect 672, 2013-03-19 - https://austingroupbugs.net/view.php?id=672 */ - write_region_inhibit_fsync = noninteractive; } void @@ -6609,9 +6591,22 @@ do (file-exists-p FILENAME) and FILENAME is handled by HANDLER, then DEFVAR_BOOL ("write-region-inhibit-fsync", write_region_inhibit_fsync, doc: /* Non-nil means don't call fsync in `write-region'. This variable affects calls to `write-region' as well as save commands. -Setting this to nil may avoid data loss if the system loses power or -the operating system crashes. By default, it is non-nil in batch mode. */); - write_region_inhibit_fsync = 0; /* See also `init_fileio' above. */ +By default, it is non-nil. + +Although setting this to nil may avoid data loss if the system loses power, +it can be a significant performance hit in the usual case, and it doesn't +necessarily cause file-save operations to actually survive a crash. */); + + /* For more on why fsync often fails to work on today's hardware, see: + Zheng M et al. Understanding the robustness of SSDs under power fault. + 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 + https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf + + For more on why fsync does not suffice even if it works properly, see: + Roche X. Necessary step(s) to synchronize filename operations on disk. + Austin Group Defect 672, 2013-03-19 + https://austingroupbugs.net/view.php?id=672 */ + write_region_inhibit_fsync = true; DEFVAR_BOOL ("delete-by-moving-to-trash", delete_by_moving_to_trash, doc: /* Specifies whether to use the system's trash can. -- 2.37.2