moneta 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +35 -38
- data/CHANGES +9 -0
- data/CONTRIBUTORS +2 -0
- data/Gemfile +143 -55
- data/README.md +5 -4
- data/lib/moneta/adapter.rb +52 -0
- data/lib/moneta/adapters/activerecord.rb +77 -68
- data/lib/moneta/adapters/activesupportcache.rb +22 -31
- data/lib/moneta/adapters/cassandra.rb +114 -116
- data/lib/moneta/adapters/client.rb +17 -18
- data/lib/moneta/adapters/couch.rb +31 -26
- data/lib/moneta/adapters/datamapper.rb +9 -5
- data/lib/moneta/adapters/daybreak.rb +15 -21
- data/lib/moneta/adapters/dbm.rb +6 -12
- data/lib/moneta/adapters/file.rb +21 -13
- data/lib/moneta/adapters/fog.rb +5 -6
- data/lib/moneta/adapters/gdbm.rb +6 -12
- data/lib/moneta/adapters/hbase.rb +10 -12
- data/lib/moneta/adapters/kyotocabinet.rb +22 -27
- data/lib/moneta/adapters/leveldb.rb +14 -20
- data/lib/moneta/adapters/lmdb.rb +19 -22
- data/lib/moneta/adapters/localmemcache.rb +7 -13
- data/lib/moneta/adapters/lruhash.rb +20 -20
- data/lib/moneta/adapters/memcached/dalli.rb +25 -33
- data/lib/moneta/adapters/memcached/native.rb +14 -20
- data/lib/moneta/adapters/memory.rb +5 -7
- data/lib/moneta/adapters/mongo.rb +53 -52
- data/lib/moneta/adapters/pstore.rb +21 -27
- data/lib/moneta/adapters/redis.rb +42 -37
- data/lib/moneta/adapters/restclient.rb +17 -25
- data/lib/moneta/adapters/riak.rb +8 -9
- data/lib/moneta/adapters/sdbm.rb +6 -12
- data/lib/moneta/adapters/sequel/mysql.rb +8 -8
- data/lib/moneta/adapters/sequel/postgres.rb +17 -17
- data/lib/moneta/adapters/sequel/postgres_hstore.rb +47 -47
- data/lib/moneta/adapters/sequel/sqlite.rb +9 -9
- data/lib/moneta/adapters/sequel.rb +56 -65
- data/lib/moneta/adapters/sqlite.rb +37 -35
- data/lib/moneta/adapters/tdb.rb +8 -14
- data/lib/moneta/adapters/tokyocabinet.rb +19 -17
- data/lib/moneta/adapters/tokyotyrant.rb +29 -30
- data/lib/moneta/adapters/yaml.rb +1 -5
- data/lib/moneta/config.rb +101 -0
- data/lib/moneta/expires.rb +0 -1
- data/lib/moneta/expires_support.rb +3 -4
- data/lib/moneta/pool.rb +1 -1
- data/lib/moneta/proxy.rb +29 -0
- data/lib/moneta/server.rb +21 -14
- data/lib/moneta/version.rb +1 -1
- data/lib/moneta/wrapper.rb +5 -0
- data/lib/moneta.rb +2 -0
- data/moneta.gemspec +1 -0
- data/spec/moneta/adapters/client/client_helper.rb +4 -3
- data/spec/moneta/adapters/faraday_helper.rb +3 -2
- data/spec/moneta/adapters/lruhash/adapter_lruhash_spec.rb +10 -6
- data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +2 -2
- data/spec/moneta/config_spec.rb +219 -0
- data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +3 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +2 -0
- data/spec/rack/session_moneta_spec.rb +44 -25
- data/spec/restserver.rb +3 -14
- metadata +24 -6
@@ -4,47 +4,39 @@ module Moneta
|
|
4
4
|
module Adapters
|
5
5
|
# Memcached backend (using gem dalli)
|
6
6
|
# @api public
|
7
|
-
class MemcachedDalli
|
8
|
-
include Defaults
|
7
|
+
class MemcachedDalli < Adapter
|
9
8
|
include ExpiresSupport
|
10
9
|
|
11
10
|
supports :create, :increment
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
self.default_expires = options.delete(:expires)
|
21
|
-
@backend = options[:backend] ||
|
22
|
-
begin
|
23
|
-
server = options.delete(:server) || '127.0.0.1:11211'
|
24
|
-
::Dalli::Client.new(server, options)
|
25
|
-
end
|
26
|
-
end
|
11
|
+
|
12
|
+
# @!method initialize(options = {})
|
13
|
+
# @param [Hash] options
|
14
|
+
# @option options [String] :server ('127.0.0.1:11211') Memcached server
|
15
|
+
# @option options [Integer] :expires Default expiration time
|
16
|
+
# @option options [::Dalli::Client] :backend Use existing backend instance
|
17
|
+
# @option options Other options passed to `Dalli::Client#new`
|
18
|
+
backend { |server: '127.0.0.1:11211', **options| ::Dalli::Client.new(server, options) }
|
27
19
|
|
28
20
|
# (see Proxy#load)
|
29
21
|
def load(key, options = {})
|
30
|
-
value =
|
22
|
+
value = backend.get(key)
|
31
23
|
if value
|
32
24
|
expires = expires_value(options, nil)
|
33
|
-
|
25
|
+
backend.set(key, value, expires || nil, raw: true) if expires != nil
|
34
26
|
value
|
35
27
|
end
|
36
28
|
end
|
37
29
|
|
38
30
|
# (see Proxy#store)
|
39
31
|
def store(key, value, options = {})
|
40
|
-
|
32
|
+
backend.set(key, value, expires_value(options) || nil, raw: true)
|
41
33
|
value
|
42
34
|
end
|
43
35
|
|
44
36
|
# (see Proxy#delete)
|
45
37
|
def delete(key, options = {})
|
46
|
-
value =
|
47
|
-
|
38
|
+
value = backend.get(key)
|
39
|
+
backend.delete(key)
|
48
40
|
value
|
49
41
|
end
|
50
42
|
|
@@ -52,9 +44,9 @@ module Moneta
|
|
52
44
|
def increment(key, amount = 1, options = {})
|
53
45
|
result =
|
54
46
|
if amount >= 0
|
55
|
-
|
47
|
+
backend.incr(key, amount, expires_value(options) || nil)
|
56
48
|
else
|
57
|
-
|
49
|
+
backend.decr(key, -amount, expires_value(options) || nil)
|
58
50
|
end
|
59
51
|
if result
|
60
52
|
result
|
@@ -67,32 +59,32 @@ module Moneta
|
|
67
59
|
|
68
60
|
# (see Proxy#clear)
|
69
61
|
def clear(options = {})
|
70
|
-
|
62
|
+
backend.flush_all
|
71
63
|
self
|
72
64
|
end
|
73
65
|
|
74
66
|
# (see Defaults#create)
|
75
67
|
def create(key, value, options = {})
|
76
|
-
|
68
|
+
!!backend.add(key, value, expires_value(options) || nil, raw: true)
|
77
69
|
end
|
78
70
|
|
79
71
|
# (see Proxy#close)
|
80
72
|
def close
|
81
|
-
|
73
|
+
backend.close
|
82
74
|
nil
|
83
75
|
end
|
84
76
|
|
85
77
|
# (see Defaults#slice)
|
86
78
|
def slice(*keys, **options)
|
87
|
-
|
79
|
+
backend.get_multi(keys).tap do |pairs|
|
88
80
|
next if pairs.empty?
|
89
81
|
expires = expires_value(options, nil)
|
90
82
|
next if expires == nil
|
91
83
|
expires = expires.to_i if Numeric === expires
|
92
84
|
expires ||= 0
|
93
|
-
|
85
|
+
backend.multi do
|
94
86
|
pairs.each do |key, value|
|
95
|
-
|
87
|
+
backend.set(key, value, expires, false)
|
96
88
|
end
|
97
89
|
end
|
98
90
|
end
|
@@ -112,7 +104,7 @@ module Moneta
|
|
112
104
|
|
113
105
|
if block_given?
|
114
106
|
keys = pairs.map { |key, _| key }.to_a
|
115
|
-
old_pairs =
|
107
|
+
old_pairs = backend.get_multi(keys)
|
116
108
|
pairs = pairs.map do |key, new_value|
|
117
109
|
if old_pairs.key? key
|
118
110
|
new_value = yield(key, old_pairs[key], new_value)
|
@@ -121,9 +113,9 @@ module Moneta
|
|
121
113
|
end
|
122
114
|
end
|
123
115
|
|
124
|
-
|
116
|
+
backend.multi do
|
125
117
|
pairs.each do |key, value|
|
126
|
-
|
118
|
+
backend.set(key, value, expires, raw: true)
|
127
119
|
end
|
128
120
|
end
|
129
121
|
|
@@ -4,30 +4,24 @@ module Moneta
|
|
4
4
|
module Adapters
|
5
5
|
# Memcached backend (using gem memcached)
|
6
6
|
# @api public
|
7
|
-
class MemcachedNative
|
8
|
-
include Defaults
|
7
|
+
class MemcachedNative < Adapter
|
9
8
|
include ExpiresSupport
|
10
9
|
|
11
10
|
supports :create, :increment
|
12
|
-
attr_reader :backend
|
13
11
|
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# It is also faster.
|
28
|
-
options[:binary_protocol] = true unless options.include?(:binary_protocol)
|
29
|
-
::Memcached.new(server, options)
|
30
|
-
end
|
12
|
+
# @!method initialize(options = {})
|
13
|
+
# @param [Hash] options
|
14
|
+
# @option options [String] :server ('127.0.0.1:11211') Memcached server
|
15
|
+
# @option options [String] :namespace Key namespace
|
16
|
+
# @option options [Integer] :expires (604800) Default expiration time
|
17
|
+
# @option options [::Memcached] :backend Use existing backend instance
|
18
|
+
# @option options Other options passed to `Memcached#new`
|
19
|
+
backend do |server: '127.0.0.1:11211', namespace: nil, **options|
|
20
|
+
options[:prefix_key] = namespace if namespace
|
21
|
+
# We don't want a limitation on the key charset. Therefore we use the binary protocol.
|
22
|
+
# It is also faster.
|
23
|
+
options[:binary_protocol] = true unless options.include?(:binary_protocol)
|
24
|
+
::Memcached.new(server, options)
|
31
25
|
end
|
32
26
|
|
33
27
|
# (see Proxy#load)
|
@@ -2,19 +2,17 @@ module Moneta
|
|
2
2
|
module Adapters
|
3
3
|
# Memory backend using a hash to store the entries
|
4
4
|
# @api public
|
5
|
-
class Memory
|
6
|
-
include Defaults
|
5
|
+
class Memory < Adapter
|
7
6
|
include NilValues
|
8
7
|
include HashAdapter
|
9
8
|
include IncrementSupport
|
10
9
|
include CreateSupport
|
11
10
|
include EachKeySupport
|
12
11
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
end
|
12
|
+
# @!method initialize(options = {})
|
13
|
+
# @param [Hash] options Options hash
|
14
|
+
# @option options [Hash] :backend Use existing backend instance
|
15
|
+
backend { {} }
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -14,14 +14,33 @@ module Moneta
|
|
14
14
|
# db['key'] = {a: 1, b: 2}
|
15
15
|
#
|
16
16
|
# @api public
|
17
|
-
class Mongo
|
18
|
-
include Defaults
|
17
|
+
class Mongo < Adapter
|
19
18
|
include ExpiresSupport
|
20
19
|
|
21
20
|
supports :each_key, :create, :increment
|
22
|
-
attr_reader :backend
|
23
21
|
|
24
|
-
|
22
|
+
config :collection, default: 'moneta'
|
23
|
+
|
24
|
+
config :db
|
25
|
+
config :database, default: 'moneta' do |database:, db:, **|
|
26
|
+
if db
|
27
|
+
warn('Moneta::Adapters::Mongo - the :db option is deprecated and will be removed in a future version. Use :database instead')
|
28
|
+
db
|
29
|
+
else
|
30
|
+
database
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
config :expires_field, default: 'expiresAt'
|
35
|
+
config :value_field, default: 'value'
|
36
|
+
config :type_field, default: 'type'
|
37
|
+
|
38
|
+
backend do |host: '127.0.0.1', port: 27017, **options|
|
39
|
+
options[:logger] ||= ::Logger.new(STDERR).tap do |logger|
|
40
|
+
logger.level = ::Logger::ERROR
|
41
|
+
end
|
42
|
+
::Mongo::Client.new(["#{host}:#{port}"], options)
|
43
|
+
end
|
25
44
|
|
26
45
|
# @param [Hash] options
|
27
46
|
# @option options [String] :collection ('moneta') MongoDB collection name
|
@@ -37,31 +56,13 @@ module Moneta
|
|
37
56
|
# @option options [::Mongo::Client] :backend Use existing backend instance
|
38
57
|
# @option options Other options passed to `Mongo::MongoClient#new`
|
39
58
|
def initialize(options = {})
|
40
|
-
|
41
|
-
@expires_field = options.delete(:expires_field) || 'expiresAt'
|
42
|
-
@value_field = options.delete(:value_field) || 'value'
|
43
|
-
@type_field = options.delete(:type_field) || 'type'
|
59
|
+
super
|
44
60
|
|
45
|
-
|
61
|
+
@database = backend.use(config.database)
|
62
|
+
@collection = @database[config.collection]
|
46
63
|
|
47
|
-
if
|
48
|
-
|
49
|
-
end
|
50
|
-
database = options.delete(:database) || options.delete(:db) || 'moneta'
|
51
|
-
backend = options[:backend] ||
|
52
|
-
begin
|
53
|
-
host = options.delete(:host) || '127.0.0.1'
|
54
|
-
port = options.delete(:port) || DEFAULT_PORT
|
55
|
-
options[:logger] ||= ::Logger.new(STDERR).tap do |logger|
|
56
|
-
logger.level = ::Logger::ERROR
|
57
|
-
end
|
58
|
-
::Mongo::Client.new(["#{host}:#{port}"], options)
|
59
|
-
end
|
60
|
-
|
61
|
-
@backend = backend.use(database)
|
62
|
-
@collection = @backend[collection]
|
63
|
-
if @backend.command(buildinfo: 1).documents.first['version'] >= '2.2'
|
64
|
-
@collection.indexes.create_one({ @expires_field => 1 }, expire_after: 0)
|
64
|
+
if @database.command(buildinfo: 1).documents.first['version'] >= '2.2'
|
65
|
+
@collection.indexes.create_one({ config.expires_field => 1 }, expire_after: 0)
|
65
66
|
else
|
66
67
|
warn 'Moneta::Adapters::Mongo - You are using MongoDB version < 2.2, expired documents will not be deleted'
|
67
68
|
end
|
@@ -78,7 +79,7 @@ module Moneta
|
|
78
79
|
|
79
80
|
if doc
|
80
81
|
update_expiry(options, nil) do |expires|
|
81
|
-
view.update_one(:$set => {
|
82
|
+
view.update_one(:$set => { config.expires_field => expires })
|
82
83
|
end
|
83
84
|
|
84
85
|
doc_to_value(doc)
|
@@ -105,7 +106,7 @@ module Moneta
|
|
105
106
|
def delete(key, options = {})
|
106
107
|
key = to_binary(key)
|
107
108
|
if doc = @collection.find(_id: key).find_one_and_delete and
|
108
|
-
!doc[
|
109
|
+
!doc[config.expires_field] || doc[config.expires_field] >= Time.now
|
109
110
|
doc_to_value(doc)
|
110
111
|
end
|
111
112
|
end
|
@@ -113,9 +114,9 @@ module Moneta
|
|
113
114
|
# (see Proxy#increment)
|
114
115
|
def increment(key, amount = 1, options = {})
|
115
116
|
@collection.find_one_and_update({ :$and => [{ _id: to_binary(key) }, not_expired] },
|
116
|
-
{ :$inc => {
|
117
|
+
{ :$inc => { config.value_field => amount } },
|
117
118
|
return_document: :after,
|
118
|
-
upsert: true)[
|
119
|
+
upsert: true)[config.value_field]
|
119
120
|
rescue ::Mongo::Error::OperationFailure
|
120
121
|
tries ||= 0
|
121
122
|
(tries += 1) < 3 ? retry : raise
|
@@ -126,8 +127,8 @@ module Moneta
|
|
126
127
|
key = to_binary(key)
|
127
128
|
@collection.insert_one(value_to_doc(key, value, options))
|
128
129
|
true
|
129
|
-
rescue ::Mongo::Error::OperationFailure =>
|
130
|
-
raise unless
|
130
|
+
rescue ::Mongo::Error::OperationFailure => error
|
131
|
+
raise unless error.code == 11000 # duplicate key error
|
131
132
|
false
|
132
133
|
end
|
133
134
|
|
@@ -139,7 +140,7 @@ module Moneta
|
|
139
140
|
|
140
141
|
# (see Proxy#close)
|
141
142
|
def close
|
142
|
-
@
|
143
|
+
@database.close
|
143
144
|
nil
|
144
145
|
end
|
145
146
|
|
@@ -152,7 +153,7 @@ module Moneta
|
|
152
153
|
pairs = view.map { |doc| [from_binary(doc[:_id]), doc_to_value(doc)] }
|
153
154
|
|
154
155
|
update_expiry(options, nil) do |expires|
|
155
|
-
view.update_many(:$set => {
|
156
|
+
view.update_many(:$set => { config.expires_field => expires })
|
156
157
|
end
|
157
158
|
|
158
159
|
pairs
|
@@ -198,18 +199,18 @@ module Moneta
|
|
198
199
|
private
|
199
200
|
|
200
201
|
def doc_to_value(doc)
|
201
|
-
case doc[
|
202
|
+
case doc[config.type_field]
|
202
203
|
when 'Hash'
|
203
204
|
doc = doc.dup
|
204
205
|
doc.delete('_id')
|
205
|
-
doc.delete(
|
206
|
-
doc.delete(
|
206
|
+
doc.delete(config.type_field)
|
207
|
+
doc.delete(config.expires_field)
|
207
208
|
doc
|
208
209
|
when 'Number'
|
209
|
-
doc[
|
210
|
+
doc[config.value_field]
|
210
211
|
else
|
211
212
|
# In ruby_bson version 2 (and probably up), #to_s no longer returns the binary data
|
212
|
-
from_binary(doc[
|
213
|
+
from_binary(doc[config.value_field])
|
213
214
|
end
|
214
215
|
end
|
215
216
|
|
@@ -217,22 +218,22 @@ module Moneta
|
|
217
218
|
case value
|
218
219
|
when Hash
|
219
220
|
value.merge('_id' => key,
|
220
|
-
|
221
|
-
#
|
222
|
-
|
221
|
+
config.type_field => 'Hash',
|
222
|
+
# expires_field must be a Time object (BSON date datatype)
|
223
|
+
config.expires_field => expires_at(options) || nil)
|
223
224
|
when Float, Integer
|
224
225
|
{ '_id' => key,
|
225
|
-
|
226
|
-
|
227
|
-
#
|
228
|
-
|
226
|
+
config.type_field => 'Number',
|
227
|
+
config.value_field => value,
|
228
|
+
# expires_field must be a Time object (BSON date datatype)
|
229
|
+
config.expires_field => expires_at(options) || nil }
|
229
230
|
when String
|
230
231
|
intvalue = value.to_i
|
231
232
|
{ '_id' => key,
|
232
|
-
|
233
|
-
|
233
|
+
config.type_field => 'String',
|
234
|
+
config.value_field => intvalue.to_s == value ? intvalue : to_binary(value),
|
234
235
|
# @expires_field must be a Time object (BSON date datatype)
|
235
|
-
|
236
|
+
config.expires_field => expires_at(options) || nil }
|
236
237
|
else
|
237
238
|
raise ArgumentError, "Invalid value type: #{value.class}"
|
238
239
|
end
|
@@ -253,8 +254,8 @@ module Moneta
|
|
253
254
|
def not_expired
|
254
255
|
{
|
255
256
|
:$or => [
|
256
|
-
{
|
257
|
-
{
|
257
|
+
{ config.expires_field => nil },
|
258
|
+
{ config.expires_field => { :$gte => Time.now } }
|
258
259
|
]
|
259
260
|
}
|
260
261
|
end
|
@@ -5,63 +5,61 @@ module Moneta
|
|
5
5
|
module Adapters
|
6
6
|
# PStore backend
|
7
7
|
# @api public
|
8
|
-
class PStore
|
9
|
-
include Defaults
|
8
|
+
class PStore < Adapter
|
10
9
|
include NilValues
|
11
10
|
|
12
11
|
supports :create, :increment, :each_key
|
13
|
-
|
12
|
+
|
13
|
+
backend do |file:, threadsafe: false|
|
14
|
+
FileUtils.mkpath(::File.dirname(file))
|
15
|
+
::PStore.new(file, threadsafe)
|
16
|
+
end
|
14
17
|
|
15
18
|
# @param [Hash] options
|
16
19
|
# @option options [String] :file PStore file
|
20
|
+
# @option options [Boolean] :threadsafe Makes the PStore thread-safe
|
17
21
|
# @option options [::PStore] :backend Use existing backend instance
|
18
22
|
def initialize(options = {})
|
19
|
-
|
20
|
-
begin
|
21
|
-
raise ArgumentError, 'Option :file is required' unless options[:file]
|
22
|
-
FileUtils.mkpath(::File.dirname(options[:file]))
|
23
|
-
new_store(options)
|
24
|
-
end
|
25
|
-
|
23
|
+
super
|
26
24
|
@id = "Moneta::Adapters::PStore(#{object_id})"
|
27
25
|
end
|
28
26
|
|
29
27
|
# (see Proxy#key?)
|
30
28
|
def key?(key, options = {})
|
31
|
-
transaction(true) {
|
29
|
+
transaction(true) { backend.root?(key) }
|
32
30
|
end
|
33
31
|
|
34
32
|
# (see Proxy#each_key)
|
35
33
|
def each_key(&block)
|
36
|
-
return enum_for(:each_key) { transaction(true) {
|
34
|
+
return enum_for(:each_key) { transaction(true) { backend.roots.size } } unless block_given?
|
37
35
|
|
38
36
|
transaction(true) do
|
39
|
-
|
37
|
+
backend.roots.each { |k| yield(k) }
|
40
38
|
end
|
41
39
|
self
|
42
40
|
end
|
43
41
|
|
44
42
|
# (see Proxy#load)
|
45
43
|
def load(key, options = {})
|
46
|
-
transaction(true) {
|
44
|
+
transaction(true) { backend[key] }
|
47
45
|
end
|
48
46
|
|
49
47
|
# (see Proxy#store)
|
50
48
|
def store(key, value, options = {})
|
51
|
-
transaction {
|
49
|
+
transaction { backend[key] = value }
|
52
50
|
end
|
53
51
|
|
54
52
|
# (see Proxy#delete)
|
55
53
|
def delete(key, options = {})
|
56
|
-
transaction {
|
54
|
+
transaction { backend.delete(key) }
|
57
55
|
end
|
58
56
|
|
59
57
|
# (see Proxy#increment)
|
60
58
|
def increment(key, amount = 1, options = {})
|
61
59
|
transaction do
|
62
|
-
existing =
|
60
|
+
existing = backend[key]
|
63
61
|
value = (existing == nil ? 0 : Integer(existing)) + amount
|
64
|
-
|
62
|
+
backend[key] = value.to_s
|
65
63
|
value
|
66
64
|
end
|
67
65
|
end
|
@@ -69,10 +67,10 @@ module Moneta
|
|
69
67
|
# (see Proxy#create)
|
70
68
|
def create(key, value, options = {})
|
71
69
|
transaction do
|
72
|
-
if
|
70
|
+
if backend.root?(key)
|
73
71
|
false
|
74
72
|
else
|
75
|
-
|
73
|
+
backend[key] = value
|
76
74
|
true
|
77
75
|
end
|
78
76
|
end
|
@@ -81,8 +79,8 @@ module Moneta
|
|
81
79
|
# (see Proxy#clear)
|
82
80
|
def clear(options = {})
|
83
81
|
transaction do
|
84
|
-
|
85
|
-
|
82
|
+
backend.roots.each do |key|
|
83
|
+
backend.delete(key)
|
86
84
|
end
|
87
85
|
end
|
88
86
|
self
|
@@ -109,10 +107,6 @@ module Moneta
|
|
109
107
|
|
110
108
|
class TransactionError < StandardError; end
|
111
109
|
|
112
|
-
def new_store(options)
|
113
|
-
::PStore.new(options[:file], options[:threadsafe])
|
114
|
-
end
|
115
|
-
|
116
110
|
def transaction(read_only = false)
|
117
111
|
case Thread.current[@id]
|
118
112
|
when read_only, false
|
@@ -122,7 +116,7 @@ module Moneta
|
|
122
116
|
else
|
123
117
|
begin
|
124
118
|
Thread.current[@id] = read_only
|
125
|
-
|
119
|
+
backend.transaction(read_only) { yield }
|
126
120
|
ensure
|
127
121
|
Thread.current[@id] = nil
|
128
122
|
end
|
@@ -4,32 +4,28 @@ module Moneta
|
|
4
4
|
module Adapters
|
5
5
|
# Redis backend
|
6
6
|
# @api public
|
7
|
-
class Redis
|
8
|
-
include Defaults
|
7
|
+
class Redis < Adapter
|
9
8
|
include ExpiresSupport
|
10
9
|
|
11
10
|
supports :create, :increment, :each_key
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
self.default_expires = options.delete(:expires)
|
20
|
-
@backend = options[:backend] || ::Redis.new(options)
|
21
|
-
end
|
11
|
+
|
12
|
+
# @!method initialize(options = {})
|
13
|
+
# @param [Hash] options
|
14
|
+
# @option options [Integer] :expires Default expiration time
|
15
|
+
# @option options [::Redis] :backend Use existing backend instance
|
16
|
+
# @option options Other options passed to `Redis#new`
|
17
|
+
backend { |**options| ::Redis.new(options) }
|
22
18
|
|
23
19
|
# (see Proxy#key?)
|
24
20
|
#
|
25
21
|
# This method considers false and 0 as "no-expire" and every positive
|
26
22
|
# number as a time to live in seconds.
|
27
23
|
def key?(key, options = {})
|
28
|
-
with_expiry_update(key, default: nil, **options) do
|
29
|
-
if
|
30
|
-
|
24
|
+
with_expiry_update(key, default: nil, **options) do |pipeline_handle|
|
25
|
+
if pipeline_handle.respond_to?(:exists?)
|
26
|
+
pipeline_handle.exists?(key)
|
31
27
|
else
|
32
|
-
|
28
|
+
pipeline_handle.exists(key)
|
33
29
|
end
|
34
30
|
end
|
35
31
|
end
|
@@ -44,8 +40,8 @@ module Moneta
|
|
44
40
|
|
45
41
|
# (see Proxy#load)
|
46
42
|
def load(key, options = {})
|
47
|
-
with_expiry_update(key, default: nil, **options) do
|
48
|
-
|
43
|
+
with_expiry_update(key, default: nil, **options) do |pipeline_handle|
|
44
|
+
pipeline_handle.get(key)
|
49
45
|
end
|
50
46
|
end
|
51
47
|
|
@@ -63,17 +59,17 @@ module Moneta
|
|
63
59
|
# (see Proxy#delete)
|
64
60
|
def delete(key, options = {})
|
65
61
|
future = nil
|
66
|
-
@backend.pipelined do
|
67
|
-
future =
|
68
|
-
|
62
|
+
@backend.pipelined do |pipeline|
|
63
|
+
future = pipeline.get(key)
|
64
|
+
pipeline.del(key)
|
69
65
|
end
|
70
66
|
future.value
|
71
67
|
end
|
72
68
|
|
73
69
|
# (see Proxy#increment)
|
74
70
|
def increment(key, amount = 1, options = {})
|
75
|
-
with_expiry_update(key, **options) do
|
76
|
-
|
71
|
+
with_expiry_update(key, **options) do |pipeline_handle|
|
72
|
+
pipeline_handle.incrby(key, amount)
|
77
73
|
end
|
78
74
|
end
|
79
75
|
|
@@ -85,10 +81,10 @@ module Moneta
|
|
85
81
|
|
86
82
|
# (see Defaults#create)
|
87
83
|
def create(key, value, options = {})
|
88
|
-
expires = expires_value(options,
|
84
|
+
expires = expires_value(options, config.expires)
|
89
85
|
|
90
86
|
if @backend.setnx(key, value)
|
91
|
-
update_expires(key, expires)
|
87
|
+
update_expires(@backend, key, expires)
|
92
88
|
true
|
93
89
|
else
|
94
90
|
false
|
@@ -103,8 +99,8 @@ module Moneta
|
|
103
99
|
|
104
100
|
# (see Defaults#values_at)
|
105
101
|
def values_at(*keys, **options)
|
106
|
-
with_expiry_update(*keys, default: nil, **options) do
|
107
|
-
|
102
|
+
with_expiry_update(*keys, default: nil, **options) do |pipeline_handle|
|
103
|
+
pipeline_handle.mget(*keys)
|
108
104
|
end
|
109
105
|
end
|
110
106
|
|
@@ -130,8 +126,8 @@ module Moneta
|
|
130
126
|
end
|
131
127
|
end
|
132
128
|
|
133
|
-
with_expiry_update(*keys, **options) do
|
134
|
-
|
129
|
+
with_expiry_update(*keys, **options) do |pipeline_handle|
|
130
|
+
pipeline_handle.mset(*pairs.to_a.flatten(1))
|
135
131
|
end
|
136
132
|
|
137
133
|
self
|
@@ -139,24 +135,33 @@ module Moneta
|
|
139
135
|
|
140
136
|
protected
|
141
137
|
|
142
|
-
def update_expires(key, expires)
|
138
|
+
def update_expires(pipeline_handle, key, expires)
|
143
139
|
case expires
|
144
140
|
when false
|
145
|
-
|
141
|
+
pipeline_handle.persist(key)
|
146
142
|
when Numeric
|
147
|
-
|
143
|
+
pipeline_handle.pexpire(key, (expires * 1000).to_i)
|
148
144
|
end
|
149
145
|
end
|
150
146
|
|
151
|
-
def with_expiry_update(*keys, default:
|
147
|
+
def with_expiry_update(*keys, default: config.expires, **options)
|
152
148
|
expires = expires_value(options, default)
|
153
149
|
if expires == nil
|
154
|
-
yield
|
150
|
+
yield(@backend)
|
155
151
|
else
|
156
152
|
future = nil
|
157
|
-
@backend.multi do
|
158
|
-
|
159
|
-
|
153
|
+
@backend.multi do |pipeline|
|
154
|
+
# as of redis 4.6 calling redis methods on the redis client itself
|
155
|
+
# is deprecated in favor of a pipeline handle provided by the
|
156
|
+
# +multi+ call. This will cause in error in redis >= 5.0.
|
157
|
+
#
|
158
|
+
# In order to continue supporting redis versions < 4.6, the following
|
159
|
+
# fallback has been introduced and can be removed once moneta
|
160
|
+
# no longer supports redis < 4.6.
|
161
|
+
|
162
|
+
pipeline_handle = pipeline || @backend
|
163
|
+
future = yield(pipeline_handle)
|
164
|
+
keys.each { |key| update_expires(pipeline_handle, key, expires) }
|
160
165
|
end
|
161
166
|
future.value
|
162
167
|
end
|