mirror of
https://github.com/taoensso/telemere.git
synced 2025-12-16 17:41:12 +00:00
[nop] Micro-optimize binding conveyance
Avoid repeatedly capturing the same callsite binding frame for each registered handler. While the perf benefit of this change is minimal, the approach is also conceptually cleaner.
This commit is contained in:
parent
8066776a80
commit
b4b06f324b
3 changed files with 35 additions and 19 deletions
|
|
@ -43,7 +43,10 @@
|
|||
{:sf-arity 4
|
||||
:ct-sig-filter impl/ct-sig-filter
|
||||
:*rt-sig-filter* impl/*rt-sig-filter*
|
||||
:*sig-handlers* impl/*sig-handlers*})
|
||||
:*sig-handlers* impl/*sig-handlers*
|
||||
:lib-dispatch-opts
|
||||
(assoc sigs/default-handler-dispatch-opts
|
||||
:convey-bindings? false)})
|
||||
|
||||
;;;; Aliases
|
||||
|
||||
|
|
|
|||
|
|
@ -279,8 +279,10 @@
|
|||
|
||||
;;;; Handlers
|
||||
|
||||
(enc/defonce ^:dynamic *sig-spy* "To support `with-signals`, etc." nil)
|
||||
(enc/defonce ^:dynamic *sig-handlers* "?[<wrapped-handler-fn>]" nil)
|
||||
(enc/defonce ^:dynamic *sig-handlers* "?[<wrapped-handler-fn>]" nil)
|
||||
|
||||
(defrecord SpyOpts [vol_ last-only? trap?])
|
||||
(def ^:dynamic *sig-spy* "?SpyOpts" nil)
|
||||
|
||||
(defn force-msg-in-sig [sig]
|
||||
(if-not (map? sig)
|
||||
|
|
@ -309,7 +311,7 @@
|
|||
([ trap-signals? form] `(with-signal false ~trap-signals? ~form))
|
||||
([raw-msg? trap-signals? form]
|
||||
`(let [sig_# (volatile! nil)]
|
||||
(binding [*sig-spy* [sig_# :last-only ~trap-signals?]]
|
||||
(binding [*sig-spy* (SpyOpts. sig_# true ~trap-signals?)]
|
||||
(enc/try* ~form (catch :all _#)))
|
||||
|
||||
(if ~raw-msg?
|
||||
|
|
@ -326,7 +328,7 @@
|
|||
([raw-msgs? trap-signals? form]
|
||||
`(let [sigs_# (volatile! nil)
|
||||
form-result#
|
||||
(binding [*sig-spy* [sigs_# (not :last-only) ~trap-signals?]]
|
||||
(binding [*sig-spy* (SpyOpts. sigs_# false ~trap-signals?)]
|
||||
(enc/try*
|
||||
(do [~form nil])
|
||||
(catch :all t# [nil t#])))
|
||||
|
|
@ -338,16 +340,23 @@
|
|||
|
||||
[form-result# (not-empty sigs#)]))))
|
||||
|
||||
#?(:clj (def ^:dynamic *sig-spy-off-thread?* false))
|
||||
(defn dispatch-signal!
|
||||
"Dispatches given signal to registered handlers, supports `with-signal/s`."
|
||||
[signal]
|
||||
(or
|
||||
(when-let [[v_ last-only? trap-signals?] *sig-spy*]
|
||||
(let [sv (sigs/signal-value signal nil)]
|
||||
(when-let [{:keys [vol_ last-only? trap?]} *sig-spy*]
|
||||
(let [sv
|
||||
#?(:cljs (sigs/signal-value signal nil)
|
||||
:clj
|
||||
(if *sig-spy-off-thread?* ; Simulate async handler
|
||||
(deref (enc/promised :user (sigs/signal-value signal nil)))
|
||||
(do (sigs/signal-value signal nil))))]
|
||||
|
||||
(if last-only?
|
||||
(vreset! v_ sv)
|
||||
(vswap! v_ #(conj (or % []) sv))))
|
||||
(when trap-signals? :stop))
|
||||
(vreset! vol_ sv)
|
||||
(vswap! vol_ #(conj (or % []) sv))))
|
||||
(when trap? :stop))
|
||||
|
||||
(sigs/call-handlers! *sig-handlers* signal)))
|
||||
|
||||
|
|
@ -639,9 +648,9 @@
|
|||
`(let [signal# ~record-form]
|
||||
(reduce-kv assoc signal# (.-kvs signal#)))))]
|
||||
|
||||
`(delay
|
||||
;; Delay (cache) shared by all handlers. Covers signal `:let` eval, signal construction,
|
||||
;; middleware (possibly expensive), etc. Throws here will be caught by handler.
|
||||
`(enc/bound-delay
|
||||
;; Delay (cache) shared by all handlers, incl. `:let` eval,
|
||||
;; signal construction, middleware, etc. Throws caught by handler.
|
||||
~do-form
|
||||
(let [~@let-form ; Allow to throw, eval BEFORE data, msg, etc.
|
||||
signal# ~signal-form]
|
||||
|
|
@ -721,7 +730,7 @@
|
|||
~@into-let-form ; Inject conditional bindings
|
||||
signal# ~signal-delay-form]
|
||||
|
||||
(dispatch-signal! ; Runner preserves dynamic bindings when async.
|
||||
(dispatch-signal!
|
||||
;; Unconditionally send same wrapped signal to all handlers.
|
||||
;; Each handler will use wrapper for handler filtering,
|
||||
;; unwrapping (realizing) only allowed signals.
|
||||
|
|
|
|||
|
|
@ -228,12 +228,16 @@
|
|||
(is (= rv6 13)) (is (= (force (get sv6 dk)) [:n 12, :c6 15]))
|
||||
(is (= @c 16) "6x run + 6x let (0x suppressed) + 4x data (2x suppressed)")]))))
|
||||
|
||||
(testing "Binding conveyance"
|
||||
(binding [*dynamic-var* :foo]
|
||||
(is (sm? (with-sig (sig! {:level :info, :data {:dynamic-var *dynamic-var*}})) {:data {:dynamic-var :foo}}))))
|
||||
(testing "Dynamic bindings, etc."
|
||||
[(binding[#?@(:clj [impl/*sig-spy-off-thread?* true])
|
||||
*dynamic-var* "foo"
|
||||
tel/*ctx* "bar"]
|
||||
(let [sv (with-sig (sig! {:level :info, :data {:*dynamic-var* *dynamic-var*, :*ctx* tel/*ctx*}}))]
|
||||
(is (sm? sv {:data {:*dynamic-var* "foo", :*ctx* "bar"}})
|
||||
"Retain dynamic bindings in place at time of signal call")))
|
||||
|
||||
(testing "Dynamic context (`*ctx*`)"
|
||||
(let [sv (with-sig (sig! {:level :info, :ctx "my-ctx"}))] (is (sm? sv {:ctx "my-ctx"}) "Can be set via call opt")))
|
||||
(let [sv (with-sig (sig! {:level :info, :ctx "my-ctx"}))]
|
||||
(is (sm? sv {:ctx "my-ctx"}) "`*ctx*` can be overridden via call opt"))])
|
||||
|
||||
(testing "Dynamic middleware (`*middleware*`)"
|
||||
[(is (sm? (tel/with-middleware nil (with-sig (sig! {:level :info }))) {:level :info }) "nil middleware ~ identity")
|
||||
|
|
|
|||
Loading…
Reference in a new issue