moneta 0.7.3 → 0.7.4

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 (178) hide show
  1. data/.travis.yml +17 -51
  2. data/CHANGES +13 -0
  3. data/Gemfile +4 -4
  4. data/README.md +79 -40
  5. data/Rakefile +40 -25
  6. data/benchmarks/run.rb +35 -5
  7. data/lib/moneta.rb +5 -5
  8. data/lib/moneta/adapters/activerecord.rb +4 -6
  9. data/lib/moneta/adapters/cassandra.rb +8 -11
  10. data/lib/moneta/adapters/couch.rb +3 -1
  11. data/lib/moneta/adapters/daybreak.rb +28 -0
  12. data/lib/moneta/adapters/fog.rb +3 -3
  13. data/lib/moneta/adapters/hbase.rb +2 -4
  14. data/lib/moneta/adapters/memcached/dalli.rb +8 -7
  15. data/lib/moneta/adapters/memcached/native.rb +8 -9
  16. data/lib/moneta/adapters/mongo.rb +42 -11
  17. data/lib/moneta/adapters/pstore.rb +4 -6
  18. data/lib/moneta/adapters/redis.rb +17 -10
  19. data/lib/moneta/adapters/restclient.rb +19 -10
  20. data/lib/moneta/adapters/sequel.rb +4 -6
  21. data/lib/moneta/adapters/tdb.rb +22 -0
  22. data/lib/moneta/expires.rb +28 -12
  23. data/lib/moneta/mixins.rb +64 -3
  24. data/lib/moneta/pool.rb +37 -0
  25. data/lib/moneta/proxy.rb +18 -7
  26. data/lib/moneta/server.rb +1 -1
  27. data/lib/moneta/shared.rb +2 -2
  28. data/lib/moneta/transformer/helper.rb +1 -1
  29. data/lib/moneta/version.rb +1 -1
  30. data/{spec/generate.rb → script/generate-specs.rb} +195 -91
  31. data/script/install-bundle.rb +35 -0
  32. data/spec/helper.rb +6 -0
  33. data/spec/moneta/adapter_activerecord_spec.rb +1 -1
  34. data/spec/moneta/adapter_cassandra_spec.rb +1 -12
  35. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +21 -0
  36. data/spec/moneta/adapter_client_spec.rb +1 -1
  37. data/spec/moneta/adapter_cookie_spec.rb +1 -1
  38. data/spec/moneta/adapter_couch_spec.rb +1 -1
  39. data/spec/moneta/adapter_datamapper_spec.rb +1 -1
  40. data/spec/moneta/adapter_daybreak_spec.rb +19 -0
  41. data/spec/moneta/adapter_dbm_spec.rb +1 -1
  42. data/spec/moneta/adapter_file_spec.rb +1 -1
  43. data/spec/moneta/adapter_fog_spec.rb +1 -1
  44. data/spec/moneta/adapter_gdbm_spec.rb +1 -1
  45. data/spec/moneta/adapter_hbase_spec.rb +1 -1
  46. data/spec/moneta/adapter_leveldb_spec.rb +1 -1
  47. data/spec/moneta/adapter_localmemcache_spec.rb +1 -1
  48. data/spec/moneta/adapter_lruhash_spec.rb +1 -1
  49. data/spec/moneta/adapter_memcached_dalli_spec.rb +1 -12
  50. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +21 -0
  51. data/spec/moneta/adapter_memcached_native_spec.rb +1 -13
  52. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +21 -0
  53. data/spec/moneta/adapter_memcached_spec.rb +1 -12
  54. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +21 -0
  55. data/spec/moneta/adapter_memory_spec.rb +1 -1
  56. data/spec/moneta/adapter_mongo_spec.rb +9 -2
  57. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +21 -0
  58. data/spec/moneta/adapter_pstore_spec.rb +1 -1
  59. data/spec/moneta/adapter_redis_spec.rb +1 -12
  60. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +21 -0
  61. data/spec/moneta/adapter_restclient_spec.rb +1 -1
  62. data/spec/moneta/adapter_riak_spec.rb +1 -1
  63. data/spec/moneta/adapter_sdbm_spec.rb +1 -1
  64. data/spec/moneta/adapter_sequel_spec.rb +1 -1
  65. data/spec/moneta/adapter_sqlite_spec.rb +1 -1
  66. data/spec/moneta/adapter_tdb_spec.rb +19 -0
  67. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -1
  68. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -1
  69. data/spec/moneta/adapter_yaml_spec.rb +1 -1
  70. data/spec/moneta/cache_file_memory_spec.rb +1 -1
  71. data/spec/moneta/cache_memory_null_spec.rb +1 -1
  72. data/spec/moneta/expires_file_spec.rb +1 -1
  73. data/spec/moneta/expires_memory_spec.rb +1 -12
  74. data/spec/moneta/expires_memory_with_default_expires_spec.rb +111 -0
  75. data/spec/moneta/lock_spec.rb +1 -1
  76. data/spec/moneta/null_adapter_spec.rb +1 -1
  77. data/spec/moneta/optionmerger_spec.rb +1 -1
  78. data/spec/moneta/pool_spec.rb +23 -0
  79. data/spec/moneta/proxy_expires_memory_spec.rb +1 -1
  80. data/spec/moneta/proxy_redis_spec.rb +1 -1
  81. data/spec/moneta/shared_spec.rb +1 -1
  82. data/spec/moneta/simple_activerecord_spec.rb +1 -1
  83. data/spec/moneta/simple_activerecord_with_expires_spec.rb +1 -1
  84. data/spec/moneta/simple_cassandra_spec.rb +1 -1
  85. data/spec/moneta/simple_client_tcp_spec.rb +1 -1
  86. data/spec/moneta/simple_client_unix_spec.rb +1 -1
  87. data/spec/moneta/simple_couch_spec.rb +1 -1
  88. data/spec/moneta/simple_couch_with_expires_spec.rb +1 -1
  89. data/spec/moneta/simple_datamapper_spec.rb +1 -1
  90. data/spec/moneta/simple_datamapper_with_expires_spec.rb +1 -1
  91. data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -1
  92. data/spec/moneta/simple_daybreak_spec.rb +144 -0
  93. data/spec/moneta/simple_daybreak_with_expires_spec.rb +145 -0
  94. data/spec/moneta/simple_dbm_spec.rb +1 -1
  95. data/spec/moneta/simple_dbm_with_expires_spec.rb +1 -1
  96. data/spec/moneta/simple_file_spec.rb +1 -1
  97. data/spec/moneta/simple_file_with_expires_spec.rb +1 -1
  98. data/spec/moneta/simple_fog_spec.rb +1 -1
  99. data/spec/moneta/simple_fog_with_expires_spec.rb +1 -1
  100. data/spec/moneta/simple_gdbm_spec.rb +1 -1
  101. data/spec/moneta/simple_gdbm_with_expires_spec.rb +1 -1
  102. data/spec/moneta/simple_hashfile_spec.rb +1 -1
  103. data/spec/moneta/simple_hashfile_with_expires_spec.rb +1 -1
  104. data/spec/moneta/simple_hbase_spec.rb +1 -1
  105. data/spec/moneta/simple_hbase_with_expires_spec.rb +1 -1
  106. data/spec/moneta/simple_leveldb_spec.rb +1 -1
  107. data/spec/moneta/simple_leveldb_with_expires_spec.rb +1 -1
  108. data/spec/moneta/simple_localmemcache_spec.rb +1 -1
  109. data/spec/moneta/simple_localmemcache_with_expires_spec.rb +1 -1
  110. data/spec/moneta/simple_lruhash_spec.rb +1 -1
  111. data/spec/moneta/simple_lruhash_with_expires_spec.rb +1 -1
  112. data/spec/moneta/simple_memcached_dalli_spec.rb +1 -1
  113. data/spec/moneta/simple_memcached_native_spec.rb +1 -1
  114. data/spec/moneta/simple_memcached_spec.rb +1 -1
  115. data/spec/moneta/simple_memory_spec.rb +1 -1
  116. data/spec/moneta/simple_memory_with_compress_spec.rb +1 -1
  117. data/spec/moneta/simple_memory_with_expires_spec.rb +1 -1
  118. data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -1
  119. data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -1
  120. data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -1
  121. data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -1
  122. data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -1
  123. data/spec/moneta/simple_mongo_spec.rb +3 -2
  124. data/spec/moneta/simple_null_spec.rb +1 -1
  125. data/spec/moneta/simple_pstore_spec.rb +1 -1
  126. data/spec/moneta/simple_pstore_with_expires_spec.rb +1 -1
  127. data/spec/moneta/simple_redis_spec.rb +1 -1
  128. data/spec/moneta/simple_restclient_spec.rb +1 -1
  129. data/spec/moneta/simple_riak_spec.rb +1 -1
  130. data/spec/moneta/simple_riak_with_expires_spec.rb +1 -1
  131. data/spec/moneta/simple_sdbm_spec.rb +1 -1
  132. data/spec/moneta/simple_sdbm_with_expires_spec.rb +1 -1
  133. data/spec/moneta/simple_sequel_spec.rb +1 -1
  134. data/spec/moneta/simple_sequel_with_expires_spec.rb +1 -1
  135. data/spec/moneta/simple_sqlite_spec.rb +1 -1
  136. data/spec/moneta/simple_sqlite_with_expires_spec.rb +1 -1
  137. data/spec/moneta/simple_tdb_spec.rb +144 -0
  138. data/spec/moneta/{simple_mongo_with_expires_spec.rb → simple_tdb_with_expires_spec.rb} +4 -4
  139. data/spec/moneta/simple_tokyocabinet_spec.rb +1 -1
  140. data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +1 -1
  141. data/spec/moneta/simple_yaml_spec.rb +1 -1
  142. data/spec/moneta/simple_yaml_with_expires_spec.rb +1 -1
  143. data/spec/moneta/stack_file_memory_spec.rb +1 -1
  144. data/spec/moneta/stack_memory_file_spec.rb +1 -1
  145. data/spec/moneta/transformer_bencode_spec.rb +1 -1
  146. data/spec/moneta/transformer_bert_spec.rb +1 -1
  147. data/spec/moneta/transformer_bson_spec.rb +1 -1
  148. data/spec/moneta/transformer_bzip2_spec.rb +1 -1
  149. data/spec/moneta/transformer_json_spec.rb +1 -1
  150. data/spec/moneta/transformer_key_marshal_spec.rb +1 -1
  151. data/spec/moneta/transformer_key_yaml_spec.rb +1 -1
  152. data/spec/moneta/transformer_lzma_spec.rb +1 -1
  153. data/spec/moneta/transformer_lzo_spec.rb +1 -1
  154. data/spec/moneta/transformer_marshal_base64_spec.rb +1 -1
  155. data/spec/moneta/transformer_marshal_escape_spec.rb +1 -1
  156. data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -1
  157. data/spec/moneta/transformer_marshal_md5_spec.rb +1 -1
  158. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -1
  159. data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -1
  160. data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -1
  161. data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -1
  162. data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -1
  163. data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -1
  164. data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -1
  165. data/spec/moneta/transformer_marshal_spec.rb +1 -1
  166. data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -1
  167. data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -1
  168. data/spec/moneta/transformer_msgpack_spec.rb +1 -1
  169. data/spec/moneta/transformer_ox_spec.rb +1 -1
  170. data/spec/moneta/transformer_quicklz_spec.rb +1 -1
  171. data/spec/moneta/transformer_snappy_spec.rb +1 -1
  172. data/spec/moneta/transformer_tnet_spec.rb +1 -1
  173. data/spec/moneta/transformer_value_marshal_spec.rb +1 -1
  174. data/spec/moneta/transformer_value_yaml_spec.rb +1 -1
  175. data/spec/moneta/transformer_yaml_spec.rb +1 -1
  176. data/spec/moneta/transformer_zlib_spec.rb +1 -1
  177. data/spec/monetaspecs.rb +105 -3
  178. metadata +35 -6
