Skip to content

Commit

Permalink
Merge pull request #382 from Shopify/expire-primary-cache-class-method
Browse files Browse the repository at this point in the history
Make expire_primary_index a class method
  • Loading branch information
DerekStride authored Mar 7, 2019
2 parents 8aadbaa + c455365 commit 32aac1a
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 29 deletions.
36 changes: 15 additions & 21 deletions lib/identity_cache/query_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ def instrumented_record_from_coder(coder) #:nodoc:
end
end

# Invalidates the primary cache index for the associated record. Will not invalidate cached attributes.
def expire_primary_key_cache_index(id)
return unless primary_cache_index_enabled
id = type_for_attribute(primary_key).cast(id)
IdentityCache.cache.delete(rails_cache_key(id))
end

private

def record_from_coder(coder) #:nodoc:
Expand Down Expand Up @@ -452,6 +459,13 @@ def prefetch_one_association(association, records)
end
end

# Invalidate the cache data associated with the record.
def expire_cache
expire_primary_index
expire_attribute_indexes
true
end

private

def fetch_recursively_cached_association(ivar_name, dehydrated_ivar_name, association_name) # :nodoc:
Expand Down Expand Up @@ -508,21 +522,7 @@ def set_inverse_of_cached_association(association_options, association_target)
end

def expire_primary_index # :nodoc:
return unless self.class.primary_cache_index_enabled

IdentityCache.logger.debug do
extra_keys =
if respond_to?(:updated_at)
old_updated_at = old_values_for_fields([:updated_at]).first
"expiring_last_updated_at=#{old_updated_at}"
else
""
end

"[IdentityCache] expiring=#{self.class.name} expiring_id=#{id} #{extra_keys}"
end

IdentityCache.cache.delete(primary_cache_index_key)
self.class.expire_primary_key_cache_index(id)
end

def expire_attribute_indexes # :nodoc:
Expand All @@ -540,12 +540,6 @@ def expire_attribute_indexes # :nodoc:
end
end

def expire_cache # :nodoc:
expire_primary_index
expire_attribute_indexes
true
end

def was_new_record? # :nodoc:
pk = self.class.primary_key
!destroyed? && transaction_changed_attributes.has_key?(pk) && transaction_changed_attributes[pk].nil?
Expand Down
6 changes: 3 additions & 3 deletions performance/cache_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def prepare
module DeletedRunner
def prepare
super
(1..@count).each {|i| ::Item.find(i).send(:expire_cache) }
(1..@count).each {|i| ::Item.find(i).expire_cache }
end
end

Expand All @@ -118,7 +118,7 @@ def prepare
orig_resolve_cache_miss = ::Item.method(:resolve_cache_miss)

::Item.define_singleton_method(:resolve_cache_miss) do |id|
records[id-1].send(:expire_cache)
records[id-1].expire_cache
orig_resolve_cache_miss.call(id)
end
IdentityCache.cache.clear
Expand All @@ -129,7 +129,7 @@ module DeletedConflictRunner
include ConflictRunner
def prepare
super
(1..@count).each {|i| ::Item.find(i).send(:expire_cache) }
(1..@count).each {|i| ::Item.find(i).expire_cache }
end
end

Expand Down
11 changes: 11 additions & 0 deletions test/cache_invalidation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ def test_cache_invalidation_expire_properly_if_child_is_embed_in_multiple_parent
end
end

def test_cache_invalidation_expire_properly_when_expired_via_class_method
record = Item.create(:title => 'foo')
record.class.fetch(record.id)

refute_nil IdentityCache.cache.fetch(record.primary_cache_index_key) { nil }

Item.expire_primary_key_cache_index(record.id)

assert_nil IdentityCache.cache.fetch(record.primary_cache_index_key) { nil }
end

def test_dedup_cache_invalidation_of_records_embedded_twice_through_different_associations
Item.cache_has_many :associated_records, embed: true
AssociatedRecord.cache_has_many :deeply_associated_records, embed: true
Expand Down
2 changes: 1 addition & 1 deletion test/fetch_multi_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def test_fetch_multi_with_non_id_primary_key

def test_fetch_multi_after_expiring_a_record
Item.fetch_multi(@joe.id, @fred.id)
@bob.send(:expire_cache)
@bob.expire_cache
assert_equal IdentityCache::DELETED, backend.read(@bob.primary_cache_index_key)

add = Spy.on(IdentityCache.cache.cache_fetcher, :add).and_call_through
Expand Down
6 changes: 3 additions & 3 deletions test/fetch_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def test_fetch_miss_with_non_id_primary_key

def test_fetch_conflict
resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
@record.send(:expire_cache)
@record.expire_cache
@record
end
add = Spy.on(fetcher, :add).and_call_through
Expand All @@ -169,11 +169,11 @@ def test_fetch_conflict
end

def test_fetch_conflict_after_delete
@record.send(:expire_cache)
@record.expire_cache
assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)

resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
@record.send(:expire_cache)
@record.expire_cache
@record
end
add = Spy.on(IdentityCache.cache.cache_fetcher, :add).and_call_through
Expand Down
2 changes: 1 addition & 1 deletion test/save_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def test_expire_cache_works_in_a_transaction
expect_cache_delete(@blob_key)

ActiveRecord::Base.transaction do
@record.send(:expire_cache)
@record.expire_cache
end
end

Expand Down

0 comments on commit 32aac1a

Please sign in to comment.