Skip to content

Commit e67878f

Browse files
committed
v6.0.0 - set {lock,cache}_storage= separately
1 parent ba1f794 commit e67878f

File tree

8 files changed

+67
-33
lines changed

8 files changed

+67
-33
lines changed

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
6.0.0
2+
3+
* Breaking changes
4+
5+
* Set lock_storage and cache_storage separately
6+
17
5.0.0
28

39
* Enhancements / breaking changes

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ Most caching libraries don't do locking, meaning that >1 process can be calculat
1313
## Quickstart
1414

1515
```ruby
16-
LockAndCache.storage = Redis.new
16+
LockAndCache.lock_storage = Redis.new db: 3
17+
LockAndCache.cache_storage = Redis.new db: 4
1718

1819
LockAndCache.lock_and_cache(:stock_price, {company: 'MSFT', date: '2015-05-05'}, expires: 10, nil_expires: 1) do
1920
# get yer stock quote
@@ -76,7 +77,8 @@ If an error is raised during calculation, that error is propagated to all waiter
7677
### Setup
7778

7879
```ruby
79-
LockAndCache.storage = Redis.new
80+
LockAndCache.lock_storage = Redis.new db: 3
81+
LockAndCache.cache_storage = Redis.new db: 4
8082
```
8183

8284
It will use this redis for both locking and storing cached values.
@@ -204,7 +206,8 @@ You can expire nil values with a different timeout (`nil_expires`) than other va
204206

205207
## Tunables
206208

207-
* `LockAndCache.storage=[redis]`
209+
* `LockAndCache.lock_storage=[redis]`
210+
* `LockAndCache.cache_storage=[redis]`
208211
* `ENV['LOCK_AND_CACHE_DEBUG']='true'` if you want some debugging output on `$stderr`
209212

210213
## Few dependencies

lib/lock_and_cache.rb

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,26 @@ module LockAndCache
2020

2121
class TimeoutWaitingForLock < StandardError; end
2222

23-
# @param redis_connection [Redis] A redis connection to be used for lock and cached value storage
24-
def LockAndCache.storage=(redis_connection)
23+
# @param redis_connection [Redis] A redis connection to be used for lock storage
24+
def LockAndCache.lock_storage=(redis_connection)
2525
raise "only redis for now" unless redis_connection.class.to_s == 'Redis'
26-
@storage = redis_connection
26+
@lock_storage = redis_connection
2727
end
2828

2929
# @return [Redis] The redis connection used for lock and cached value storage
30-
def LockAndCache.storage
31-
@storage
30+
def LockAndCache.lock_storage
31+
@lock_storage
32+
end
33+
34+
# @param redis_connection [Redis] A redis connection to be used for cached value storage
35+
def LockAndCache.cache_storage=(redis_connection)
36+
raise "only redis for now" unless redis_connection.class.to_s == 'Redis'
37+
@cache_storage = redis_connection
38+
end
39+
40+
# @return [Redis] The redis connection used for cached value storage
41+
def LockAndCache.cache_storage
42+
@cache_storage
3243
end
3344

3445
# @param logger [Logger] A logger.
@@ -41,13 +52,22 @@ def LockAndCache.logger
4152
@logger
4253
end
4354

44-
# Flush LockAndCache's storage.
55+
# Flush LockAndCache's cached value storage.
56+
#
57+
# @note If you are sharing a redis database, it will clear it...
58+
#
59+
# @note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
60+
def LockAndCache.flush_cache
61+
cache_storage.flushdb
62+
end
63+
64+
# Flush LockAndCache's lock storage.
4565
#
4666
# @note If you are sharing a redis database, it will clear it...
4767
#
4868
# @note If you want to clear a single key, try `LockAndCache.clear(key)` (standalone mode) or `#lock_and_cache_clear(method_id, *key_parts)` in context mode.
49-
def LockAndCache.flush
50-
storage.flushdb
69+
def LockAndCache.flush_locks
70+
lock_storage.flushdb
5171
end
5272

5373
# Lock and cache based on a key.

lib/lock_and_cache/action.rb

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ def lock_digest
3232
@lock_digest ||= key.lock_digest
3333
end
3434

35-
def storage
36-
@storage ||= LockAndCache.storage or raise("must set LockAndCache.storage=[Redis]")
35+
def lock_storage
36+
@lock_storage ||= LockAndCache.lock_storage or raise("must set LockAndCache.lock_storage=[Redis]")
37+
end
38+
39+
def cache_storage
40+
@cache_storage ||= LockAndCache.cache_storage or raise("must set LockAndCache.cache_storage=[Redis]")
3741
end
3842