data/lib/moneta.rb CHANGED
@@ -2,6 +2,7 @@ module Moneta
2
2
  autoload :Builder, 'moneta/builder'
3
3
  autoload :Cache, 'moneta/cache'
4
4
  autoload :Defaults, 'moneta/mixins'
5
+ autoload :ExpiresSupport, 'moneta/mixins'
5
6
  autoload :Expires, 'moneta/expires'
6
7
  autoload :HashAdapter, 'moneta/mixins'
7
8
  autoload :IncrementSupport, 'moneta/mixins'
@@ -10,6 +11,7 @@ module Moneta
10
11
  autoload :Net, 'moneta/mixins'
11
12
  autoload :OptionMerger, 'moneta/optionmerger'
12
13
  autoload :OptionSupport, 'moneta/mixins'
14
+ autoload :Pool, 'moneta/pool'
13
15
  autoload :Proxy, 'moneta/proxy'
14
16
  autoload :Server, 'moneta/server'
15
17
  autoload :Shared, 'moneta/shared'
@@ -23,6 +25,7 @@ module Moneta
23
25
  autoload :Client, 'moneta/adapters/client'
24
26
  autoload :Cookie, 'moneta/adapters/cookie'
25
27
  autoload :Couch, 'moneta/adapters/couch'
28
+ autoload :Daybreak, 'moneta/adapters/daybreak'
26
29
  autoload :DBM, 'moneta/adapters/dbm'
