@@ -15,6 +15,7 @@ class FillLock
1515 class << self
1616 def from_cache ( marker , client_id , data_version )
1717 raise ArgumentError unless marker == FILL_LOCKED
18+
1819 new ( client_id : client_id , data_version : data_version )
1920 end
2021
@@ -69,13 +70,11 @@ def fetch_multi(keys, &block)
6970 results
7071 end
7172
72- def fetch ( key , fill_lock_duration : nil , lock_wait_tries : 2 )
73+ def fetch ( key , fill_lock_duration : nil , lock_wait_tries : 2 , & block )
7374 if fill_lock_duration && IdentityCache . should_fill_cache?
74- fetch_with_fill_lock ( key , fill_lock_duration , lock_wait_tries ) do
75- yield
76- end
75+ fetch_with_fill_lock ( key , fill_lock_duration , lock_wait_tries , &block )
7776 else
78- fetch_without_fill_lock ( key ) { yield }
77+ fetch_without_fill_lock ( key , & block )
7978 end
8079 end
8180
@@ -88,16 +87,19 @@ def fetch_without_fill_lock(key)
8887 unless value . nil?
8988 return value
9089 end
90+
9191 data = yield
9292 break unless IdentityCache . should_fill_cache?
93+
9394 data
9495 end
9596 data
9697 end
9798
98- def fetch_with_fill_lock ( key , fill_lock_duration , lock_wait_tries )
99+ def fetch_with_fill_lock ( key , fill_lock_duration , lock_wait_tries , & block )
99100 raise ArgumentError , "fill_lock_duration must be greater than 0.0" unless fill_lock_duration > 0.0
100101 raise ArgumentError , "lock_wait_tries must be greater than 0" unless lock_wait_tries > 0
102+
101103 lock = nil
102104 using_fallback_key = false
103105 expiration_options = EMPTY_HASH
@@ -122,13 +124,14 @@ def fetch_with_fill_lock(key, fill_lock_duration, lock_wait_tries)
122124 return data
123125 else
124126 raise LockWaitTimeout if lock_wait_tries <= 0
127+
125128 lock_wait_tries -= 1
126129
127130 # If fill failed in the other client, then it might be failing fast
128131 # so avoid waiting the typical amount of time for a lock wait. The
129132 # semian gem can be used to handle failing fast when the database is slow.
130133 if lock . fill_failed?
131- return fetch_without_fill_lock ( key ) { yield }
134+ return fetch_without_fill_lock ( key , & block )
132135 end
133136
134137 # lock wait
@@ -167,8 +170,10 @@ def fetch_with_fill_lock(key, fill_lock_duration, lock_wait_tries)
167170 def mark_fill_failure_on_lock ( key , expiration_options )
168171 @cache_backend . cas ( key , expiration_options ) do |value |
169172 break unless FillLock . cache_value? ( value )
173+
170174 lock = FillLock . from_cache ( *value )
171175 break if lock . client_id != client_id
176+
172177 lock . mark_failed
173178 lock . cache_value
174179 end
@@ -229,10 +234,12 @@ def fill_with_lock(key, data, my_lock, expiration_options)
229234 upserted = upsert ( key , expiration_options ) do |value |
230235 return false if value . nil? || value == IdentityCache ::DELETED
231236 return true unless FillLock . cache_value? ( value ) # already filled
237+
232238 current_lock = FillLock . from_cache ( *value )
233239 if current_lock . data_version != my_lock . data_version
234240 return false # invalidated then relocked
235241 end
242+
236243 data
237244 end
238245
@@ -285,6 +292,7 @@ def cas_multi(keys)
285292
286293 break if updates . empty?
287294 break unless IdentityCache . should_fill_cache?
295+
288296 updates
289297 end
290298 result
@@ -298,6 +306,7 @@ def add_multi(keys)
298306
299307 def add ( key , value , expiration_options = EMPTY_HASH )
300308 return false unless IdentityCache . should_fill_cache?
309+
301310 @cache_backend . write ( key , value , { unless_exist : true , **expiration_options } )
302311 end
303312 end
0 commit comments