moneta 0.7.11 → 0.7.12
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.
- data/.travis.yml +2 -0
- data/CHANGES +5 -0
- data/Gemfile +5 -5
- data/Rakefile +2 -2
- data/lib/moneta.rb +1 -1
- data/lib/moneta/adapters/activerecord.rb +15 -5
- data/lib/moneta/adapters/cassandra.rb +1 -2
- data/lib/moneta/adapters/datamapper.rb +1 -1
- data/lib/moneta/adapters/file.rb +17 -17
- data/lib/moneta/adapters/sequel.rb +21 -16
- data/lib/moneta/adapters/sqlite.rb +2 -0
- data/lib/moneta/transformer/config.rb +1 -1
- data/lib/moneta/version.rb +1 -1
- data/script/benchmarks +9 -9
- data/script/generate-specs +73 -27
- data/script/install-bundle +1 -0
- data/spec/helper.rb +5 -3
- data/spec/moneta/adapter_activerecord_spec.rb +5 -3
- data/spec/moneta/adapter_client_spec.rb +2 -0
- data/spec/moneta/adapter_datamapper_spec.rb +6 -5
- data/spec/moneta/adapter_file_spec.rb +2 -0
- data/spec/moneta/adapter_hbase_spec.rb +1 -0
- data/spec/moneta/adapter_memcached_dalli_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_native_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_mongo_spec.rb +2 -0
- data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_pstore_spec.rb +2 -0
- data/spec/moneta/adapter_redis_spec.rb +2 -0
- data/spec/moneta/adapter_redis_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_sequel_spec.rb +3 -1
- data/spec/moneta/adapter_tokyotyrant_spec.rb +2 -0
- data/spec/moneta/adapter_yaml_spec.rb +2 -0
- data/spec/moneta/cache_file_memory_spec.rb +2 -0
- data/spec/moneta/expires_file_spec.rb +2 -0
- data/spec/moneta/pool_spec.rb +2 -0
- data/spec/moneta/proxy_redis_spec.rb +2 -0
- data/spec/moneta/shared_tcp_spec.rb +2 -0
- data/spec/moneta/shared_unix_spec.rb +2 -0
- data/spec/moneta/simple_activerecord_spec.rb +3 -1
- data/spec/moneta/simple_activerecord_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_client_tcp_spec.rb +2 -0
- data/spec/moneta/simple_client_unix_spec.rb +2 -0
- data/spec/moneta/simple_datamapper_spec.rb +2 -1
- data/spec/moneta/simple_datamapper_with_expires_spec.rb +2 -1
- data/spec/moneta/simple_datamapper_with_repository_spec.rb +2 -1
- data/spec/moneta/simple_file_spec.rb +2 -0
- data/spec/moneta/simple_file_with_expires_spec.rb +2 -0
- data/spec/moneta/simple_hashfile_spec.rb +2 -0
- data/spec/moneta/simple_hashfile_with_expires_spec.rb +2 -0
- data/spec/moneta/simple_hbase_spec.rb +1 -0
- data/spec/moneta/simple_hbase_with_expires_spec.rb +2 -0
- data/spec/moneta/simple_memcached_dalli_spec.rb +2 -0
- data/spec/moneta/simple_memcached_native_spec.rb +2 -0
- data/spec/moneta/simple_memcached_spec.rb +2 -0
- data/spec/moneta/simple_mongo_spec.rb +2 -0
- data/spec/moneta/simple_pstore_spec.rb +2 -0
- data/spec/moneta/simple_pstore_with_expires_spec.rb +2 -0
- data/spec/moneta/simple_redis_spec.rb +2 -0
- data/spec/moneta/simple_sequel_spec.rb +3 -1
- data/spec/moneta/simple_sequel_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_tokyotyrant_spec.rb +2 -0
- data/spec/moneta/simple_tokyotyrant_with_expires_spec.rb +2 -0
- data/spec/moneta/simple_yaml_spec.rb +2 -0
- data/spec/moneta/simple_yaml_with_expires_spec.rb +2 -0
- data/spec/moneta/stack_memory_file_spec.rb +2 -0
- data/spec/monetaspecs.rb +50 -0
- data/spec/rack/moneta_cookies_spec.rb +2 -1
- metadata +2 -2
data/.travis.yml
CHANGED
@@ -14,6 +14,8 @@ before_install:
|
|
14
14
|
- script/install-bundle
|
15
15
|
- script/upload-bundle
|
16
16
|
install: 'echo "Bundle installed"'
|
17
|
+
before_script:
|
18
|
+
- mysql -e 'create database moneta;'
|
17
19
|
env:
|
18
20
|
global:
|
19
21
|
- secure: "B0vx1g1CB1A6mM3B/iy2ATicfS4OXT80bb2RVe8mSRsPzez1B4q4Q4hJcaMI\nrMARONN8Krtnti+IqvmDnB0Z0AKYMEyIc+zT37zJOCjLdkLJl+x/thuU/MbC\nvlLVwjMf6JE2EUzTfORDRFYc5ycCqfsfgNk1Go0D2CPT6P9u9uQ="
|
data/CHANGES
CHANGED
data/Gemfile
CHANGED
@@ -29,9 +29,9 @@ gem 'faraday'
|
|
29
29
|
gem 'daybreak'
|
30
30
|
gem 'dm-core'
|
31
31
|
gem 'dm-migrations'
|
32
|
-
gem 'dm-
|
32
|
+
gem 'dm-mysql-adapter'
|
33
33
|
gem 'fog'
|
34
|
-
gem 'activerecord', '>= 3.2.
|
34
|
+
gem 'activerecord', '>= 3.2.11'
|
35
35
|
gem 'redis'
|
36
36
|
gem 'mongo'
|
37
37
|
gem 'sequel'
|
@@ -53,9 +53,9 @@ end
|
|
53
53
|
gem 'memcached', :platforms => :ruby
|
54
54
|
gem 'jruby-memcached', :platforms => :jruby
|
55
55
|
gem 'sqlite3', :platforms => :ruby
|
56
|
-
gem 'jdbc-sqlite3', :platforms => :jruby
|
57
56
|
gem 'activerecord-jdbc-adapter', :platforms => :jruby
|
58
|
-
gem 'activerecord-
|
57
|
+
gem 'activerecord-jdbcmysql-adapter', :platforms => :jruby
|
58
|
+
gem 'mysql2', '>= 0.3.12b5', :platforms => :ruby
|
59
59
|
# gdbm for jruby needs ffi
|
60
60
|
gem 'ffi', :platforms => :jruby
|
61
61
|
gem 'gdbm', :platforms => :jruby
|
@@ -65,5 +65,5 @@ gem 'rack'
|
|
65
65
|
gem 'rack-cache'
|
66
66
|
|
67
67
|
# Rails integration testing
|
68
|
-
gem 'actionpack'
|
68
|
+
gem 'actionpack', '>= 3.2.11'
|
69
69
|
gem 'minitest'
|
data/Rakefile
CHANGED
@@ -33,8 +33,8 @@ task :test do
|
|
33
33
|
# QuickLZ is also not maintained on Github, but on Bitbucket
|
34
34
|
# and I don't know where the issue tracker is.
|
35
35
|
#
|
36
|
-
# *
|
37
|
-
unstable = specs.select {|s| s =~ /quicklz|
|
36
|
+
# * Cassandra fails spuriously (An expert has to check the adapter!)
|
37
|
+
unstable = specs.select {|s| s =~ /quicklz|cassandra/ }
|
38
38
|
specs -= unstable
|
39
39
|
|
40
40
|
if group =~ /^(\d+)\/(\d+)$/
|
data/lib/moneta.rb
CHANGED
@@ -103,7 +103,7 @@ module Moneta
|
|
103
103
|
raise ArgumentError, 'Name must be Symbol' unless Symbol === name
|
104
104
|
case name
|
105
105
|
when :Sequel, :ActiveRecord, :Couch, :DataMapper
|
106
|
-
# Sequel accept only base64 keys and values
|
106
|
+
# Sequel, DataMapper and AR accept only base64 keys and values
|
107
107
|
# FIXME: Couch should work only with :marshal but this raises an error on 1.9
|
108
108
|
transformer[:key] << :base64
|
109
109
|
transformer[:value] << :base64
|
@@ -78,11 +78,21 @@ module Moneta
|
|
78
78
|
|
79
79
|
# (see Proxy#increment)
|
80
80
|
def increment(key, amount = 1, options = {})
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
@table.transaction do
|
82
|
+
if record = @table.where(:k => key).lock.first
|
83
|
+
value = Utils.to_int(record.v) + amount
|
84
|
+
record.v = value.to_s
|
85
|
+
record.save
|
86
|
+
value
|
87
|
+
elsif create(key, amount.to_s, options)
|
88
|
+
amount
|
89
|
+
else
|
90
|
+
raise 'Concurrent modification'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
rescue
|
94
|
+
tries ||= 0
|
95
|
+
(tries += 1) < 10 ? retry : raise
|
86
96
|
end
|
87
97
|
|
88
98
|
# (see Proxy#create)
|
@@ -62,8 +62,7 @@ module Moneta
|
|
62
62
|
|
63
63
|
# (see Proxy#load)
|
64
64
|
def load(key, options = {})
|
65
|
-
value = @backend.get(@cf, key)
|
66
|
-
if value
|
65
|
+
if value = @backend.get(@cf, key)
|
67
66
|
expires = expires_value(options, nil)
|
68
67
|
@backend.insert(@cf, key, {'value' => value['value'] }, :ttl => expires || nil) if expires != nil
|
69
68
|
value['value']
|
data/lib/moneta/adapters/file.rb
CHANGED
@@ -6,9 +6,7 @@ module Moneta
|
|
6
6
|
# @api public
|
7
7
|
class File
|
8
8
|
include Defaults
|
9
|
-
|
10
|
-
|
11
|
-
supports :create
|
9
|
+
supports :create, :increment
|
12
10
|
|
13
11
|
# @param [Hash] options
|
14
12
|
# @option options [String] :dir Directory where files will be stored
|
@@ -64,7 +62,22 @@ module Moneta
|
|
64
62
|
|
65
63
|
# (see Proxy#increment)
|
66
64
|
def increment(key, amount = 1, options = {})
|
67
|
-
|
65
|
+
path = store_path(key)
|
66
|
+
::File.open(path, 'rb+') do |f|
|
67
|
+
Thread.pass until f.flock(::File::LOCK_EX)
|
68
|
+
value = Utils.to_int(f.read) + amount
|
69
|
+
f.truncate(0)
|
70
|
+
f.pos = 0
|
71
|
+
f.write(value.to_s)
|
72
|
+
value
|
73
|
+
end
|
74
|
+
rescue Errno::ENOENT
|
75
|
+
if create(key, amount.to_s, options)
|
76
|
+
amount
|
77
|
+
else
|
78
|
+
# Concurrent modification
|
79
|
+
retry
|
80
|
+
end
|
68
81
|
end
|
69
82
|
|
70
83
|
# (see Proxy#create)
|
@@ -82,19 +95,6 @@ module Moneta
|
|
82
95
|
|
83
96
|
protected
|
84
97
|
|
85
|
-
def lock(key, &block)
|
86
|
-
path = store_path(key)
|
87
|
-
return yield unless ::File.exist?(path)
|
88
|
-
::File.open(path, 'r+') do |f|
|
89
|
-
begin
|
90
|
-
Thread.pass until f.flock(::File::LOCK_EX)
|
91
|
-
yield
|
92
|
-
ensure
|
93
|
-
f.flock(::File::LOCK_UN)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
98
|
def store_path(key)
|
99
99
|
::File.join(@dir, key)
|
100
100
|
end
|
@@ -16,7 +16,7 @@ module Moneta
|
|
16
16
|
# @option options All other options passed to `Sequel#connect`
|
17
17
|
# @option options [Sequel connection] :backend Use existing backend instance
|
18
18
|
def initialize(options = {})
|
19
|
-
table = options.delete(:table) || :moneta
|
19
|
+
table = (options.delete(:table) || :moneta).to_sym
|
20
20
|
@backend = options[:backend] ||
|
21
21
|
begin
|
22
22
|
raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
|
@@ -42,12 +42,10 @@ module Moneta
|
|
42
42
|
|
43
43
|
# (see Proxy#store)
|
44
44
|
def store(key, value, options = {})
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@table.update(:k => key, :v => value)
|
50
|
-
end
|
45
|
+
begin
|
46
|
+
@table.insert(:k => key, :v => value)
|
47
|
+
rescue ::Sequel::DatabaseError
|
48
|
+
@table.where(:k => key).update(:v => value)
|
51
49
|
end
|
52
50
|
value
|
53
51
|
rescue ::Sequel::DatabaseError
|
@@ -57,9 +55,7 @@ module Moneta
|
|
57
55
|
|
58
56
|
# (see Proxy#store)
|
59
57
|
def create(key, value, options = {})
|
60
|
-
@
|
61
|
-
@table.insert(:k => key, :v => value)
|
62
|
-
end
|
58
|
+
@table.insert(:k => key, :v => value)
|
63
59
|
true
|
64
60
|
rescue ::Sequel::DatabaseError
|
65
61
|
# FIXME: This catches too many errors
|
@@ -73,22 +69,25 @@ module Moneta
|
|
73
69
|
locked_table = @table.for_update
|
74
70
|
if record = locked_table[:k => key]
|
75
71
|
value = Utils.to_int(record[:v]) + amount
|
76
|
-
locked_table.
|
72
|
+
locked_table.where(:k => key).update(:v => value.to_s)
|
77
73
|
value
|
78
74
|
else
|
79
75
|
locked_table.insert(:k => key, :v => amount.to_s)
|
80
76
|
amount
|
81
77
|
end
|
82
78
|
end
|
79
|
+
rescue ::Sequel::DatabaseError
|
80
|
+
# FIXME: This catches too many errors
|
81
|
+
# it should only catch a not-unique-exception
|
82
|
+
tries ||= 0
|
83
|
+
(tries += 1) < 10 ? retry : raise
|
83
84
|
end
|
84
85
|
|
85
86
|
# (see Proxy#delete)
|
86
87
|
def delete(key, options = {})
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
value
|
91
|
-
end
|
88
|
+
if value = load(key, options)
|
89
|
+
@table.filter(:k => key).delete
|
90
|
+
value
|
92
91
|
end
|
93
92
|
end
|
94
93
|
|
@@ -97,6 +96,12 @@ module Moneta
|
|
97
96
|
@table.delete
|
98
97
|
self
|
99
98
|
end
|
99
|
+
|
100
|
+
# (see Proxy#close)
|
101
|
+
def close
|
102
|
+
@backend.disconnect
|
103
|
+
nil
|
104
|
+
end
|
100
105
|
end
|
101
106
|
end
|
102
107
|
end
|
@@ -14,6 +14,7 @@ module Moneta
|
|
14
14
|
# @param [Hash] options
|
15
15
|
# @option options [String] :file Database file
|
16
16
|
# @option options [String] :table ('moneta') Table name
|
17
|
+
# @option options [Fixnum] :busy_timeout (1000) Sqlite timeout if database is busy
|
17
18
|
# @option options [::Sqlite3::Database] :backend Use existing backend instance
|
18
19
|
def initialize(options = {})
|
19
20
|
table = options[:table] || 'moneta'
|
@@ -22,6 +23,7 @@ module Moneta
|
|
22
23
|
raise ArgumentError, 'Option :file is required' unless options[:file]
|
23
24
|
::SQLite3::Database.new(options[:file])
|
24
25
|
end
|
26
|
+
@backend.busy_timeout(options[:busy_timeout] || 1000)
|
25
27
|
@backend.execute("create table if not exists #{table} (k blob not null primary key, v blob)")
|
26
28
|
@stmts =
|
27
29
|
[@select = @backend.prepare("select v from #{table} where k = ?"),
|
@@ -25,7 +25,7 @@ module Moneta
|
|
25
25
|
[ :encode, "%s.unpack('m').first", "[%s].pack('m').gsub(\"\n\", '')" ],
|
26
26
|
:escape => [ :encode, 'Helper.unescape(%s)', 'Helper.escape(%s)' ],
|
27
27
|
:hmac => [ :hmac, 'Helper.hmacverify(%s, options[:secret] || @secret)',
|
28
|
-
'Helper.hmacsign(%s, options[:secret] || @secret)',
|
28
|
+
'Helper.hmacsign(%s, options[:secret] || @secret)', 'openssl' ],
|
29
29
|
:truncate => [ :truncate, nil, 'Helper.truncate(%s, @maxlen)', 'digest/md5' ],
|
30
30
|
:md5 => [ :digest, nil, '::Digest::MD5.hexdigest(%s)', 'digest/md5' ],
|
31
31
|
:rmd160 => [ :digest, nil, '::Digest::RMD160.hexdigest(%s)', 'digest/rmd160' ],
|
data/lib/moneta/version.rb
CHANGED
data/script/benchmarks
CHANGED
@@ -34,18 +34,18 @@ class MonetaBenchmarks
|
|
34
34
|
# SDBM is unstable, YAML is too slow
|
35
35
|
# :SDBM => { :file => "#{DIR}/sdbm" },
|
36
36
|
# :YAML => { :file => "#{DIR}/yaml" },
|
37
|
-
:ActiveRecord => { :connection => { :adapter
|
37
|
+
:ActiveRecord => { :table => 'activerecord', :connection => { :adapter => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'), :database => 'moneta' } },
|
38
38
|
:Cassandra => {},
|
39
39
|
:Client => {},
|
40
40
|
:Couch => {},
|
41
41
|
:DBM => { :file => "#{DIR}/dbm" },
|
42
|
-
:DataMapper => { :setup =>
|
42
|
+
:DataMapper => { :setup => 'mysql://root:@localhost/moneta', :table => 'datamapper' },
|
43
43
|
:Daybreak => { :file => "#{DIR}/daybreak" },
|
44
44
|
:File => { :dir => "#{DIR}/file" },
|
45
45
|
:GDBM => { :file => "#{DIR}/gdbm" },
|
46
46
|
:HBase => {},
|
47
47
|
:HashFile => { :dir => "#{DIR}/hashfile" },
|
48
|
-
:KyotoCabinet => { :file =>
|
48
|
+
:KyotoCabinet => { :file => "#{DIR}/kyotocabinet.kch" },
|
49
49
|
:LRUHash => {},
|
50
50
|
:LevelDB => { :dir => "#{DIR}/leveldb" },
|
51
51
|
:LocalMemCache => { :file => "#{DIR}/lmc" },
|
@@ -57,10 +57,10 @@ class MonetaBenchmarks
|
|
57
57
|
:Redis => {},
|
58
58
|
:RestClient => { :url => 'http://localhost:8808/' },
|
59
59
|
:Riak => {},
|
60
|
-
:Sequel => { :db => '
|
60
|
+
:Sequel => { :db => (defined?(JRUBY_VERSION) ? 'jdbc:mysql' : 'mysql2') + '://root:@localhost/moneta', :table => 'sequel' },
|
61
61
|
:Sqlite => { :file => ':memory:' },
|
62
62
|
:TDB => { :file => "#{DIR}/tdb" },
|
63
|
-
:TokyoCabinet => { :file =>
|
63
|
+
:TokyoCabinet => { :file => "#{DIR}/tokyocabinet" },
|
64
64
|
:TokyoTyrant => {},
|
65
65
|
}
|
66
66
|
|
@@ -79,7 +79,7 @@ class MonetaBenchmarks
|
|
79
79
|
:runs => 3,
|
80
80
|
:keys => 1000,
|
81
81
|
:min_key_len => 3,
|
82
|
-
:max_key_len =>
|
82
|
+
:max_key_len => 128,
|
83
83
|
:key_dist => :uniform,
|
84
84
|
:min_val_len => 0,
|
85
85
|
:max_val_len => 1024,
|
@@ -89,7 +89,7 @@ class MonetaBenchmarks
|
|
89
89
|
:runs => 3,
|
90
90
|
:keys => 100,
|
91
91
|
:min_key_len => 3,
|
92
|
-
:max_key_len =>
|
92
|
+
:max_key_len => 128,
|
93
93
|
:key_dist => :uniform,
|
94
94
|
:min_val_len => 0,
|
95
95
|
:max_val_len => 10240,
|
@@ -109,7 +109,7 @@ class MonetaBenchmarks
|
|
109
109
|
:runs => 3,
|
110
110
|
:keys => 1000,
|
111
111
|
:min_key_len => 3,
|
112
|
-
:max_key_len =>
|
112
|
+
:max_key_len => 128,
|
113
113
|
:key_dist => :normal,
|
114
114
|
:min_val_len => 0,
|
115
115
|
:max_val_len => 1024,
|
@@ -119,7 +119,7 @@ class MonetaBenchmarks
|
|
119
119
|
:runs => 3,
|
120
120
|
:keys => 100,
|
121
121
|
:min_key_len => 3,
|
122
|
-
:max_key_len =>
|
122
|
+
:max_key_len => 128,
|
123
123
|
:key_dist => :normal,
|
124
124
|
:min_val_len => 0,
|
125
125
|
:max_val_len => 10240,
|
data/script/generate-specs
CHANGED
@@ -38,15 +38,19 @@ class Specs
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def without_increment
|
41
|
-
new(:specs => specs - [:increment] + [:not_increment])
|
41
|
+
new(:specs => specs - [:increment, :concurrent_increment] + [:not_increment])
|
42
|
+
end
|
43
|
+
|
44
|
+
def without_concurrent
|
45
|
+
new(:specs => specs - [:concurrent_increment, :concurrent_create])
|
42
46
|
end
|
43
47
|
|
44
48
|
def without_persist
|
45
|
-
new(:specs => specs - [:persist, :multiprocess] + [:not_persist])
|
49
|
+
new(:specs => specs - [:persist, :multiprocess, :concurrent_increment, :concurrent_create] + [:not_persist])
|
46
50
|
end
|
47
51
|
|
48
52
|
def without_multiprocess
|
49
|
-
new(:specs => specs - [:multiprocess])
|
53
|
+
new(:specs => specs - [:multiprocess, :concurrent_increment, :concurrent_create])
|
50
54
|
end
|
51
55
|
|
52
56
|
def with_expires
|
@@ -95,12 +99,12 @@ class Specs
|
|
95
99
|
end
|
96
100
|
|
97
101
|
def without_create
|
98
|
-
new(:specs => specs - [:create, :create_expires] + [:not_create])
|
102
|
+
new(:specs => specs - [:create, :concurrent_create, :create_expires] + [:not_create])
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
|
-
ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :persist, :multiprocess, :create, :features], :key => %w(string), :value => %w(string))
|
103
|
-
STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist, :multiprocess, :create, :features])
|
106
|
+
ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :concurrent_increment, :concurrent_create, :persist, :multiprocess, :create, :features], :key => %w(string), :value => %w(string))
|
107
|
+
STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :concurrent_increment, :concurrent_create, :persist, :multiprocess, :create, :features])
|
104
108
|
TRANSFORMER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :transform_value, :increment, :create, :features])
|
105
109
|
|
106
110
|
header = "# Generated by #{File.basename(__FILE__)}\n"
|
@@ -352,12 +356,12 @@ end
|
|
352
356
|
'simple_sqlite' => {
|
353
357
|
:store => :Sqlite,
|
354
358
|
:options => ':file => File.join(make_tempdir, "simple_sqlite")',
|
355
|
-
:specs => STANDARD_SPECS
|
359
|
+
:specs => STANDARD_SPECS.without_concurrent
|
356
360
|
},
|
357
361
|
'simple_sqlite_with_expires' => {
|
358
362
|
:store => :Sqlite,
|
359
363
|
:options => ':file => File.join(make_tempdir, "simple_sqlite_with_expires"), :expires => true',
|
360
|
-
:specs => STANDARD_SPECS.with_expires
|
364
|
+
:specs => STANDARD_SPECS.with_expires.without_concurrent
|
361
365
|
},
|
362
366
|
'simple_redis' => {
|
363
367
|
:store => :Redis,
|
@@ -419,27 +423,27 @@ end
|
|
419
423
|
},
|
420
424
|
'simple_sequel' => {
|
421
425
|
:store => :Sequel,
|
422
|
-
:options => ':db => (defined?(JRUBY_VERSION) ? "jdbc:
|
426
|
+
:options => ':db => (defined?(JRUBY_VERSION) ? "jdbc:mysql" : "mysql2") + "://root:@localhost/moneta", :table => "simple_sequel"',
|
423
427
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)',
|
424
428
|
:specs => STANDARD_SPECS
|
425
429
|
},
|
426
430
|
'simple_sequel_with_expires' => {
|
427
431
|
:store => :Sequel,
|
428
|
-
:options => ':db => (defined?(JRUBY_VERSION) ? "jdbc:
|
432
|
+
:options => ':db => (defined?(JRUBY_VERSION) ? "jdbc:mysql" : "mysql2") + "://root:@localhost/moneta", :table => "simple_sequel_with_expires", :expires => true',
|
429
433
|
:specs => STANDARD_SPECS.with_expires,
|
430
434
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)'
|
431
435
|
},
|
432
436
|
'simple_datamapper' => {
|
433
437
|
:store => :DataMapper,
|
434
438
|
:specs => STANDARD_SPECS.without_increment,
|
435
|
-
:options => ':setup => "
|
439
|
+
:options => ':setup => "mysql://root:@localhost/moneta", :table => "simple_datamapper"',
|
436
440
|
# DataMapper needs default repository to be setup
|
437
441
|
:preamble => "require 'dm-core'\nDataMapper.setup(:default, :adapter => :in_memory)\n",
|
438
442
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)'
|
439
443
|
},
|
440
444
|
'simple_datamapper_with_expires' => {
|
441
445
|
:store => :DataMapper,
|
442
|
-
:options => ':setup => "
|
446
|
+
:options => ':setup => "mysql://root:@localhost/moneta", :table => "simple_datamapper_with_expires", :expires => true',
|
443
447
|
# DataMapper needs default repository to be setup
|
444
448
|
:preamble => "require 'dm-core'\nDataMapper.setup(:default, :adapter => :in_memory)\n",
|
445
449
|
:specs => STANDARD_SPECS.without_increment.with_expires,
|
@@ -448,7 +452,7 @@ end
|
|
448
452
|
'simple_datamapper_with_repository' => {
|
449
453
|
:store => :DataMapper,
|
450
454
|
:specs => STANDARD_SPECS.without_increment,
|
451
|
-
:options => ':repository => :repo, :setup => "
|
455
|
+
:options => ':repository => :repo, :setup => "mysql://root:@localhost/moneta", :table => "simple_datamapper_with_repository"',
|
452
456
|
# DataMapper needs default repository to be setup
|
453
457
|
:preamble => "require 'dm-core'\nDataMapper.setup(:default, :adapter => :in_memory)\n",
|
454
458
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)'
|
@@ -456,12 +460,12 @@ end
|
|
456
460
|
'simple_activerecord' => {
|
457
461
|
:store => :ActiveRecord,
|
458
462
|
:specs => STANDARD_SPECS,
|
459
|
-
:options => ":connection => { :adapter => (defined?(JRUBY_VERSION) ? '
|
463
|
+
:options => ":table => 'simple_activerecord', :connection => { :adapter => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'), :database => 'moneta' }",
|
460
464
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)'
|
461
465
|
},
|
462
466
|
'simple_activerecord_with_expires' => {
|
463
467
|
:store => :ActiveRecord,
|
464
|
-
:options => ":connection => { :adapter => (defined?(JRUBY_VERSION) ? '
|
468
|
+
:options => ":table => 'simple_activerecord_with_expires', :connection => { :adapter => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'), :database => 'moneta' }, :expires => true",
|
465
469
|
:specs => STANDARD_SPECS.with_expires,
|
466
470
|
:load_value => '::Marshal.load(value.unpack(\'m\').first)'
|
467
471
|
},
|
@@ -491,14 +495,14 @@ end
|
|
491
495
|
use :WeakCreate
|
492
496
|
adapter :Couch, :db => 'weak_create'
|
493
497
|
end},
|
494
|
-
:specs => ADAPTER_SPECS.without_increment
|
498
|
+
:specs => ADAPTER_SPECS.without_increment.without_concurrent
|
495
499
|
},
|
496
500
|
'weak_increment' => {
|
497
501
|
:build => %{Moneta.build do
|
498
502
|
use :WeakIncrement
|
499
503
|
adapter :Couch, :db => 'weak_increment'
|
500
504
|
end},
|
501
|
-
:specs => ADAPTER_SPECS.without_create
|
505
|
+
:specs => ADAPTER_SPECS.without_create.without_concurrent
|
502
506
|
},
|
503
507
|
'expires_memory' => {
|
504
508
|
:build => %{Moneta.build do
|
@@ -1097,7 +1101,7 @@ it 'compile transformer class' do
|
|
1097
1101
|
end}
|
1098
1102
|
},
|
1099
1103
|
'adapter_activerecord' => {
|
1100
|
-
:build => "Moneta::Adapters::ActiveRecord.new(:connection => { :adapter => (defined?(JRUBY_VERSION) ? '
|
1104
|
+
:build => "Moneta::Adapters::ActiveRecord.new(:table => 'adapter_activerecord', :connection => { :adapter => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'), :database => 'moneta' })",
|
1101
1105
|
:specs => ADAPTER_SPECS,
|
1102
1106
|
:tests => %{
|
1103
1107
|
it 'updates an existing key/value' do
|
@@ -1108,9 +1112,9 @@ it 'updates an existing key/value' do
|
|
1108
1112
|
end
|
1109
1113
|
|
1110
1114
|
it 'uses an existing connection' do
|
1111
|
-
ActiveRecord::Base.establish_connection :adapter => (defined?(JRUBY_VERSION) ? '
|
1115
|
+
ActiveRecord::Base.establish_connection :adapter => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'), :database => 'moneta'
|
1112
1116
|
|
1113
|
-
store = Moneta::Adapters::ActiveRecord.new
|
1117
|
+
store = Moneta::Adapters::ActiveRecord.new(:table => 'activerecord_existing')
|
1114
1118
|
store.table.should be_table_exists
|
1115
1119
|
end
|
1116
1120
|
}
|
@@ -1146,16 +1150,16 @@ end
|
|
1146
1150
|
:specs => ADAPTER_SPECS.without_increment.without_create
|
1147
1151
|
},
|
1148
1152
|
'adapter_datamapper' => {
|
1149
|
-
:build => 'Moneta::Adapters::DataMapper.new(:setup => "
|
1153
|
+
:build => 'Moneta::Adapters::DataMapper.new(:setup => "mysql://root:@localhost/moneta", :table => "adapter_datamapper")',
|
1150
1154
|
# DataMapper needs default repository to be setup
|
1151
1155
|
:preamble => "require 'dm-core'\nDataMapper.setup(:default, :adapter => :in_memory)\n",
|
1152
1156
|
:specs => ADAPTER_SPECS.without_increment,
|
1153
1157
|
:tests => %q{
|
1154
1158
|
it 'does not cross contaminate when storing' do
|
1155
|
-
first = Moneta::Adapters::DataMapper.new(:setup => "
|
1159
|
+
first = Moneta::Adapters::DataMapper.new(:setup => "mysql://root:@localhost/moneta", :table => "datamapper_first")
|
1156
1160
|
first.clear
|
1157
1161
|
|
1158
|
-
second = Moneta::Adapters::DataMapper.new(:repository => :sample, :setup => "
|
1162
|
+
second = Moneta::Adapters::DataMapper.new(:repository => :sample, :setup => "mysql://root:@localhost/moneta", :table => "datamapper_second")
|
1159
1163
|
second.clear
|
1160
1164
|
|
1161
1165
|
first['key'] = 'value'
|
@@ -1166,10 +1170,10 @@ it 'does not cross contaminate when storing' do
|
|
1166
1170
|
end
|
1167
1171
|
|
1168
1172
|
it 'does not cross contaminate when deleting' do
|
1169
|
-
first = Moneta::Adapters::DataMapper.new(:setup => "
|
1173
|
+
first = Moneta::Adapters::DataMapper.new(:setup => "mysql://root:@localhost/moneta", :table => "datamapper_first")
|
1170
1174
|
first.clear
|
1171
1175
|
|
1172
|
-
second = Moneta::Adapters::DataMapper.new(:repository => :sample, :setup => "
|
1176
|
+
second = Moneta::Adapters::DataMapper.new(:repository => :sample, :setup => "mysql://root:@localhost/moneta", :table => "datamapper_second")
|
1173
1177
|
second.clear
|
1174
1178
|
|
1175
1179
|
first['key'] = 'value'
|
@@ -1304,12 +1308,12 @@ end}
|
|
1304
1308
|
:specs => ADAPTER_SPECS.without_multiprocess
|
1305
1309
|
},
|
1306
1310
|
'adapter_sequel' => {
|
1307
|
-
:build => 'Moneta::Adapters::Sequel.new(:db => (defined?(JRUBY_VERSION) ? "jdbc:
|
1311
|
+
:build => 'Moneta::Adapters::Sequel.new(:db => (defined?(JRUBY_VERSION) ? "jdbc:mysql" : "mysql2") + "://root:@localhost/moneta", :table => "adapter_sequel")',
|
1308
1312
|
:specs => ADAPTER_SPECS
|
1309
1313
|
},
|
1310
1314
|
'adapter_sqlite' => {
|
1311
1315
|
:build => 'Moneta::Adapters::Sqlite.new(:file => File.join(make_tempdir, "adapter_sqlite"))',
|
1312
|
-
:specs => ADAPTER_SPECS
|
1316
|
+
:specs => ADAPTER_SPECS.without_concurrent
|
1313
1317
|
},
|
1314
1318
|
'adapter_kyotocabinet' => {
|
1315
1319
|
:build => 'Moneta::Adapters::KyotoCabinet.new(:file => File.join(make_tempdir, "adapter_kyotocabinet.kch"))',
|
@@ -1966,6 +1970,48 @@ it 'does not support #decrement' do
|
|
1966
1970
|
end.to raise_error(NotImplementedError)
|
1967
1971
|
end}
|
1968
1972
|
|
1973
|
+
SPECS['concurrent_increment'] = %{def increment_thread(name)
|
1974
|
+
Thread.new do
|
1975
|
+
s = new_store
|
1976
|
+
1000.times do |i|
|
1977
|
+
s.increment('counter')
|
1978
|
+
s.store("\#{name}\#{i}", i.to_s, :expires => false)
|
1979
|
+
sleep 0.01 if i % 100 == 0
|
1980
|
+
end
|
1981
|
+
s.close
|
1982
|
+
end
|
1983
|
+
end
|
1984
|
+
|
1985
|
+
it 'have atomic increment across multiple processes' do
|
1986
|
+
a = increment_thread('a')
|
1987
|
+
b = increment_thread('b')
|
1988
|
+
a.join
|
1989
|
+
b.join
|
1990
|
+
1000.times do |i|
|
1991
|
+
store["a\#{i}"].should == i.to_s
|
1992
|
+
store["b\#{i}"].should == i.to_s
|
1993
|
+
end
|
1994
|
+
store.raw['counter'].should == 2000.to_s
|
1995
|
+
end}
|
1996
|
+
|
1997
|
+
SPECS['concurrent_create'] = %{def create_thread(name)
|
1998
|
+
a = Thread.new do
|
1999
|
+
s = new_store
|
2000
|
+
1000.times do |i|
|
2001
|
+
s[i.to_s].should == name if s.create(i.to_s, name, :expires => false)
|
2002
|
+
sleep 0.01 if i % 100 == 0
|
2003
|
+
end
|
2004
|
+
s.close
|
2005
|
+
end
|
2006
|
+
end
|
2007
|
+
|
2008
|
+
it 'have atomic create across multiple processes' do
|
2009
|
+
a = create_thread('a')
|
2010
|
+
b = create_thread('b')
|
2011
|
+
a.join
|
2012
|
+
b.join
|
2013
|
+
end}
|
2014
|
+
|
1969
2015
|
SPECS['increment'] = %{it 'initializes in #increment with 1' do
|
1970
2016
|
store.key?('inckey').should be_false
|
1971
2017
|
store.increment('inckey').should == 1
|