Ihor Radchenko <yanta...@posteo.net> writes:

> I have addressed the poor performance of `file-truename' and
> `find-buffer-visiting' in 
> https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=b7a737ef49e
> That commit should be a part of Emacs 30.1 release, while you are on
> Emacs 30.0.50 pre-release. Try to upgrade your emacs.

That looks great! 

I upgrade my emacs today and redo the test, it indeed makes a great
speedup compare to before, see (1).

I then wrote a draft patch (attached below) to cache the entry position
to org-id-locations, which give a 10x speedup of org-id-find, see (2).

Though the pure hashtable way is still faster, but now, I think, it's
enough for me to use those new org-element-cache APIs.

Thanks for the pointer!


(1) Testing results before and after upgrade:

before upgrade

org-id-find        1000        6.4504779999  0.0064504779
org-entry-get      1000        0.0776989999  7.769...e-05
x/org-id-prop      1000        0.0090050000  9.005...e-06

after

org-id-find     1000        1.8941470000  0.0018941470
org-entry-get   1000        0.1785620000  0.0001785620
x/org-id-prop   1000        0.0136359999  1.363...e-05


(2) org-id-find+org-element-cache:

x/org-id-prop                9002        4.944075      0.0005492196
org-id-find                  9002        3.9981600000  0.0004441413
org-entry-get                9005        3.4076170000  0.0003784138
org-element-cache-get-key    9002        0.8524290000  9.469...e-05
org-element-cache-store-key  2           0.000152      7.6e-05


Environment:

Org mode version 9.8-pre (release_9.7.28-319-g24d155 @ 
~/.emacs.d/org-mode/lisp/)
GNU Emacs 31.0.50 (build 3, x86_64-w64-mingw32) of 2025-04-26


>From c4fed8529791f20e10c2119c6390bc6288c2a667 Mon Sep 17 00:00:00 2001
From: doerthous <doerth...@gmail.com>
Date: Sat, 26 Apr 2025 14:31:40 +0800
Subject: [PATCH] org-id: Cache entry position.

* org-id (org-id-find): cache entry position in org-id-locations.
---
 lisp/org-id.el | 47 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/lisp/org-id.el b/lisp/org-id.el
index 6ff63b295..4b3c159b3 100644
--- a/lisp/org-id.el
+++ b/lisp/org-id.el
@@ -396,15 +396,38 @@ With optional argument MARKERP, return the position as a new marker."
   (cond
    ((symbolp id) (setq id (symbol-name id)))
    ((numberp id) (setq id (number-to-string id))))
-  (let ((file (org-id-find-id-file id))
-	org-agenda-new-buffers where)
-    (when file
-      (setq where (org-id-find-id-in-file id file markerp)))
+  (let* ((loc (org-id--find-id-location id))
+         (file (if (consp loc) (car loc) loc))
+         (pos (if (consp loc) (cdr loc)))
+	 org-agenda-new-buffers where buf)
+    (cond
+     ;; When loc is a cons cell, check whether it's valid or not.
+     ((consp loc)
+      (setq buf (or (find-buffer-visiting file)
+                    (find-file-noselect file)))
+      (with-current-buffer buf
+        (when (equal (org-entry-get pos "ID") id)
+          ;; Make sure we're looking at entry's heading.
+          (org-with-wide-buffer
+           (goto-char pos)
+           (unless (org-at-heading-p)
+             (setq pos (org-back-to-heading-or-point-min) (point))))
+          (setq where (if markerp
+                          (move-marker (make-marker) pos buf)
+                        (cons file pos))))))
+     ((stringp file)
+      (setq where (org-id-find-id-in-file id file markerp))))
+
     (unless where
       (org-id-update-id-locations nil t)
       (setq file (org-id-find-id-file id))
       (when file
 	(setq where (org-id-find-id-in-file id file markerp))))
+
+    ;; Update id location cache.
+    (when (and where (or (not (consp loc)) (not (= (cdr loc) pos))))
+      (setq loc (if markerp (cons file (marker-position where)) where))
+      (puthash id loc org-id-locations))
     where))
 
 ;;; Internal functions
@@ -660,9 +683,12 @@ If SILENT is non-nil, messages are suppressed."
 (defun org-id-hash-to-alist (hash)
   "Turn an org-id HASH into an alist.
 This is to be able to write it to a file."
+  ;; org-id-locations: hash, ID -> file or ID -> (file-name . point)
+  ;; .org-id-locations: alist, file-name -> IDs
   (let (res x)
     (maphash
      (lambda (k v)
+       (unless (stringp v) (setq v (car v)))
        (if (setq x (assoc v res))
 	   (setcdr x (cons k (cdr x)))
 	 (push (list v k) res)))
@@ -700,9 +726,10 @@ This is to be able to write it to a file."
 
 ;; Finding entries with specified id
 
-;;;###autoload
-(defun org-id-find-id-file (id)
-  "Query the id database for the file in which ID is located."
+(defun org-id--find-id-location (id)
+  "Query the id database for the location in which ID is located.
+
+Return a filename or cons cell (file-name . position)."
   (unless org-id-locations (org-id-locations-load))
   (or (and org-id-locations
 	   (hash-table-p org-id-locations)
@@ -712,6 +739,12 @@ This is to be able to write it to a file."
         (buffer-file-name (or (buffer-base-buffer (current-buffer))
 			      (current-buffer))))))
 
+;;;###autoload
+(defun org-id-find-id-file (id)
+  "Query the id database for the file in which ID is located."
+  (let ((loc (org-id--find-id-location id)))
+    (if (stringp loc) loc (car loc))))
+
 (defun org-id-find-id-in-file (id file &optional markerp)
   "Return the position of the entry ID in FILE.
 
-- 
2.44.0.windows.1

Reply via email to