27
30
  autoload :DataMapper, 'moneta/adapters/datamapper'
28
31
  autoload :File, 'moneta/adapters/file'
@@ -45,6 +48,7 @@ module Moneta
45
48
  autoload :SDBM, 'moneta/adapters/sdbm'
46
49
  autoload :Sequel, 'moneta/adapters/sequel'
47
50
  autoload :Sqlite, 'moneta/adapters/sqlite'
51
+ autoload :TDB, 'moneta/adapters/tdb'
48
52
  autoload :TokyoCabinet, 'moneta/adapters/tokyocabinet'
49
53
  autoload :YAML, 'moneta/adapters/yaml'
50
54
  end
@@ -98,10 +102,6 @@ module Moneta
98
102
  # Riak accepts only utf-8 keys over the http interface
99
103
  # We use base64 encoding therefore.
100
104
  transformer[:key] << :base64
101
- when :Memcached, :MemcachedDalli, :MemcachedNative
102
- # Memcached supports expires already
103
- options[:expires] = expires if Integer === expires
104
- expires = false
105
105
  when :PStore, :YAML, :Null
106
106
  # For PStore and YAML only the key has to be a string
107
107
  transformer.delete(:value) if transformer[:value] == [:marshal]
@@ -112,7 +112,7 @@ module Moneta
112
112
  when :File
