moneta 0.7.9 → 0.7.10

Sign up to get free protection for your applications and to get access to all the features.
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