diff --git a/app/models/solid_cache/entry.rb b/app/models/solid_cache/entry.rb index a7943c9..555d6e9 100644 --- a/app/models/solid_cache/entry.rb +++ b/app/models/solid_cache/entry.rb @@ -52,7 +52,7 @@ def lock_and_write(key, &block) uncached do result = lock.where(key_hash: key_hash_for(key)).pick(:key, :value) new_value = block.call(result&.first == key ? result[1] : nil) - write(key, new_value) + write(key, new_value) if new_value new_value end end diff --git a/lib/solid_cache/store/api.rb b/lib/solid_cache/store/api.rb index 042fb28..8a24056 100644 --- a/lib/solid_cache/store/api.rb +++ b/lib/solid_cache/store/api.rb @@ -39,16 +39,27 @@ def read_serialized_entry(key, **options) entry_read(key) end - def write_entry(key, entry, raw: false, **options) + def write_entry(key, entry, raw: false, unless_exist: false, **options) payload = serialize_entry(entry, raw: raw, **options) - # No-op for us, but this writes it to the local cache - write_serialized_entry(key, payload, raw: raw, **options) - entry_write(key, payload) + if unless_exist + written = false + entry_lock_and_write(key) do |value| + if value.nil? || deserialize_entry(value, **options).expired? + written = true + payload + end + end + else + written = entry_write(key, payload) + end + + write_serialized_entry(key, payload, raw: raw, returning: written, **options) + written end - def write_serialized_entry(key, payload, raw: false, unless_exist: false, expires_in: nil, race_condition_ttl: nil, **options) - true + def write_serialized_entry(key, payload, raw: false, unless_exist: false, expires_in: nil, race_condition_ttl: nil, returning: true, **options) + returning end def read_serialized_entries(keys) diff --git a/lib/solid_cache/store/entries.rb b/lib/solid_cache/store/entries.rb index d3edf63..5c18fe3 100644 --- a/lib/solid_cache/store/entries.rb +++ b/lib/solid_cache/store/entries.rb @@ -29,7 +29,9 @@ def entry_clear def entry_lock_and_write(key, &block) writing_key(key, failsafe: :increment) do - Entry.lock_and_write(key, &block) + Entry.lock_and_write(key) do |value| + block.call(value).tap { |result| track_writes(1) if result } + end end end diff --git a/test/unit/solid_cache_test.rb b/test/unit/solid_cache_test.rb index f4d782f..d3306f7 100644 --- a/test/unit/solid_cache_test.rb +++ b/test/unit/solid_cache_test.rb @@ -54,6 +54,17 @@ class SolidCacheTest < ActiveSupport::TestCase cache = lookup_store(max_age: 7200) assert_equal 7200, cache.max_age end + + def test_write_with_unless_exist + assert_equal true, @cache.write("foo", 1) + assert_equal false, @cache.write("foo", 1, unless_exist: true) + end + + def test_write_expired_value_with_unless_exist + assert_equal true, @cache.write(1, "aaaa", expires_in: 1.second) + travel 2.seconds + assert_equal true, @cache.write(1, "bbbb", expires_in: 1.second, unless_exist: true) + end end class SolidCacheFailsafeTest < ActiveSupport::TestCase