emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: when does :cache not cache?


From: Ihor Radchenko
Subject: Re: when does :cache not cache?
Date: Sun, 12 Dec 2021 15:45:50 +0800

Eric S Fraga <e.fraga@ucl.ac.uk> writes:

> in the paper I am writing, I have a number of gnuplot src blocks, some
> of which process a significant amount of data so take some time to
> generate the actual plots.  The data are static so caching the results
> make sense.  However, even though I have ":cache yes" on each of these
> named src blocks, and I have (for good measure), the property
> "header-args:gnuplot" set to ":cache yes" as well, the plots are being
> regenerated each time I export to PDF via LaTeX.

I was able to reproduce. The reason why caching does not work is related
to the way :var assignments work in ob-gnuplot. We dump the table data
into temporary files and refer to those files in generated gnuplot
script body. The temporary files names change on every execution and the
gnuplot script hash is never going to be the same.

I am attaching tentative patch to fix the issue.
The patch introduces a new functionality to ob-core.el allowing more
stable temporary file names. I am not sure if my implementation is the
best way to solve the problem, so comments are welcome.

Best,
Ihor

>From ac11b4d08edd577b29a398296364b4340096a6ae Mon Sep 17 00:00:00 2001
Message-Id: 
<ac11b4d08edd577b29a398296364b4340096a6ae.1639294626.git.yantar92@gmail.com>
From: Ihor Radchenko <yantar92@gmail.com>
Date: Sun, 12 Dec 2021 15:31:35 +0800
Subject: [PATCH] ob-gnuplot.el: Make :cache argument work with :var
 assignments

* lisp/ob-core.el (org-babel-temporary-stable-directory): New variable
holding a temporary directory name that does not change between Emacs
sessions.
(org-babel-remove-temporary-stable-directory): New function removing
`org-babel-temporary-stable-directory' on Emacs shutdown.
(org-babel-temp-stable-file): Generate stable temporary file name for
object storage.  The file name is constant with for equal objects.
(org-babel-execute-src-block): Explicitly identify that if the result
is cached.
* lisp/ob-gnuplot.el (org-babel-gnuplot-process-vars): Make use of
`org-babel-stable-file' to make expanded body stable with respect to
:var assignments.

Fixes https://orgmode.org/list/87mtn1o5mn.fsf@ucl.ac.uk
---
 lisp/ob-core.el    | 52 +++++++++++++++++++++++++++++++++++++++++++++-
 lisp/ob-gnuplot.el |  5 ++++-
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 7a9467b0e..d572423b7 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -735,7 +735,8 @@ (defun org-babel-execute-src-block (&optional arg info 
params)
            (forward-line)
            (skip-chars-forward " \t")
            (let ((result (org-babel-read-result)))
-             (message (replace-regexp-in-string "%" "%%" (format "%S" result)))
+             (message (format "Cached: %s"
+                               (replace-regexp-in-string "%" "%%" (format "%S" 
result))))
              result)))
         ((org-babel-confirm-evaluate info)
          (let* ((lang (nth 0 info))
@@ -3112,6 +3113,22 @@   (defvar org-babel-temporary-directory
 Used by `org-babel-temp-file'.  This directory will be removed on
 Emacs shutdown."))
 
+(defvar org-babel-temporary-stable-directory)
+(unless (or noninteractive (boundp 'org-babel-temporary-stable-directory))
+  (defvar org-babel-temporary-stable-directory
+    (or (and (boundp 'org-babel-temporary-stable-directory)
+            (file-exists-p org-babel-temporary-stable-directory)
+            org-babel-temporary-stable-directory)
+        (condition-case nil
+            (make-directory
+            (expand-file-name
+              "babel-stable"
+              (temporary-file-directory)))
+          (t nil)))
+    "Directory to hold temporary files created to execute code blocks.
+Used by `org-babel-temp-file'.  This directory will be removed on
+Emacs shutdown."))
+
 (defcustom org-babel-remote-temporary-directory "/tmp/"
   "Directory to hold temporary files on remote hosts."
   :group 'org-babel
@@ -3155,6 +3172,30 @@ (defun org-babel-temp-file (prefix &optional suffix)
               temporary-file-directory)))
       (make-temp-file prefix nil suffix))))
 
+(defun org-babel-temp-stable-file (data prefix &optional suffix)
+  "Create a temporary file in the 
`org-babel-remove-temporary-stable-directory'.
+The file name is stable with respect to DATA.  The file name is
+constructed like the following: PREFIXDATAhashSUFFIX."
+  (if (file-remote-p default-directory)
+      (let* ((prefix
+              (concat (file-remote-p default-directory)
+                      (expand-file-name
+                      prefix org-babel-temporary-stable-directory)))
+             (path (concat prefix (format "%s" (sxhash data)) (or suffix ""))))
+        (with-temp-file path)
+        path)
+    (let* ((temporary-file-directory
+           (or (and (boundp 'org-babel-temporary-stable-directory)
+                    (file-exists-p org-babel-temporary-stable-directory)
+                    org-babel-temporary-stable-directory)
+               temporary-file-directory))
+           (path (concat
+                  (expand-file-name
+                  prefix org-babel-temporary-stable-directory)
+                  (format "%s" (sxhash data)) (or suffix ""))))
+      (with-temp-file path)
+      path)))
+
 (defun org-babel-remove-temporary-directory ()
   "Remove `org-babel-temporary-directory' on Emacs shutdown."
   (when (and (boundp 'org-babel-temporary-directory)
@@ -3178,7 +3219,16 @@ (defun org-babel-remove-temporary-directory ()
                    org-babel-temporary-directory
                  "[directory not defined]"))))))
 
+(defun org-babel-remove-temporary-stable-directory ()
+  "Remove `org-babel-temporary-stable-directory' and on Emacs shutdown."
+  (when (and (boundp 'org-babel-temporary-stable-directory)
+            (file-exists-p org-babel-temporary-stable-directory))
+    (let ((org-babel-temporary-directory
+           org-babel-temporary-stable-directory))
+      (org-babel-remove-temporary-directory))))
+
 (add-hook 'kill-emacs-hook #'org-babel-remove-temporary-directory)
+(add-hook 'kill-emacs-hook #'org-babel-remove-temporary-stable-directory)
 
 (defun org-babel-one-header-arg-safe-p (pair safe-list)
   "Determine if the PAIR is a safe babel header arg according to SAFE-LIST.
diff --git a/lisp/ob-gnuplot.el b/lisp/ob-gnuplot.el
index 8c4a5957b..f831b4996 100644
--- a/lisp/ob-gnuplot.el
+++ b/lisp/ob-gnuplot.el
@@ -94,7 +94,10 @@ (defun org-babel-gnuplot-process-vars (params)
               (let* ((first  (car val))
                      (tablep (or (listp first) (symbolp first))))
                 (if tablep val (mapcar 'list val)))
-              (org-babel-temp-file "gnuplot-") params)
+               ;; Make temporary file name stable with respect to data.
+               ;; If we do not do it, :cache argument becomes useless.
+               (org-babel-temp-stable-file params "gnuplot-")
+               params)
            (if (and (stringp val)
                     (file-remote-p val)  ;; check if val is a remote file
                     (file-exists-p val)) ;; call to file-exists-p is slow, 
maybe remove it
-- 
2.32.0


reply via email to

[Prev in Thread] Current Thread [Next in Thread]