|
71 | 71 | (require 'seq) |
72 | 72 | (require 'subr-x) |
73 | 73 | (require 'cl-lib) |
| 74 | +(require 'queue) |
74 | 75 | (require 'nrepl-dict) |
75 | 76 | (require 'nrepl-bencode) |
76 | 77 | (require 'tramp) |
@@ -110,6 +111,24 @@ Setting this to nil disables the timeout functionality." |
110 | 111 | When true some special buffers like the server buffer will be hidden." |
111 | 112 | :type 'boolean) |
112 | 113 |
|
| 114 | +(defcustom nrepl-completed-requests-max-size 1000 |
| 115 | + "Maximum number of completed-request handlers retained per connection. |
| 116 | +
|
| 117 | +nREPL servers occasionally send late messages for requests whose |
| 118 | +\"done\" status has already arrived (typically a sub-second window). |
| 119 | +We keep the recently-completed handlers around so those messages still |
| 120 | +get dispatched. Without a bound, the table grew unbounded for the |
| 121 | +lifetime of the connection. |
| 122 | +
|
| 123 | +Eviction is FIFO: when the table is full, the oldest entry is dropped |
| 124 | +to make room for the newest. 1000 is ample in practice -- requests |
| 125 | +complete in milliseconds, so this caps roughly a second of activity. |
| 126 | +Set to 0 to disable the cache entirely; late messages will then become |
| 127 | +log warnings." |
| 128 | + :type 'integer |
| 129 | + :safe #'integerp |
| 130 | + :package-version '(cider . "1.22.0")) |
| 131 | + |
113 | 132 | ;;; Buffer Local Declarations |
114 | 133 |
|
115 | 134 | ;; These variables are used to track the state of nREPL connections |
@@ -138,6 +157,10 @@ To be used for tooling calls (i.e. completion, eldoc, etc)") |
138 | 157 |
|
139 | 158 | (defvar-local nrepl-completed-requests nil) |
140 | 159 |
|
| 160 | +(defvar-local nrepl--completed-requests-order nil |
| 161 | + "FIFO of ids in `nrepl-completed-requests', used for bounded eviction. |
| 162 | +See `nrepl-completed-requests-max-size'.") |
| 163 | + |
141 | 164 | (defvar-local nrepl-last-sync-response nil |
142 | 165 | "Result of the last sync request.") |
143 | 166 |
|
@@ -583,7 +606,8 @@ client buffer. Return the newly created client process." |
583 | 606 | nrepl-tunnel-buffer (when-let* ((tunnel (plist-get endpoint :tunnel))) |
584 | 607 | (process-buffer tunnel)) |
585 | 608 | nrepl-pending-requests (make-hash-table :test 'equal) |
586 | | - nrepl-completed-requests (make-hash-table :test 'equal))) |
| 609 | + nrepl-completed-requests (make-hash-table :test 'equal) |
| 610 | + nrepl--completed-requests-order (queue-create))) |
587 | 611 |
|
588 | 612 | (with-current-buffer client-buf |
589 | 613 | (nrepl--init-client-sessions client-proc) |
@@ -658,12 +682,22 @@ Used by the client to clean up session state on disconnect.") |
658 | 682 |
|
659 | 683 | (defun nrepl--mark-id-completed (id) |
660 | 684 | "Move ID from `nrepl-pending-requests' to `nrepl-completed-requests'. |
661 | | -It is safe to call this function multiple times on the same ID." |
662 | | - ;; FIXME: This should go away eventually when we get rid of |
663 | | - ;; pending-request hash table |
| 685 | +The completed table is bounded by `nrepl-completed-requests-max-size'; |
| 686 | +when the cap is reached the oldest entry is evicted FIFO. |
| 687 | +
|
| 688 | +It is safe to call this function multiple times on the same ID -- the |
| 689 | +second call is a no-op because the entry has already been moved out of |
| 690 | +`nrepl-pending-requests'." |
664 | 691 | (when-let* ((handler (gethash id nrepl-pending-requests))) |
665 | 692 | (puthash id handler nrepl-completed-requests) |
666 | | - (remhash id nrepl-pending-requests))) |
| 693 | + (remhash id nrepl-pending-requests) |
| 694 | + (when nrepl--completed-requests-order |
| 695 | + (queue-enqueue nrepl--completed-requests-order id) |
| 696 | + (when (and (> nrepl-completed-requests-max-size 0) |
| 697 | + (> (queue-length nrepl--completed-requests-order) |
| 698 | + nrepl-completed-requests-max-size)) |
| 699 | + (remhash (queue-dequeue nrepl--completed-requests-order) |
| 700 | + nrepl-completed-requests))))) |
667 | 701 |
|
668 | 702 | (defun nrepl-notify (msg type) |
669 | 703 | "Handle a server notification with MSG and TYPE. |
|
0 commit comments