moneta 0.7.4 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -2
- data/.travis.yml +20 -13
- data/CHANGES +5 -0
- data/Gemfile +24 -25
- data/LICENSE +1 -1
- data/README.md +32 -16
- data/Rakefile +36 -6
- data/lib/moneta/builder.rb +20 -6
- data/lib/moneta/mixins.rb +11 -4
- data/lib/moneta/version.rb +1 -1
- data/script/benchmarks +378 -0
- data/script/{generate-specs.rb → generate-specs} +92 -83
- data/script/install-bundle +26 -0
- data/script/kill-travis +16 -0
- data/script/start-services +8 -0
- data/script/upload-bundle +2 -0
- data/spec/helper.rb +9 -3
- data/spec/moneta/adapter_activerecord_spec.rb +1 -1
- data/spec/moneta/adapter_cassandra_spec.rb +1 -1
- data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +2 -2
- data/spec/moneta/adapter_client_spec.rb +1 -1
- data/spec/moneta/adapter_cookie_spec.rb +2 -2
- data/spec/moneta/adapter_couch_spec.rb +1 -1
- data/spec/moneta/adapter_datamapper_spec.rb +1 -1
- data/spec/moneta/adapter_daybreak_spec.rb +2 -2
- data/spec/moneta/adapter_dbm_spec.rb +1 -1
- data/spec/moneta/adapter_file_spec.rb +1 -1
- data/spec/moneta/adapter_fog_spec.rb +2 -2
- data/spec/moneta/adapter_gdbm_spec.rb +1 -1
- data/spec/moneta/adapter_hbase_spec.rb +1 -1
- data/spec/moneta/adapter_leveldb_spec.rb +1 -1
- data/spec/moneta/adapter_localmemcache_spec.rb +1 -1
- data/spec/moneta/adapter_lruhash_spec.rb +2 -2
- data/spec/moneta/adapter_memcached_dalli_spec.rb +1 -1
- data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapter_memcached_native_spec.rb +1 -1
- data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapter_memcached_spec.rb +1 -1
- data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapter_memory_spec.rb +19 -1
- data/spec/moneta/adapter_mongo_spec.rb +2 -2
- data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapter_pstore_spec.rb +1 -1
- data/spec/moneta/adapter_redis_spec.rb +1 -1
- data/spec/moneta/adapter_redis_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapter_restclient_spec.rb +1 -1
- data/spec/moneta/adapter_riak_spec.rb +1 -1
- data/spec/moneta/adapter_sdbm_spec.rb +1 -1
- data/spec/moneta/adapter_sequel_spec.rb +1 -1
- data/spec/moneta/adapter_sqlite_spec.rb +1 -1
- data/spec/moneta/adapter_tdb_spec.rb +1 -1
- data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -1
- data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -1
- data/spec/moneta/adapter_yaml_spec.rb +1 -1
- data/spec/moneta/cache_file_memory_spec.rb +2 -2
- data/spec/moneta/cache_memory_null_spec.rb +2 -2
- data/spec/moneta/expires_file_spec.rb +1 -1
- data/spec/moneta/expires_memory_spec.rb +19 -19
- data/spec/moneta/expires_memory_with_default_expires_spec.rb +19 -19
- data/spec/moneta/lock_spec.rb +19 -1
- data/spec/moneta/null_adapter_spec.rb +1 -1
- data/spec/moneta/optionmerger_spec.rb +14 -1
- data/spec/moneta/pool_spec.rb +1 -1
- data/spec/moneta/proxy_expires_memory_spec.rb +19 -1
- data/spec/moneta/proxy_redis_spec.rb +1 -1
- data/spec/moneta/shared_spec.rb +3 -3
- data/spec/moneta/simple_activerecord_spec.rb +1 -1
- data/spec/moneta/simple_activerecord_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_cassandra_spec.rb +1 -1
- data/spec/moneta/simple_client_tcp_spec.rb +1 -1
- data/spec/moneta/simple_client_unix_spec.rb +1 -1
- data/spec/moneta/simple_couch_spec.rb +1 -1
- data/spec/moneta/simple_couch_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_datamapper_spec.rb +1 -1
- data/spec/moneta/simple_datamapper_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -1
- data/spec/moneta/simple_daybreak_spec.rb +1 -1
- data/spec/moneta/simple_daybreak_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_dbm_spec.rb +1 -1
- data/spec/moneta/simple_dbm_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_file_spec.rb +1 -1
- data/spec/moneta/simple_file_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_fog_spec.rb +1 -1
- data/spec/moneta/simple_fog_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_gdbm_spec.rb +1 -1
- data/spec/moneta/simple_gdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_hashfile_spec.rb +1 -1
- data/spec/moneta/simple_hashfile_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_hbase_spec.rb +1 -1
- data/spec/moneta/simple_hbase_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_leveldb_spec.rb +1 -1
- data/spec/moneta/simple_leveldb_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_localmemcache_spec.rb +1 -1
- data/spec/moneta/simple_localmemcache_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_lruhash_spec.rb +1 -1
- data/spec/moneta/simple_lruhash_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_memcached_dalli_spec.rb +1 -1
- data/spec/moneta/simple_memcached_native_spec.rb +1 -1
- data/spec/moneta/simple_memcached_spec.rb +1 -1
- data/spec/moneta/simple_memory_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_compress_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -1
- data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -1
- data/spec/moneta/simple_mongo_spec.rb +1 -1
- data/spec/moneta/simple_null_spec.rb +1 -1
- data/spec/moneta/simple_pstore_spec.rb +1 -1
- data/spec/moneta/simple_pstore_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_redis_spec.rb +1 -1
- data/spec/moneta/simple_restclient_spec.rb +1 -1
- data/spec/moneta/simple_riak_spec.rb +1 -1
- data/spec/moneta/simple_riak_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_sdbm_spec.rb +1 -1
- data/spec/moneta/simple_sdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_sequel_spec.rb +1 -1
- data/spec/moneta/simple_sequel_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_sqlite_spec.rb +1 -1
- data/spec/moneta/simple_sqlite_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_tdb_spec.rb +1 -1
- data/spec/moneta/simple_tdb_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_tokyocabinet_spec.rb +1 -1
- data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +1 -1
- data/spec/moneta/simple_yaml_spec.rb +1 -1
- data/spec/moneta/simple_yaml_with_expires_spec.rb +1 -1
- data/spec/moneta/stack_file_memory_spec.rb +2 -2
- data/spec/moneta/stack_memory_file_spec.rb +3 -3
- data/spec/moneta/transformer_bencode_spec.rb +1 -1
- data/spec/moneta/transformer_bert_spec.rb +1 -1
- data/spec/moneta/transformer_bson_spec.rb +1 -1
- data/spec/moneta/transformer_bzip2_spec.rb +1 -1
- data/spec/moneta/transformer_json_spec.rb +1 -1
- data/spec/moneta/transformer_key_marshal_spec.rb +19 -19
- data/spec/moneta/transformer_key_yaml_spec.rb +19 -19
- data/spec/moneta/transformer_lzma_spec.rb +1 -1
- data/spec/moneta/transformer_lzo_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_base64_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_escape_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_md5_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -1
- data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -1
- data/spec/moneta/transformer_msgpack_spec.rb +1 -1
- data/spec/moneta/transformer_ox_spec.rb +1 -1
- data/spec/moneta/transformer_quicklz_spec.rb +1 -1
- data/spec/moneta/transformer_snappy_spec.rb +1 -1
- data/spec/moneta/transformer_tnet_spec.rb +1 -1
- data/spec/moneta/transformer_value_marshal_spec.rb +1 -1
- data/spec/moneta/transformer_value_yaml_spec.rb +1 -1
- data/spec/moneta/transformer_yaml_spec.rb +1 -1
- data/spec/moneta/transformer_zlib_spec.rb +1 -1
- data/spec/monetaspecs.rb +655 -151
- metadata +8 -6
- data/benchmarks/run.rb +0 -327
- data/script/install-bundle.rb +0 -35
data/script/benchmarks
ADDED
@@ -0,0 +1,378 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
require 'benchmark'
|
5
|
+
require 'moneta'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
class String
|
9
|
+
def random(n)
|
10
|
+
(1..n).map { self[rand(size),1] }.join
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Array
|
15
|
+
def sum
|
16
|
+
inject(0, &:+)
|
17
|
+
end
|
18
|
+
|
19
|
+
def randomize
|
20
|
+
rest, result = dup, []
|
21
|
+
result << rest.slice!(rand(rest.size)) until result.size == size
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class MonetaBenchmarks
|
27
|
+
DIR = __FILE__ + '.tmp'
|
28
|
+
FileUtils.mkpath(DIR)
|
29
|
+
|
30
|
+
STORES = {
|
31
|
+
# SDBM is unstable
|
32
|
+
# :SDBM => { :file => "#{DIR}/sdbm" },
|
33
|
+
# YAML is so fucking slow
|
34
|
+
# :YAML => { :file => "#{DIR}/yaml" },
|
35
|
+
:ActiveRecord => { :connection => { :adapter => 'sqlite3', :database => ':memory:' } },
|
36
|
+
:Cassandra => {},
|
37
|
+
:Client => {},
|
38
|
+
:Couch => {},
|
39
|
+
:DBM => { :file => "#{DIR}/dbm" },
|
40
|
+
:DataMapper => { :setup => "sqlite3:#{DIR}/datamapper" },
|
41
|
+
:Daybreak => { :file => "#{DIR}/daybreak" },
|
42
|
+
:File => { :dir => "#{DIR}/file" },
|
43
|
+
:GDBM => { :file => "#{DIR}/gdbm" },
|
44
|
+
:HBase => {},
|
45
|
+
:HashFile => { :dir => "#{DIR}/hashfile" },
|
46
|
+
:LRUHash => {},
|
47
|
+
:LevelDB => { :dir => "#{DIR}/leveldb" },
|
48
|
+
:LocalMemCache => { :file => "#{DIR}/lmc" },
|
49
|
+
:MemcachedDalli => {},
|
50
|
+
:MemcachedNative => {},
|
51
|
+
:Memory => {},
|
52
|
+
:Mongo => {},
|
53
|
+
:PStore => { :file => "#{DIR}/pstore" },
|
54
|
+
:Redis => {},
|
55
|
+
:RestClient => { :url => 'http://localhost:8808/' },
|
56
|
+
:Riak => {},
|
57
|
+
:Sequel => { :db => 'sqlite:/' },
|
58
|
+
:Sqlite => { :file => ':memory:' },
|
59
|
+
:TDB => { :file => "#{DIR}/tdb" },
|
60
|
+
}
|
61
|
+
|
62
|
+
CONFIGS = {
|
63
|
+
:uniform_small => {
|
64
|
+
:runs => 3,
|
65
|
+
:keys => 1000,
|
66
|
+
:min_key_length => 1,
|
67
|
+
:max_key_length => 32,
|
68
|
+
:key_dist => :uniform,
|
69
|
+
:min_val_length => 0,
|
70
|
+
:max_val_length => 256,
|
71
|
+
:val_dist => :uniform
|
72
|
+
},
|
73
|
+
:uniform_medium => {
|
74
|
+
:runs => 3,
|
75
|
+
:keys => 100,
|
76
|
+
:min_key_length => 3,
|
77
|
+
:max_key_length => 200,
|
78
|
+
:key_dist => :uniform,
|
79
|
+
:min_val_length => 0,
|
80
|
+
:max_val_length => 1024,
|
81
|
+
:val_dist => :uniform
|
82
|
+
},
|
83
|
+
:uniform_large => {
|
84
|
+
:runs => 3,
|
85
|
+
:keys => 100,
|
86
|
+
:min_key_length => 3,
|
87
|
+
:max_key_length => 200,
|
88
|
+
:key_dist => :uniform,
|
89
|
+
:min_val_length => 0,
|
90
|
+
:max_val_length => 10240,
|
91
|
+
:val_dist => :uniform
|
92
|
+
},
|
93
|
+
:normal_small => {
|
94
|
+
:runs => 3,
|
95
|
+
:keys => 1000,
|
96
|
+
:min_key_length => 1,
|
97
|
+
:max_key_length => 32,
|
98
|
+
:key_dist => :normal,
|
99
|
+
:min_val_length => 0,
|
100
|
+
:max_val_length => 256,
|
101
|
+
:val_dist => :normal
|
102
|
+
},
|
103
|
+
:normal_medium => {
|
104
|
+
:runs => 3,
|
105
|
+
:keys => 100,
|
106
|
+
:min_key_length => 3,
|
107
|
+
:max_key_length => 200,
|
108
|
+
:key_dist => :normal,
|
109
|
+
:min_val_length => 0,
|
110
|
+
:max_val_length => 1024,
|
111
|
+
:val_dist => :normal
|
112
|
+
},
|
113
|
+
:normal_large => {
|
114
|
+
:runs => 3,
|
115
|
+
:keys => 100,
|
116
|
+
:min_key_length => 3,
|
117
|
+
:max_key_length => 200,
|
118
|
+
:key_dist => :normal,
|
119
|
+
:min_val_length => 0,
|
120
|
+
:max_val_length => 10240,
|
121
|
+
:val_dist => :normal
|
122
|
+
},
|
123
|
+
}
|
124
|
+
|
125
|
+
DICT = 'ABCDEFGHIJKLNOPQRSTUVWXYZabcdefghijklnopqrstuvwxyz123456789'.freeze
|
126
|
+
HEADER = "\n Minimum Maximum Total Average Ops/s"
|
127
|
+
SEPARATOR = '=' * 68
|
128
|
+
|
129
|
+
module Rand
|
130
|
+
extend self
|
131
|
+
|
132
|
+
def normal_rand(mean, stddev)
|
133
|
+
# Box-Muller transform
|
134
|
+
theta = 2 * Math::PI * (rand(1e10) / 1e10)
|
135
|
+
scale = stddev * Math.sqrt(-2 * Math.log(1 - (rand(1e10) / 1e10)))
|
136
|
+
[mean + scale * Math.cos(theta),
|
137
|
+
mean + scale * Math.sin(theta)]
|
138
|
+
end
|
139
|
+
|
140
|
+
def uniform(min, max)
|
141
|
+
rand(max - min) + min
|
142
|
+
end
|
143
|
+
|
144
|
+
def normal(min, max)
|
145
|
+
mean = (min + max) / 2
|
146
|
+
stddev = (max - min) / 4
|
147
|
+
loop do
|
148
|
+
val = normal_rand(mean, stddev)
|
149
|
+
return val.first if val.first >= min && val.first <= max
|
150
|
+
return val.last if val.last >= min && val.last <= max
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def parallel(&block)
|
156
|
+
if defined?(JRUBY_VERSION)
|
157
|
+
Thread.new(&block)
|
158
|
+
else
|
159
|
+
Process.fork(&block)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def write_histogram(file, sizes)
|
164
|
+
min = sizes.min
|
165
|
+
delta = sizes.max - min
|
166
|
+
histogram = []
|
167
|
+
sizes.each do |s|
|
168
|
+
s = 10 * (s - min) / delta
|
169
|
+
histogram[s] ||= 0
|
170
|
+
histogram[s] += 1
|
171
|
+
end
|
172
|
+
File.open(file, 'w') do |f|
|
173
|
+
histogram.each_with_index { |n,i| f.puts "#{i*delta/10+min} #{n}" }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def start_servers
|
178
|
+
parallel do
|
179
|
+
begin
|
180
|
+
Moneta::Server.new(Moneta.new(:Memory)).run
|
181
|
+
rescue Exception => ex
|
182
|
+
puts "\e[31mFailed to start Moneta server - #{ex.message}\e[0m"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
parallel do
|
187
|
+
begin
|
188
|
+
require 'rack'
|
189
|
+
require 'webrick'
|
190
|
+
require 'rack/moneta_rest'
|
191
|
+
|
192
|
+
# Keep webrick quiet
|
193
|
+
::WEBrick::HTTPServer.class_eval do
|
194
|
+
def access_log(config, req, res); end
|
195
|
+
end
|
196
|
+
::WEBrick::BasicLog.class_eval do
|
197
|
+
def log(level, data); end
|
198
|
+
end
|
199
|
+
|
200
|
+
Rack::Server.start(:app => Rack::Builder.app do
|
201
|
+
use Rack::Lint
|
202
|
+
run Rack::MonetaRest.new(:store => :Memory)
|
203
|
+
end,
|
204
|
+
:environment => :none,
|
205
|
+
:server => :webrick,
|
206
|
+
:Port => 8808)
|
207
|
+
rescue Exception => ex
|
208
|
+
puts "\e[31mFailed to start Rack server - #{ex.message}\e[0m"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
sleep 1 # Wait for servers
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_stores
|
216
|
+
STORES.each do |name, options|
|
217
|
+
begin
|
218
|
+
if name == :DataMapper
|
219
|
+
begin
|
220
|
+
require 'dm-core'
|
221
|
+
DataMapper.setup(:default, :adapter => :in_memory)
|
222
|
+
rescue LoadError => ex
|
223
|
+
puts "\e[31mFailed to load DataMapper - #{ex.message}\e[0m"
|
224
|
+
end
|
225
|
+
elsif name == :Riak
|
226
|
+
require 'riak'
|
227
|
+
Riak.disable_list_keys_warnings = true
|
228
|
+
end
|
229
|
+
|
230
|
+
cache = Moneta.new(name, options.dup)
|
231
|
+
cache['test'] = 'test'
|
232
|
+
rescue Exception => ex
|
233
|
+
puts "\e[31m#{name} not benchmarked - #{ex.message}\e[0m"
|
234
|
+
STORES.delete(name)
|
235
|
+
ensure
|
236
|
+
cache.close if cache
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def generate_data
|
242
|
+
until @data.size == @config[:keys]
|
243
|
+
key = DICT.random(Rand.send(@config[:key_dist], @config[:min_key_length], @config[:max_key_length]))
|
244
|
+
@data[key] = DICT.random(Rand.send(@config[:val_dist], @config[:min_val_length], @config[:max_val_length]))
|
245
|
+
end
|
246
|
+
|
247
|
+
key_lengths, val_lengths = @data.keys.map(&:size), @data.values.map(&:size)
|
248
|
+
@data = @data.to_a
|
249
|
+
|
250
|
+
write_histogram("#{DIR}/key.histogram", key_lengths)
|
251
|
+
write_histogram("#{DIR}/value.histogram", val_lengths)
|
252
|
+
|
253
|
+
puts "\n\e[1m\e[34m#{SEPARATOR}\n\e[34mComputing keys and values...\n\e[34m#{SEPARATOR}\e[0m"
|
254
|
+
puts %{ Minimum Maximum Total Average}
|
255
|
+
puts 'Key Length % 8d % 8d % 8d % 8d ' % [key_lengths.min, key_lengths.max, key_lengths.sum, key_lengths.sum / @data.size]
|
256
|
+
puts 'Value Length % 8d % 8d % 8d % 8d ' % [val_lengths.min, val_lengths.max, val_lengths.sum, val_lengths.sum / @data.size]
|
257
|
+
end
|
258
|
+
|
259
|
+
def print_config
|
260
|
+
puts "\e[1m\e[36m#{SEPARATOR}\n\e[36mConfig #{@config_name}\n\e[36m#{SEPARATOR}\e[0m"
|
261
|
+
@config.each do |k,v|
|
262
|
+
puts '%-16s = %-10s' % [k,v]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def print_store_stats(name)
|
267
|
+
puts HEADER
|
268
|
+
[:write, :read, :sum].each do |i|
|
269
|
+
total = @stats[name][i].sum
|
270
|
+
ops = (@config[:runs] * @data.size) / total
|
271
|
+
line = '%-17.17s %-5s % 8d % 8d % 8d % 8d % 8d' %
|
272
|
+
[name, i, @stats[name][i].min * 1000, @stats[name][i].max * 1000,
|
273
|
+
total * 1000, total * 1000 / @config[:runs], ops]
|
274
|
+
@summary << [-ops, line << "\n"] if i == :sum
|
275
|
+
puts line
|
276
|
+
end
|
277
|
+
|
278
|
+
errors = @stats[name][:error].sum
|
279
|
+
if errors > 0
|
280
|
+
puts "\e[31m%-23.23s % 8d % 8d % 8d % 8d\e[0m" %
|
281
|
+
['Read errors', @stats[name][:error].min, @stats[name][:error].max, errors, errors / @config[:runs]]
|
282
|
+
else
|
283
|
+
puts "\e[32mNo read errors"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def benchmark_store(name, options)
|
288
|
+
puts "\n\e[1m\e[34m#{SEPARATOR}\n\e[34m#{name}\n\e[34m#{SEPARATOR}\e[0m"
|
289
|
+
|
290
|
+
store = Moneta.new(name, options.dup)
|
291
|
+
|
292
|
+
@stats[name] = {
|
293
|
+
:write => [],
|
294
|
+
:read => [],
|
295
|
+
:sum => [],
|
296
|
+
:error => []
|
297
|
+
}
|
298
|
+
|
299
|
+
%w(Rehearse Measure).each do |type|
|
300
|
+
state = ''
|
301
|
+
print "%s [%#{2 * @config[:runs]}s] " % [type, state]
|
302
|
+
|
303
|
+
@config[:runs].times do |run|
|
304
|
+
store.clear
|
305
|
+
print "%s[%-#{2 * @config[:runs]}s] " % ["\b" * (2 * @config[:runs] + 3), state << 'W']
|
306
|
+
|
307
|
+
@data = @data.randomize
|
308
|
+
m1 = Benchmark.measure do
|
309
|
+
@data.each {|k,v| store[k] = v }
|
310
|
+
end
|
311
|
+
|
312
|
+
print "%s[%-#{2 * @config[:runs]}s] " % ["\b" * (2 * @config[:runs] + 3), state << 'R']
|
313
|
+
|
314
|
+
@data = @data.randomize
|
315
|
+
error = 0
|
316
|
+
m2 = Benchmark.measure do
|
317
|
+
@data.each do |k, v|
|
318
|
+
error += 1 if v != store[k]
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
if type == 'Measure'
|
323
|
+
@stats[name][:write] << m1.real
|
324
|
+
@stats[name][:error] << error
|
325
|
+
@stats[name][:read] << m2.real
|
326
|
+
@stats[name][:sum] << (m1.real + m2.real)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
print_store_stats(name)
|
332
|
+
rescue StandardError => ex
|
333
|
+
puts "\n\e[31mFailed to benchmark #{name} - #{ex.message}\e[0m\n"
|
334
|
+
ensure
|
335
|
+
store.close if store
|
336
|
+
end
|
337
|
+
|
338
|
+
def run_benchmarks
|
339
|
+
STORES.each {|name, options| benchmark_store(name, options) }
|
340
|
+
end
|
341
|
+
|
342
|
+
def print_summary
|
343
|
+
puts "\n\e[1m\e[36m#{SEPARATOR}\n\e[36mSummary #{@config_name}: #{@config[:runs]} runs, #{@data.size} keys\n\e[36m#{SEPARATOR}\e[0m#{HEADER}\n"
|
344
|
+
@summary.sort_by(&:first).each do |entry|
|
345
|
+
puts entry.last
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def initialize(args)
|
350
|
+
@config_name = args.size == 1 ? args.first.to_sym : :uniform_medium
|
351
|
+
unless @config = CONFIGS[@config_name]
|
352
|
+
puts "Configuration #{@config_name} not found"
|
353
|
+
exit
|
354
|
+
end
|
355
|
+
|
356
|
+
# Disable jruby stdout pollution by memcached
|
357
|
+
if defined?(JRUBY_VERSION)
|
358
|
+
require 'java'
|
359
|
+
properties = java.lang.System.getProperties();
|
360
|
+
properties.put('net.spy.log.LoggerImpl', 'net.spy.memcached.compat.log.SunLogger');
|
361
|
+
java.lang.System.setProperties(properties);
|
362
|
+
java.util.logging.Logger.getLogger('').setLevel(java.util.logging.Level::OFF)
|
363
|
+
end
|
364
|
+
|
365
|
+
@stats, @data, @summary = {}, {}, []
|
366
|
+
end
|
367
|
+
|
368
|
+
def run
|
369
|
+
start_servers
|
370
|
+
test_stores
|
371
|
+
print_config
|
372
|
+
generate_data
|
373
|
+
run_benchmarks
|
374
|
+
print_summary
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
MonetaBenchmarks.new(ARGV).run
|
@@ -2,43 +2,55 @@
|
|
2
2
|
|
3
3
|
PATH = File.expand_path(File.join(__FILE__, '..', '..', 'spec'))
|
4
4
|
|
5
|
+
class Array
|
6
|
+
def without(*x)
|
7
|
+
a = dup
|
8
|
+
x.each {|y| a.delete(y) }
|
9
|
+
a
|
10
|
+
end
|
11
|
+
|
12
|
+
def with(*x)
|
13
|
+
a = dup
|
14
|
+
x.each {|y| a << y }
|
15
|
+
a
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
5
19
|
class Specs
|
6
20
|
attr_reader :key, :value, :specs
|
7
21
|
|
8
|
-
def initialize(
|
9
|
-
@specs = specs
|
10
|
-
@key = key || %w(object string hash boolean nil integer)
|
11
|
-
@value = value || %w(object string hash boolean nil integer)
|
22
|
+
def initialize(options = {})
|
23
|
+
@specs = options.delete(:specs).to_a
|
24
|
+
@key = options.delete(:key) || %w(object string hash boolean nil integer)
|
25
|
+
@value = options.delete(:value) || %w(object string hash boolean nil integer)
|
26
|
+
end
|
27
|
+
|
28
|
+
def new(options)
|
29
|
+
Specs.new({:specs => specs, :key => key, :value => value}.merge(options))
|
12
30
|
end
|
13
31
|
|
14
32
|
def stringkeys_only
|
15
|
-
|
33
|
+
new(:key => %w(string))
|
16
34
|
end
|
17
35
|
|
18
36
|
def stringvalues_only
|
19
|
-
|
37
|
+
new(:value => %w(string))
|
20
38
|
end
|
21
39
|
|
22
40
|
def simplekeys_only
|
23
|
-
|
41
|
+
new(:key => %w(string hash integer))
|
24
42
|
end
|
25
43
|
|
26
44
|
def simplevalues_only
|
27
|
-
|
45
|
+
new(:value => %w(string hash integer))
|
28
46
|
end
|
29
47
|
|
30
48
|
def without_increment
|
31
|
-
|
32
|
-
a.delete(:increment)
|
33
|
-
a << :not_increment
|
34
|
-
Specs.new(a, key, value)
|
49
|
+
new(:specs => specs.without(:increment).with(:not_increment))
|
35
50
|
end
|
36
51
|
|
37
52
|
def without_persist
|
38
|
-
|
39
|
-
a.delete(:persist)
|
40
|
-
a << :not_persist
|
41
|
-
Specs.new(a, key, value)
|
53
|
+
new(:specs => specs.without(:persist).with(:not_persist))
|
42
54
|
end
|
43
55
|
|
44
56
|
def with_expires
|
@@ -48,66 +60,45 @@ class Specs
|
|
48
60
|
a << :transform_value_with_expires
|
49
61
|
end
|
50
62
|
a << :expires
|
51
|
-
|
63
|
+
new(:specs => a)
|
52
64
|
end
|
53
65
|
|
54
66
|
def with_native_expires
|
55
|
-
|
56
|
-
a << :expires
|
57
|
-
Specs.new(a, key, value)
|
67
|
+
new(:specs => specs.with(:expires))
|
58
68
|
end
|
59
69
|
|
60
70
|
def without_marshallable
|
61
|
-
|
62
|
-
a.delete(:marshallable_value)
|
63
|
-
a.delete(:marshallable_key)
|
64
|
-
Specs.new(a, key, value)
|
71
|
+
new(:specs => specs.without(:marshallable_value, :marshallable_key))
|
65
72
|
end
|
66
73
|
|
67
74
|
def without_transform
|
68
|
-
|
69
|
-
a.delete(:marshallable_value)
|
70
|
-
a.delete(:marshallable_key)
|
71
|
-
a.delete(:transform_value)
|
72
|
-
Specs.new(a, key, value)
|
75
|
+
new(:specs => specs.without(:marshallable_value, :marshallable_key, :transform_value))
|
73
76
|
end
|
74
77
|
|
75
|
-
def
|
76
|
-
|
77
|
-
a.delete(:returndifferent)
|
78
|
-
Specs.new(a, key, value)
|
78
|
+
def returnsame
|
79
|
+
new(:specs => specs.without(:returndifferent).with(:returnsame))
|
79
80
|
end
|
80
81
|
|
81
82
|
def without_marshallable_key
|
82
|
-
|
83
|
-
a.delete(:marshallable_key)
|
84
|
-
Specs.new(a, key, value)
|
83
|
+
new(:specs => specs.without(:marshallable_key))
|
85
84
|
end
|
86
85
|
|
87
86
|
def without_marshallable_value
|
88
|
-
|
89
|
-
a.delete(:marshallable_value)
|
90
|
-
Specs.new(a, key, value)
|
87
|
+
new(:specs => specs.without(:marshallable_value))
|
91
88
|
end
|
92
89
|
|
93
90
|
def without_store
|
94
|
-
|
95
|
-
a.delete(:store)
|
96
|
-
a.delete(:transform_value)
|
97
|
-
a.delete(:marshallable_value)
|
98
|
-
Specs.new(a, key, value)
|
91
|
+
new(:specs => specs.without(:store, :transform_value, :marshallable_value))
|
99
92
|
end
|
100
93
|
|
101
94
|
def with_default_expires
|
102
|
-
|
103
|
-
a << :default_expires
|
104
|
-
Specs.new(a, key, value)
|
95
|
+
new(:specs => specs.with(:default_expires))
|
105
96
|
end
|
106
97
|
end
|
107
98
|
|
108
|
-
ADAPTER_SPECS = Specs.new([:null, :store, :returndifferent, :increment, :persist], %w(string), %w(string))
|
109
|
-
STANDARD_SPECS = Specs.new([:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist])
|
110
|
-
TRANSFORMER_SPECS = Specs.new([:null, :store, :returndifferent, :transform_value, :increment])
|
99
|
+
ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :persist], :key => %w(string), :value => %w(string))
|
100
|
+
STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist])
|
101
|
+
TRANSFORMER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :transform_value, :increment])
|
111
102
|
|
112
103
|
header = "# Generated by #{File.basename(__FILE__)}\n"
|
113
104
|
|
@@ -402,7 +393,7 @@ end
|
|
402
393
|
},
|
403
394
|
'null_adapter' => {
|
404
395
|
:build => 'Moneta::Adapters::Null.new',
|
405
|
-
:specs => Specs.new([:null, :not_increment, :not_persist])
|
396
|
+
:specs => Specs.new(:specs => [:null, :not_increment, :not_persist])
|
406
397
|
},
|
407
398
|
'simple_sequel' => {
|
408
399
|
:store => :Sequel,
|
@@ -478,14 +469,14 @@ end
|
|
478
469
|
use :Expires
|
479
470
|
adapter :Memory
|
480
471
|
end},
|
481
|
-
:specs => STANDARD_SPECS.without_transform.with_expires.without_persist
|
472
|
+
:specs => STANDARD_SPECS.without_transform.with_expires.without_persist.returnsame
|
482
473
|
},
|
483
474
|
'expires_memory_with_default_expires' => {
|
484
475
|
:build => %{Moneta.build do
|
485
476
|
use :Expires, :expires => 1
|
486
477
|
adapter :Memory
|
487
478
|
end},
|
488
|
-
:specs => STANDARD_SPECS.without_transform.with_expires.with_default_expires.without_persist
|
479
|
+
:specs => STANDARD_SPECS.without_transform.with_expires.with_default_expires.without_persist.returnsame
|
489
480
|
},
|
490
481
|
'expires_file' => {
|
491
482
|
:build => %{Moneta.build do
|
@@ -522,7 +513,7 @@ end},
|
|
522
513
|
use :Proxy
|
523
514
|
adapter :Memory
|
524
515
|
end},
|
525
|
-
:specs => STANDARD_SPECS.without_transform.with_expires.
|
516
|
+
:specs => STANDARD_SPECS.without_transform.with_expires.returnsame.without_persist
|
526
517
|
},
|
527
518
|
'cache_file_memory' => {
|
528
519
|
:build => %{Moneta.build do
|
@@ -531,7 +522,7 @@ end},
|
|
531
522
|
cache { adapter :Memory }
|
532
523
|
end
|
533
524
|
end},
|
534
|
-
:specs => ADAPTER_SPECS,
|
525
|
+
:specs => ADAPTER_SPECS.returnsame,
|
535
526
|
:tests => %{
|
536
527
|
it 'stores loaded values in cache' do
|
537
528
|
store.backend['foo'] = 'bar'
|
@@ -552,15 +543,15 @@ end
|
|
552
543
|
cache(Moneta::Adapters::Null.new)
|
553
544
|
end
|
554
545
|
end},
|
555
|
-
:specs => ADAPTER_SPECS.without_persist
|
546
|
+
:specs => ADAPTER_SPECS.without_persist.returnsame
|
556
547
|
},
|
557
548
|
'shared' => {
|
558
549
|
:build => %{Moneta.build do
|
559
550
|
use(:Shared, :port => 9001) do
|
560
|
-
adapter :
|
551
|
+
adapter :PStore, :file => File.join(make_tempdir, 'shared')
|
561
552
|
end
|
562
553
|
end},
|
563
|
-
:specs => ADAPTER_SPECS
|
554
|
+
:specs => ADAPTER_SPECS,
|
564
555
|
:tests => %{
|
565
556
|
it 'shares values' do
|
566
557
|
store['shared_key'] = 'shared_value'
|
@@ -576,7 +567,7 @@ end
|
|
576
567
|
use(:Stack) do
|
577
568
|
add(Moneta.new(:Null))
|
578
569
|
add(Moneta::Adapters::Null.new)
|
579
|
-
add { adapter :File, :dir => File.join(make_tempdir, "
|
570
|
+
add { adapter :File, :dir => File.join(make_tempdir, "stack_file_memory") }
|
580
571
|
add { adapter :Memory }
|
581
572
|
end
|
582
573
|
end},
|
@@ -588,17 +579,17 @@ end},
|
|
588
579
|
add(Moneta.new(:Null))
|
589
580
|
add(Moneta::Adapters::Null.new)
|
590
581
|
add { adapter :Memory }
|
591
|
-
add { adapter :File, :dir => File.join(make_tempdir, "
|
582
|
+
add { adapter :File, :dir => File.join(make_tempdir, "stack_memory_file") }
|
592
583
|
end
|
593
584
|
end},
|
594
|
-
:specs => STANDARD_SPECS.without_increment.without_transform.stringkeys_only.stringvalues_only
|
585
|
+
:specs => STANDARD_SPECS.without_increment.returnsame.without_transform.stringkeys_only.stringvalues_only
|
595
586
|
},
|
596
587
|
'lock' => {
|
597
588
|
:build => %{Moneta.build do
|
598
589
|
use :Lock
|
599
590
|
adapter :Memory
|
600
591
|
end},
|
601
|
-
:specs => STANDARD_SPECS.without_transform.
|
592
|
+
:specs => STANDARD_SPECS.without_transform.returnsame.without_persist
|
602
593
|
},
|
603
594
|
'pool' => {
|
604
595
|
:build => %{Moneta.build do
|
@@ -725,7 +716,7 @@ end},
|
|
725
716
|
use :Transformer, :key => :marshal
|
726
717
|
adapter :Memory
|
727
718
|
end},
|
728
|
-
:specs => TRANSFORMER_SPECS,
|
719
|
+
:specs => TRANSFORMER_SPECS.returnsame,
|
729
720
|
:load_value => 'value'
|
730
721
|
},
|
731
722
|
'transformer_value_marshal' => {
|
@@ -749,7 +740,7 @@ end},
|
|
749
740
|
use :Transformer, :key => :yaml
|
750
741
|
adapter :Memory
|
751
742
|
end},
|
752
|
-
:specs => TRANSFORMER_SPECS,
|
743
|
+
:specs => TRANSFORMER_SPECS.returnsame,
|
753
744
|
:load_value => 'value'
|
754
745
|
},
|
755
746
|
'transformer_value_yaml' => {
|
@@ -888,7 +879,7 @@ end
|
|
888
879
|
:specs => ADAPTER_SPECS.without_increment.with_native_expires
|
889
880
|
},
|
890
881
|
'adapter_cassandra_with_default_expires' => {
|
891
|
-
:build => %{Moneta::Adapters::Cassandra.new(:expires => 1)},
|
882
|
+
:build => %{Moneta::Adapters::Cassandra.new(:keyspace => 'adapter_cassandra_with_default_expires', :expires => 1)},
|
892
883
|
:specs => ADAPTER_SPECS.without_increment.with_native_expires.with_default_expires
|
893
884
|
},
|
894
885
|
'adapter_hbase' => {
|
@@ -897,7 +888,7 @@ end
|
|
897
888
|
},
|
898
889
|
'adapter_cookie' => {
|
899
890
|
:build => 'Moneta::Adapters::Cookie.new',
|
900
|
-
:specs => ADAPTER_SPECS.without_persist
|
891
|
+
:specs => ADAPTER_SPECS.without_persist.returnsame
|
901
892
|
},
|
902
893
|
'adapter_couch' => {
|
903
894
|
:build => "Moneta::Adapters::Couch.new(:db => 'adapter_couch')",
|
@@ -949,7 +940,7 @@ end
|
|
949
940
|
},
|
950
941
|
'adapter_daybreak' => {
|
951
942
|
:build => 'Moneta::Adapters::Daybreak.new(:file => File.join(make_tempdir, "adapter_daybreak"))',
|
952
|
-
:specs => ADAPTER_SPECS
|
943
|
+
:specs => ADAPTER_SPECS.returnsame
|
953
944
|
},
|
954
945
|
'adapter_file' => {
|
955
946
|
:build => 'Moneta::Adapters::File.new(:dir => File.join(make_tempdir, "adapter_file"))',
|
@@ -962,7 +953,8 @@ end
|
|
962
953
|
:dir => 'moneta')",
|
963
954
|
# Put Fog into testing mode
|
964
955
|
:preamble => "require 'fog'\nFog.mock!\n",
|
965
|
-
|
956
|
+
# Fog returns same object in mocking mode (in-memory store)
|
957
|
+
:specs => ADAPTER_SPECS.without_increment.returnsame
|
966
958
|
},
|
967
959
|
'adapter_gdbm' => {
|
968
960
|
:build => 'Moneta::Adapters::GDBM.new(:file => File.join(make_tempdir, "adapter_gdbm"))',
|
@@ -998,11 +990,11 @@ end
|
|
998
990
|
},
|
999
991
|
'adapter_memory' => {
|
1000
992
|
:build => 'Moneta::Adapters::Memory.new',
|
1001
|
-
:specs => STANDARD_SPECS.without_transform.
|
993
|
+
:specs => STANDARD_SPECS.without_transform.returnsame.without_persist
|
1002
994
|
},
|
1003
995
|
'adapter_lruhash' => {
|
1004
996
|
:build => 'Moneta::Adapters::LRUHash.new',
|
1005
|
-
:specs => ADAPTER_SPECS.without_persist,
|
997
|
+
:specs => ADAPTER_SPECS.without_persist.returnsame,
|
1006
998
|
:tests => %{
|
1007
999
|
it 'deletes oldest' do
|
1008
1000
|
store = Moneta::Adapters::LRUHash.new(:max_size => 10)
|
@@ -1023,7 +1015,7 @@ end}
|
|
1023
1015
|
:specs => ADAPTER_SPECS.with_native_expires,
|
1024
1016
|
:tests => %{
|
1025
1017
|
it 'automatically deletes expired document' do
|
1026
|
-
store.store('key', 'val', :expires =>
|
1018
|
+
store.store('key', 'val', :expires => 5)
|
1027
1019
|
store.instance_variable_get(:@collection).find_one('_id' => ::BSON::Binary.new('key')).should_not be_nil
|
1028
1020
|
sleep 70 # Mongo needs up to 60 seconds
|
1029
1021
|
store.instance_variable_get(:@collection).find_one('_id' => ::BSON::Binary.new('key')).should be_nil
|
@@ -1082,7 +1074,7 @@ end}
|
|
1082
1074
|
},
|
1083
1075
|
'optionmerger' => {
|
1084
1076
|
:store => :Memory,
|
1085
|
-
:specs => Specs.new
|
1077
|
+
:specs => Specs.new,
|
1086
1078
|
:tests => %{
|
1087
1079
|
it '#with should return OptionMerger' do
|
1088
1080
|
options = {:optionname => :optionvalue}
|
@@ -1160,6 +1152,19 @@ it 'has method #prefix' do
|
|
1160
1152
|
|
1161
1153
|
store.prefix('a').raw.default_options.should == {:store=>{:raw=>true,:prefix=>'a'},:load=>{:raw=>true,:prefix=>'a'},
|
1162
1154
|
:delete=>{:raw=>true,:prefix=>'a'},:key? => {:prefix=>'a'},:increment=>{:prefix=>'a'}}
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
it 'supports adding proxis using #with' do
|
1158
|
+
compressed_store = store.with(:prefix => 'compressed') do
|
1159
|
+
use :Transformer, :value => :zlib
|
1160
|
+
end
|
1161
|
+
store['key'] = 'uncompressed value'
|
1162
|
+
compressed_store['key'] = 'compressed value'
|
1163
|
+
store['key'].should == 'uncompressed value'
|
1164
|
+
compressed_store['key'].should == 'compressed value'
|
1165
|
+
store.key?('compressedkey').should be_true
|
1166
|
+
# Check if value is compressed
|
1167
|
+
compressed_store['key'].should_not == store['compressedkey']
|
1163
1168
|
end}
|
1164
1169
|
},
|
1165
1170
|
}
|
@@ -1299,13 +1304,17 @@ end}
|
|
1299
1304
|
|
1300
1305
|
(SPECS["store_#{key_type}key_#{val_type}value"] ||= []) << code
|
1301
1306
|
|
1302
|
-
|
1307
|
+
if val_type != 'boolean' && val_type != 'nil' && val_type != 'integer'
|
1308
|
+
(SPECS["returndifferent_#{key_type}key_#{val_type}value"] ||= []) << %{it 'guarantees that a different value is retrieved' do
|
1303
1309
|
value = #{val1}
|
1304
|
-
store[#{key1}] =
|
1305
|
-
store[#{key1}].should_not be_equal(
|
1310
|
+
store[#{key1}] = value
|
1311
|
+
store[#{key1}].should_not be_equal(value)
|
1312
|
+
end}
|
1313
|
+
(SPECS["returnsame_#{key_type}key_#{val_type}value"] ||= []) << %{it 'guarantees that the same value is retrieved' do
|
1314
|
+
value = #{val1}
|
1315
|
+
store[#{key1}] = value
|
1316
|
+
store[#{key1}].should be_equal(value)
|
1306
1317
|
end}
|
1307
|
-
if val_type != 'boolean' && val_type != 'nil' && val_type != 'integer'
|
1308
|
-
(SPECS["returndifferent_#{key_type}key_#{val_type}value"] ||= []) << code
|
1309
1318
|
end
|
1310
1319
|
|
1311
1320
|
code = %{it 'persists values' do
|
@@ -1374,9 +1383,9 @@ it 'supports updating the expiration time in load' do
|
|
1374
1383
|
sleep 1
|
1375
1384
|
store.load('key2', :expires => 3).should == 'val2'
|
1376
1385
|
store['key2'].should == 'val2'
|
1377
|
-
sleep
|
1386
|
+
sleep 2
|
1378
1387
|
store['key2'].should == 'val2'
|
1379
|
-
sleep
|
1388
|
+
sleep 2
|
1380
1389
|
store['key2'].should be_nil
|
1381
1390
|
end
|
1382
1391
|
|
@@ -1400,9 +1409,9 @@ it 'supports updating the expiration time in key?' do
|
|
1400
1409
|
sleep 1
|
1401
1410
|
store.key?('key2', :expires => 3).should be_true
|
1402
1411
|
store['key2'].should == 'val2'
|
1403
|
-
sleep
|
1412
|
+
sleep 2
|
1404
1413
|
store['key2'].should == 'val2'
|
1405
|
-
sleep
|
1414
|
+
sleep 2
|
1406
1415
|
store['key2'].should be_nil
|
1407
1416
|
end
|
1408
1417
|
|
@@ -1426,9 +1435,9 @@ it 'supports updating the expiration time in fetch' do
|
|
1426
1435
|
sleep 1
|
1427
1436
|
store.fetch('key1', nil, :expires => 3).should == 'val1'
|
1428
1437
|
store['key1'].should == 'val1'
|
1429
|
-
sleep
|
1438
|
+
sleep 2
|
1430
1439
|
store['key1'].should == 'val1'
|
1431
|
-
sleep
|
1440
|
+
sleep 2
|
1432
1441
|
store['key1'].should be_nil
|
1433
1442
|
end
|
1434
1443
|
|