unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Atomic file replacement in Emacs
@ 2020-10-21 16:27 Zhu Zihao
  2020-10-21 19:49 ` Andreas Schwab
  0 siblings, 1 reply; 7+ messages in thread
From: Zhu Zihao @ 2020-10-21 16:27 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1572 bytes --]

It's a very common case to persist data structure using `pp` or `prin1`.
However, the core function of saving a buffer, `write-region` is not
atomic. If your data structure is very very large, and something
happened(e.g. you sent SIGKILL to Emacs, or the power of your computer
was cut) during saving, it will probably result in a broken file.

File system should provide some atomic operation to deal with these
conditions. There's a "trick" to do this job -- write to a temp file in
same directory, then use libc's rename to override origin file. Because
rename is atomic in same mount point. Our file can be replaced
atomically.

I'd like to suggest a implementation draft here. If you think this is good, I
can help make a patch to add it to files.el

~~~

(defmacro with-atomic-file-replacement (file &rest body)
  "Open FILE in a temp buffer and evaluate BODY in it, replace the FILE with the buffer content atomically"
  (declare (debug t) (indent 1))
  `(call-with-atomic-file-replacement ,file (lambda () ,@body)))

(defun call-with-atomic-file-replacement (file func)
  ;; The atomic of rename in libc was guaranteed by POSIX
  ;; standard, it will fail if we rename file between two mount point. So create
  ;; temp file in the same dir  of FILE.
  (let* ((full (expand-file-name file))
         (dir (file-name-directory full))
         (tmpfile (make-temp-file dir)))
    (with-temp-buffer
      (setq buffer-file-name tmpfile)
      (insert-file-contents-literally full)
      (funcall func)
      (basic-save-buffer)
      (rename-file tmpfile full t))))



