branch: elpa/hyperdrive
commit e2ddaa770c863245cfb0157e5264c81a0eada36a
Author: Joseph Turner <jos...@ushin.org>
Commit: Joseph Turner <jos...@ushin.org>

    Change: (hyperdrive-fill-version-ranges) Only recurse from ENTRY
    
    Previously, this function recursed backward from all unknown ranges in
    the version ranges for ENTRY.  Now, it only recurses backward from
    ENTRY's version.
---
 hyperdrive-lib.el  | 166 ++++++++++++++++++++++++++++++++---------------------
 hyperdrive-vars.el |   5 ++
 2 files changed, 104 insertions(+), 67 deletions(-)

diff --git a/hyperdrive-lib.el b/hyperdrive-lib.el
index 62edca6ec7..de2991428f 100644
--- a/hyperdrive-lib.el
+++ b/hyperdrive-lib.el
@@ -730,74 +730,106 @@ Returns the ranges cons cell for ENTRY."
       (setf (map-elt ranges range-start) `(:existsp nil :range-end ,range-end)
             (hyperdrive-entry-version-ranges entry) (cl-sort ranges #'< :key 
#'car)))))
 
-(cl-defun hyperdrive-fill-version-ranges (entry &key then)
-  "Asynchronously fill in versions ranges for ENTRY and call THEN.
-First fill latest version of ENTRY's hyperdrive.  Then recurse
-backward through some unknown ranges and fill them.  Once all
-requests return, call THEN with no arguments."
-  ;; TODO: Limit the number of recursive calls made.
+;; (cl-defun hyperdrive-fill-version-ranges (entry &key then)
+;;   "Asynchronously fill in versions ranges for ENTRY and call THEN.
+;; First fill latest version of ENTRY's hyperdrive.  Then recurse
+;; backward through some unknown ranges and fill them.  Once all
+;; requests return, call THEN with no arguments."
+;;   ;; TODO: Limit the number of recursive calls made.
+;;   (declare (indent defun))
+;;   ;; Filling drive's latest version lets us display the full history,
+;;   ;; and it ensures that the final range is not unknown.
+;;   (hyperdrive-fill-latest-version (hyperdrive-entry-hyperdrive entry))
+;;   (let* ((ranges-no-gaps (hyperdrive-entry-version-ranges-no-gaps entry))
+;;          (ranges-to-fill
+;;           (cl-delete-if-not
+;;            ;; Select certain unknown ranges to be filled. Unknown
+;;            ;; ranges are filled by requesting the version at its
+;;            ;; range-end. The entry at the range-end of an unknown
+;;            ;; ranges which is followed by a nonexistent entry is
+;;            ;; likely to also be nonexistent. By only attempting to
+;;            ;; fill unknown ranges which are either followed by a
+;;            ;; existent range or are themselves the final range, we
+;;            ;; minimize the number of unnecessary requests.
+;;            (pcase-lambda (`(,_range-start . ,(map (:existsp existsp) 
(:range-end range-end))))
+;;              (and (eq 'unknown existsp)
+;;                   (if-let ((next-range (map-elt ranges-no-gaps (1+ 
range-end))))
+;;                       ;; If next range exists, fill it.
+;;                       (eq t (map-elt next-range :existsp))
+;;                     ;; This is the final range: fill it.
+;;                     t)))
+;;            ranges-no-gaps))
+;;          queue)
+;;     (if ranges-to-fill
+;;         (progn
+;;           ;; TODO: When `plz' lets us handle errors in the queue finalizer, 
add that here.
+;;           (setf queue (make-plz-queue :limit hyperdrive-queue-size :finally 
then))
+;;           (cl-labels ((fill-recursively (unknown-entry)
+;;                         ;; NOTE: `fill-recursively' is recursive logically 
but
+;;                         ;; not technically, because each call is in the 
async callback.
+;;                         ;; Fill entry at its version, then if its previous
+;;                         ;; version is unknown, recurse on previous version.
+;;                         (hyperdrive-fill unknown-entry
+;;                           ;; `hyperdrive-fill' is only used here for 
updating
+;;                           ;; `hyperdrive-version-ranges'. The copied entry 
is thrown away.
+;;                           :then (lambda (filled-entry)
+;;                                   ;; Don't use `hyperdrive-entry-previous' 
here, since it makes a sync request
+;;                                   (pcase-let ((`(,range-start . ,_plist) 
(hyperdrive-entry-version-range filled-entry)))
+;;                                     (setf (hyperdrive-entry-version 
filled-entry) (1- range-start))
+;;                                     (when (eq 'unknown 
(hyperdrive-entry-exists-p filled-entry))
+;;                                       ;; Recurse backward through history, 
filling unknown
+;;                                       ;; entries. Stop recursing at known 
nonexistent entry.
+;;                                       (fill-recursively filled-entry))))
+;;                           :else (lambda (err)
+;;                                   (pcase (plz-response-status 
(plz-error-response err))
+;;                                     ;; FIXME: If plz-error is a curl-error, 
this block will fail.
+;;                                     ;; TODO: How to handle entries which 
have never been known
+;;                                     ;; existent. From a UI perspective, the 
history buffer
+;;                                     ;; should display the versions at which 
the entry is known
+;;                                     ;; non-existent. However, we don't want 
to store loads of
+;;                                     ;; non-existent entries in 
`hyperdrive-version-ranges'.
+;;                                     (404 nil)
+;;                                     (_ (signal (car err) (cdr err))))
+;;                                   err)
+;;                           :queue queue)))
+;;             (pcase-dolist (`(,_range-start . ,(map (:range-end range-end))) 
ranges-to-fill)
+;;               ;; TODO: Consider using async iterator instead (with 
`iter-defun' or `aio'?)
+;;               (let ((range-end-entry (hyperdrive-copy-tree entry t)))
+;;                 (setf (hyperdrive-entry-version range-end-entry) range-end)
+;;                 (fill-recursively range-end-entry)))))
+;;       (funcall then))))
+
+(cl-defun hyperdrive-fill-version-ranges
+    (entry &key (limit hyperdrive-fill-version-ranges-limit) finally queue)
+  "Asynchronously fill in versions ranges for ENTRY.
+Recurse backward from ENTRY's version, filling unknown entries no
+more than LIMIT times.  Once all requests return, call FINALLY
+with no arguments.
+
+The QUEUE argument is used in recursive calls."
+  ;; NOTE: `hyperdrive-fill-version-ranges' is recursive logically but not
+  ;; technically, because each call is in the async callback.
   (declare (indent defun))
-  ;; Filling drive's latest version lets us display the full history,
-  ;; and it ensures that the final range is not unknown.
-  (hyperdrive-fill-latest-version (hyperdrive-entry-hyperdrive entry))
-  (let* ((ranges-no-gaps (hyperdrive-entry-version-ranges-no-gaps entry))
-         (ranges-to-fill
-          (cl-delete-if-not
-           ;; Select certain unknown ranges to be filled. Unknown
-           ;; ranges are filled by requesting the version at its
-           ;; range-end. The entry at the range-end of an unknown
-           ;; ranges which is followed by a nonexistent entry is
-           ;; likely to also be nonexistent. By only attempting to
-           ;; fill unknown ranges which are either followed by a
-           ;; existent range or are themselves the final range, we
-           ;; minimize the number of unnecessary requests.
-           (pcase-lambda (`(,_range-start . ,(map (:existsp existsp) 
(:range-end range-end))))
-             (and (eq 'unknown existsp)
-                  (if-let ((next-range (map-elt ranges-no-gaps (1+ 
range-end))))
-                      ;; If next range exists, fill it.
-                      (eq t (map-elt next-range :existsp))
-                    ;; This is the final range: fill it.
-                    t)))
-           ranges-no-gaps))
-         queue)
-    (if ranges-to-fill
-        (progn
-          ;; TODO: When `plz' lets us handle errors in the queue finalizer, 
add that here.
-          (setf queue (make-plz-queue :limit hyperdrive-queue-size :finally 
then))
-          (cl-labels ((fill-recursively (unknown-entry)
-                        ;; NOTE: `fill-recursively' is recursive logically but
-                        ;; not technically, because each call is in the async 
callback.
-                        ;; Fill entry at its version, then if its previous
-                        ;; version is unknown, recurse on previous version.
-                        (hyperdrive-fill unknown-entry
-                          ;; `hyperdrive-fill' is only used here for updating
-                          ;; `hyperdrive-version-ranges'. The copied entry is 
thrown away.
-                          :then (lambda (filled-entry)
-                                  ;; Don't use `hyperdrive-entry-previous' 
here, since it makes a sync request
-                                  (pcase-let ((`(,range-start . ,_plist) 
(hyperdrive-entry-version-range filled-entry)))
-                                    (setf (hyperdrive-entry-version 
filled-entry) (1- range-start))
-                                    (when (eq 'unknown 
(hyperdrive-entry-exists-p filled-entry))
-                                      ;; Recurse backward through history, 
filling unknown
-                                      ;; entries. Stop recursing at known 
nonexistent entry.
-                                      (fill-recursively filled-entry))))
-                          :else (lambda (err)
-                                  (pcase (plz-response-status 
(plz-error-response err))
-                                    ;; FIXME: If plz-error is a curl-error, 
this block will fail.
-                                    ;; TODO: How to handle entries which have 
never been known
-                                    ;; existent. From a UI perspective, the 
history buffer
-                                    ;; should display the versions at which 
the entry is known
-                                    ;; non-existent. However, we don't want to 
store loads of
-                                    ;; non-existent entries in 
`hyperdrive-version-ranges'.
-                                    (404 nil)
-                                    (_ (signal (car err) (cdr err))))
-                                  err)
-                          :queue queue)))
-            (pcase-dolist (`(,_range-start . ,(map (:range-end range-end))) 
ranges-to-fill)
-              ;; TODO: Consider using async iterator instead (with 
`iter-defun' or `aio'?)
-              (let ((range-end-entry (hyperdrive-copy-tree entry t)))
-                (setf (hyperdrive-entry-version range-end-entry) range-end)
-                (fill-recursively range-end-entry)))))
-      (funcall then))))
+  (unless queue
+    (setf queue (make-plz-queue :limit hyperdrive-queue-size
+                                :finally (when finally finally))))
+  (hyperdrive-fill (hyperdrive-copy-tree entry t)
+    :then (lambda (filled-entry)
+            (when (cl-plusp limit)
+              ;; Don't use `hyperdrive-entry-previous' here, since it makes a 
sync request
+              (pcase-let ((`(,range-start . ,_plist) 
(hyperdrive-entry-version-range filled-entry)))
+                (setf (hyperdrive-entry-version filled-entry) (1- range-start))
+                (when (eq 'unknown (hyperdrive-entry-exists-p filled-entry))
+                  ;; Recurse backward through history, filling unknown entries.
+                  ;; Stop recursing at known nonexistent entry or at the limit.
+                  (hyperdrive-fill-version-ranges filled-entry
+                    :limit (1- limit) :finally finally :queue queue)))))
+    :else (lambda (err)
+            (pcase (plz-response-status (plz-error-response err))
+              ;; FIXME: If plz-error is a curl-error, this block will fail.
+              (404 nil) ;; The loop stops if entry is not found, but don't 
error
+              (_ (signal (car err) (cdr err)))))
+    :queue queue))
 
 (defun hyperdrive-fill-metadata (hyperdrive)
   "Fill HYPERDRIVE's public metadata and return it.
diff --git a/hyperdrive-vars.el b/hyperdrive-vars.el
index f1541117c6..cec7a5cfae 100644
--- a/hyperdrive-vars.el
+++ b/hyperdrive-vars.el
@@ -151,6 +151,11 @@ through a shell)."
   ;; TODO: Consider a separate option for upload queue size, etc.
   :type 'natnum)
 
+(defcustom hyperdrive-fill-version-ranges-limit 10
+  ;; TODO(doc) Document `hyperdrive-fill-version-ranges-limit'.
+  "Default maximum number of requests when filling version history."
+  :type 'natnum)
+
 (defcustom hyperdrive-render-html t
   "Render HTML hyperdrive files with EWW."
   :type 'boolean)

Reply via email to