We use Clojure for a "rules engine". Each function represents a rule and metadata describes the rule and provides some static configuration for the rule itself. The system is immutable and concurrent.
If two or more Threads invoke the same Var concurrently they end up blocking each other because AReference#meta() is synchronized (see attached screenshot, the red dots).
(defn
^{:rule {:remote-address "127.0.0.1"}}
example
[request]
(let [rule (:rule (meta #'example))]
(= (:remote-address rule) (:remote-address request))))
*Approach:* Replace synchronized block with a rwlock for greater read concurrency. This approach removes meta read contention (see real world example in comments). However, it comes with the downsides of:
* extra field for every AReference (all namespaces, vars, atoms, refs, and agents)
* adds construction of lock into construction of AReference (affects perf and startup time)
*Patch:* clj-1888-2.patch replaces synchronized with a rwlock for greater read concurrency
*Alternatives:*
* Use volatile for _meta and synchronized for alter/reset. Allow read of _meta just under the volatile - would this be safe enough?
* Extend AReference from ReentrantReadWriteLock instead of holding one - this is pretty weird but would have a different (potentially better) footprint for memory/construction.