Class: CMDx::Stores::Memory
- Inherits:
-
Object
- Object
- CMDx::Stores::Memory
- Defined in:
- lib/cmdx/stores/memory.rb
Overview
Process-local key/value store with optional per-key TTL. Thread-safe via an internal mutex. Suitable for tests and single-process dev; not shared across workers.
Instance Method Summary collapse
-
#decr(key, ttl: nil) ⇒ Integer
Value after decrement (floors at
0, removing the key). -
#del(key) ⇒ Integer
1when a key was removed,0otherwise. -
#del_if(key, expected) ⇒ Boolean
Whether the key was removed.
-
#get(key) ⇒ String?
Stored value, or
nilwhen missing or expired. -
#incr(key, ttl: nil) ⇒ Integer
Value after increment.
-
#initialize ⇒ Memory
constructor
A new instance of Memory.
-
#set(key, value, ttl: nil, nx: false, xx: false) ⇒ Boolean
Whether the value was written.
-
#ttl(key) ⇒ Integer?
Whole seconds until expiry, or
nilwhen missing or expired.
Constructor Details
#initialize ⇒ Memory
Returns a new instance of Memory.
10 11 12 13 |
# File 'lib/cmdx/stores/memory.rb', line 10 def initialize @mutex = Mutex.new @entries = {} end |
Instance Method Details
#decr(key, ttl: nil) ⇒ Integer
Returns value after decrement (floors at 0, removing the key).
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/cmdx/stores/memory.rb', line 98 def decr(key, ttl: nil) key = Stores.key!(key) Stores.ttl!(ttl) if ttl @mutex.synchronize do entry = @entries[key] if entry && expired?(entry) @entries.delete(key) entry = nil end count = entry ? entry[:value].to_i : 0 count = count.positive? ? count - 1 : 0 expires_at = entry&.fetch(:expires_at, nil) if count.zero? @entries.delete(key) else @entries[key] = { value: count.to_s, expires_at: } end count end end |
#del(key) ⇒ Integer
Returns 1 when a key was removed, 0 otherwise.
125 126 127 128 129 130 131 |
# File 'lib/cmdx/stores/memory.rb', line 125 def del(key) key = Stores.key!(key) @mutex.synchronize do @entries.delete(key) ? 1 : 0 end end |
#del_if(key, expected) ⇒ Boolean
Returns whether the key was removed.
136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/cmdx/stores/memory.rb', line 136 def del_if(key, expected) key = Stores.key!(key) @mutex.synchronize do entry = @entries[key] return false unless entry && !expired?(entry) return false unless entry[:value] == expected.to_s @entries.delete(key) true end end |
#get(key) ⇒ String?
Returns stored value, or nil when missing or expired.
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/cmdx/stores/memory.rb', line 17 def get(key) key = Stores.key!(key) @mutex.synchronize do entry = @entries[key] return unless entry return if expired?(entry) entry[:value] end end |
#incr(key, ttl: nil) ⇒ Integer
Returns value after increment.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/cmdx/stores/memory.rb', line 58 def incr(key, ttl: nil) key = Stores.key!(key) ttl = Stores.ttl!(ttl) if ttl @mutex.synchronize do entry = @entries[key] if entry && expired?(entry) @entries.delete(key) entry = nil end count = entry ? entry[:value].to_i + 1 : 1 expires_at = (Util.monotonic_now + ttl if ttl) @entries[key] = { value: count.to_s, expires_at: } count end end |
#set(key, value, ttl: nil, nx: false, xx: false) ⇒ Boolean
Returns whether the value was written.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/cmdx/stores/memory.rb', line 36 def set(key, value, ttl: nil, nx: false, xx: false) key = Stores.key!(key) ttl = Stores.ttl!(ttl) if ttl Stores.nx_xx!(nx, xx) expires_at = ttl ? Util.monotonic_now + ttl : nil @mutex.synchronize do entry = @entries[key] present = entry && !expired?(entry) return false if nx && present return false if xx && !present @entries[key] = { value: value.to_s, expires_at: } true end end |
#ttl(key) ⇒ Integer?
Returns whole seconds until expiry, or nil when missing or expired.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/cmdx/stores/memory.rb', line 79 def ttl(key) key = Stores.key!(key) @mutex.synchronize do entry = @entries[key] return unless entry return if expired?(entry) expires_at = entry[:expires_at] return unless expires_at remaining = expires_at - Util.monotonic_now remaining.positive? ? remaining.ceil : nil end end |