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.
Files changed (52) hide show
  1. data/.travis.yml +2 -2
  2. data/CHANGES +6 -0
  3. data/Gemfile +2 -0
  4. data/README.md +7 -4
  5. data/Rakefile +2 -2
  6. data/lib/moneta.rb +1 -0
  7. data/lib/moneta/adapters/activerecord.rb +1 -2
  8. data/lib/moneta/adapters/cassandra.rb +31 -26
  9. data/lib/moneta/adapters/cookie.rb +2 -2
  10. data/lib/moneta/adapters/couch.rb +5 -3
  11. data/lib/moneta/adapters/daybreak.rb +13 -9
  12. data/lib/moneta/adapters/dbm.rb +7 -3
  13. data/lib/moneta/adapters/file.rb +4 -3
  14. data/lib/moneta/adapters/fog.rb +5 -2
  15. data/lib/moneta/adapters/gdbm.rb +7 -3
  16. data/lib/moneta/adapters/hbase.rb +11 -9
  17. data/lib/moneta/adapters/kyotocabinet.rb +13 -8
  18. data/lib/moneta/adapters/leveldb.rb +9 -5
  19. data/lib/moneta/adapters/localmemcache.rb +7 -3
  20. data/lib/moneta/adapters/memcached/dalli.rb +16 -11
  21. data/lib/moneta/adapters/memcached/native.rb +20 -15
  22. data/lib/moneta/adapters/memory.rb +2 -1
  23. data/lib/moneta/adapters/mongo.rb +13 -8
  24. data/lib/moneta/adapters/pstore.rb +24 -21
  25. data/lib/moneta/adapters/redis.rb +14 -12
  26. data/lib/moneta/adapters/restclient.rb +10 -7
  27. data/lib/moneta/adapters/riak.rb +5 -1
  28. data/lib/moneta/adapters/sdbm.rb +7 -3
  29. data/lib/moneta/adapters/sequel.rb +13 -8
  30. data/lib/moneta/adapters/sqlite.rb +15 -10
  31. data/lib/moneta/adapters/tdb.rb +8 -4
  32. data/lib/moneta/adapters/tokyocabinet.rb +15 -10
  33. data/lib/moneta/adapters/tokyotyrant.rb +107 -0
  34. data/lib/moneta/cache.rb +17 -17
  35. data/lib/moneta/mixins.rb +7 -5
  36. data/lib/moneta/version.rb +1 -1
  37. data/lib/rack/moneta_store.rb +1 -1
  38. data/lib/rack/session/moneta.rb +6 -3
  39. data/script/benchmarks +28 -28
  40. data/script/generate-specs +96 -41
  41. data/script/memusage +40 -0
  42. data/script/start-services +1 -0
  43. data/spec/helper.rb +4 -1
  44. data/spec/moneta/adapter_tokyotyrant_spec.rb +30 -0
  45. data/spec/moneta/cache_file_memory_spec.rb +3 -3
  46. data/spec/moneta/cache_memory_null_spec.rb +1 -1
  47. data/spec/moneta/simple_tokyotyrant_spec.rb +155 -0
  48. data/spec/moneta/simple_tokyotyrant_with_expires_spec.rb +157 -0
  49. data/spec/monetaspecs.rb +79 -37
  50. data/spec/rack/moneta_store_spec.rb +1 -1
  51. data/spec/rack/session_moneta_spec.rb +27 -0
  52. 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
- @client = ::Net::HTTP.start(url.host, url.port)
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 = @client.request_head(@path + key)
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 = @client.request_get(@path + key)
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 = @client.request_post(@path + key, value)
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 = @client.request(::Net::HTTP::Delete.new(@path + key))
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
- @client.request(::Net::HTTP::Delete.new(@path))
49
+ @backend.request(::Net::HTTP::Delete.new(@path))
47
50
  self
48
51
  end
49
52
 
50
53
  def close
51
- @client.finish
54
+ @backend.finish
52
55
  nil
53
56
  end
54
57
  end
@@ -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
- @bucket = ::Riak::Client.new(options).bucket(bucket)
23
+ @backend = options[:backend] || ::Riak::Client.new(options)
24
+ @bucket = @backend.bucket(bucket)
21
25
  end
22
26
 
23
27
  # (see Proxy#key?)
@@ -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
- raise ArgumentError, 'Option :file is required' unless options[:file]
12
- @hash = ::SDBM.new(options[:file])
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
- @hash.close
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
- @db = ::Sequel.connect(db, options)
20
- @db.create_table?(table) do
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 = @db[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
- @db.transaction do
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
- @db.transaction do
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
- @db.transaction do
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
- @db.transaction do
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
- @db = ::SQLite3::Database.new(options[:file])
20
- @db.execute("create table if not exists #{table} (k blob not null primary key, v blob)")
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 = @db.prepare("select v from #{table} where k = ?"),
23
- @replace = @db.prepare("replace into #{table} values (?, ?)"),
24
- @delete = @db.prepare("delete from #{table} where k = ?"),
25
- @clear = @db.prepare("delete from #{table}"),
26
- @create = @db.prepare("insert into #{table} values (?, ?)")]
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
- @db.transaction(:exclusive) { return super }
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
- @db.close
83
+ @backend.close
79
84
  nil
80
85
  end
81
86
  end
@@ -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
- def initialize(options = {})
11
- raise ArgumentError, 'Option :file is required' unless file = options.delete(:file)
12
- @hash = ::TDB.new(file, options)
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
- @hash.close
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
- raise ArgumentError, 'Option :file is required' unless options[:file]
13
- if options[:type] == :bdb
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
- @hash = ::TokyoCabinet::HDB.new
18
- @hash.open(options[:file], ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
19
- end or raise @hash.errmsg(@hash.ecode)
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
- @hash.delete(key)
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
- @hash.putkeep(key, value)
38
+ @backend.putkeep(key, value)
34
39
  end
35
40
 
36
41
  # (see Proxy#close)
37
42
  def close
38
- @hash.close
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
@@ -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
- # backend { adapter :File, :dir => 'data' }
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 backend(store = nil, &block)
25
- raise 'Backend already set' if @store.backend
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.backend = store || Moneta.build(&block)
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, :backend
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] :backend Moneta store used as backend
42
+ # @option options [Moneta store] :adapter Moneta store used as adapter
43
43
  # @yieldparam Builder block
44
44
  def initialize(options = {}, &block)
45
- @cache, @backend = options[:cache], options[:backend]
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) || @backend.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 = @backend.load(key, options)
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
- @backend.store(key, value, options)
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
- @backend.increment(key, amount, options)
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 @backend.create(key, value, options)
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
- @backend.delete(key, options)
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
- @backend.clear(options)
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
- @backend.close
102
+ @adapter.close
103
103
  end
104
104
 
105
105
  # (see Proxy#features)
106
106
  def features
107
- @features ||= ((@cache.features + [:create, :increment]) & @backend.features).freeze
107
+ @features ||= ((@cache.features + [:create, :increment]) & @adapter.features).freeze
108
108
  end
109
109
  end
110
110
  end