identity_cache 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +7 -6
- data/.ruby-version +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +27 -19
- data/Rakefile +24 -0
- data/dev.yml +12 -16
- data/gemfiles/Gemfile.latest-release +1 -0
- data/gemfiles/Gemfile.min-supported +1 -1
- data/gemfiles/Gemfile.rails-edge +1 -0
- data/lib/identity_cache/cache_fetcher.rb +5 -0
- data/lib/identity_cache/cached/attribute.rb +15 -3
- data/lib/identity_cache/cached/primary_index.rb +5 -1
- data/lib/identity_cache/memoized_cache_proxy.rb +10 -0
- data/lib/identity_cache/parent_model_expiration.rb +0 -4
- data/lib/identity_cache/version.rb +1 -1
- data/lib/identity_cache.rb +57 -39
- metadata +3 -4
- data/isogun.yml +0 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 463112ddb217364a26a8232ef1958c45bdb24fc7dcd891be3e7d4db4ca4d29a4
|
|
4
|
+
data.tar.gz: 13ea742aca4c33f710a6f8a229f6cf0531dba50291c1ec7c67bce735028ce527
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d4c3cae9c3c4a6444f62d84242326da8901e0aa66895c8b6d2916930a5824fe402299d5e7c6270982e37fa9cd97991310756320aea0fb93b64a1f515a27f1c1f
|
|
7
|
+
data.tar.gz: 5512f9b845a4bc9ea8821d6e8563bc4307ba46a32fe32f1f5d2a708b624be3a5ed72c1b64fe2a9ade21f52ffa8d6c3220e23bc3bb433249bceb4d6eacdf7ba67
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -19,11 +19,11 @@ jobs:
|
|
|
19
19
|
ruby: '3.0'
|
|
20
20
|
gemfile: "Gemfile.min-supported"
|
|
21
21
|
- name: 'Latest released & run rubocop'
|
|
22
|
-
ruby: '3.
|
|
22
|
+
ruby: '3.3'
|
|
23
23
|
gemfile: "Gemfile.latest-release"
|
|
24
24
|
rubocop: true
|
|
25
25
|
- name: 'Rails edge'
|
|
26
|
-
ruby: '3.
|
|
26
|
+
ruby: '3.3'
|
|
27
27
|
gemfile: "Gemfile.rails-edge"
|
|
28
28
|
edge: true
|
|
29
29
|
|
|
@@ -69,25 +69,26 @@ jobs:
|
|
|
69
69
|
run: |
|
|
70
70
|
sudo apt-get update
|
|
71
71
|
sudo apt-get -y install libmemcached-dev libmysqlclient-dev libpq-dev libsasl2-dev
|
|
72
|
+
|
|
72
73
|
- uses: actions/checkout@v2
|
|
73
74
|
- name: Set up Ruby
|
|
74
75
|
uses: ruby/setup-ruby@v1
|
|
75
76
|
with:
|
|
76
77
|
ruby-version: ${{ matrix.entry.ruby }}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
gem install bundler
|
|
80
|
-
bundle install --jobs 4 --retry 3
|
|
78
|
+
bundler-cache: true
|
|
79
|
+
|
|
81
80
|
- name: Test with mysql
|
|
82
81
|
env:
|
|
83
82
|
DB: mysql2
|
|
84
83
|
run: bundle exec rake test
|
|
84
|
+
|
|
85
85
|
- name: Test with postgres and memcached_store
|
|
86
86
|
env:
|
|
87
87
|
DB: postgresql
|
|
88
88
|
POSTGRES_PASSWORD: postgres
|
|
89
89
|
ADAPTER: memcached
|
|
90
90
|
run: bundle exec rake test
|
|
91
|
+
|
|
91
92
|
- name: Run rubocop
|
|
92
93
|
if: matrix.entry.rubocop
|
|
93
94
|
run: bundle exec rubocop
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.3.4
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.6.2
|
|
6
|
+
|
|
7
|
+
- Support deferred expiry of associations and attributes. Add a rake task to create test database.
|
|
8
|
+
|
|
9
|
+
## 1.6.1
|
|
10
|
+
|
|
11
|
+
- Fix deprecation warnings on Active Record 7.2. (#575)
|
|
12
|
+
|
|
5
13
|
## 1.6.0
|
|
6
14
|
|
|
7
15
|
- Introduce `.with_deferred_parent_expiration`, which takes a block and avoids duplicate parent cache expiry. (#569)
|
data/Gemfile
CHANGED
|
@@ -9,7 +9,7 @@ gem "rubocop-shopify", "~> 2.9.0", require: false
|
|
|
9
9
|
|
|
10
10
|
gem "mysql2", "~> 0.5.3", platform: :mri
|
|
11
11
|
gem "pg", ">= 0.18", "< 2.0", platform: :mri
|
|
12
|
-
gem "memcached", "
|
|
12
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify", platform: :mri
|
|
13
13
|
gem "memcached_store", "~> 2.3.2", platform: :mri
|
|
14
14
|
gem "dalli", "~> 3.2.3"
|
|
15
15
|
gem "cityhash", "~> 0.6.0", platform: :mri
|
data/Gemfile.lock
CHANGED
|
@@ -1,52 +1,59 @@
|
|
|
1
|
+
GIT
|
|
2
|
+
remote: https://github.com/Shopify/memcached.git
|
|
3
|
+
revision: 54a89bae698896a00fd2ceeb142dada6285f73ed
|
|
4
|
+
branch: 1-0-stable-shopify
|
|
5
|
+
specs:
|
|
6
|
+
memcached (1.9.0)
|
|
7
|
+
|
|
1
8
|
PATH
|
|
2
9
|
remote: .
|
|
3
10
|
specs:
|
|
4
|
-
identity_cache (1.6.
|
|
11
|
+
identity_cache (1.6.2)
|
|
5
12
|
activerecord (>= 7.0)
|
|
6
13
|
ar_transaction_changes (~> 1.1)
|
|
7
14
|
|
|
8
15
|
GEM
|
|
9
16
|
remote: https://rubygems.org/
|
|
10
17
|
specs:
|
|
11
|
-
activemodel (7.
|
|
12
|
-
activesupport (= 7.
|
|
13
|
-
activerecord (7.
|
|
14
|
-
activemodel (= 7.
|
|
15
|
-
activesupport (= 7.
|
|
18
|
+
activemodel (7.2.0)
|
|
19
|
+
activesupport (= 7.2.0)
|
|
20
|
+
activerecord (7.2.0)
|
|
21
|
+
activemodel (= 7.2.0)
|
|
22
|
+
activesupport (= 7.2.0)
|
|
16
23
|
timeout (>= 0.4.0)
|
|
17
|
-
activesupport (7.
|
|
24
|
+
activesupport (7.2.0)
|
|
18
25
|
base64
|
|
19
26
|
bigdecimal
|
|
20
|
-
concurrent-ruby (~> 1.0, >= 1.
|
|
27
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
21
28
|
connection_pool (>= 2.2.5)
|
|
22
29
|
drb
|
|
23
30
|
i18n (>= 1.6, < 2)
|
|
31
|
+
logger (>= 1.4.2)
|
|
24
32
|
minitest (>= 5.1)
|
|
25
|
-
|
|
26
|
-
tzinfo (~> 2.0)
|
|
33
|
+
securerandom (>= 0.3)
|
|
34
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
27
35
|
ar_transaction_changes (1.1.9)
|
|
28
36
|
activerecord (>= 5.2.0)
|
|
29
37
|
ast (2.4.2)
|
|
30
38
|
base64 (0.2.0)
|
|
31
|
-
bigdecimal (3.1.
|
|
39
|
+
bigdecimal (3.1.8)
|
|
32
40
|
byebug (11.1.3)
|
|
33
41
|
cityhash (0.6.0)
|
|
34
|
-
concurrent-ruby (1.
|
|
42
|
+
concurrent-ruby (1.3.4)
|
|
35
43
|
connection_pool (2.4.1)
|
|
36
44
|
dalli (3.2.3)
|
|
37
45
|
drb (2.2.1)
|
|
38
|
-
i18n (1.14.
|
|
46
|
+
i18n (1.14.5)
|
|
39
47
|
concurrent-ruby (~> 1.0)
|
|
40
48
|
json (2.7.1)
|
|
41
49
|
language_server-protocol (3.17.0.3)
|
|
42
|
-
|
|
50
|
+
logger (1.6.0)
|
|
43
51
|
memcached_store (2.3.4)
|
|
44
52
|
activesupport (>= 6)
|
|
45
53
|
memcached (~> 1.8)
|
|
46
|
-
minitest (5.
|
|
54
|
+
minitest (5.25.1)
|
|
47
55
|
mocha (2.1.0)
|
|
48
56
|
ruby2_keywords (>= 0.0.5)
|
|
49
|
-
mutex_m (0.2.0)
|
|
50
57
|
mysql2 (0.5.6)
|
|
51
58
|
parallel (1.24.0)
|
|
52
59
|
parser (3.3.0.5)
|
|
@@ -57,8 +64,8 @@ GEM
|
|
|
57
64
|
rainbow (3.1.1)
|
|
58
65
|
rake (13.1.0)
|
|
59
66
|
regexp_parser (2.9.0)
|
|
60
|
-
rexml (3.
|
|
61
|
-
strscan
|
|
67
|
+
rexml (3.3.6)
|
|
68
|
+
strscan
|
|
62
69
|
rubocop (1.61.0)
|
|
63
70
|
json (~> 2.3)
|
|
64
71
|
language_server-protocol (>= 3.17.0)
|
|
@@ -76,6 +83,7 @@ GEM
|
|
|
76
83
|
rubocop (~> 1.33)
|
|
77
84
|
ruby-progressbar (1.13.0)
|
|
78
85
|
ruby2_keywords (0.0.5)
|
|
86
|
+
securerandom (0.3.1)
|
|
79
87
|
spy (1.0.5)
|
|
80
88
|
stackprof (0.2.26)
|
|
81
89
|
strscan (3.1.0)
|
|
@@ -94,7 +102,7 @@ DEPENDENCIES
|
|
|
94
102
|
cityhash (~> 0.6.0)
|
|
95
103
|
dalli (~> 3.2.3)
|
|
96
104
|
identity_cache!
|
|
97
|
-
memcached
|
|
105
|
+
memcached!
|
|
98
106
|
memcached_store (~> 2.3.2)
|
|
99
107
|
minitest (~> 5.14)
|
|
100
108
|
mocha (~> 2.0)
|
data/Rakefile
CHANGED
|
@@ -47,3 +47,27 @@ namespace :profile do
|
|
|
47
47
|
ruby "./performance/profile.rb"
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
|
+
|
|
51
|
+
namespace :db do
|
|
52
|
+
desc "Create the identity_cache_test database"
|
|
53
|
+
task :create do
|
|
54
|
+
require "mysql2"
|
|
55
|
+
|
|
56
|
+
config = {
|
|
57
|
+
host: ENV.fetch("MYSQL_HOST") || "localhost",
|
|
58
|
+
port: ENV.fetch("MYSQL_PORT") || 1037,
|
|
59
|
+
username: ENV.fetch("MYSQL_USER") || "root",
|
|
60
|
+
password: ENV.fetch("MYSQL_PASSWORD") || "",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
client = Mysql2::Client.new(config)
|
|
65
|
+
client.query("CREATE DATABASE IF NOT EXISTS identity_cache_test")
|
|
66
|
+
puts "Database 'identity_cache_test' created successfully. host: #{config[:host]}, port: #{config[:port]}"
|
|
67
|
+
rescue Mysql2::Error => e
|
|
68
|
+
puts "Error creating database: #{e.message}"
|
|
69
|
+
ensure
|
|
70
|
+
client&.close
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/dev.yml
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
name: identity-cache
|
|
2
2
|
|
|
3
3
|
up:
|
|
4
|
-
- homebrew:
|
|
5
|
-
- mysql-client@5.7:
|
|
6
|
-
or: [mysql@5.7]
|
|
7
|
-
conflicts: [mysql-connector-c, mysql, mysql-client]
|
|
8
4
|
- ruby
|
|
9
|
-
- isogun
|
|
10
5
|
- bundler
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
- memcached
|
|
7
|
+
- mysql
|
|
8
|
+
- custom:
|
|
9
|
+
name: create database identity_cache_test
|
|
10
|
+
met?: mysql -u root -h 127.0.0.1 -P 1037 -e "SHOW DATABASES;" | grep identity_cache_test
|
|
11
|
+
meet: bundle exec rake db:create
|
|
16
12
|
|
|
17
13
|
commands:
|
|
18
14
|
test:
|
|
@@ -20,7 +16,7 @@ commands:
|
|
|
20
16
|
optional:
|
|
21
17
|
argument: file
|
|
22
18
|
optional: args...
|
|
23
|
-
desc:
|
|
19
|
+
desc: "Run tests"
|
|
24
20
|
run: |
|
|
25
21
|
if [[ $# -eq 0 ]]; then
|
|
26
22
|
bundle exec rake test
|
|
@@ -29,21 +25,21 @@ commands:
|
|
|
29
25
|
fi
|
|
30
26
|
|
|
31
27
|
style:
|
|
32
|
-
desc:
|
|
28
|
+
desc: "Run rubocop checks"
|
|
33
29
|
run: bundle exec rubocop "$@"
|
|
34
30
|
|
|
35
31
|
check:
|
|
36
|
-
desc:
|
|
32
|
+
desc: "Run tests and style checks"
|
|
37
33
|
run: bundle exec rake test && bundle exec rubocop
|
|
38
34
|
|
|
39
35
|
benchmark-cpu:
|
|
40
|
-
desc:
|
|
36
|
+
desc: "Run the identity cache CPU benchmark"
|
|
41
37
|
run: bundle exec rake benchmark:cpu
|
|
42
38
|
|
|
43
39
|
profile:
|
|
44
|
-
desc:
|
|
40
|
+
desc: "Profile IDC code"
|
|
45
41
|
run: bundle exec rake profile:run
|
|
46
42
|
|
|
47
43
|
update-serialization-format:
|
|
48
|
-
desc:
|
|
44
|
+
desc: "Update serialization format test fixture"
|
|
49
45
|
run: bundle exec rake update_serialization_format
|
|
@@ -6,7 +6,7 @@ gem "ar_transaction_changes", "~> 1.1.0"
|
|
|
6
6
|
gem "activerecord", "~> 7.0.0"
|
|
7
7
|
gem "mysql2", "~> 0.5"
|
|
8
8
|
gem "pg", "~> 1.1"
|
|
9
|
-
gem "memcached", "
|
|
9
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify"
|
|
10
10
|
gem "memcached_store", "~> 2.3.2"
|
|
11
11
|
gem "dalli", "~> 2.7.11"
|
|
12
12
|
gem "cityhash", "~> 0.6.0"
|
data/gemfiles/Gemfile.rails-edge
CHANGED
|
@@ -5,6 +5,7 @@ gem "activerecord", github: "rails/rails", branch: "main"
|
|
|
5
5
|
gem "activesupport", github: "rails/rails", branch: "main"
|
|
6
6
|
gem "mysql2", "~> 0.5"
|
|
7
7
|
gem "pg", "~> 1.1"
|
|
8
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify"
|
|
8
9
|
gem "memcached_store"
|
|
9
10
|
gem "dalli"
|
|
10
11
|
gem "cityhash"
|
|
@@ -60,6 +60,11 @@ module IdentityCache
|
|
|
60
60
|
@cache_backend.write(key, IdentityCache::DELETED, expires_in: IdentityCache::DELETED_TTL.seconds)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
def delete_multi(keys)
|
|
64
|
+
key_values = keys.map { |key| [key, IdentityCache::DELETED] }.to_h
|
|
65
|
+
@cache_backend.write_multi(key_values, expires_in: IdentityCache::DELETED_TTL.seconds)
|
|
66
|
+
end
|
|
67
|
+
|
|
63
68
|
def clear
|
|
64
69
|
@cache_backend.clear
|
|
65
70
|
end
|
|
@@ -39,12 +39,24 @@ module IdentityCache
|
|
|
39
39
|
|
|
40
40
|
unless record.send(:was_new_record?)
|
|
41
41
|
old_key = old_cache_key(record)
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
if Thread.current[:idc_deferred_expiration]
|
|
44
|
+
Thread.current[:idc_attributes_to_expire] << old_key
|
|
45
|
+
# defer the deletion, and don't block the following deletion
|
|
46
|
+
all_deleted = true
|
|
47
|
+
else
|
|
48
|
+
all_deleted = IdentityCache.cache.delete(old_key)
|
|
49
|
+
end
|
|
43
50
|
end
|
|
44
51
|
unless record.destroyed?
|
|
45
52
|
new_key = new_cache_key(record)
|
|
46
53
|
if new_key != old_key
|
|
47
|
-
|
|
54
|
+
if Thread.current[:idc_deferred_expiration]
|
|
55
|
+
Thread.current[:idc_attributes_to_expire] << new_key
|
|
56
|
+
all_deleted = true
|
|
57
|
+
else
|
|
58
|
+
all_deleted = IdentityCache.cache.delete(new_key) && all_deleted
|
|
59
|
+
end
|
|
48
60
|
end
|
|
49
61
|
end
|
|
50
62
|
|
|
@@ -152,9 +164,9 @@ module IdentityCache
|
|
|
152
164
|
end
|
|
153
165
|
|
|
154
166
|
def old_cache_key(record)
|
|
167
|
+
changes = record.transaction_changed_attributes
|
|
155
168
|
old_key_values = key_fields.map do |field|
|
|
156
169
|
field_string = field.to_s
|
|
157
|
-
changes = record.transaction_changed_attributes
|
|
158
170
|
if record.destroyed? && changes.key?(field_string)
|
|
159
171
|
changes[field_string]
|
|
160
172
|
elsif record.persisted? && changes.key?(field_string)
|
|
@@ -45,7 +45,11 @@ module IdentityCache
|
|
|
45
45
|
|
|
46
46
|
def expire(id)
|
|
47
47
|
id = cast_id(id)
|
|
48
|
-
|
|
48
|
+
if Thread.current[:idc_deferred_expiration]
|
|
49
|
+
Thread.current[:idc_records_to_expire] << cache_key(id)
|
|
50
|
+
else
|
|
51
|
+
IdentityCache.cache.delete(cache_key(id))
|
|
52
|
+
end
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
def cache_key(id)
|
|
@@ -70,6 +70,16 @@ module IdentityCache
|
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
def delete_multi(keys)
|
|
74
|
+
memoizing = memoizing?
|
|
75
|
+
ActiveSupport::Notifications.instrument("cache_delete_multi.identity_cache", memoizing: memoizing) do
|
|
76
|
+
if memoizing
|
|
77
|
+
keys.each { |key| memoized_key_values.delete(key) }
|
|
78
|
+
end
|
|
79
|
+
@cache_fetcher.delete_multi(keys)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
73
83
|
def fetch(key, cache_fetcher_options = {}, &block)
|
|
74
84
|
memo_misses = 0
|
|
75
85
|
cache_misses = 0
|
|
@@ -47,10 +47,6 @@ module IdentityCache
|
|
|
47
47
|
add_parents_to_cache_expiry_set(parents_to_expire)
|
|
48
48
|
parents_to_expire.select! { |parent| parent.class.primary_cache_index_enabled }
|
|
49
49
|
parents_to_expire.reduce(true) do |all_expired, parent|
|
|
50
|
-
if Thread.current[:idc_deferred_parent_expiration]
|
|
51
|
-
Thread.current[:idc_parent_records_for_cache_expiry] << parent
|
|
52
|
-
next parent
|
|
53
|
-
end
|
|
54
50
|
parent.expire_primary_index && all_expired
|
|
55
51
|
end
|
|
56
52
|
end
|
data/lib/identity_cache.rb
CHANGED
|
@@ -60,7 +60,7 @@ module IdentityCache
|
|
|
60
60
|
|
|
61
61
|
class InverseAssociationError < StandardError; end
|
|
62
62
|
|
|
63
|
-
class
|
|
63
|
+
class NestedDeferredCacheExpirationBlockError < StandardError; end
|
|
64
64
|
|
|
65
65
|
class UnsupportedScopeError < StandardError; end
|
|
66
66
|
|
|
@@ -117,27 +117,36 @@ module IdentityCache
|
|
|
117
117
|
!readonly
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
pool.
|
|
120
|
+
# Rails wraps each of your tests in a transaction, so that any changes
|
|
121
|
+
# made to the database during the test can be rolled back afterwards.
|
|
122
|
+
# These transactions are flagged as "unjoinable", which tries to make
|
|
123
|
+
# your application behave as if they weren't there. In particular:
|
|
124
|
+
#
|
|
125
|
+
# - Opening another transaction during the test creates a savepoint,
|
|
126
|
+
# which can be rolled back independently of the main transaction.
|
|
127
|
+
# - When those nested transactions complete, any `after_commit`
|
|
128
|
+
# callbacks for records modified during the transaction will run,
|
|
129
|
+
# even though the changes haven't actually been committed yet.
|
|
130
|
+
#
|
|
131
|
+
# By ignoring unjoinable transactions, IdentityCache's behaviour
|
|
132
|
+
# during your test suite will more closely match production.
|
|
133
|
+
#
|
|
134
|
+
# When there are no open transactions, `current_transaction` returns a
|
|
135
|
+
# special `NullTransaction` object that is unjoinable, meaning we will
|
|
136
|
+
# use the cache.
|
|
137
|
+
if ActiveRecord::ConnectionAdapters::ConnectionPool.method_defined?(:active_connection)
|
|
138
|
+
def should_use_cache? # :nodoc:
|
|
139
|
+
ActiveRecord::Base.connection_handler.connection_pool_list(ActiveRecord::Base.current_role).none? do |pool|
|
|
140
|
+
pool.active_connection? &&
|
|
141
|
+
pool.active_connection.current_transaction.joinable?
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
else
|
|
145
|
+
def should_use_cache? # :nodoc:
|
|
146
|
+
ActiveRecord::Base.connection_handler.connection_pool_list(ActiveRecord::Base.current_role).none? do |pool|
|
|
147
|
+
pool.active_connection? &&
|
|
148
|
+
pool.connection.current_transaction.joinable?
|
|
149
|
+
end
|
|
141
150
|
end
|
|
142
151
|
end
|
|
143
152
|
|
|
@@ -193,42 +202,51 @@ module IdentityCache
|
|
|
193
202
|
result
|
|
194
203
|
end
|
|
195
204
|
|
|
196
|
-
# Executes a block with deferred
|
|
197
|
-
#
|
|
198
|
-
# completes, it
|
|
199
|
-
#
|
|
200
|
-
# is already active on the current thread.
|
|
205
|
+
# Executes a block with deferred cache expiration, ensuring that the records' (parent,
|
|
206
|
+
# children and attributes) cache expiration is deferred until the block completes. When
|
|
207
|
+
# the block completes, it issues delete_multi calls for all the records and attributes
|
|
208
|
+
# that were marked for expiration.
|
|
201
209
|
#
|
|
202
210
|
# == Parameters:
|
|
203
211
|
# No parameters.
|
|
204
212
|
#
|
|
205
213
|
# == Raises:
|
|
206
|
-
#
|
|
214
|
+
# NestedDeferredCacheExpirationBlockError if a deferred cache expiration block is already active.
|
|
207
215
|
#
|
|
208
216
|
# == Yield:
|
|
209
|
-
# Runs the provided block with deferred
|
|
217
|
+
# Runs the provided block with deferred cache expiration.
|
|
210
218
|
#
|
|
211
219
|
# == Returns:
|
|
212
220
|
# The result of executing the provided block.
|
|
213
221
|
#
|
|
214
222
|
# == Ensures:
|
|
215
|
-
# Cleans up thread-local variables related to deferred
|
|
223
|
+
# Cleans up thread-local variables related to deferred cache expiration regardless
|
|
216
224
|
# of whether the block raises an exception.
|
|
217
|
-
def
|
|
218
|
-
raise
|
|
225
|
+
def with_deferred_expiration
|
|
226
|
+
raise NestedDeferredCacheExpirationBlockError if Thread.current[:idc_deferred_expiration]
|
|
219
227
|
|
|
220
|
-
Thread.current[:
|
|
221
|
-
Thread.current[:
|
|
228
|
+
Thread.current[:idc_deferred_expiration] = true
|
|
229
|
+
Thread.current[:idc_records_to_expire] = Set.new
|
|
230
|
+
Thread.current[:idc_attributes_to_expire] = Set.new
|
|
222
231
|
|
|
223
232
|
result = yield
|
|
224
233
|
|
|
225
|
-
Thread.current[:
|
|
226
|
-
Thread.current[:
|
|
227
|
-
|
|
234
|
+
Thread.current[:idc_deferred_expiration] = nil
|
|
235
|
+
if Thread.current[:idc_records_to_expire].any?
|
|
236
|
+
IdentityCache.cache.delete_multi(
|
|
237
|
+
Thread.current[:idc_records_to_expire]
|
|
238
|
+
)
|
|
239
|
+
end
|
|
240
|
+
if Thread.current[:idc_attributes_to_expire].any?
|
|
241
|
+
IdentityCache.cache.delete_multi(
|
|
242
|
+
Thread.current[:idc_attributes_to_expire]
|
|
243
|
+
)
|
|
244
|
+
end
|
|
228
245
|
result
|
|
229
246
|
ensure
|
|
230
|
-
Thread.current[:
|
|
231
|
-
Thread.current[:
|
|
247
|
+
Thread.current[:idc_deferred_expiration] = nil
|
|
248
|
+
Thread.current[:idc_records_to_expire].clear
|
|
249
|
+
Thread.current[:idc_attributes_to_expire].clear
|
|
232
250
|
end
|
|
233
251
|
|
|
234
252
|
def with_fetch_read_only_records(value = true)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: identity_cache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Camilo Lopez
|
|
@@ -14,7 +14,7 @@ authors:
|
|
|
14
14
|
autorequire:
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
|
-
date: 2024-
|
|
17
|
+
date: 2024-10-10 00:00:00.000000000 Z
|
|
18
18
|
dependencies:
|
|
19
19
|
- !ruby/object:Gem::Dependency
|
|
20
20
|
name: activerecord
|
|
@@ -127,7 +127,6 @@ files:
|
|
|
127
127
|
- gemfiles/Gemfile.min-supported
|
|
128
128
|
- gemfiles/Gemfile.rails-edge
|
|
129
129
|
- identity_cache.gemspec
|
|
130
|
-
- isogun.yml
|
|
131
130
|
- lib/identity_cache.rb
|
|
132
131
|
- lib/identity_cache/belongs_to_caching.rb
|
|
133
132
|
- lib/identity_cache/cache_fetcher.rb
|
|
@@ -192,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
192
191
|
- !ruby/object:Gem::Version
|
|
193
192
|
version: '0'
|
|
194
193
|
requirements: []
|
|
195
|
-
rubygems_version: 3.5.
|
|
194
|
+
rubygems_version: 3.5.21
|
|
196
195
|
signing_key:
|
|
197
196
|
specification_version: 4
|
|
198
197
|
summary: IdentityCache lets you specify how you want to cache your model objects,
|