Browse Source

oc-basic: Speed up cached bibliography retrival

* lisp/oc-basic.el (org-cite-basic--file-id-cache): New variable
storing hash of bibliography file contents.
(org-cite-basic--parse-bibliography): Skip buffer hash calculation
when bibliography file is unchanged on disk.  Calculating buffer hash
on every call is slow when bibliography file is large.

* lisp/org-compat.el:
(org-file-has-changed-p--hash-table, org-file-has-changed-p): Define
`file-has-changed-p' from Emacs 29 if necessary.

See https://list.orgmode.org/LO2P265MB1758E12E04832DC712F5A8E9DC149@LO2P265MB1758.GBRP265.PROD.OUTLOOK.COM/T/#t
Ihor Radchenko 3 years ago
parent
commit
7ddc5b57c0
2 changed files with 38 additions and 2 deletions
  1. 9 2
      lisp/oc-basic.el
  2. 29 0
      lisp/org-compat.el

+ 9 - 2
lisp/oc-basic.el

@@ -233,6 +233,8 @@ Return a hash table with citation references as keys and fields alist as values.
                 entries)))
                 entries)))
     entries))
     entries))
 
 
+(defvar org-cite-basic--file-id-cache nil
+  "Hash table linking files to their hash.")
 (defun org-cite-basic--parse-bibliography (&optional info)
 (defun org-cite-basic--parse-bibliography (&optional info)
   "List all entries available in the buffer.
   "List all entries available in the buffer.
 
 
@@ -245,14 +247,19 @@ table where keys are references and values are association lists between fields,
 as symbols, and values as strings or nil.
 as symbols, and values as strings or nil.
 
 
 Optional argument INFO is the export state, as a property list."
 Optional argument INFO is the export state, as a property list."
+  (unless (hash-table-p org-cite-basic--file-id-cache)
+    (setq org-cite-basic--file-id-cache (make-hash-table :test #'equal)))
   (if (plist-member info :cite-basic/bibliography)
   (if (plist-member info :cite-basic/bibliography)
       (plist-get info :cite-basic/bibliography)
       (plist-get info :cite-basic/bibliography)
     (let ((results nil))
     (let ((results nil))
       (dolist (file (org-cite-list-bibliography-files))
       (dolist (file (org-cite-list-bibliography-files))
         (when (file-readable-p file)
         (when (file-readable-p file)
           (with-temp-buffer
           (with-temp-buffer
-            (insert-file-contents file)
-	    (let* ((file-id (cons file (org-buffer-hash)))
+            (when (or (org-file-has-changed-p file)
+                      (not (gethash file org-cite-basic--file-id-cache)))
+              (insert-file-contents file)
+              (puthash file (org-buffer-hash) org-cite-basic--file-id-cache))
+	    (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache)))
                    (entries
                    (entries
                     (or (cdr (assoc file-id org-cite-basic--bibliography-cache))
                     (or (cdr (assoc file-id org-cite-basic--bibliography-cache))
                         (let ((table
                         (let ((table

+ 29 - 0
lisp/org-compat.el

@@ -71,6 +71,35 @@
 (defvar org-table-tab-recognizes-table.el)
 (defvar org-table-tab-recognizes-table.el)
 (defvar org-table1-hline-regexp)
 (defvar org-table1-hline-regexp)
 
 
+
+;;; Emacs < 29 compatibility
+
+(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal)
+  "Internal variable used by `org-file-has-changed-p'.")
+
+(if (fboundp 'file-has-changed-p)
+    (defalias 'org-file-has-changed-p #'file-has-changed-p)
+  (defun org-file-has-changed-p (file &optional tag)
+    "Return non-nil if FILE has changed.
+The size and modification time of FILE are compared to the size
+and modification time of the same FILE during a previous
+invocation of `org-file-has-changed-p'.  Thus, the first invocation
+of `org-file-has-changed-p' always returns non-nil when FILE exists.
+The optional argument TAG, which must be a symbol, can be used to
+limit the comparison to invocations with identical tags; it can be
+the symbol of the calling function, for example."
+    (let* ((file (directory-file-name (expand-file-name file)))
+           (remote-file-name-inhibit-cache t)
+           (fileattr (file-attributes file 'integer))
+	   (attr (and fileattr
+                      (cons (file-attribute-size fileattr)
+		            (file-attribute-modification-time fileattr))))
+	   (sym (concat (symbol-name tag) "@" file))
+	   (cachedattr (gethash sym org-file-has-changed-p--hash-table)))
+      (when (not (equal attr cachedattr))
+        (puthash sym attr org-file-has-changed-p--hash-table)))))
+
+
 
 
 ;;; Emacs < 28.1 compatibility
 ;;; Emacs < 28.1 compatibility