113
113
  # Use escaping
114
114
  transformer[:key] << :escape
115
- when :Cassandra, :Redis
115
+ when :Cassandra, :Redis, :Mongo, :Memcached, :MemcachedDalli, :MemcachedNative
116
116
  # Expires already supported
117
117
  options[:expires] = expires if Integer === expires
118
118
  expires = false
@@ -6,6 +6,7 @@ module Moneta
6
6
  # @api public
7
7
  class ActiveRecord
8
8
  include Defaults
9
+ include IncrementSupport
9
10
 
10
11
  def self.tables
11
12
  @tables ||= {}
@@ -66,13 +67,10 @@ module Moneta
66
67
  # (see Proxy#increment)
67
68
  def increment(key, amount = 1, options = {})
68
69
  record = @table.where(:k => key).lock.first_or_initialize
69
- value = record.v
70
- intvalue = value.to_i
71
- raise 'Tried to increment non integer value' unless value == nil || intvalue.to_s == value.to_s
72
- intvalue += amount
73
- record.v = intvalue.to_s
70
+ value = convert_for_increment(record.v) + amount
71
+ record.v = value.to_s
74
72
  record.save
75
- intvalue
73
+ value
76
74
  end
77
75
 
78
76
  # (see Proxy#clear)
@@ -9,6 +9,7 @@ module Moneta
9
9
  # @api public
10
10
  class Cassandra
11
11
  include Defaults
12
+ include ExpiresSupport
12
13
 
13
14
  # @param [Hash] options
14
15
  # @option options [String] :keyspace ('moneta') Cassandra keyspace
@@ -19,7 +20,7 @@ module Moneta
19
20
  def initialize(options = {})
20
21
  options[:host] ||= '127.0.0.1'
21
22
  options[:port] ||= 9160
