From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Zhu Zihao Newsgroups: gmane.emacs.devel Subject: Atomic file replacement in Emacs Date: Thu, 22 Oct 2020 00:27:50 +0800 Message-ID: <868sbzk0hl.fsf@163.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="24269"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.4.13; emacs 27.1 To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Oct 21 18:45:14 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVHEg-0006Bm-K7 for ged-emacs-devel@m.gmane-mx.org; Wed, 21 Oct 2020 18:45:14 +0200 Original-Received: from localhost ([::1]:50444 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kVHEf-0006PT-J3 for ged-emacs-devel@m.gmane-mx.org; Wed, 21 Oct 2020 12:45:13 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:35360) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kVHDH-0004kn-Bz for emacs-devel@gnu.org; Wed, 21 Oct 2020 12:43:52 -0400 Original-Received: from mail-m975.mail.163.com ([123.126.97.5]:39372) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kVHDC-00073U-2O for emacs-devel@gnu.org; Wed, 21 Oct 2020 12:43:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Message-ID:Date:MIME-Version; bh=OQlm7 WaL0bM9h2oKKboqGLxY+JsRgSJJ2a60aIqwmA4=; b=QApLmQfMPsozLBmpILn0x aU/GuEfcimgvZnXu4Ovj6zPdgOH1fEAmhpjUlgdvUcJ/9TO6EfAfIWuIAu6zUA8a RVt3QhPMViuJhexfmNHuNHx2JmYHnBhxOAWg58gl1OqWpLCj/aEXxT+7qpMKQiFM lT3fyHmH8HrB9vGCI4e4Mo= Original-Received: from asus-laptop (unknown [27.39.88.139]) by smtp5 (Coremail) with SMTP id HdxpCgDnHC6IYZBfs7KVTQ--.82S2; Thu, 22 Oct 2020 00:27:52 +0800 (CST) X-CM-TRANSID: HdxpCgDnHC6IYZBfs7KVTQ--.82S2 X-Coremail-Antispam: 1Uf129KBjvJXoW7AF15GFW5Cr4kKr4kWw4Uurg_yoW8XFyfpF WfKr4qyrWkZryFkw4kAF1xJryavrZYv34a9FZ5W348CryFgr4jvFWftr45Ar1UWr4fGw4k Xa1qy34kWw45Jr7anT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07UfpndUUUUU= X-Originating-IP: [27.39.88.139] X-CM-SenderInfo: pdoosuxxwbztlvw6il2tof0z/xtbBTQnEr1r77hocNgAAsQ Received-SPF: pass client-ip=123.126.97.5; envelope-from=all_but_last@163.com; helo=mail-m975.mail.163.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/21 12:27:54 X-ACL-Warn: Detected OS = Linux 3.1-3.10 X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:258240 Archived-At: --=-=-= Content-Type: text/plain 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)))) --=-=-= Content-Type: text/plain -----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----- --=-=-=--