[-- Attachment #2: Type: text/plain, Size: 613 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256


- --
Retrieve my public GPG key from: https://meta.sr.ht/~citreu.pgp
Zihao
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE7NCVzXX6efyusptG1SOVn+xGFqYFAl+QYYYACgkQ1SOVn+xG
FqbKoAf7BjNawuGgbwYgZNIE4j2WT6x2Zbi2E3RuoPfqmww/GXgzHDjc+TlctH0T
+hJVDb7+SrvhaOv4rjYu8gUIDZK67lpZD/axtVJfxV1+yqKA5MtVZdgw6xsPir4y
+40QkcgWUcD6EtSaqR85vjj80st8HKouUEn16f6hB2Dh9kptd4DfvVJYKV+7ndP2
yjKDseIgmNNiHny3jKw1HON+h9O9+10YLysFXieoKq3paTHmIHChoNhb898FPKEd
f/P8hTiV3ZAvLgLU6pLzN46MrYoUR8m72o4ZwzFn5gn/B/Bke6oRKEZLs1vHavBw
2quRGNG+SdKUDpDO/SvXmbWe635uPA==
=BoM1
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 16:27 Atomic file replacement in Emacs Zhu Zihao
@ 2020-10-21 19:49 ` Andreas Schwab
  2020-10-21 20:32   ` Stefan Monnier
                     ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Andreas Schwab @ 2020-10-21 19:49 UTC (permalink / raw)
  To: Zhu Zihao; +Cc: emacs-devel

There is already file-precious-flag.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 19:49 ` Andreas Schwab
@ 2020-10-21 20:32   ` Stefan Monnier
  2020-10-21 20:38     ` Andreas Schwab
  2020-10-21 23:25   ` Zhu Zihao
  2020-10-22  6:35   ` Zhu Zihao
  2 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2020-10-21 20:32 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Zhu Zihao, emacs-devel

> There is already file-precious-flag.

This is used by `save-buffer` but not by `write-region`, so it only
works if you use a proper "file buffer".


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 20:32   ` Stefan Monnier
@ 2020-10-21 20:38     ` Andreas Schwab
  2020-10-21 20:46       ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Andreas Schwab @ 2020-10-21 20:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Zhu Zihao, emacs-devel

On Okt 21 2020, Stefan Monnier wrote:

>> There is already file-precious-flag.
>
> This is used by `save-buffer` but not by `write-region`, so it only
> works if you use a proper "file buffer".

It is used by basic-save-buffer.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 20:38     ` Andreas Schwab
@ 2020-10-21 20:46       ` Stefan Monnier
  0 siblings, 0 replies; 7+ messages in thread
From: Stefan Monnier @ 2020-10-21 20:46 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Zhu Zihao, emacs-devel

>>> There is already file-precious-flag.
>> This is used by `save-buffer` but not by `write-region`, so it only
>> works if you use a proper "file buffer".
> It is used by basic-save-buffer.

Duh!  Indeed, I didn't pay enough attention to the code, I assumed it
was wrapping `write-region`.


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 19:49 ` Andreas Schwab
  2020-10-21 20:32   ` Stefan Monnier
@ 2020-10-21 23:25   ` Zhu Zihao
  2020-10-22  6:35   ` Zhu Zihao
  2 siblings, 0 replies; 7+ messages in thread
From: Zhu Zihao @ 2020-10-21 23:25 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: emacs-devel

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256


Andreas Schwab writes:

> There is already file-precious-flag.
>
> Andreas.


Nice! Thank you for remind me this good feature.

- --
Retrieve my GPG public key at: https://meta.sr.ht/~citreu.pgp
Zihao
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE7NCVzXX6efyusptG1SOVn+xGFqYFAl+Qw1gACgkQ1SOVn+xG
FqarzAf/fRqxjIN9HrQ0LaPX+seziCKsj5SSKjQrrw051rNO6gEFhfVBmV0E4MqE
fH0J+4ZQaJoMFl1FZ9gBc5TMyZ+x6etQwP78m7JyBZrj/f3lIIGLtDL3fV4Ja7j4
CDe5EOf1n1xoTNO9zZYXQOhu9pRtUCbmUpEc5CD28GKsuwdQkHIcyR0DA0maqudF
SKlMaYjzWIm3JBdwMRAhNAWW8FEIhJ0dpRY+jgw1OZn9TUUsgoLpJ+U169woDk92
vdJnPRgM5fmWG0NpBoJta3WDfyrOxRhQm2XQVw2eQvFskcxvg7M7aUac4EmCWf99
/kc4vAVT6LIK3NlH+FH5NnrAWAEPCg==
=0gix
-----END PGP SIGNATURE-----




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Atomic file replacement in Emacs
  2020-10-21 19:49 ` Andreas Schwab
  2020-10-21 20:32   ` Stefan Monnier
  2020-10-21 23:25   ` Zhu Zihao
@ 2020-10-22  6:35   ` Zhu Zihao
  2 siblings, 0 replies; 7+ messages in thread
From: Zhu Zihao @ 2020-10-22  6:35 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

This looks good, but there's still a question.

`file-precious-flag` is handled by `basic-save-buffer`. This is a large
function designed for daily save usage, it will touch recentf and vc.
But for a cache/persistent file, we don't want to make big noise, we
just want to save it silently. We may need something like

(write-region nil nil "XXXX" nil nil)

Can we simplify this case?


Andreas Schwab writes:

> There is already file-precious-flag.
>
> Andreas.


-- 
Retrieve my public GPG key: https://meta.sr.ht/~citreu.pgp

Zihao

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-10-22  6:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-21 16:27 Atomic file replacement in Emacs Zhu Zihao
2020-10-21 19:49 ` Andreas Schwab
2020-10-21 20:32   ` Stefan Monnier
2020-10-21 20:38     ` Andreas Schwab
2020-10-21 20:46       ` Stefan Monnier
2020-10-21 23:25   ` Zhu Zihao
2020-10-22  6:35   ` Zhu Zihao

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).