22
- @expires = options[:expires]
23
+ self.default_expires = options[:expires]
23
24
  keyspace = (options[:keyspace] ||= 'moneta')
24
25
  @cf = (options[:column_family] || 'moneta').to_sym
25
26
  @client = ::Cassandra.new('system', "#{options[:host]}:#{options[:port]}")
@@ -35,7 +36,7 @@ module Moneta
35
36
  begin
36
37
  @client.add_keyspace(ks_def)
37
38
  rescue Exception => ex
38
- puts "Cassandra: #{ex.message}"
39
+ warn "Cassandra: #{ex.message}"
39
40
  end
40
41
  break if @client.keyspaces.include?(keyspace)
41
42
  sleep 0.1
@@ -47,9 +48,7 @@ module Moneta
47
48
  # (see Proxy#key?)
48
49
  def key?(key, options = {})
49
50
  if @client.exists?(@cf, key)
50
- if options.include?(:expires) && (value = load(key))
51
- store(key, value, options)
52
- end
51
+ load(key, options) if options.include?(:expires)
53
52
  true
54
53
  else
55
54
  false
@@ -60,17 +59,15 @@ module Moneta
60
59
  def load(key, options = {})
61
60
  value = @client.get(@cf, key)
62
61
  if value
63
- if options.include?(:expires)
64
- store(key, value['value'], options)
65
- else
66
- value['value']
67
- end
62
+ expires = expires_value(options, nil)
63
+ @client.insert(@cf, key, {'value' => value['value'] }, :ttl => expires || nil) if expires != nil
64
+ value['value']
68
65
  end
69
66
  end
70
67
 
71
68
  # (see Proxy#store)
72
69
  def store(key, value, options = {})
73
- @client.insert(@cf, key, {'value' => value}, :ttl => (options[:expires] || @expires))
70
+ @client.insert(@cf, key, {'value' => value}, :ttl => expires_value(options) || nil)
74
71
  value
75
72
  end
76
73
 
@@ -8,10 +8,12 @@ module Moneta
8
8
  include Defaults
9
9
 
10
10
  # @param [Hash] options
11
+ # @option options [String] :host ('http://127.0.0.1:5984') Couch host
11
12
  # @option options [String] :db ('moneta') Couch database
12
13
  def initialize(options = {})
13
14
  options[:db] ||= 'moneta'
14
- @db = ::CouchRest.database!(options[:db])
15
+ options[:host] ||= '127.0.0.1:5984'
16
+ @db = CouchRest.new(options[:host]).database!(options[:db])
15
17
  end
16
18
 
17
19
  # (see Proxy#key?)
@@ -0,0 +1,28 @@
1
+ require 'daybreak'
2
+
3
+ module Moneta
4
+ module Adapters
5
+ # Daybreak backend
6
+ # @api public
7
+ class Daybreak < Memory
8
+ # Disable serialization, we have `Moneta::Transformer` for that
9
+ class DB < ::Daybreak::DB
10
+ def serialize(value) value; end
11
+ def parse(value) value; end
12
+ end
13
+
14
+ # @param [Hash] options
15
+ # @option options [String] :file Database file
16
+ def initialize(options = {})
17
+ raise ArgumentError, 'Option :file is required' unless options[:file]
18
+ @hash = DB.new(options[:file])
19
+ end
20
+
21
+ # (see Proxy#close)
22
+ def close
23
+ @hash.close!
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,4 +1,4 @@
1
- require 'fog'
1
+ require 'fog/storage'
2
2
 
3
3
  module Moneta
4
4
  module Adapters
@@ -13,7 +13,7 @@ module Moneta
13
13
  def initialize(options = {})
14
14
  raise ArgumentError, 'Option :dir is required' unless dir = options.delete(:dir)
15
15
  storage = ::Fog::Storage.new(options)
16
- @directory = storage.directories.create(:key => dir)
16
+ @directory = storage.directories.get(dir) || storage.directories.create(:key => dir)
17
17
  end
18
18
 
19
19
  # (see Proxy#key?)
@@ -38,7 +38,7 @@ module Moneta
38
38
 
39
39
  # (see Proxy#store)
40
40
  def store(key, value, options = {})
