ar_cache 1.1.0 → 2.0.0
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/CHANGELOG.md +0 -10
- data/Gemfile.common +2 -0
- data/Gemfile.lock +89 -80
- data/README.md +20 -6
- data/README.zh-CN.md +165 -0
- data/ar_cache.gemspec +1 -0
- data/lib/ar_cache.rb +42 -15
- data/lib/ar_cache/active_record/associations/has_one_through_association.rb +10 -7
- data/lib/ar_cache/active_record/associations/singular_association.rb +2 -4
- data/lib/ar_cache/active_record/connection_adapters/abstract/database_statements.rb +20 -15
- data/lib/ar_cache/active_record/connection_adapters/abstract/transaction.rb +37 -32
- data/lib/ar_cache/active_record/core.rb +4 -5
- data/lib/ar_cache/active_record/insert_all.rb +1 -4
- data/lib/ar_cache/active_record/model_schema.rb +1 -7
- data/lib/ar_cache/active_record/persistence.rb +3 -4
- data/lib/ar_cache/active_record/relation.rb +7 -14
- data/lib/ar_cache/configuration.rb +34 -42
- data/lib/ar_cache/marshal.rb +28 -26
- data/lib/ar_cache/mock_table.rb +4 -12
- data/lib/ar_cache/query.rb +25 -15
- data/lib/ar_cache/table.rb +45 -60
- data/lib/ar_cache/version.rb +1 -1
- data/lib/ar_cache/where_clause.rb +35 -26
- data/lib/generators/ar_cache/install_generator.rb +0 -7
- data/lib/generators/ar_cache/templates/configuration.rb +20 -25
- metadata +23 -5
- data/lib/ar_cache/record.rb +0 -54
- data/lib/ar_cache/store.rb +0 -38
- data/lib/generators/ar_cache/templates/migrate/create_ar_cache_records.rb.tt +0 -16
data/lib/ar_cache/version.rb
CHANGED
@@ -8,7 +8,14 @@ module ArCache
|
|
8
8
|
@klass = klass
|
9
9
|
@table = klass.ar_cache_table
|
10
10
|
@predicates = predicates
|
11
|
-
|
11
|
+
end
|
12
|
+
|
13
|
+
def missed_values
|
14
|
+
@missed_values ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def invalid_keys
|
18
|
+
@invalid_keys ||= []
|
12
19
|
end
|
13
20
|
|
14
21
|
def cacheable?
|
@@ -24,8 +31,8 @@ module ArCache
|
|
24
31
|
count = 0
|
25
32
|
|
26
33
|
bool = index.all? do |column|
|
27
|
-
where_values_hash[column].tap do
|
28
|
-
if
|
34
|
+
(Thread.current[:ar_cache_reflection] ? where_values_hash.key?(column) : where_values_hash[column]).tap do
|
35
|
+
if where_values_hash[column].is_a?(Array)
|
29
36
|
@multi_values_key = column
|
30
37
|
count += 1
|
31
38
|
end
|
@@ -52,15 +59,15 @@ module ArCache
|
|
52
59
|
@cache_hash = {}
|
53
60
|
multi_values_key = @multi_values_key || @index.first
|
54
61
|
|
55
|
-
Array(where_values_hash[multi_values_key]).each do |v|
|
62
|
+
Array.wrap(where_values_hash[multi_values_key]).each do |v|
|
56
63
|
@cache_hash[table.cache_key(where_values_hash, @index, multi_values_key, v)] = v
|
57
64
|
end
|
58
65
|
|
59
66
|
return @cache_hash if primary_key_index?
|
60
67
|
|
61
68
|
@original_cache_hash = @cache_hash
|
62
|
-
@cache_hash = ArCache
|
63
|
-
@original_cache_hash.each { |k, v|
|
69
|
+
@cache_hash = ArCache.read_multi(*@cache_hash.keys, raw: true)
|
70
|
+
@original_cache_hash.each { |k, v| missed_values << v unless @cache_hash.key?(k) }
|
64
71
|
@cache_hash = @cache_hash.invert
|
65
72
|
|
66
73
|
@cache_hash
|
@@ -73,26 +80,28 @@ module ArCache
|
|
73
80
|
end
|
74
81
|
|
75
82
|
def missed_hash
|
76
|
-
@missed_hash ||=
|
83
|
+
@missed_hash ||= missed_values.empty? ? {} : { (@multi_values_key || @index.first) => missed_values }
|
77
84
|
end
|
78
85
|
|
79
86
|
def add_missed_values(key)
|
80
87
|
if primary_key_index?
|
81
|
-
|
88
|
+
missed_values << cache_hash[key]
|
82
89
|
else
|
83
|
-
|
90
|
+
missed_values << @original_cache_hash[cache_hash[key]]
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
94
|
+
def add_blank_primary_cache_key(key)
|
95
|
+
invalid_keys << key
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_invalid_second_cache_key(key)
|
99
|
+
# invalid_keys << key # The primary key index is reliable.
|
100
|
+
invalid_keys << cache_hash[key] unless primary_key_index?
|
92
101
|
end
|
93
102
|
|
94
103
|
def delete_invalid_keys
|
95
|
-
ArCache
|
104
|
+
ArCache.delete_multi(invalid_keys) if invalid_keys.any?
|
96
105
|
end
|
97
106
|
|
98
107
|
# This module is based on ActiveRecord::Relation::WhereClause modified
|
@@ -100,13 +109,10 @@ module ArCache
|
|
100
109
|
def where_values_hash
|
101
110
|
@where_values_hash ||= equalities(predicates).each_with_object({}) do |node, hash|
|
102
111
|
# Don't support Arel::Nodes::NamedFunction.
|
103
|
-
# But we don't judge it, because it will raise exception if it is Arel::Nodes::NamedFunction object.
|
104
112
|
next if table.name != node.left.relation.name
|
105
113
|
|
106
114
|
name = node.left.name.to_s
|
107
115
|
value = extract_node_value(node.right)
|
108
|
-
next if value.respond_to?(:size) && value.size > ArCache::Configuration.index_column_max_size
|
109
|
-
|
110
116
|
hash[name] = value
|
111
117
|
end
|
112
118
|
rescue NoMethodError, ActiveModel::RangeError
|
@@ -133,15 +139,18 @@ module ArCache
|
|
133
139
|
end
|
134
140
|
|
135
141
|
private def extract_node_value(node)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
142
|
+
case node
|
143
|
+
when Array
|
144
|
+
node.map { |v| extract_node_value(v) }
|
145
|
+
when Arel::Nodes::BindParam
|
146
|
+
value_for_database(node.value)
|
147
|
+
when Arel::Nodes::Casted, Arel::Nodes::Quoted
|
148
|
+
value_for_database(node)
|
149
|
+
end
|
150
|
+
end
|
144
151
|
|
152
|
+
private def value_for_database(node)
|
153
|
+
value = node.value_for_database # Maybe raise ActiveModel::RangeError
|
145
154
|
value.is_a?(Date) ? value.to_s : value
|
146
155
|
end
|
147
156
|
end
|
@@ -1,21 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails/generators'
|
4
|
-
require 'rails/generators/migration'
|
5
|
-
require 'rails/generators/active_record/migration'
|
6
4
|
|
7
5
|
module ArCache
|
8
6
|
module Generators
|
9
7
|
class InstallGenerator < Rails::Generators::Base
|
10
|
-
include Rails::Generators::Migration
|
11
|
-
include ::ActiveRecord::Generators::Migration
|
12
|
-
|
13
8
|
source_root File.expand_path('templates', __dir__)
|
14
9
|
|
15
10
|
def copy_initializer_file
|
16
11
|
copy_file 'configuration.rb', 'config/initializers/ar_cache.rb'
|
17
|
-
|
18
|
-
migration_template 'migrate/create_ar_cache_records.rb', 'db/migrate/create_ar_cache_records.rb'
|
19
12
|
end
|
20
13
|
end
|
21
14
|
end
|
@@ -2,33 +2,28 @@
|
|
2
2
|
|
3
3
|
# For more information, please see: https://github.com/OuYangJinTing/ar_cache/README.md
|
4
4
|
ArCache.configure do |config|
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# NOTE: Please change true if database happened some problems
|
6
|
+
# Arcache default use database share lock to ensure that the cache is correct.
|
7
|
+
config.cache_lock = false # Boolean
|
7
8
|
|
8
|
-
#
|
9
|
+
# The cache tool.
|
10
|
+
config.cache_store = defined?(Rails) ? Rails.cache : ActiveSupport::Cache::MemoryStore.new
|
9
11
|
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
# Serialize and deserialize cached data.
|
14
|
-
# config.coder = [YAML|JSON] # default YAML
|
15
|
-
|
16
|
-
# Support the maximum length of index column value.
|
17
|
-
# config.index_column_max_size = Integer # default 64
|
12
|
+
# The cache key valid time.
|
13
|
+
config.expires_in = 1.week # Integer
|
18
14
|
|
19
15
|
# ArCache switch.
|
20
|
-
|
21
|
-
|
22
|
-
# Whether to support
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# }
|
16
|
+
config.disabled = false # Boolean
|
17
|
+
|
18
|
+
# Whether to support select column sql.
|
19
|
+
config.select_disabled = true # Boolean
|
20
|
+
|
21
|
+
config.tables_options = {
|
22
|
+
# table_name: {
|
23
|
+
# disabled: Boolean,
|
24
|
+
# select_disabled: Boolean,
|
25
|
+
# unique_indexes: Array # eg: [:id, [:name, :statue]], The default is the unique index column of the table.
|
26
|
+
# },
|
27
|
+
# ...
|
28
|
+
}
|
34
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OuYangJinTing
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -30,6 +30,26 @@ dependencies:
|
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '7'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: oj
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '3'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '4'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '3'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '4'
|
33
53
|
description: An modern cacheing library for ActiveRecord inspired by cache-money and
|
34
54
|
second_level_cache.
|
35
55
|
email:
|
@@ -48,6 +68,7 @@ files:
|
|
48
68
|
- Gemfile.lock
|
49
69
|
- LICENSE.txt
|
50
70
|
- README.md
|
71
|
+
- README.zh-CN.md
|
51
72
|
- Rakefile
|
52
73
|
- ar_cache.gemspec
|
53
74
|
- bin/activerecord-test
|
@@ -72,14 +93,11 @@ files:
|
|
72
93
|
- lib/ar_cache/marshal.rb
|
73
94
|
- lib/ar_cache/mock_table.rb
|
74
95
|
- lib/ar_cache/query.rb
|
75
|
-
- lib/ar_cache/record.rb
|
76
|
-
- lib/ar_cache/store.rb
|
77
96
|
- lib/ar_cache/table.rb
|
78
97
|
- lib/ar_cache/version.rb
|
79
98
|
- lib/ar_cache/where_clause.rb
|
80
99
|
- lib/generators/ar_cache/install_generator.rb
|
81
100
|
- lib/generators/ar_cache/templates/configuration.rb
|
82
|
-
- lib/generators/ar_cache/templates/migrate/create_ar_cache_records.rb.tt
|
83
101
|
homepage: https://github.com/OuYangJinTing/ar_cache
|
84
102
|
licenses:
|
85
103
|
- MIT
|
data/lib/ar_cache/record.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ArCache
|
4
|
-
class Record < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
|
5
|
-
self.table_name = 'ar_cache_records'
|
6
|
-
|
7
|
-
default_scope { skip_ar_cache }
|
8
|
-
|
9
|
-
def self.get(table_name)
|
10
|
-
find_by(table_name: table_name)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.version(table)
|
14
|
-
(get(table.name) || store(table)).version
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.update_version(table)
|
18
|
-
record = get(table.name)
|
19
|
-
return store(table).version unless record
|
20
|
-
|
21
|
-
record.update_version
|
22
|
-
record.version
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.store(table)
|
26
|
-
record = get(table.name) || new(table_name: table.name)
|
27
|
-
record.store(table)
|
28
|
-
record
|
29
|
-
end
|
30
|
-
|
31
|
-
def store(table)
|
32
|
-
with_optimistic_retry do
|
33
|
-
self.version += 1 unless table_md5 == table.md5
|
34
|
-
self.table_md5 = table.md5
|
35
|
-
|
36
|
-
save! if changed?
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def update_version
|
41
|
-
with_optimistic_retry do
|
42
|
-
self.version += 1
|
43
|
-
save!
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private def with_optimistic_retry
|
48
|
-
yield
|
49
|
-
rescue ::ActiveRecord::StaleObjectError
|
50
|
-
reload
|
51
|
-
retry
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/ar_cache/store.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ArCache
|
4
|
-
class Store
|
5
|
-
@options = { raw: true, expires_in: ArCache::Configuration.expires_in }.freeze
|
6
|
-
|
7
|
-
class << self
|
8
|
-
delegate :delete, :delete_multi, :clear, :exist?, to: 'ArCache::Configuration.cache_store'
|
9
|
-
|
10
|
-
def write(name, value)
|
11
|
-
ArCache::Configuration.cache_store.write(name, dump(value), @options)
|
12
|
-
end
|
13
|
-
|
14
|
-
def write_multi(hash)
|
15
|
-
hash.each { |k, v| hash[k] = dump(v) }
|
16
|
-
ArCache::Configuration.cache_store.write_multi(hash, @options)
|
17
|
-
end
|
18
|
-
|
19
|
-
def read(name)
|
20
|
-
load(ArCache::Configuration.cache_store.read(name, @options))
|
21
|
-
end
|
22
|
-
|
23
|
-
def read_multi(names)
|
24
|
-
entries = ArCache::Configuration.cache_store.read_multi(*names, @options)
|
25
|
-
entries.each { |k, v| entries[k] = load(v) }
|
26
|
-
entries
|
27
|
-
end
|
28
|
-
|
29
|
-
private def dump(value)
|
30
|
-
ArCache::Configuration.coder.dump(value)
|
31
|
-
end
|
32
|
-
|
33
|
-
private def load(value)
|
34
|
-
ArCache::Configuration.coder.load(value) if value
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class CreateArCacheMonitors < ActiveRecord::Migration[<%= ActiveRecord::VERSION::MAJOR %>.<%= ActiveRecord::VERSION::MINOR %>]
|
4
|
-
def change
|
5
|
-
create_table :ar_cache_records do |t|
|
6
|
-
t.string :table_name, null: false
|
7
|
-
t.string :table_md5, null: false, limit: 32, default: '0' * 32
|
8
|
-
t.integer :version, null: false, default: 0
|
9
|
-
t.integer :lock_version, null: false, default: 0
|
10
|
-
|
11
|
-
t.timestamps null: false
|
12
|
-
|
13
|
-
t.index :table_name, unique: true
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|