perf(rpc): O(1) notification queue via head/tail cell (P2)
ober
f3934ab4215c9163e91566d606f2da021afaa08b
--- a/signal/rpc.ss +++ b/signal/rpc.ss @@ -38,7 +38,9 @@ ;; proc : process-port-rec from (std misc process) ;; next-id-box : box holding the next JSON-RPC request id ;; pending : reserved for future async correlation - ;; notif-box : box holding FIFO queue of pending notifications + ;; notif-box : box holding a FIFO queue cell (#f when empty, else a + ;; (head . tail) pair of the first/last cons cells) so enqueue + ;; and dequeue are both O(1) under a notification burst. (defstruct signal-cli (proc next-id-box pending notif-box)) (def (spawn-signal-cli account) @@ -54,7 +56,7 @@ (trace-event! "spawn" (join-command cmd)) (trace-event! "pid" (number->string (process-port-pid proc))) (fork-thread (lambda () (drain-stderr-to-current-error-port proc))) - (make-signal-cli proc (box 1) (make-hashtable equal-hash equal?) (box '())))) + (make-signal-cli proc (box 1) (make-hashtable equal-hash equal?) (box #f)))) (def (signal-cli-pid sc) (process-port-pid (signal-cli-proc sc))) @@ -153,8 +155,11 @@ (def (enqueue-notification! sc msg) (let* ([b (signal-cli-notif-box sc)] - [cur (unbox b)]) - (set-box! b (append cur (list msg))))) + [q (unbox b)] + [cell (cons msg '())]) + (set-box! b (if q + (begin (set-cdr! (cdr q) cell) (cons (car q) cell)) + (cons cell cell))))) (def (rpc-call sc method params) (let* ([id (next-id! sc)] @@ -183,9 +188,12 @@ (let* ([b (signal-cli-notif-box sc)] [q (unbox b)]) (cond - [(pair? q) - (set-box! b (cdr q)) - (car q)] + [q + (let* ([head (car q)] + [msg (car head)] + [rest (cdr head)]) + (set-box! b (and (pair? rest) (cons rest (cdr q)))) + msg)] [else (let ([msg (read-frame sc)]) (cond @@ -198,8 +206,8 @@ (def (drain-notifications sc) (let* ([b (signal-cli-notif-box sc)] [q (unbox b)]) - (set-box! b '()) - q)) + (set-box! b #f) + (if q (car q) '()))) (def (join-command xs) (cond