41
- @directory.files.create(:key => key, :body => value)
41
+ @directory.files.create(options.merge(:key => key, :body => value))
42
42
  value
43
43
  end
44
44
 
@@ -6,6 +6,7 @@ module Moneta
6
6
  # @api public
7
7
  class HBase
8
8
  include Defaults
9
+ include IncrementSupport
9
10
 
10
11
  # @param [Hash] options
11
12
  # @option options [String] :host ('127.0.0.1') Server host name
@@ -46,10 +47,7 @@ module Moneta
46
47
  def increment(key, amount = 1, options = {})
47
48
  result = @table.atomic_increment(key, @column, amount)
48
49
  # HACK: Throw error if applied to invalid value
49
- if result == 0
50
- value = load(key)
51
- raise 'Tried to increment non integer value' unless value.to_s == value.to_i.to_s
52
- end
50
+ convert_for_increment(load(key)) if result == 0
53
51
  result
54
52
  end
55
53
 
@@ -6,13 +6,14 @@ module Moneta
6
6
  # @api public
7
7
  class MemcachedDalli
8
8
  include Defaults
9
+ include ExpiresSupport
9
10
 
10
11
  # @param [Hash] options
11
12
  # @option options [String] :server ('127.0.0.1:11211') Memcached server
12
13
  # @option options [Integer] :expires Default expiration time
13
14
  # @option options Other options passed to `Dalli::Client#new`
14
15
  def initialize(options = {})
15
- options[:expires_in] = options.delete(:expires)
16
+ self.default_expires = options.delete(:expires)
16
17
  server = options.delete(:server) || '127.0.0.1:11211'
17
18
  @cache = ::Dalli::Client.new(server, options)
18
19
  end
@@ -20,16 +21,16 @@ module Moneta
20
21
  # (see Proxy#load)
21
22
  def load(key, options = {})
22
23
  value = @cache.get(key)
23
- if value && options.include?(:expires)
24
- store(key, value, options)
25
- else
24
+ if value
25
+ expires = expires_value(options, nil)
26
+ @cache.set(key, value, expires || nil, :raw => true) if expires != nil
26
27
  value
27
28
  end
28
29
  end
29
30
 
30
31
  # (see Proxy#store)
31
32
  def store(key, value, options = {})
32
- @cache.set(key, value, options[:expires], :raw => true)
33
+ @cache.set(key, value, expires_value(options) || nil, :raw => true)
33
34
  value
34
35
  end
35
36
 
@@ -45,9 +46,9 @@ module Moneta
45
46
  # FIXME: There is a Dalli bug, load(key) returns a wrong value after increment
46
47
  # therefore we set default = nil and create the counter manually
47
48
  result = if amount >= 0
48
- @cache.incr(key, amount, options[:expires], nil)
49
+ @cache.incr(key, amount, expires_value(options) || nil, nil)
49
50
  else
50
- @cache.decr(key, -amount, options[:expires], nil)
51
+ @cache.decr(key, -amount, expires_value(options) || nil, nil)
51
52
  end
52
53
  if result
53
54
  result
@@ -6,6 +6,8 @@ module Moneta
6
6
  # @api public
7
7
  class MemcachedNative
8
8
  include Defaults
9
+ include IncrementSupport
10
+ include ExpiresSupport
9
11
 
10
12
  # @param [Hash] options
11
13
  # @option options [String] :server ('127.0.0.1:11211') Memcached server
@@ -14,7 +16,7 @@ module Moneta
14
16
  # @option options Other options passed to `Memcached#new`
15
17
  def initialize(options = {})
16
18
  server = options.delete(:server) || '127.0.0.1:11211'
17
- @expires = options.delete(:expires) || 604800
19
+ self.default_expires = options.delete(:expires)
18
20
  options.merge!(:prefix_key => options.delete(:namespace)) if options[:namespace]
19
21
  # We don't want a limitation on the key charset. Therefore we use the binary protocol.
20
22
  # It is also faster.
@@ -25,9 +27,9 @@ module Moneta
25
27
  # (see Proxy#load)
26
28
  def load(key, options = {})
27
29
  value = @cache.get(key, false)
28
- if value && options.include?(:expires)
29
- store(key, value, options)
30
- else
30
+ if value
31
+ expires = expires_value(options, nil)
32
+ @cache.set(key, value, expires || 0, false) if expires != nil
31
33
  value
