Module: RactorRailsShim::Patches::HashComputeIfAbsent::Overrides
- Defined in:
- lib/ractor_rails_shim/patches/hash_compute_if_absent.rb
Instance Method Summary collapse
-
#compute_if_absent(key) ⇒ Object
Semantics MUST match
Concurrent::Map#compute_if_absentexactly: - if the key is present (even with a nil value), return the stored value WITHOUT invoking the block; - otherwise invoke the block, STORE the result (including nil), and return it.
Instance Method Details
#compute_if_absent(key) ⇒ Object
Semantics MUST match Concurrent::Map#compute_if_absent exactly:
- if the key is present (even with a nil value), return the stored
value WITHOUT invoking the block;
- otherwise invoke the block, STORE the result (including nil), and
return it.
The nil-storing behaviour is load-bearing: Concurrent::Map stores
nil results so the block doesn't re-run; the original shim
implementation used IES[key] ||= yield in the frozen branch, which
SKIPS nil — a divergent semantics that re-invokes the block on every
lookup for any cache slot whose computed value is nil.
For a MUTABLE cache the shim freezes the replaced Hash (so it is shareable across workers); mutating it would raise FrozenError. So when the receiver is frozen we route the store to per-Ractor IES keyed by the Hash identity and the key — giving each worker its own cache entry without mutating the shared object. The frozen branch mirrors the mutable one: check presence first (via IES key?), invoke the block only on miss, store the result (including nil) via IES=.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/ractor_rails_shim/patches/hash_compute_if_absent.rb', line 48 def compute_if_absent(key) if frozen? # Check the receiver first — a present key (even nil-valued) # returns without invoking the block, matching Concurrent::Map. return self[key] if key?(key) # Per-Ractor IES slot, namespaced by this Hash's object_id so # two frozen hashes with the same key don't collide. Use a # two-level structure (Hash per receiver) so the presence check # (`key?`) and the store share the same slot. slot = RactorRailsShim.storage[:rrs_cia] ||= {} bucket = slot[object_id] ||= {} return bucket[key] if bucket.key?(key) bucket[key] = yield(key) elsif key?(key) self[key] else self[key] = yield(key) end end |