all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Zhu Zihao <all_but_last@163.com>
To: emacs-devel@gnu.org
Subject: Atomic file replacement in Emacs
Date: Thu, 22 Oct 2020 00:27:50 +0800	[thread overview]
Message-ID: <868sbzk0hl.fsf@163.com> (raw)

[-- 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-----

             reply	other threads:[~2020-10-21 16:27 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-21 16:27 Zhu Zihao [this message]
2020-10-21 19:49 ` Atomic file replacement in Emacs 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=868sbzk0hl.fsf@163.com \
    --to=all_but_last@163.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.