moneta 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/CONTRIBUTORS +2 -0
- data/Gemfile +1 -0
- data/LICENSE +1 -1
- data/lib/active_support/cache/moneta_store.rb +5 -4
- data/lib/moneta/adapters/sequel.rb +9 -0
- data/lib/moneta/version.rb +1 -1
- data/moneta.gemspec +2 -2
- data/script/parallel-tests +12 -0
- data/spec/active_support/cache_moneta_store_spec.rb +155 -93
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e375eca1c232dfe6bf7732660b158162bd5b887
|
4
|
+
data.tar.gz: 30219ec6a3496650ea09927d1d6140d377f48730
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39edafb80920ff47c04b215fd74d77f9e49363588bdf988649637d24219e1e164b8887c46289be4455a0fbaf5315fe5b768fd0b56f5a594594ba44f28ff1ece9
|
7
|
+
data.tar.gz: ba16585476906490eaa5df9be59c24cd5d49cd82eacdc9b6960f59456bc461a603334abce9c70894e9de12af1f55b13d16710137171a47a4588670e72bf0f4f7
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
1.0.0
|
2
|
+
|
3
|
+
* Adapters::Sequel - allow usage of Sequel extensions and connection validation
|
4
|
+
* ActiveSupport::Cache::MonetaStore - dup options before mutating them
|
5
|
+
* ActiveSupport::Cache::MonetaStore - allow writing raw values
|
6
|
+
|
1
7
|
0.8.1
|
2
8
|
|
3
9
|
* Adapters::TokyoTyrant - more consistent error handling
|
data/CONTRIBUTORS
CHANGED
@@ -26,6 +26,8 @@ Potapov Sergey <blake131313@gmail.com>
|
|
26
26
|
Quin Hoxie <quin@aboutus.org>
|
27
27
|
Ryan T. Hosford <tad.hosford@gmail.com>
|
28
28
|
Scott Wadden <scott.wadden@gmail.com>
|
29
|
+
Timo Goebel <timo.goebel@dm.de>
|
29
30
|
Tom Meier <ozmeier@yahoo.co.uk>
|
31
|
+
Tony Han <h.bing612@gmail.com>
|
30
32
|
Xavier Shay <xavier@rhnh.net>
|
31
33
|
Yehuda Katz <wycats@gmail.com>
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -38,7 +38,8 @@ module ActiveSupport
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def write_entry(key, entry, options)
|
41
|
-
|
41
|
+
value = options[:raw] ? entry.value.to_s : entry
|
42
|
+
@store.store(key, value, moneta_options(options))
|
42
43
|
true
|
43
44
|
end
|
44
45
|
|
@@ -50,9 +51,9 @@ module ActiveSupport
|
|
50
51
|
private
|
51
52
|
|
52
53
|
def moneta_options(options)
|
53
|
-
options
|
54
|
-
|
55
|
-
|
54
|
+
new_options = options ? options.dup : {}
|
55
|
+
new_options[:expires] = new_options.delete(:expires_in).to_i if new_options.include?(:expires_in)
|
56
|
+
new_options
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
@@ -17,15 +17,24 @@ module Moneta
|
|
17
17
|
# @param [Hash] options
|
18
18
|
# @option options [String] :db Sequel database
|
19
19
|
# @option options [String/Symbol] :table (:moneta) Table name
|
20
|
+
# @option options [Array] :extensions ([]) List of Sequel extensions
|
21
|
+
# @option options [Integer] :connection_validation_timeout (nil) Sequel connection_validation_timeout
|
20
22
|
# @option options All other options passed to `Sequel#connect`
|
21
23
|
# @option options [Sequel connection] :backend Use existing backend instance
|
22
24
|
def initialize(options = {})
|
23
25
|
table = (options.delete(:table) || :moneta).to_sym
|
26
|
+
extensions = options.delete(:extensions) || []
|
27
|
+
raise ArgumentError, 'Option :extensions must be an Array' unless extensions.is_a?(Array)
|
28
|
+
connection_validation_timeout = options.delete(:connection_validation_timeout)
|
24
29
|
@backend = options[:backend] ||
|
25
30
|
begin
|
26
31
|
raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
|
27
32
|
::Sequel.connect(db, options)
|
28
33
|
end
|
34
|
+
extensions.each do |extension|
|
35
|
+
@backend.extension(extension.to_sym)
|
36
|
+
end
|
37
|
+
@backend.pool.connection_validation_timeout = connection_validation_timeout if connection_validation_timeout
|
29
38
|
@backend.create_table?(table) do
|
30
39
|
String :k, null: false, primary_key: true
|
31
40
|
File :v
|
data/lib/moneta/version.rb
CHANGED
data/moneta.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = 'moneta'
|
7
7
|
s.version = Moneta::VERSION
|
8
8
|
s.date = Date.today.to_s
|
9
|
-
s.authors = ['Daniel Mendler', 'Yehuda Katz', 'Hannes Georg']
|
10
|
-
s.email = %w{mail@daniel-mendler.de wycats@gmail.com hannes.georg@googlemail.com}
|
9
|
+
s.authors = ['Daniel Mendler', 'Yehuda Katz', 'Hannes Georg', 'Alastair Pharo']
|
10
|
+
s.email = %w{mail@daniel-mendler.de wycats@gmail.com hannes.georg@googlemail.com asppsa@gmail.com}
|
11
11
|
s.description = 'A unified interface to key/value stores'
|
12
12
|
s.extra_rdoc_files = %w{README.md SPEC.md LICENSE}
|
13
13
|
s.files = `git ls-files`.split("\n")
|
data/script/parallel-tests
CHANGED
@@ -68,6 +68,18 @@ parallel = []
|
|
68
68
|
parallel << serial
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
# The activesupport cache specs also use memcached
|
73
|
+
activesupport_cache_specs = specs.grep(/active_support.+cache/)
|
74
|
+
specs -= activesupport_cache_specs
|
75
|
+
|
76
|
+
if memcache_specs = parallel.find{ |serial| serial.all?{ |s| s.match /memcached/ } }
|
77
|
+
activesupport_cache_specs.each(&memcache_specs.method(:push))
|
78
|
+
else
|
79
|
+
parallel += activesupport_cache_specs
|
80
|
+
end
|
81
|
+
|
82
|
+
# All the left-overs
|
71
83
|
parallel += specs.map {|s| [s] }
|
72
84
|
|
73
85
|
threads = []
|
@@ -3,7 +3,20 @@ require 'active_support'
|
|
3
3
|
require 'active_support/cache/moneta_store'
|
4
4
|
require 'ostruct'
|
5
5
|
|
6
|
-
|
6
|
+
module MonetaStoreHelpers
|
7
|
+
def with_notifications
|
8
|
+
described_class.instrument = true
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
described_class.instrument = false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.include(MonetaStoreHelpers)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "cache_moneta_store" do
|
7
20
|
before(:all) do
|
8
21
|
@events = []
|
9
22
|
ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args|
|
@@ -13,185 +26,234 @@ describe ActiveSupport::Cache::MonetaStore do
|
|
13
26
|
|
14
27
|
before(:each) do
|
15
28
|
@events.clear
|
16
|
-
@store = ActiveSupport::Cache::MonetaStore.new(store: Moneta.new(:Memory))
|
17
|
-
@rabbit = OpenStruct.new name: 'bunny'
|
18
|
-
@white_rabbit = OpenStruct.new color: 'white'
|
19
|
-
|
20
|
-
@store.write 'rabbit', @rabbit
|
21
|
-
@store.delete 'counter'
|
22
|
-
@store.delete 'rub-a-dub'
|
23
29
|
end
|
24
30
|
|
25
|
-
|
26
|
-
|
27
|
-
|
31
|
+
# All stores should implement this basic behavior.
|
32
|
+
shared_examples :basic_store do
|
33
|
+
before(:each) do
|
34
|
+
@rabbit = OpenStruct.new name: 'bunny'
|
35
|
+
@white_rabbit = OpenStruct.new color: 'white'
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
37
|
+
store.clear
|
38
|
+
store.write 'rabbit', @rabbit
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
sleep 2
|
38
|
-
@store.read('rabbit').should be_nil
|
39
|
-
end
|
41
|
+
it 'reads the data' do
|
42
|
+
store.read('rabbit').should == @rabbit
|
43
|
+
end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
it 'writes the data' do
|
46
|
+
store.write 'rabbit', @white_rabbit
|
47
|
+
store.read('rabbit').should == @white_rabbit
|
48
|
+
end
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
it 'deletes data' do
|
51
|
+
store.delete 'rabbit'
|
52
|
+
store.read('rabbit').should be_nil
|
53
|
+
end
|
50
54
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@store.fetch('rub-a-dub').should == 'Flora de Cana'
|
56
|
-
@store.fetch('rabbit', force: true) # force cache miss
|
57
|
-
@store.fetch('rabbit', force: true, expires_in: 1.second) { @white_rabbit }
|
58
|
-
@store.fetch('rabbit').should == @white_rabbit
|
59
|
-
sleep 2
|
60
|
-
@store.fetch('rabbit').should be_nil
|
61
|
-
end
|
55
|
+
it 'verifies existence of an object in the store' do
|
56
|
+
store.exist?('rabbit').should be true
|
57
|
+
(!!store.exist?('rab-a-dub')).should be false
|
58
|
+
end
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
it 'fetches data' do
|
61
|
+
store.fetch('rabbit').should == @rabbit
|
62
|
+
store.fetch('rub-a-dub').should be_nil
|
63
|
+
store.fetch('rub-a-dub') { 'Flora de Cana' }
|
64
|
+
store.fetch('rub-a-dub').should == 'Flora de Cana'
|
65
|
+
end
|
69
66
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
it 'reads multiple keys' do
|
68
|
+
store.write 'irish whisky', 'Jameson'
|
69
|
+
result = store.read_multi 'rabbit', 'irish whisky'
|
70
|
+
result['rabbit'].should == @rabbit
|
71
|
+
result['irish whisky'].should == 'Jameson'
|
72
|
+
end
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
it 'reads multiple keys and returns only the matched ones' do
|
75
|
+
store.delete 'irish whisky'
|
76
|
+
result = store.read_multi 'rabbit', 'irish whisky'
|
77
|
+
result.should_not include('irish whisky')
|
78
|
+
result.should include('rabbit')
|
79
|
+
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
82
|
+
shared_examples :expiry do
|
83
|
+
it 'writes the data with expiration time' do
|
84
|
+
store.write 'rabbit', @white_rabbit, expires_in: 1.second
|
85
|
+
store.read('rabbit').should == @white_rabbit
|
86
|
+
sleep 2
|
87
|
+
store.read('rabbit').should be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "sets expiry on cache miss" do
|
91
|
+
store.fetch('rabbit', force: true) # force cache miss
|
92
|
+
store.fetch('rabbit', force: true, expires_in: 1.second) { @white_rabbit }
|
93
|
+
store.fetch('rabbit').should == @white_rabbit
|
94
|
+
sleep 2
|
95
|
+
store.fetch('rabbit').should be_nil
|
96
|
+
end
|
87
97
|
|
88
|
-
|
89
|
-
|
90
|
-
|
98
|
+
it 'does not set expiry on cache hit' do
|
99
|
+
store.fetch('rabbit', expires_in: 1.second) { @white_rabbit }.should == @rabbit
|
100
|
+
sleep 2
|
101
|
+
store.fetch('rabbit').should == @rabbit
|
102
|
+
end
|
91
103
|
end
|
92
104
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
105
|
+
# A store *may* implement this
|
106
|
+
shared_examples :increment_decrement do
|
107
|
+
it 'increments a key' do
|
108
|
+
store.write 'counter', 0, raw: true
|
109
|
+
3.times { store.increment 'counter' }
|
110
|
+
store.read('counter', raw: true).to_i.should == 3
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'decrements a key' do
|
114
|
+
store.write 'counter', 0, raw: true
|
115
|
+
3.times { store.increment 'counter' }
|
116
|
+
2.times { store.decrement 'counter' }
|
117
|
+
store.read('counter', raw: true).to_i.should == 1
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'increments a key by given value' do
|
121
|
+
store.write 'counter', 0, raw: true
|
122
|
+
store.increment 'counter', 3
|
123
|
+
store.read('counter', raw: true).to_i.should == 3
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'decrements a key by given value' do
|
127
|
+
store.write 'counter', 0, raw: true
|
128
|
+
3.times { store.increment 'counter' }
|
129
|
+
store.decrement 'counter', 2
|
130
|
+
store.read('counter', raw: true).to_i.should == 1
|
131
|
+
end
|
97
132
|
end
|
98
133
|
|
99
|
-
|
134
|
+
shared_examples :basic_instrumentation do
|
100
135
|
it 'notifies on #fetch' do
|
101
136
|
with_notifications do
|
102
|
-
|
137
|
+
store.fetch('radiohead') { 'House Of Cards' }
|
103
138
|
end
|
104
139
|
|
105
|
-
read
|
106
|
-
|
140
|
+
read = @events.shift
|
107
141
|
read.name.should == 'cache_read.active_support'
|
108
142
|
read.payload.should == { key: 'radiohead', super_operation: :fetch }
|
109
143
|
|
144
|
+
generate = @events.shift
|
110
145
|
generate.name.should == 'cache_generate.active_support'
|
111
146
|
generate.payload.should == { key: 'radiohead' }
|
112
147
|
|
148
|
+
write = @events.shift
|
113
149
|
write.name.should == 'cache_write.active_support'
|
114
150
|
write.payload.should == { key: 'radiohead' }
|
115
151
|
end
|
116
152
|
|
117
153
|
it 'notifies on #read' do
|
118
154
|
with_notifications do
|
119
|
-
|
155
|
+
store.read 'metallica'
|
120
156
|
end
|
121
157
|
|
122
|
-
read = @events.
|
158
|
+
read = @events.shift
|
123
159
|
read.name.should == 'cache_read.active_support'
|
124
160
|
read.payload.should == { key: 'metallica', hit: false }
|
125
161
|
end
|
126
162
|
|
127
163
|
it 'notifies on #write' do
|
128
164
|
with_notifications do
|
129
|
-
|
165
|
+
store.write 'depeche mode', 'Enjoy The Silence'
|
130
166
|
end
|
131
167
|
|
132
|
-
write = @events.
|
168
|
+
write = @events.shift
|
133
169
|
write.name.should == 'cache_write.active_support'
|
134
170
|
write.payload.should == { key: 'depeche mode' }
|
135
171
|
end
|
136
172
|
|
137
173
|
it 'notifies on #delete' do
|
138
174
|
with_notifications do
|
139
|
-
|
175
|
+
store.delete 'the new cardigans'
|
140
176
|
end
|
141
177
|
|
142
|
-
delete = @events.
|
178
|
+
delete = @events.shift
|
143
179
|
delete.name.should == 'cache_delete.active_support'
|
144
180
|
delete.payload.should == { key: 'the new cardigans' }
|
145
181
|
end
|
146
182
|
|
147
183
|
it 'notifies on #exist?' do
|
148
184
|
with_notifications do
|
149
|
-
|
185
|
+
store.exist? 'the smiths'
|
150
186
|
end
|
151
187
|
|
152
|
-
exist = @events.
|
188
|
+
exist = @events.shift
|
153
189
|
exist.name.should == 'cache_exist?.active_support'
|
154
190
|
exist.payload.should == { key: 'the smiths' }
|
155
191
|
end
|
156
192
|
|
193
|
+
end
|
194
|
+
|
195
|
+
# This doesn't seem to be documented at all, so we follow the
|
196
|
+
# behavior of MemCacheStore.
|
197
|
+
shared_examples :increment_decrement_instrumentation do
|
157
198
|
it 'notifies on #increment' do
|
158
199
|
with_notifications do
|
159
|
-
|
200
|
+
store.increment 'pearl jam'
|
160
201
|
end
|
161
202
|
|
162
|
-
increment = @events.
|
203
|
+
increment = @events.shift
|
163
204
|
increment.name.should == 'cache_increment.active_support'
|
164
205
|
increment.payload.should == { key: 'pearl jam', amount: 1 }
|
165
206
|
end
|
166
207
|
|
167
208
|
it 'notifies on #decrement' do
|
168
209
|
with_notifications do
|
169
|
-
|
210
|
+
store.decrement 'placebo'
|
170
211
|
end
|
171
212
|
|
172
|
-
decrement = @events.
|
213
|
+
decrement = @events.shift
|
173
214
|
decrement.name.should == 'cache_decrement.active_support'
|
174
215
|
decrement.payload.should == { key: 'placebo', amount: 1 }
|
175
216
|
end
|
217
|
+
end
|
176
218
|
|
177
|
-
|
219
|
+
describe ActiveSupport::Cache::MonetaStore do
|
220
|
+
let(:store){ described_class.new(store: Moneta.new(:Memory)) }
|
221
|
+
|
222
|
+
include_examples :basic_store
|
223
|
+
include_examples :expiry
|
224
|
+
include_examples :increment_decrement
|
225
|
+
include_examples :basic_instrumentation
|
226
|
+
include_examples :increment_decrement_instrumentation
|
227
|
+
|
228
|
+
# FIXME: no other store does this -- perhaps this should be
|
229
|
+
# removed.
|
230
|
+
it 'notifies on #clear' do
|
178
231
|
with_notifications do
|
179
|
-
|
232
|
+
store.clear
|
180
233
|
end
|
181
234
|
|
182
|
-
clear = @events.
|
235
|
+
clear = @events.shift
|
183
236
|
clear.name.should == 'cache_clear.active_support'
|
184
237
|
clear.payload.should == { key: nil }
|
185
238
|
end
|
186
239
|
end
|
187
240
|
|
188
|
-
|
241
|
+
describe ActiveSupport::Cache::MemoryStore do
|
242
|
+
let(:store){ described_class.new }
|
189
243
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
ActiveSupport::Cache::MonetaStore.instrument = false
|
244
|
+
include_examples :basic_store
|
245
|
+
include_examples :expiry
|
246
|
+
include_examples :increment_decrement
|
247
|
+
include_examples :basic_instrumentation
|
195
248
|
end
|
196
|
-
end
|
197
249
|
|
250
|
+
describe ActiveSupport::Cache::MemCacheStore do
|
251
|
+
let(:store){ described_class.new }
|
252
|
+
|
253
|
+
include_examples :basic_store
|
254
|
+
include_examples :expiry
|
255
|
+
include_examples :increment_decrement
|
256
|
+
include_examples :basic_instrumentation
|
257
|
+
include_examples :increment_decrement_instrumentation
|
258
|
+
end
|
259
|
+
end
|
metadata
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moneta
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
8
|
- Yehuda Katz
|
9
9
|
- Hannes Georg
|
10
|
+
- Alastair Pharo
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
13
|
-
date:
|
14
|
+
date: 2017-03-08 00:00:00.000000000 Z
|
14
15
|
dependencies: []
|
15
16
|
description: A unified interface to key/value stores
|
16
17
|
email:
|
17
18
|
- mail@daniel-mendler.de
|
18
19
|
- wycats@gmail.com
|
19
20
|
- hannes.georg@googlemail.com
|
21
|
+
- asppsa@gmail.com
|
20
22
|
executables: []
|
21
23
|
extensions: []
|
22
24
|
extra_rdoc_files:
|