32
34
  end
33
35
  rescue ::Memcached::NotFound
@@ -36,7 +38,7 @@ module Moneta
36
38
  # (see Proxy#store)
37
39
  def store(key, value, options = {})
38
40
  # TTL must be Fixnum
39
- @cache.set(key, value, options[:expires] || @expires, false)
41
+ @cache.set(key, value, expires_value(options) || 0, false)
40
42
  value
41
43
  end
42
44
 
@@ -56,10 +58,7 @@ module Moneta
56
58
  @cache.decrement(key, -amount)
57
59
  end
58
60
  # HACK: Throw error if applied to invalid value
59
- if result == 0
60
- value = @cache.get(key, false) rescue nil
61
- raise 'Tried to increment non integer value' unless value.to_s == value.to_i.to_s
62
- end
61
+ convert_for_increment((@cache.get(key, false) rescue nil)) if result == 0
63
62
  result
64
63
  rescue ::Memcached::NotFound => ex
65
64
  store(key, amount.to_s, options)
@@ -3,28 +3,60 @@ require 'mongo'
3
3
  module Moneta
4
4
  module Adapters
5
5
  # MongoDB backend
6
+ #
7
+ # Supports expiration, documents will be automatically removed starting
8
+ # with mongodb >= 2.2 (see http://docs.mongodb.org/manual/tutorial/expire-data/).
9
+ #
6
10
  # @api public
7
11
  class Mongo
8
12
  include Defaults
13
+ include ExpiresSupport
9
14
 
10
15
  # @param [Hash] options
11
16
  # @option options [String] :collection ('moneta') MongoDB collection name
12
17
  # @option options [String] :host ('127.0.0.1') MongoDB server host
13
18
  # @option options [Integer] :port (MongoDB default port) MongoDB server port
14
19
  # @option options [String] :db ('moneta') MongoDB database
20
+ # @option options [Integer] :expires Default expiration time
15
21
  def initialize(options = {})
22
+ self.default_expires = options.delete(:expires)
16
23
  collection = options.delete(:collection) || 'moneta'
17
24
  host = options.delete(:host) || '127.0.0.1'
18
- port = options.delete(:port) || ::Mongo::Connection::DEFAULT_PORT
25
+ port = options.delete(:port) || ::Mongo::MongoClient::DEFAULT_PORT
19
26
  db = options.delete(:db) || 'moneta'
20
- connection = ::Mongo::Connection.new(host, port, options)
27
+ connection = ::Mongo::MongoClient.new(host, port, options)
21
28
  @collection = connection.db(db).collection(collection)
29
+ if connection.server_version >= '2.2'
30
+ @collection.ensure_index([['expiresAt', ::Mongo::ASCENDING]], :expireAfterSeconds => 0)
31
+ else
32
+ warn 'You are using MongoDB version < 2.2, expired documents will not be deleted'
33
+ end
22
34
  end
23
35
 
24
36
  # (see Proxy#load)
25
37
  def load(key, options = {})
26
- value = @collection.find_one('_id' => ::BSON::Binary.new(key))
27
- value && value['value'].to_s
38
+ key = ::BSON::Binary.new(key)
39
+ doc = @collection.find_one('_id' => key)
40
+ if doc && (!doc['expiresAt'] || doc['expiresAt'] >= Time.now)
41
+ expires = expires_at(options, nil)
42
+ @collection.update({ '_id' => key },
43
+ # expiresAt must be a Time object (BSON date datatype)
44
+ { '$set' => { 'expiresAt' => expires || nil } }) if expires != nil
45
+ doc['value'].to_s
46
+ end
47
+ end
48
+
49
+ # (see Proxy#store)
50
+ def store(key, value, options = {})
51
+ key = ::BSON::Binary.new(key)
52
+ intvalue = value.to_i
53
+ @collection.update({ '_id' => key },
54
+ { '_id' => key,
55
+ 'value' => intvalue.to_s == value ? intvalue : ::BSON::Binary.new(value),
56
+ # expiresAt must be a Time object (BSON date datatype)
57
+ 'expiresAt' => expires_at(options) || nil },
58
+ { :upsert => true })
59
+ value
28
60
  end
