branch: externals/org commit 38cd9b0a3a789ca7e49a1bb98d5b3c4b2257fe4a Author: Ihor Radchenko <yanta...@posteo.net> Commit: Ihor Radchenko <yanta...@posteo.net>
org-persist: Avoid writing index frequently * lisp/org-persist.el (org-persist--write-elisp-file): Do not write index every time. Remove optional argument. (org-persist-write:index): Update call. (org-persist--merge-index): When BASE is nil, just return OTHER. This speeds things up when we have no index loaded. (org-persist-register): (org-persist-unregister): (org-persist-read): (org-persist-load-all): (org-persist-write-all): (org-persist-gc): Make sure that index is synchronized with disk and conflicting (non-equal) entries are dropped. This is an alternative approach compared to 7999433067 that avoid frequent idnex writes (which are slow). We instead _read_ index solving the problem of multiple Emacs instances writing to cache in different, faster, way. Link: https://orgmode.org/list/87h63cj1c5....@gmail.com --- lisp/org-persist.el | 104 +++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index d96a303820..ae75ab7afc 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -454,15 +454,12 @@ FORMAT and ARGS are passed to `message'." ;; FIXME: `pp' is very slow when writing even moderately large datasets ;; We should probably drop it or find some fast formatter. -(defun org-persist--write-elisp-file - (file data &optional no-circular pp inhibit-writing-index) +(defun org-persist--write-elisp-file (file data &optional no-circular pp) "Write to index and then write elisp DATA to FILE. When optional argument NO-CIRCULAR is non-nil, do not bind `print-circle' to t. When optional argument PP is non-nil, pretty-print the data (slow on -moderately large data). -INHIBIT-WRITING-INDEX will disable writing index file. -" +moderately large data)." ;; Fsync slightly reduces the chance of an incomplete filesystem ;; write, however on modern hardware its effectiveness is ;; questionable and it is insufficient to guarantee complete writes. @@ -488,28 +485,23 @@ INHIBIT-WRITING-INDEX will disable writing index file. print-number-table (start-time (float-time)) (tmp-file (make-temp-file "org-persist-"))) - ;; Every time we write cache data, make sure that index is up to - ;; date. This prevents situation when two Emacs sessions are writing - ;; different data under the same cache key, but do not update the - ;; index metadata about the cache data written (e.g. hash). - (when (or inhibit-writing-index (org-persist--save-index)) - (unless (file-exists-p (file-name-directory file)) - (make-directory (file-name-directory file) t)) - ;; Do not write to FILE directly. Another Emacs instance may be - ;; doing the same at the same time. Instead, write to new - ;; temporary file and then rename it (renaming is atomic - ;; operation that does not create data races). - ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=75209#35 - (with-temp-file tmp-file - (insert ";; -*- mode: lisp-data; -*-\n") - (if pp - (let ((pp-use-max-width nil)) ; Emacs bug#58687 - (pp data (current-buffer))) - (prin1 data (current-buffer)))) - (rename-file tmp-file file 'overwrite) - (org-persist--display-time - (- (float-time) start-time) - "Writing to %S" file)))) + (unless (file-exists-p (file-name-directory file)) + (make-directory (file-name-directory file) t)) + ;; Do not write to FILE directly. Another Emacs instance may be + ;; doing the same at the same time. Instead, write to new + ;; temporary file and then rename it (renaming is atomic + ;; operation that does not create data races). + ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=75209#35 + (with-temp-file tmp-file + (insert ";; -*- mode: lisp-data; -*-\n") + (if pp + (let ((pp-use-max-width nil)) ; Emacs bug#58687 + (pp data (current-buffer))) + (prin1 data (current-buffer)))) + (rename-file tmp-file file 'overwrite) + (org-persist--display-time + (- (float-time) start-time) + "Writing to %S" file))) (defmacro org-persist-gc:generic (container collection) "Garbage collect CONTAINER data from COLLECTION." @@ -944,7 +936,7 @@ Otherwise, return t." (let ((index-file (org-file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) - (org-persist--write-elisp-file index-file org-persist--index t nil t) + (org-persist--write-elisp-file index-file org-persist--index t nil) (setq org-persist--index-age (file-attribute-modification-time (file-attributes index-file))) index-file))) @@ -973,26 +965,28 @@ Otherwise, return t." "Attempt to merge new index items in OTHER into BASE. Items with different details are considered too difficult, and skipped." (if other - (let ((new (cl-set-difference other base :test #'equal)) - (base-files (mapcar (lambda (s) (plist-get s :persist-file)) base)) - (combined (reverse base))) - (dolist (item (nreverse new)) - (unless (or (memq 'index (mapcar #'car (plist-get item :container))) - (not (file-exists-p + (if (not base) other + (let ((new (cl-set-difference other base :test #'equal)) + (base-files (mapcar (lambda (s) (plist-get s :persist-file)) base)) + (combined (reverse base))) + (dolist (item (nreverse new)) + (unless (or (memq 'index (mapcar #'car (plist-get item :container))) + (not (file-exists-p (org-file-name-concat org-persist-directory (plist-get item :persist-file)))) - (member (plist-get item :persist-file) base-files)) - (push item combined))) - (nreverse combined)) + (member (plist-get item :persist-file) base-files)) + (push item combined))) + (nreverse combined))) base)) ;;;; Public API -(cl-defun org-persist-register (container &optional associated &rest misc - &key inherit - &key (expiry org-persist-default-expiry) - &key (write-immediately nil) - &allow-other-keys) +(cl-defun org-persist-register + ( container &optional associated &rest misc + &key inherit + &key (expiry org-persist-default-expiry) + &key (write-immediately nil) + &allow-other-keys) "Register CONTAINER in ASSOCIATED to be persistent across Emacs sessions. Optional key INHERIT makes CONTAINER dependent on another container. Such dependency means that data shared between variables will be @@ -1007,7 +1001,9 @@ MISC will be appended to the collection. It must be alternating :KEY VALUE pairs. When WRITE-IMMEDIATELY is non-nil, the return value will be the same with `org-persist-write'." - (unless org-persist--index (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (setq container (org-persist--normalize-container container)) (setq associated (org-persist--normalize-associated associated)) (when inherit @@ -1035,7 +1031,9 @@ with `org-persist-write'." When ASSOCIATED is `all', unregister CONTAINER everywhere. When REMOVE-RELATED is non-nil, remove all the containers stored with the CONTAINER as well." - (unless org-persist--index (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (setq container (org-persist--normalize-container container)) (if (eq associated 'all) (mapc (lambda (collection) @@ -1072,7 +1070,9 @@ CONTAINER as well. For example: (org-persist-read \"My data\") ; => \"My data\" (org-persist-read \"My data\" nil nil nil :read-related t) ; => (\"My data\" \"test\")" - (unless org-persist--index (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (setq associated (org-persist--normalize-associated associated)) (setq container (org-persist--normalize-container container)) (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) @@ -1120,7 +1120,9 @@ have the same meaning as in `org-persist-read'." (defun org-persist-load-all (&optional associated) "Restore all the persistent data associated with ASSOCIATED." - (unless org-persist--index (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (setq associated (org-persist--normalize-associated associated)) (let (all-containers) (dolist (collection org-persist--index) @@ -1175,7 +1177,9 @@ When IGNORE-RETURN is non-nil, just return t on success without calling (defun org-persist-write-all (&optional associated) "Save all the persistent data. When ASSOCIATED is non-nil, only save the matching data." - (unless org-persist--index (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (setq associated (org-persist--normalize-associated associated)) (if (and (equal 1 (length org-persist--index)) @@ -1287,9 +1291,9 @@ Remove current sessions from `org-persist-gc-lock-file'." (defun org-persist-gc () "Remove expired or unregistered containers and orphaned files. Also, remove containers associated with non-existing files." - (if org-persist--index - (org-persist--merge-index-with-disk) - (org-persist--load-index)) + ;; Sync cache with disk, dropping conflicting items between multiple + ;; Emacsen. + (org-persist--merge-index-with-disk) (let (new-index (remote-files-num 0) (orphan-files