3943
def load_existing(existing)
@@ -51,7 +55,7 @@ def perform
5155
raise "heartbeat_expires must be >= 2 seconds" unless heartbeat_expires >= 2
5256
heartbeat_frequency = (heartbeat_expires / 2).ceil
5357
LockAndCache.logger.debug { "[lock_and_cache] A1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
54-
if storage.exists(digest) and (existing = storage.get(digest)).is_a?(String)
58+
if cache_storage.exists(digest) and (existing = cache_storage.get(digest)).is_a?(String)
5559
return load_existing(existing)
5660
end
5761
LockAndCache.logger.debug { "[lock_and_cache] B1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
@@ -60,14 +64,14 @@ def perform
6064
acquired = false
6165
begin
6266
Timeout.timeout(max_lock_wait, TimeoutWaitingForLock) do
63-
until storage.set(lock_digest, lock_secret, nx: true, ex: heartbeat_expires)
67+
until lock_storage.set(lock_digest, lock_secret, nx: true, ex: heartbeat_expires)
6468
LockAndCache.logger.debug { "[lock_and_cache] C1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
6569
sleep rand
6670
end
6771
acquired = true
6872
end
6973
LockAndCache.logger.debug { "[lock_and_cache] D1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
70-
if storage.exists(digest) and (existing = storage.get(digest)).is_a?(String)
74+
if cache_storage.exists(digest) and (existing = cache_storage.get(digest)).is_a?(String)
7175
LockAndCache.logger.debug { "[lock_and_cache] E1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
7276
retval = load_existing existing
7377
end
@@ -83,8 +87,8 @@ def perform
8387
break if done
8488
LockAndCache.logger.debug { "[lock_and_cache] heartbeat2 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
8589
# FIXME use lua to check the value
86-
raise "unexpectedly lost lock for #{key.debug}" unless storage.get(lock_digest) == lock_secret
87-
storage.set lock_digest, lock_secret, xx: true, ex: heartbeat_expires
90+
raise "unexpectedly lost lock for #{key.debug}" unless lock_storage.get(lock_digest) == lock_secret
91+
lock_storage.set lock_digest, lock_secret, xx: true, ex: heartbeat_expires
8892
end
8993
end
9094
begin
@@ -100,32 +104,32 @@ def perform
100104
end
101105
end
102106
ensure
103-
storage.del lock_digest if acquired
107+
lock_storage.del lock_digest if acquired
104108
end
105109
retval
106110
end
107111

108112
def set_error(exception)
109-
storage.set digest, ::Marshal.dump(ERROR_MAGIC_KEY => exception.message), ex: 1
113+
cache_storage.set digest, ::Marshal.dump(ERROR_MAGIC_KEY => exception.message), ex: 1
110114
end
111115

112116
NIL = Marshal.dump nil
113117
def set_nil
114118
if nil_expires
115-
storage.set digest, NIL, ex: nil_expires
119+
cache_storage.set digest, NIL, ex: nil_expires
116120
elsif expires
117-
storage.set digest, NIL, ex: expires
121+
cache_storage.set digest, NIL, ex: expires
118122
else
119-
storage.set digest, NIL
123+
cache_storage.set digest, NIL
120124
end
121125
end
122126

123127
def set_non_nil(retval)
124128
raise "expected not null #{retval.inspect}" if retval.nil?
125129
if expires
126-
storage.set digest, ::Marshal.dump(retval), ex: expires
130+
cache_storage.set digest, ::Marshal.dump(retval), ex: expires
127131
else
128-
storage.set digest, ::Marshal.dump(retval)
132+
cache_storage.set digest, ::Marshal.dump(retval)
129133
end
130134
end
131135
end

lib/lock_and_cache/key.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,17 @@ def key
9898
end
9999

100100
def locked?
101-
LockAndCache.storage.exists lock_digest
101+
LockAndCache.lock_storage.exists lock_digest
102102
end
103103

104104
def cached?
105-
LockAndCache.storage.exists digest
105+
LockAndCache.cache_storage.exists digest
106106
end
107107

108108
def clear
109109
LockAndCache.logger.debug { "[lock_and_cache] clear #{debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" }
110-
storage = LockAndCache.storage
111-
storage.del digest
112-
storage.del lock_digest
110+
LockAndCache.cache_storage.del digest
111+
LockAndCache.lock_storage.del lock_digest
113112
end
114113

115114
alias debug key

lib/lock_and_cache/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module LockAndCache
2-
VERSION = '5.0.0'
2+
VERSION = '6.0.0'
33
end

spec/lock_and_cache_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ def lock_and_cache_key
140140

141141
describe LockAndCache do
142142
before do
143-
LockAndCache.flush
143+
LockAndCache.flush_locks
144+
LockAndCache.flush_cache
144145
end
145146

146147
it 'has a version number' do

spec/spec_helper.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
require 'timeout'
55

66
require 'redis'
7-
LockAndCache.storage = Redis.new
7+
LockAndCache.lock_storage = Redis.new db: 3
8+
LockAndCache.cache_storage = Redis.new db: 4
89

910
require 'thread/pool'
1011

0 commit comments

Comments
 (0)