second_level_cache 2.2.6 → 2.3.0.beta
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 +10 -0
- data/README.md +16 -10
- data/lib/second_level_cache/active_record/fetch_by_uniq_key.rb +2 -2
- data/lib/second_level_cache/record_marshal.rb +3 -0
- data/lib/second_level_cache/version.rb +1 -1
- data/lib/second_level_cache.rb +10 -3
- data/second_level_cache.gemspec +1 -1
- data/test/model/account.rb +1 -1
- data/test/model/animal.rb +2 -2
- data/test/model/book.rb +1 -1
- data/test/model/image.rb +1 -1
- data/test/model/post.rb +1 -1
- data/test/model/topic.rb +1 -1
- data/test/model/user.rb +6 -2
- data/test/record_marshal_test.rb +6 -0
- data/test/second_level_cache_test.rb +4 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98025234cd167d1057980109b910f6988747877b
|
4
|
+
data.tar.gz: 40f729aac59034003e7f6404321f47bfd8f67a55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb1d412af6f56f3e20938b4744f0a48b3d18abc4a556847001edf4a1fa13aaabb9ece974fa9d11720177f011970c3f085d0fd984e920bf21b4b9018dac47b01e
|
7
|
+
data.tar.gz: dcec779ee5c1733a03b8058a3a7dc243ce33698af648e583d4ce118a879032f36f1da961da1a61c096edded58ccbdddb77bc44c812557f57fa3898460a919353
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -40,7 +40,7 @@ For example, cache User objects:
|
|
40
40
|
|
41
41
|
```ruby
|
42
42
|
class User < ActiveRecord::Base
|
43
|
-
|
43
|
+
second_level_cache expires_in: 1.week
|
44
44
|
end
|
45
45
|
```
|
46
46
|
|
@@ -67,7 +67,9 @@ Expires cache:
|
|
67
67
|
user = User.find(1)
|
68
68
|
user.expire_second_level_cache
|
69
69
|
```
|
70
|
+
|
70
71
|
or expires cache using class method:
|
72
|
+
|
71
73
|
```ruby
|
72
74
|
User.expire_second_level_cache(1)
|
73
75
|
```
|
@@ -97,15 +99,15 @@ User.select("id, name").find(1)
|
|
97
99
|
```ruby
|
98
100
|
# user and account's write_second_level_cache operation will invoke after the logger.
|
99
101
|
ActiveRecord::Base.transaction do
|
100
|
-
|
101
|
-
|
102
|
-
|
102
|
+
user.save
|
103
|
+
account.save
|
104
|
+
Rails.logger.info "info"
|
103
105
|
end # <- Cache write
|
104
106
|
|
105
107
|
# if you want to do something after user and account's write_second_level_cache operation, do this way:
|
106
108
|
ActiveRecord::Base.transaction do
|
107
|
-
|
108
|
-
|
109
|
+
user.save
|
110
|
+
account.save
|
109
111
|
end # <- Cache write
|
110
112
|
Rails.logger.info "info"
|
111
113
|
```
|
@@ -119,8 +121,9 @@ DatabaseCleaner.strategy = :truncation
|
|
119
121
|
## Configure
|
120
122
|
|
121
123
|
In production env, we recommend to use [Dalli](https://github.com/mperham/dalli) as Rails cache store.
|
124
|
+
|
122
125
|
```ruby
|
123
|
-
|
126
|
+
config.cache_store = [:dalli_store, APP_CONFIG["memcached_host"], { namespace: "ns", compress: true }]
|
124
127
|
```
|
125
128
|
|
126
129
|
## Tips:
|
@@ -131,15 +134,17 @@ you can only change the `cache_key_prefix`:
|
|
131
134
|
```ruby
|
132
135
|
SecondLevelCache.configure.cache_key_prefix = "slc1"
|
133
136
|
```
|
134
|
-
|
137
|
+
|
138
|
+
* SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.
|
139
|
+
* When your want change the model cache version by manualy, just add the `version` option like this:
|
135
140
|
|
136
141
|
```ruby
|
137
142
|
class User < ActiveRecord::Base
|
138
|
-
|
143
|
+
second_level_cache version: 2, expires_in: 1.week
|
139
144
|
end
|
140
145
|
```
|
141
146
|
|
142
|
-
* It provides a great feature, not hits db when fetching record via unique key(not primary key).
|
147
|
+
* It provides a great feature, not hits db when fetching record via unique key (not primary key).
|
143
148
|
|
144
149
|
```ruby
|
145
150
|
# this will fetch from cache
|
@@ -156,6 +161,7 @@ user = User.fetch_by_uniq_keys!(nick_name: "hooopo") # this will raise `ActiveRe
|
|
156
161
|
Answer.includes(:question).limit(10).order("id DESC").each{|answer| answer.question.title}
|
157
162
|
Answer Load (0.2ms) SELECT `answers`.* FROM `answers` ORDER BY id DESC LIMIT 10 # Only one SQL query and one Rails.cache.read_multi fetching operation.
|
158
163
|
```
|
164
|
+
|
159
165
|
[Details for read_multi feature](http://hooopo.writings.io/articles/a9cae5e0).
|
160
166
|
|
161
167
|
## Contributors
|
@@ -21,7 +21,7 @@ module SecondLevelCache
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def fetch_by_uniq_keys!(where_values)
|
24
|
-
fetch_by_uniq_keys(where_values) ||
|
24
|
+
fetch_by_uniq_keys(where_values) || raise(::ActiveRecord::RecordNotFound)
|
25
25
|
end
|
26
26
|
|
27
27
|
def fetch_by_uniq_key(value, uniq_key_name)
|
@@ -33,7 +33,7 @@ module SecondLevelCache
|
|
33
33
|
def fetch_by_uniq_key!(value, uniq_key_name)
|
34
34
|
# puts "[Deprecated] will remove in the future,
|
35
35
|
# use fetch_by_uniq_keys! method instead."
|
36
|
-
fetch_by_uniq_key(value, uniq_key_name) ||
|
36
|
+
fetch_by_uniq_key(value, uniq_key_name) || raise(::ActiveRecord::RecordNotFound)
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
@@ -31,6 +31,9 @@ module RecordMarshal
|
|
31
31
|
next if attributes[name].nil? || attributes[name].is_a?(String)
|
32
32
|
if coder.is_a?(::ActiveRecord::Coders::YAMLColumn)
|
33
33
|
attributes[name] = coder.dump(attributes[name]) if attributes[name].is_a?(coder.object_class)
|
34
|
+
elsif coder.is_a?(::ActiveRecord::Store::IndifferentCoder)
|
35
|
+
# https://github.com/rails/rails/blob/5b14129/activerecord/lib/active_record/store.rb#L179
|
36
|
+
attributes[name] = coder.dump(attributes[name])
|
34
37
|
elsif coder == ::ActiveRecord::Coders::JSON
|
35
38
|
attributes[name] = attributes[name].to_json
|
36
39
|
end
|
data/lib/second_level_cache.rb
CHANGED
@@ -20,11 +20,11 @@ module SecondLevelCache
|
|
20
20
|
|
21
21
|
delegate :logger, :cache_store, :cache_key_prefix, to: SecondLevelCache
|
22
22
|
|
23
|
-
def
|
23
|
+
def second_level_cache(options = {})
|
24
24
|
@second_level_cache_enabled = true
|
25
25
|
@second_level_cache_options = options
|
26
|
-
@second_level_cache_options[:expires_in] ||= 1.week
|
27
26
|
@second_level_cache_options[:version] ||= 0
|
27
|
+
@second_level_cache_options[:expires_in] ||= 1.week
|
28
28
|
relation.class.send :prepend, SecondLevelCache::ActiveRecord::FinderMethods
|
29
29
|
prepend SecondLevelCache::ActiveRecord::Core
|
30
30
|
end
|
@@ -46,8 +46,15 @@ module SecondLevelCache
|
|
46
46
|
@second_level_cache_enabled = old
|
47
47
|
end
|
48
48
|
|
49
|
+
# Get MD5 digest of this Model schema
|
50
|
+
# http://api.rubyonrails.org/classes/ActiveRecord/Core/ClassMethods.html#method-i-inspect
|
49
51
|
def cache_version
|
50
|
-
|
52
|
+
return @cache_version if defined? @cache_version
|
53
|
+
# This line is copy from:
|
54
|
+
# https://github.com/rails/rails/blob/f9a5f48/activerecord/lib/active_record/core.rb#L236
|
55
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
|
56
|
+
model_schema_digest = Digest::MD5.hexdigest(attr_list)
|
57
|
+
@cache_version = "#{second_level_cache_options[:version]}/#{model_schema_digest}"
|
51
58
|
end
|
52
59
|
|
53
60
|
def second_level_cache_key(id)
|
data/second_level_cache.gemspec
CHANGED
@@ -37,5 +37,5 @@ Gem::Specification.new do |gem|
|
|
37
37
|
gem.add_development_dependency 'rake'
|
38
38
|
gem.add_development_dependency 'pry'
|
39
39
|
gem.add_development_dependency 'database_cleaner', '~> 1.3.0'
|
40
|
-
gem.add_development_dependency 'rubocop'
|
40
|
+
gem.add_development_dependency 'rubocop'
|
41
41
|
end
|
data/test/model/account.rb
CHANGED
data/test/model/animal.rb
CHANGED
data/test/model/book.rb
CHANGED
data/test/model/image.rb
CHANGED
data/test/model/post.rb
CHANGED
data/test/model/topic.rb
CHANGED
data/test/model/user.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
ActiveRecord::Base.connection.create_table(:users, force: true) do |t|
|
2
2
|
t.text :options
|
3
3
|
t.text :json_options
|
4
|
+
t.text :extras
|
4
5
|
t.string :name, unique: true
|
5
6
|
t.string :email
|
6
7
|
t.integer :status, default: 0
|
@@ -24,9 +25,12 @@ end
|
|
24
25
|
|
25
26
|
class User < ActiveRecord::Base
|
26
27
|
CACHE_VERSION = 3
|
28
|
+
second_level_cache(version: CACHE_VERSION, expires_in: 3.days)
|
29
|
+
|
27
30
|
serialize :options, Array
|
28
31
|
serialize :json_options, JSON if ::ActiveRecord::VERSION::STRING >= '4.1.0'
|
29
|
-
|
32
|
+
store :extras, accessors: [:tagline, :gender]
|
33
|
+
|
30
34
|
has_one :account
|
31
35
|
has_one :forked_user_link, foreign_key: 'forked_to_user_id'
|
32
36
|
has_one :forked_from_user, through: :forked_user_link
|
@@ -39,7 +43,7 @@ class User < ActiveRecord::Base
|
|
39
43
|
end
|
40
44
|
|
41
45
|
class Namespace < ActiveRecord::Base
|
42
|
-
|
46
|
+
second_level_cache version: 1, expires_in: 3.days
|
43
47
|
|
44
48
|
belongs_to :user
|
45
49
|
end
|
data/test/record_marshal_test.rb
CHANGED
@@ -4,14 +4,17 @@ class RecordMarshalTest < ActiveSupport::TestCase
|
|
4
4
|
def setup
|
5
5
|
if ::ActiveRecord::VERSION::STRING >= '4.1.0'
|
6
6
|
@json_options = { 'name' => 'Test', 'age' => 18, 'hash' => { 'name' => 'dup' } }
|
7
|
+
@extras = { 'tagline' => 'Hello world', 'gender' => 1 }
|
7
8
|
@user = User.create name: 'csdn',
|
8
9
|
email: 'test@csdn.com',
|
9
10
|
options: [1, 2],
|
11
|
+
extras: @extras,
|
10
12
|
json_options: @json_options,
|
11
13
|
status: :active
|
12
14
|
else
|
13
15
|
@user = User.create name: 'csdn',
|
14
16
|
email: 'test@csdn.com',
|
17
|
+
extras: @extras,
|
15
18
|
options: [1, 2]
|
16
19
|
end
|
17
20
|
end
|
@@ -30,6 +33,9 @@ class RecordMarshalTest < ActiveSupport::TestCase
|
|
30
33
|
assert_equal Array, User.read_second_level_cache(@user.id).reload.options.class
|
31
34
|
assert_equal User.read_second_level_cache(@user.id).changed?, false
|
32
35
|
assert_equal [1, 2], User.read_second_level_cache(@user.id).options
|
36
|
+
assert_equal @extras, User.read_second_level_cache(@user.id).extras
|
37
|
+
assert_equal 'Hello world', User.read_second_level_cache(@user.id).tagline
|
38
|
+
assert_equal 1, User.read_second_level_cache(@user.id).gender
|
33
39
|
if ::ActiveRecord::VERSION::STRING >= '4.1.0'
|
34
40
|
result = User.read_second_level_cache(@user.id)
|
35
41
|
assert_equal @json_options['name'], result.json_options['name']
|
@@ -6,7 +6,10 @@ class SecondLevelCacheTest < ActiveSupport::TestCase
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def test_should_get_cache_key
|
9
|
-
|
9
|
+
attr_list = User.attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
|
10
|
+
table_digest = Digest::MD5.hexdigest(attr_list)
|
11
|
+
refute_nil table_digest
|
12
|
+
assert_equal "slc/users/#{@user.id}/#{User::CACHE_VERSION}/#{table_digest}", @user.second_level_cache_key
|
10
13
|
end
|
11
14
|
|
12
15
|
def test_should_write_and_read_cache
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: second_level_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hooopo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -110,16 +110,16 @@ dependencies:
|
|
110
110
|
name: rubocop
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
|
-
- - "
|
113
|
+
- - ">="
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version: 0
|
115
|
+
version: '0'
|
116
116
|
type: :development
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
|
-
- - "
|
120
|
+
- - ">="
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: 0
|
122
|
+
version: '0'
|
123
123
|
description: Write Through and Read Through caching library inspired by CacheMoney
|
124
124
|
and cache_fu, support ActiveRecord 4.
|
125
125
|
email:
|
@@ -184,9 +184,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
184
|
version: '0'
|
185
185
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
186
|
requirements:
|
187
|
-
- - "
|
187
|
+
- - ">"
|
188
188
|
- !ruby/object:Gem::Version
|
189
|
-
version:
|
189
|
+
version: 1.3.1
|
190
190
|
requirements: []
|
191
191
|
rubyforge_project:
|
192
192
|
rubygems_version: 2.5.1
|