29
61
 
30
62
  # (see Proxy#delete)
@@ -34,13 +66,12 @@ module Moneta
34
66
  value
35
67
  end
36
68
 
37
- # (see Proxy#store)
38
- def store(key, value, options = {})
39
- key = ::BSON::Binary.new(key)
40
- @collection.update({ '_id' => key },
41
- { '_id' => key, 'value' => ::BSON::Binary.new(value) },
42
- { :upsert => true })
43
- value
69
+ # (see Proxy#increment)
70
+ def increment(key, amount = 1, options = {})
71
+ @collection.find_and_modify(:query => { '_id' => ::BSON::Binary.new(key) },
72
+ :update => { '$inc' => { 'value' => amount } },
73
+ :new => true,
74
+ :upsert => true)['value']
44
75
  end
45
76
 
46
77
  # (see Proxy#clear)
@@ -6,6 +6,7 @@ module Moneta
6
6
  # @api public
7
7
  class PStore
8
8
  include Defaults
9
+ include IncrementSupport
9
10
 
10
11
  # @param [Hash] options
11
12
  # @option options [String] :file PStore file
@@ -38,12 +39,9 @@ module Moneta
38
39
  # (see Proxy#increment)
39
40
  def increment(key, amount = 1, options = {})
40
41
  @pstore.transaction do
41
- value = @pstore[key]
42
- intvalue = value.to_i
43
- raise 'Tried to increment non integer value' unless value == nil || intvalue.to_s == value.to_s
44
- intvalue += amount
45
- @pstore[key] = intvalue.to_s
46
- intvalue
42
+ value = convert_for_increment(@pstore[key]) + amount
43
+ @pstore[key] = value.to_s
44
+ value
47
45
  end
48
46
  end
49
47
 
@@ -6,21 +6,20 @@ module Moneta
6
6
  # @api public
7
7
  class Redis
8
8
  include Defaults
9
+ include ExpiresSupport
9
10
 
10
11
  # @param [Hash] options
11
12
  # @option options [Integer] :expires Default expiration time
12
13
  # @option options Other options passed to `Redis#new`
13
14
  def initialize(options = {})
14
- @expires = options.delete(:expires)
15
+ self.default_expires = options.delete(:expires)
15
16
  @redis = ::Redis.new(options)
16
17
  end
17
18
 
18
19
  # (see Proxy#key?)
19
20
  def key?(key, options = {})
20
21
  if @redis.exists(key)
21
- if expires = options[:expires]
22
- @redis.expire(key, expires)
23
- end
22
+ update_expires(key, options, nil)
24
23
  true
25
24
  else
26
25
  false
@@ -30,15 +29,13 @@ module Moneta
30
29
  # (see Proxy#load)
31
30
  def load(key, options = {})
32
31
  value = @redis.get(key)
33
- if value && (expires = options[:expires])
34
- @redis.expire(key, expires)
35
- end
32
+ update_expires(key, options, nil)
36
33
  value
37
34
  end
38
35
 
39
36
  # (see Proxy#store)
40
37
  def store(key, value, options = {})
41
- if expires = (options[:expires] || @expires)
38
+ if expires = expires_value(options)
42
39
  @redis.setex(key, expires, value)
43
40
  else
44
41
  @redis.set(key, value)
@@ -57,8 +54,7 @@ module Moneta
57
54
  # (see Proxy#increment)
58
55
  def increment(key, amount = 1, options = {})
59
56
  value = @redis.incrby(key, amount)
60
- expires = (options[:expires] || @expires)
61
- @redis.expire(key, expires) if expires
57
+ update_expires(key, options)
62
58
  value
63
59
  end
64
60
 
@@ -67,6 +63,17 @@ module Moneta
67
63
  @redis.flushdb
68
64
  self
69
65
  end
66
+
67
+ protected
68
+
69
+ def update_expires(key, options, default = @default_expires)
70
+ case expires = expires_value(options, default)
71
+ when false
72
+ @redis.persist(key)
73
+ when Numeric
74
+ @redis.expire(key, expires)
75
+ end
76
+ end
70
77
  end
71
78
  end
72
79
  end