moneta 0.7.9 → 0.7.10
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 -2
- data/CHANGES +6 -0
- data/Gemfile +2 -0
- data/README.md +7 -4
- data/Rakefile +2 -2
- data/lib/moneta.rb +1 -0
- data/lib/moneta/adapters/activerecord.rb +1 -2
- data/lib/moneta/adapters/cassandra.rb +31 -26
- data/lib/moneta/adapters/cookie.rb +2 -2
- data/lib/moneta/adapters/couch.rb +5 -3
- data/lib/moneta/adapters/daybreak.rb +13 -9
- data/lib/moneta/adapters/dbm.rb +7 -3
- data/lib/moneta/adapters/file.rb +4 -3
- data/lib/moneta/adapters/fog.rb +5 -2
- data/lib/moneta/adapters/gdbm.rb +7 -3
- data/lib/moneta/adapters/hbase.rb +11 -9
- data/lib/moneta/adapters/kyotocabinet.rb +13 -8
- data/lib/moneta/adapters/leveldb.rb +9 -5
- data/lib/moneta/adapters/localmemcache.rb +7 -3
- data/lib/moneta/adapters/memcached/dalli.rb +16 -11
- data/lib/moneta/adapters/memcached/native.rb +20 -15
- data/lib/moneta/adapters/memory.rb +2 -1
- data/lib/moneta/adapters/mongo.rb +13 -8
- data/lib/moneta/adapters/pstore.rb +24 -21
- data/lib/moneta/adapters/redis.rb +14 -12
- data/lib/moneta/adapters/restclient.rb +10 -7
- data/lib/moneta/adapters/riak.rb +5 -1
- data/lib/moneta/adapters/sdbm.rb +7 -3
- data/lib/moneta/adapters/sequel.rb +13 -8
- data/lib/moneta/adapters/sqlite.rb +15 -10
- data/lib/moneta/adapters/tdb.rb +8 -4
- data/lib/moneta/adapters/tokyocabinet.rb +15 -10
- data/lib/moneta/adapters/tokyotyrant.rb +107 -0
- data/lib/moneta/cache.rb +17 -17
- data/lib/moneta/mixins.rb +7 -5
- data/lib/moneta/version.rb +1 -1
- data/lib/rack/moneta_store.rb +1 -1
- data/lib/rack/session/moneta.rb +6 -3
- data/script/benchmarks +28 -28
- data/script/generate-specs +96 -41
- data/script/memusage +40 -0
- data/script/start-services +1 -0
- data/spec/helper.rb +4 -1
- data/spec/moneta/adapter_tokyotyrant_spec.rb +30 -0
- data/spec/moneta/cache_file_memory_spec.rb +3 -3
- data/spec/moneta/cache_memory_null_spec.rb +1 -1
- data/spec/moneta/simple_tokyotyrant_spec.rb +155 -0
- data/spec/moneta/simple_tokyotyrant_with_expires_spec.rb +157 -0
- data/spec/monetaspecs.rb +79 -37
- data/spec/rack/moneta_store_spec.rb +1 -1
- data/spec/rack/session_moneta_spec.rb +27 -0
- metadata +10 -3
@@ -7,48 +7,51 @@ module Moneta
|
|
7
7
|
class RestClient
|
8
8
|
include Defaults
|
9
9
|
|
10
|
+
attr_reader :backend
|
11
|
+
|
10
12
|
# @param [Hash] options
|
11
13
|
# @option options [String] :url URL
|
14
|
+
# @option options [::Net::HTTP] :backend Use existing backend instance
|
12
15
|
def initialize(options = {})
|
13
16
|
raise ArgumentError, 'Option :url is required' unless url = options[:url]
|
14
17
|
url = URI(url)
|
15
18
|
@path = url.path
|
16
|
-
@
|
19
|
+
@backend = options[:backend] || ::Net::HTTP.start(url.host, url.port)
|
17
20
|
end
|
18
21
|
|
19
22
|
# (see Proxy#key?)
|
20
23
|
def key?(key, options = {})
|
21
|
-
response = @
|
24
|
+
response = @backend.request_head(@path + key)
|
22
25
|
response.code == '200'
|
23
26
|
end
|
24
27
|
|
25
28
|
# (see Proxy#load)
|
26
29
|
def load(key, options = {})
|
27
|
-
response = @
|
30
|
+
response = @backend.request_get(@path + key)
|
28
31
|
response.code == '200' ? response.body : nil
|
29
32
|
end
|
30
33
|
|
31
34
|
# (see Proxy#store)
|
32
35
|
def store(key, value, options = {})
|
33
|
-
response = @
|
36
|
+
response = @backend.request_post(@path + key, value)
|
34
37
|
raise "HTTP error #{response.code}" unless response.code == '200'
|
35
38
|
value
|
36
39
|
end
|
37
40
|
|
38
41
|
# (see Proxy#delete)
|
39
42
|
def delete(key, options = {})
|
40
|
-
response = @
|
43
|
+
response = @backend.request(::Net::HTTP::Delete.new(@path + key))
|
41
44
|
response.code == '200' ? response.body : nil
|
42
45
|
end
|
43
46
|
|
44
47
|
# (see Proxy#clear)
|
45
48
|
def clear(options = {})
|
46
|
-
@
|
49
|
+
@backend.request(::Net::HTTP::Delete.new(@path))
|
47
50
|
self
|
48
51
|
end
|
49
52
|
|
50
53
|
def close
|
51
|
-
@
|
54
|
+
@backend.finish
|
52
55
|
nil
|
53
56
|
end
|
54
57
|
end
|
data/lib/moneta/adapters/riak.rb
CHANGED
@@ -10,14 +10,18 @@ module Moneta
|
|
10
10
|
class Riak
|
11
11
|
include Defaults
|
12
12
|
|
13
|
+
attr_reader :backend
|
14
|
+
|
13
15
|
# @param [Hash] options
|
14
16
|
# @option options [String] :bucket ('moneta') Bucket name
|
15
17
|
# @option options [String] :content_type ('application/octet-stream') Default content type
|
16
18
|
# @option options All other options passed to `Riak::Client#new`
|
19
|
+
# @option options [::Riak::Client] :backend Use existing backend instance
|
17
20
|
def initialize(options = {})
|
18
21
|
bucket = options.delete(:bucket) || 'moneta'
|
19
22
|
@content_type = options.delete(:content_type) || 'application/octet-stream'
|
20
|
-
@
|
23
|
+
@backend = options[:backend] || ::Riak::Client.new(options)
|
24
|
+
@bucket = @backend.bucket(bucket)
|
21
25
|
end
|
22
26
|
|
23
27
|
# (see Proxy#key?)
|
data/lib/moneta/adapters/sdbm.rb
CHANGED
@@ -7,14 +7,18 @@ module Moneta
|
|
7
7
|
class SDBM < Memory
|
8
8
|
# @param [Hash] options
|
9
9
|
# @option options [String] :file Database file
|
10
|
+
# @option options [::SDBM] :backend Use existing backend instance
|
10
11
|
def initialize(options = {})
|
11
|
-
|
12
|
-
|
12
|
+
@backend = options[:backend] ||
|
13
|
+
begin
|
14
|
+
raise ArgumentError, 'Option :file is required' unless options[:file]
|
15
|
+
::SDBM.new(options[:file])
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
# (see Proxy#close)
|
16
20
|
def close
|
17
|
-
@
|
21
|
+
@backend.close
|
18
22
|
nil
|
19
23
|
end
|
20
24
|
end
|
@@ -8,20 +8,25 @@ module Moneta
|
|
8
8
|
include Defaults
|
9
9
|
|
10
10
|
supports :create, :increment
|
11
|
+
attr_reader :backend
|
11
12
|
|
12
13
|
# @param [Hash] options
|
13
14
|
# @option options [String] :db Sequel database
|
14
15
|
# @option options [String/Symbol] :table (:moneta) Table name
|
15
16
|
# @option options All other options passed to `Sequel#connect`
|
17
|
+
# @option options [Sequel connection] :backend Use existing backend instance
|
16
18
|
def initialize(options = {})
|
17
|
-
raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
|
18
19
|
table = options.delete(:table) || :moneta
|
19
|
-
@
|
20
|
-
|
20
|
+
@backend = options[:backend] ||
|
21
|
+
begin
|
22
|
+
raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
|
23
|
+
::Sequel.connect(db, options)
|
24
|
+
end
|
25
|
+
@backend.create_table?(table) do
|
21
26
|
String :k, :null => false, :primary_key => true
|
22
27
|
String :v
|
23
28
|
end
|
24
|
-
@table = @
|
29
|
+
@table = @backend[table]
|
25
30
|
end
|
26
31
|
|
27
32
|
# (see Proxy#key?)
|
@@ -37,7 +42,7 @@ module Moneta
|
|
37
42
|
|
38
43
|
# (see Proxy#store)
|
39
44
|
def store(key, value, options = {})
|
40
|
-
@
|
45
|
+
@backend.transaction do
|
41
46
|
begin
|
42
47
|
@table.insert(:k => key, :v => value)
|
43
48
|
rescue ::Sequel::DatabaseError
|
@@ -52,7 +57,7 @@ module Moneta
|
|
52
57
|
|
53
58
|
# (see Proxy#store)
|
54
59
|
def create(key, value, options = {})
|
55
|
-
@
|
60
|
+
@backend.transaction do
|
56
61
|
@table.insert(:k => key, :v => value)
|
57
62
|
end
|
58
63
|
true
|
@@ -64,7 +69,7 @@ module Moneta
|
|
64
69
|
|
65
70
|
# (see Proxy#increment)
|
66
71
|
def increment(key, amount = 1, options = {})
|
67
|
-
@
|
72
|
+
@backend.transaction do
|
68
73
|
locked_table = @table.for_update
|
69
74
|
if record = locked_table[:k => key]
|
70
75
|
value = Utils.to_int(record[:v]) + amount
|
@@ -79,7 +84,7 @@ module Moneta
|
|
79
84
|
|
80
85
|
# (see Proxy#delete)
|
81
86
|
def delete(key, options = {})
|
82
|
-
@
|
87
|
+
@backend.transaction do
|
83
88
|
if value = load(key, options)
|
84
89
|
@table.filter(:k => key).delete
|
85
90
|
value
|
@@ -9,21 +9,26 @@ module Moneta
|
|
9
9
|
include IncrementSupport
|
10
10
|
|
11
11
|
supports :create
|
12
|
+
attr_reader :backend
|
12
13
|
|
13
14
|
# @param [Hash] options
|
14
15
|
# @option options [String] :file Database file
|
15
16
|
# @option options [String] :table ('moneta') Table name
|
17
|
+
# @option options [::Sqlite3::Database] :backend Use existing backend instance
|
16
18
|
def initialize(options = {})
|
17
|
-
raise ArgumentError, 'Option :file is required' unless options[:file]
|
18
19
|
table = options[:table] || 'moneta'
|
19
|
-
@
|
20
|
-
|
20
|
+
@backend = options[:backend] ||
|
21
|
+
begin
|
22
|
+
raise ArgumentError, 'Option :file is required' unless options[:file]
|
23
|
+
::SQLite3::Database.new(options[:file])
|
24
|
+
end
|
25
|
+
@backend.execute("create table if not exists #{table} (k blob not null primary key, v blob)")
|
21
26
|
@stmts =
|
22
|
-
[@select = @
|
23
|
-
@replace = @
|
24
|
-
@delete = @
|
25
|
-
@clear = @
|
26
|
-
@create = @
|
27
|
+
[@select = @backend.prepare("select v from #{table} where k = ?"),
|
28
|
+
@replace = @backend.prepare("replace into #{table} values (?, ?)"),
|
29
|
+
@delete = @backend.prepare("delete from #{table} where k = ?"),
|
30
|
+
@clear = @backend.prepare("delete from #{table}"),
|
31
|
+
@create = @backend.prepare("insert into #{table} values (?, ?)")]
|
27
32
|
end
|
28
33
|
|
29
34
|
# (see Proxy#key?)
|
@@ -52,7 +57,7 @@ module Moneta
|
|
52
57
|
|
53
58
|
# (see Proxy#increment)
|
54
59
|
def increment(key, amount = 1, options = {})
|
55
|
-
@
|
60
|
+
@backend.transaction(:exclusive) { return super }
|
56
61
|
end
|
57
62
|
|
58
63
|
# (see Proxy#clear)
|
@@ -75,7 +80,7 @@ module Moneta
|
|
75
80
|
# (see Proxy#close)
|
76
81
|
def close
|
77
82
|
@stmts.each {|s| s.close }
|
78
|
-
@
|
83
|
+
@backend.close
|
79
84
|
nil
|
80
85
|
end
|
81
86
|
end
|
data/lib/moneta/adapters/tdb.rb
CHANGED
@@ -7,14 +7,18 @@ module Moneta
|
|
7
7
|
class TDB < Memory
|
8
8
|
# @param [Hash] options
|
9
9
|
# @option options [String] :file Database file
|
10
|
-
|
11
|
-
|
12
|
-
@
|
10
|
+
# @option options [::TDB] :backend Use existing backend instance
|
11
|
+
def initialize(options)
|
12
|
+
@backend = options[:backend] ||
|
13
|
+
begin
|
14
|
+
raise ArgumentError, 'Option :file is required' unless file = options.delete(:file)
|
15
|
+
::TDB.new(file, options)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
# (see Proxy#close)
|
16
20
|
def close
|
17
|
-
@
|
21
|
+
@backend.close
|
18
22
|
nil
|
19
23
|
end
|
20
24
|
end
|
@@ -8,34 +8,39 @@ module Moneta
|
|
8
8
|
# @param [Hash] options
|
9
9
|
# @option options [String] :file Database file
|
10
10
|
# @option options [Symbol] :type (:hdb) Database type (:bdb and :hdb possible)
|
11
|
+
# @option options [::TokyoCabinet::*DB] :backend Use existing backend instance
|
11
12
|
def initialize(options = {})
|
12
|
-
|
13
|
-
|
14
|
-
@hash = ::TokyoCabinet::BDB.new
|
15
|
-
@hash.open(options[:file], ::TokyoCabinet::BDB::OWRITER | ::TokyoCabinet::BDB::OCREAT)
|
13
|
+
if options[:backend]
|
14
|
+
@backend = options[:backend]
|
16
15
|
else
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
raise ArgumentError, 'Option :file is required' unless options[:file]
|
17
|
+
if options[:type] == :bdb
|
18
|
+
@backend = ::TokyoCabinet::BDB.new
|
19
|
+
@backend.open(options[:file], ::TokyoCabinet::BDB::OWRITER | ::TokyoCabinet::BDB::OCREAT)
|
20
|
+
else
|
21
|
+
@backend = ::TokyoCabinet::HDB.new
|
22
|
+
@backend.open(options[:file], ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
|
23
|
+
end or raise @backend.errmsg(@backend.ecode)
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
# (see Proxy#delete)
|
23
28
|
def delete(key, options = {})
|
24
29
|
value = load(key, options)
|
25
30
|
if value
|
26
|
-
@
|
31
|
+
@backend.delete(key)
|
27
32
|
value
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
36
|
# (see Proxy#create)
|
32
37
|
def create(key, value, options = {})
|
33
|
-
@
|
38
|
+
@backend.putkeep(key, value)
|
34
39
|
end
|
35
40
|
|
36
41
|
# (see Proxy#close)
|
37
42
|
def close
|
38
|
-
@
|
43
|
+
@backend.close
|
39
44
|
nil
|
40
45
|
end
|
41
46
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'tokyotyrant'
|
2
|
+
|
3
|
+
module Moneta
|
4
|
+
module Adapters
|
5
|
+
# TokyoTyrant backend
|
6
|
+
# @api public
|
7
|
+
class TokyoTyrant
|
8
|
+
include Defaults
|
9
|
+
|
10
|
+
supports :create, :increment
|
11
|
+
attr_reader :backend
|
12
|
+
|
13
|
+
# @param [Hash] options
|
14
|
+
# @option options [String] :host ('127.0.0.1') Server host name
|
15
|
+
# @option options [Integer] :port (1978) Server port
|
16
|
+
# @option options [::TokyoTyrant::RDB] :backend Use existing backend instance
|
17
|
+
def initialize(options = {})
|
18
|
+
if options[:backend]
|
19
|
+
@backend = options[:backend]
|
20
|
+
else
|
21
|
+
@backend = ::TokyoTyrant::RDB.new
|
22
|
+
@backend.open(options[:host] || '127.0.0.1',
|
23
|
+
options[:port] || 1978) or raise @backend.errmsg(@backend.ecode)
|
24
|
+
end
|
25
|
+
probe = '__tokyotyrant_endianness_probe'
|
26
|
+
@backend.delete(probe)
|
27
|
+
@backend.addint(probe, 1)
|
28
|
+
@pack = @backend.delete(probe) == [1].pack('l>') ? 'l>' : 'l<'
|
29
|
+
end
|
30
|
+
|
31
|
+
# (see Proxy#key?)
|
32
|
+
def key?(key, options = {})
|
33
|
+
@backend.has_key?(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
# (see Proxy#load)
|
37
|
+
def load(key, options = {})
|
38
|
+
value = @backend[key]
|
39
|
+
value && unpack(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
# (see Proxy#store)
|
43
|
+
def store(key, value, options = {})
|
44
|
+
@backend[key] = pack(value)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
# (see Proxy#delete)
|
49
|
+
def delete(key, options = {})
|
50
|
+
value = load(key, options)
|
51
|
+
if value
|
52
|
+
@backend.delete(key)
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# (see Proxy#increment)
|
58
|
+
def increment(key, amount = 1, options = {})
|
59
|
+
@backend.addint(key, amount) || raise('Tried to increment non integer value')
|
60
|
+
end
|
61
|
+
|
62
|
+
# (see Proxy#create)
|
63
|
+
def create(key, value, options = {})
|
64
|
+
@backend.putkeep(key, pack(value))
|
65
|
+
end
|
66
|
+
|
67
|
+
# (see Proxy#clear)
|
68
|
+
def clear(options = {})
|
69
|
+
@backend.clear
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
# (see Proxy#close)
|
74
|
+
def close
|
75
|
+
@backend.close
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def pack(value)
|
82
|
+
intvalue = value.to_i
|
83
|
+
if intvalue >= 0 && intvalue <= 0xFFFFFFFF && intvalue.to_s == value
|
84
|
+
# Pack as 4 byte integer
|
85
|
+
[intvalue].pack(@pack)
|
86
|
+
elsif value.bytesize >= 4
|
87
|
+
# Add nul character to make value distinguishable from integer
|
88
|
+
value + "\0"
|
89
|
+
else
|
90
|
+
value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def unpack(value)
|
95
|
+
if value.bytesize == 4
|
96
|
+
# Unpack 4 byte integer
|
97
|
+
value.unpack(@pack).first.to_s
|
98
|
+
elsif value.bytesize >= 5 && value[-1] == ?\0
|
99
|
+
# Remove nul character
|
100
|
+
value[0..-2]
|
101
|
+
else
|
102
|
+
value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/moneta/cache.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Moneta
|
2
|
-
# Combines two stores. One is used as cache, the other as backend.
|
2
|
+
# Combines two stores. One is used as cache, the other as backend adapter.
|
3
3
|
#
|
4
4
|
# @example Add `Moneta::Cache` to proxy stack
|
5
5
|
# Moneta.build do
|
6
6
|
# use(:Cache) do
|
7
|
-
#
|
7
|
+
# adapter { adapter :File, :dir => 'data' }
|
8
8
|
# cache { adapter :Memory }
|
9
9
|
# end
|
10
10
|
# end
|
@@ -21,10 +21,10 @@ module Moneta
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# @api public
|
24
|
-
def
|
25
|
-
raise '
|
24
|
+
def adapter(store = nil, &block)
|
25
|
+
raise 'Adapter already set' if @store.adapter
|
26
26
|
raise ArgumentError, 'Only argument or block allowed' if store && block
|
27
|
-
@store.
|
27
|
+
@store.adapter = store || Moneta.build(&block)
|
28
28
|
end
|
29
29
|
|
30
30
|
# @api public
|
@@ -35,27 +35,27 @@ module Moneta
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
attr_accessor :cache, :
|
38
|
+
attr_accessor :cache, :adapter
|
39
39
|
|
40
40
|
# @param [Hash] options Options hash
|
41
41
|
# @option options [Moneta store] :cache Moneta store used as cache
|
42
|
-
# @option options [Moneta store] :
|
42
|
+
# @option options [Moneta store] :adapter Moneta store used as adapter
|
43
43
|
# @yieldparam Builder block
|
44
44
|
def initialize(options = {}, &block)
|
45
|
-
@cache, @
|
45
|
+
@cache, @adapter = options[:cache], options[:adapter]
|
46
46
|
DSL.new(self, &block) if block_given?
|
47
47
|
end
|
48
48
|
|
49
49
|
# (see Proxy#key?)
|
50
50
|
def key?(key, options = {})
|
51
|
-
@cache.key?(key, options) || @
|
51
|
+
@cache.key?(key, options) || @adapter.key?(key, options)
|
52
52
|
end
|
53
53
|
|
54
54
|
# (see Proxy#load)
|
55
55
|
def load(key, options = {})
|
56
56
|
value = @cache.load(key, options)
|
57
57
|
if value == nil
|
58
|
-
value = @
|
58
|
+
value = @adapter.load(key, options)
|
59
59
|
@cache.store(key, value, options) if value != nil
|
60
60
|
end
|
61
61
|
value
|
@@ -64,18 +64,18 @@ module Moneta
|
|
64
64
|
# (see Proxy#store)
|
65
65
|
def store(key, value, options = {})
|
66
66
|
@cache.store(key, value, options)
|
67
|
-
@
|
67
|
+
@adapter.store(key, value, options)
|
68
68
|
end
|
69
69
|
|
70
70
|
# (see Proxy#increment)
|
71
71
|
def increment(key, amount = 1, options = {})
|
72
72
|
@cache.delete(key, options)
|
73
|
-
@
|
73
|
+
@adapter.increment(key, amount, options)
|
74
74
|
end
|
75
75
|
|
76
76
|
# (see Proxy#create)
|
77
77
|
def create(key, value, options = {})
|
78
|
-
if @
|
78
|
+
if @adapter.create(key, value, options)
|
79
79
|
@cache.store(key, value, options)
|
80
80
|
true
|
81
81
|
else
|
@@ -86,25 +86,25 @@ module Moneta
|
|
86
86
|
# (see Proxy#delete)
|
87
87
|
def delete(key, options = {})
|
88
88
|
@cache.delete(key, options)
|
89
|
-
@
|
89
|
+
@adapter.delete(key, options)
|
90
90
|
end
|
91
91
|
|
92
92
|
# (see Proxy#clear)
|
93
93
|
def clear(options = {})
|
94
94
|
@cache.clear(options)
|
95
|
-
@
|
95
|
+
@adapter.clear(options)
|
96
96
|
self
|
97
97
|
end
|
98
98
|
|
99
99
|
# (see Proxy#close)
|
100
100
|
def close
|
101
101
|
@cache.close
|
102
|
-
@
|
102
|
+
@adapter.close
|
103
103
|
end
|
104
104
|
|
105
105
|
# (see Proxy#features)
|
106
106
|
def features
|
107
|
-
@features ||= ((@cache.features + [:create, :increment]) & @
|
107
|
+
@features ||= ((@cache.features + [:create, :increment]) & @adapter.features).freeze
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|