moneta 0.7.6 → 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. data/CHANGES +15 -0
  2. data/README.md +160 -50
  3. data/Rakefile +11 -2
  4. data/SPEC.md +7 -2
  5. data/lib/moneta.rb +7 -1
  6. data/lib/moneta/adapters/activerecord.rb +27 -3
  7. data/lib/moneta/adapters/cassandra.rb +1 -1
  8. data/lib/moneta/adapters/client.rb +8 -2
  9. data/lib/moneta/adapters/cookie.rb +1 -1
  10. data/lib/moneta/adapters/couch.rb +2 -1
  11. data/lib/moneta/adapters/datamapper.rb +16 -0
  12. data/lib/moneta/adapters/daybreak.rb +19 -1
  13. data/lib/moneta/adapters/file.rb +12 -0
  14. data/lib/moneta/adapters/hbase.rb +1 -2
  15. data/lib/moneta/adapters/lruhash.rb +4 -1
  16. data/lib/moneta/adapters/memcached.rb +7 -3
  17. data/lib/moneta/adapters/memcached/dalli.rb +8 -2
  18. data/lib/moneta/adapters/memcached/native.rb +10 -3
  19. data/lib/moneta/adapters/memory.rb +1 -0
  20. data/lib/moneta/adapters/mongo.rb +32 -5
  21. data/lib/moneta/adapters/pstore.rb +13 -2
  22. data/lib/moneta/adapters/redis.rb +19 -0
  23. data/lib/moneta/adapters/restclient.rb +1 -1
  24. data/lib/moneta/adapters/sequel.rb +20 -6
  25. data/lib/moneta/adapters/sqlite.rb +13 -1
  26. data/lib/moneta/adapters/tokyocabinet.rb +5 -0
  27. data/lib/moneta/cache.rb +10 -0
  28. data/lib/moneta/expires.rb +19 -22
  29. data/lib/moneta/lock.rb +2 -2
  30. data/lib/moneta/mixins.rb +33 -11
  31. data/lib/moneta/optionmerger.rb +1 -1
  32. data/lib/moneta/proxy.rb +13 -8
  33. data/lib/moneta/server.rb +13 -6
  34. data/lib/moneta/shared.rb +6 -10
  35. data/lib/moneta/synchronize.rb +125 -0
  36. data/lib/moneta/transformer.rb +50 -42
  37. data/lib/moneta/transformer/config.rb +34 -32
  38. data/lib/moneta/utils.rb +20 -0
  39. data/lib/moneta/version.rb +1 -1
  40. data/lib/moneta/weak.rb +17 -0
  41. data/lib/moneta/wrapper.rb +5 -0
  42. data/lib/rack/moneta_cookies.rb +2 -2
  43. data/lib/rack/moneta_store.rb +4 -4
  44. data/script/benchmarks +3 -9
  45. data/script/generate-specs +278 -41
  46. data/script/install-bundle +2 -2
  47. data/spec/moneta/adapter_activerecord_spec.rb +1 -0
  48. data/spec/moneta/adapter_cassandra_spec.rb +1 -0
  49. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +1 -0
  50. data/spec/moneta/adapter_client_spec.rb +1 -0
  51. data/spec/moneta/adapter_cookie_spec.rb +1 -0
  52. data/spec/moneta/adapter_couch_spec.rb +1 -0
  53. data/spec/moneta/adapter_datamapper_spec.rb +1 -0
  54. data/spec/moneta/adapter_daybreak_spec.rb +1 -0
  55. data/spec/moneta/adapter_dbm_spec.rb +1 -0
  56. data/spec/moneta/adapter_file_spec.rb +1 -0
  57. data/spec/moneta/adapter_fog_spec.rb +1 -0
  58. data/spec/moneta/adapter_gdbm_spec.rb +1 -1
  59. data/spec/moneta/adapter_hbase_spec.rb +1 -0
  60. data/spec/moneta/adapter_leveldb_spec.rb +1 -0
  61. data/spec/moneta/adapter_localmemcache_spec.rb +1 -0
  62. data/spec/moneta/adapter_lruhash_spec.rb +1 -0
  63. data/spec/moneta/adapter_memcached_dalli_spec.rb +2 -0
  64. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +2 -0
  65. data/spec/moneta/adapter_memcached_native_spec.rb +2 -0
  66. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +2 -0
  67. data/spec/moneta/adapter_memcached_spec.rb +2 -0
  68. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +2 -0
  69. data/spec/moneta/adapter_memory_spec.rb +1 -0
  70. data/spec/moneta/adapter_mongo_spec.rb +2 -0
  71. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +2 -0
  72. data/spec/moneta/adapter_pstore_spec.rb +1 -0
  73. data/spec/moneta/adapter_redis_spec.rb +2 -0
  74. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +2 -0
  75. data/spec/moneta/adapter_restclient_spec.rb +1 -0
  76. data/spec/moneta/adapter_riak_spec.rb +1 -0
  77. data/spec/moneta/adapter_sdbm_spec.rb +1 -0
  78. data/spec/moneta/adapter_sequel_spec.rb +1 -0
  79. data/spec/moneta/adapter_sqlite_spec.rb +1 -0
  80. data/spec/moneta/adapter_tdb_spec.rb +1 -0
  81. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -0
  82. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -0
  83. data/spec/moneta/adapter_yaml_spec.rb +1 -0
  84. data/spec/moneta/cache_file_memory_spec.rb +1 -0
  85. data/spec/moneta/cache_memory_null_spec.rb +1 -0
  86. data/spec/moneta/expires_file_spec.rb +3 -1
  87. data/spec/moneta/expires_memory_spec.rb +2 -0
  88. data/spec/moneta/expires_memory_with_default_expires_spec.rb +2 -0
  89. data/spec/moneta/lock_spec.rb +1 -0
  90. data/spec/moneta/mutex_spec.rb +71 -0
  91. data/spec/moneta/null_adapter_spec.rb +1 -0
  92. data/spec/moneta/optionmerger_spec.rb +5 -7
  93. data/spec/moneta/pool_spec.rb +1 -0
  94. data/spec/moneta/proxy_expires_memory_spec.rb +2 -0
  95. data/spec/moneta/proxy_redis_spec.rb +2 -0
  96. data/spec/moneta/semaphore_spec.rb +84 -0
  97. data/spec/moneta/{shared_spec.rb → shared_tcp_spec.rb} +4 -3
  98. data/spec/moneta/shared_unix_spec.rb +37 -0
  99. data/spec/moneta/simple_activerecord_spec.rb +1 -0
  100. data/spec/moneta/simple_activerecord_with_expires_spec.rb +3 -1
  101. data/spec/moneta/simple_cassandra_spec.rb +1 -0
  102. data/spec/moneta/simple_client_tcp_spec.rb +1 -0
  103. data/spec/moneta/simple_client_unix_spec.rb +3 -2
  104. data/spec/moneta/simple_couch_spec.rb +1 -0
  105. data/spec/moneta/simple_couch_with_expires_spec.rb +2 -1
  106. data/spec/moneta/simple_datamapper_spec.rb +1 -0
  107. data/spec/moneta/simple_datamapper_with_expires_spec.rb +3 -1
  108. data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -0
  109. data/spec/moneta/simple_daybreak_spec.rb +1 -0
  110. data/spec/moneta/simple_daybreak_with_expires_spec.rb +3 -1
  111. data/spec/moneta/simple_dbm_spec.rb +1 -0
  112. data/spec/moneta/simple_dbm_with_expires_spec.rb +3 -1
  113. data/spec/moneta/simple_file_spec.rb +1 -0
  114. data/spec/moneta/simple_file_with_expires_spec.rb +3 -1
  115. data/spec/moneta/simple_fog_spec.rb +1 -0
  116. data/spec/moneta/simple_fog_with_expires_spec.rb +2 -1
  117. data/spec/moneta/simple_gdbm_spec.rb +1 -0
  118. data/spec/moneta/simple_gdbm_with_expires_spec.rb +3 -1
  119. data/spec/moneta/simple_hashfile_spec.rb +1 -0
  120. data/spec/moneta/simple_hashfile_with_expires_spec.rb +3 -1
  121. data/spec/moneta/simple_hbase_spec.rb +1 -0
  122. data/spec/moneta/simple_hbase_with_expires_spec.rb +3 -1
  123. data/spec/moneta/simple_leveldb_spec.rb +1 -0
  124. data/spec/moneta/simple_leveldb_with_expires_spec.rb +3 -1
  125. data/spec/moneta/simple_localmemcache_spec.rb +1 -0
  126. data/spec/moneta/simple_localmemcache_with_expires_spec.rb +2 -1
  127. data/spec/moneta/simple_lruhash_spec.rb +1 -0
  128. data/spec/moneta/simple_lruhash_with_expires_spec.rb +3 -1
  129. data/spec/moneta/simple_memcached_dalli_spec.rb +2 -0
  130. data/spec/moneta/simple_memcached_native_spec.rb +2 -0
  131. data/spec/moneta/simple_memcached_spec.rb +2 -0
  132. data/spec/moneta/simple_memory_spec.rb +1 -0
  133. data/spec/moneta/simple_memory_with_compress_spec.rb +1 -0
  134. data/spec/moneta/simple_memory_with_expires_spec.rb +3 -1
  135. data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -0
  136. data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -0
  137. data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -0
  138. data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -0
  139. data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -0
  140. data/spec/moneta/simple_mongo_spec.rb +2 -0
  141. data/spec/moneta/simple_null_spec.rb +1 -0
  142. data/spec/moneta/simple_pstore_spec.rb +1 -0
  143. data/spec/moneta/simple_pstore_with_expires_spec.rb +3 -1
  144. data/spec/moneta/simple_redis_spec.rb +2 -0
  145. data/spec/moneta/simple_restclient_spec.rb +1 -0
  146. data/spec/moneta/simple_riak_spec.rb +1 -0
  147. data/spec/moneta/simple_riak_with_expires_spec.rb +2 -1
  148. data/spec/moneta/simple_sdbm_spec.rb +1 -0
  149. data/spec/moneta/simple_sdbm_with_expires_spec.rb +3 -1
  150. data/spec/moneta/simple_sequel_spec.rb +1 -0
  151. data/spec/moneta/simple_sequel_with_expires_spec.rb +3 -1
  152. data/spec/moneta/simple_sqlite_spec.rb +1 -0
  153. data/spec/moneta/simple_sqlite_with_expires_spec.rb +3 -1
  154. data/spec/moneta/simple_tdb_spec.rb +1 -0
  155. data/spec/moneta/simple_tdb_with_expires_spec.rb +3 -1
  156. data/spec/moneta/simple_tokyocabinet_spec.rb +1 -0
  157. data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +3 -1
  158. data/spec/moneta/simple_yaml_spec.rb +1 -0
  159. data/spec/moneta/simple_yaml_with_expires_spec.rb +3 -1
  160. data/spec/moneta/stack_file_memory_spec.rb +1 -0
  161. data/spec/moneta/stack_memory_file_spec.rb +1 -0
  162. data/spec/moneta/transformer_bencode_spec.rb +1 -0
  163. data/spec/moneta/transformer_bert_spec.rb +1 -0
  164. data/spec/moneta/transformer_bson_spec.rb +1 -0
  165. data/spec/moneta/transformer_bzip2_spec.rb +1 -0
  166. data/spec/moneta/transformer_json_spec.rb +1 -0
  167. data/spec/moneta/transformer_key_inspect_spec.rb +73 -0
  168. data/spec/moneta/transformer_key_marshal_spec.rb +1 -0
  169. data/spec/moneta/transformer_key_to_s_spec.rb +1 -0
  170. data/spec/moneta/transformer_key_yaml_spec.rb +1 -0
  171. data/spec/moneta/transformer_lzma_spec.rb +1 -0
  172. data/spec/moneta/transformer_lzo_spec.rb +1 -0
  173. data/spec/moneta/transformer_marshal_base64_spec.rb +1 -0
  174. data/spec/moneta/transformer_marshal_escape_spec.rb +1 -0
  175. data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -0
  176. data/spec/moneta/transformer_marshal_md5_spec.rb +1 -0
  177. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -0
  178. data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -0
  179. data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -0
  180. data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -0
  181. data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -0
  182. data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -0
  183. data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -0
  184. data/spec/moneta/transformer_marshal_spec.rb +1 -0
  185. data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -0
  186. data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -0
  187. data/spec/moneta/transformer_msgpack_spec.rb +1 -0
  188. data/spec/moneta/transformer_ox_spec.rb +1 -0
  189. data/spec/moneta/transformer_quicklz_spec.rb +1 -0
  190. data/spec/moneta/transformer_snappy_spec.rb +1 -0
  191. data/spec/moneta/transformer_tnet_spec.rb +1 -0
  192. data/spec/moneta/transformer_value_marshal_spec.rb +1 -0
  193. data/spec/moneta/transformer_value_yaml_spec.rb +1 -0
  194. data/spec/moneta/transformer_yaml_spec.rb +1 -0
  195. data/spec/moneta/transformer_zlib_spec.rb +1 -0
  196. data/spec/moneta/weak_create_spec.rb +114 -0
  197. data/spec/moneta/weak_increment_spec.rb +114 -0
  198. data/spec/monetaspecs.rb +75 -2
  199. data/spec/rack/moneta_cookies_spec.rb +1 -1
  200. metadata +20 -4
@@ -20,7 +20,8 @@ module Moneta
20
20
  [@select = @db.prepare("select v from #{table} where k = ?"),
21
21
  @replace = @db.prepare("replace into #{table} values (?, ?)"),
22
22
  @delete = @db.prepare("delete from #{table} where k = ?"),
23
- @clear = @db.prepare("delete from #{table}")]
23
+ @clear = @db.prepare("delete from #{table}"),
24
+ @create = @db.prepare("insert into #{table} values (?, ?)")]
24
25
  end
25
26
 
26
27
  # (see Proxy#key?)
@@ -58,6 +59,17 @@ module Moneta
58
59
  self
59
60
  end
60
61
 
62
+ # (see Default#create)
63
+ def create(key, value, options = {})
64
+ @create.execute!(key,value)
65
+ true
66
+ rescue SQLite3::ConstraintException
67
+ # If you know a better way to detect whether an insert-ignore
68
+ # suceeded, please tell me.
69
+ @create.reset!
70
+ false
71
+ end
72
+
61
73
  # (see Proxy#close)
62
74
  def close
63
75
  @stmts.each {|s| s.close }
@@ -29,6 +29,11 @@ module Moneta
29
29
  end
30
30
  end
31
31
 
32
+ # (see Proxy#create)
33
+ def create(key, value, options = {})
34
+ @hash.putkeep(key, value)
35
+ end
36
+
32
37
  # (see Proxy#close)
33
38
  def close
34
39
  @hash.close
data/lib/moneta/cache.rb CHANGED
@@ -73,6 +73,16 @@ module Moneta
73
73
  @backend.increment(key, amount, options)
74
74
  end
75
75
 
76
+ # (see Proxy#create)
77
+ def create(key, value, options = {})
78
+ if @backend.create(key, value, options)
79
+ @cache.store(key, value, options)
80
+ true
81
+ else
82
+ false
83
+ end
84
+ end
85
+
76
86
  # (see Proxy#delete)
77
87
  def delete(key, options = {})
78
88
  @cache.delete(key, options)
@@ -21,8 +21,7 @@ module Moneta
21
21
  # Transformer might raise exception
22
22
  load_entry(key, options) != nil
23
23
  rescue Exception
24
- options.include?(:expires) && (options = options.dup; options.delete(:expires))
25
- super(key, options)
24
+ super(key, Utils.without(options, :expires))
26
25
  end
27
26
 
28
27
  # (see Proxy#load)
@@ -36,11 +35,7 @@ module Moneta
36
35
  def store(key, value, options = {})
37
36
  return super if options.include?(:raw)
38
37
  expires = expires_at(options)
39
- if options.include?(:expires)
40
- options = options.dup
41
- options.delete(:expires)
42
- end
43
- store_entry(key, value, expires, options)
38
+ super(key, new_entry(value, expires), Utils.without(options, :expires))
44
39
  value
45
40
  end
46
41
 
@@ -51,14 +46,18 @@ module Moneta
51
46
  value if !expires || Time.now.to_i <= expires
52
47
  end
53
48
 
49
+ # (see Proxy#store)
50
+ def create(key, value, options = {})
51
+ return super if options.include?(:raw)
52
+ expires = expires_at(options)
53
+ @adapter.create(key, new_entry(value, expires), Utils.without(options, :expires))
54
+ end
55
+
54
56
  private
55
57
 
56
58
  def load_entry(key, options)
57
59
  new_expires = expires_at(options, nil)
58
- if options.include?(:expires)
59
- options = options.dup
60
- options.delete(:expires)
61
- end
60
+ options = Utils.without(options, :expires)
62
61
  entry = @adapter.load(key, options)
63
62
  if entry != nil
64
63
  value, expires = entry
@@ -66,7 +65,7 @@ module Moneta
66
65
  delete(key)
67
66
  nil
68
67
  elsif new_expires != nil
69
- store_entry(key, value, new_expires, options)
68
+ @adapter.store(key, new_entry(value, new_expires), options)
70
69
  entry
71
70
  else
72
71
  entry
@@ -74,16 +73,14 @@ module Moneta
74
73
  end
75
74
  end
76
75
 
77
- def store_entry(key, value, expires, options)
78
- entry =
79
- if expires
80
- [value, expires.to_i]
81
- elsif Array === value || value == nil
82
- [value]
83
- else
84
- value
85
- end
86
- @adapter.store(key, entry, options)
76
+ def new_entry(value, expires)
77
+ if expires
78
+ [value, expires.to_i]
79
+ elsif Array === value || value == nil
80
+ [value]
81
+ else
82
+ value
83
+ end
87
84
  end
88
85
  end
89
86
  end
data/lib/moneta/lock.rb CHANGED
@@ -6,10 +6,10 @@ module Moneta
6
6
  class Lock < Wrapper
7
7
  # @param [Moneta store] adapter The underlying store
8
8
  # @param [Hash] options
9
- # @option options [String] :mutex (Mutex.new) Mutex object
9
+ # @option options [String] :mutex (::Mutex.new) Mutex object
10
10
  def initialize(adapter, options = {})
11
11
  super
12
- @lock = options[:mutex] || Mutex.new
12
+ @lock = options[:mutex] || ::Mutex.new
13
13
  end
14
14
 
15
15
  protected
data/lib/moneta/mixins.rb CHANGED
@@ -24,7 +24,7 @@ module Moneta
24
24
  def raw
25
25
  @raw_store ||=
26
26
  begin
27
- store = with(:raw => true, :only => [:load, :store, :delete])
27
+ store = with(:raw => true, :only => [:load, :store, :create, :delete])
28
28
  store.instance_variable_set(:@raw_store, store)
29
29
  store
30
30
  end
@@ -45,7 +45,7 @@ module Moneta
45
45
  # @return [OptionMerger]
46
46
  # @api public
47
47
  def expires(expires)
48
- with(:expires => expires, :only => [:store, :increment])
48
+ with(:expires => expires, :only => [:store, :create, :increment])
49
49
  end
50
50
  end
51
51
 
@@ -58,8 +58,8 @@ module Moneta
58
58
  #
59
59
  # @param [Object] key
60
60
  # @param [Hash] options
61
- # @option options [Integer] :expires Update expiration time (See `Moneta::Expires`)
62
- # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
61
+ # @option options [Integer] :expires Update expiration time (See {Expires})
62
+ # @option options [String] :prefix Prefix key (See {Transformer})
63
63
  # @option options Other options as defined by the adapters or middleware
64
64
  # @return [Boolean]
65
65
  # @api public
@@ -149,6 +149,19 @@ module Moneta
149
149
  def []=(key, value)
150
150
  store(key, value)
151
151
  end
152
+
153
+ # Atomically sets a key to value if it's not set.
154
+ #
155
+ # @note Not every Moneta store implements this method,
156
+ # a NotImplementedError is raised if it is not supported.
157
+ # @param [Object] key
158
+ # @param [Object] value
159
+ # @param [Hash] options
160
+ # @return [Boolean] key was set
161
+ # @api public
162
+ def create(key, value, options = {})
163
+ raise NotImplementedError, 'create is not supported'
164
+ end
152
165
  end
153
166
 
154
167
  # @api private
@@ -156,17 +169,26 @@ module Moneta
156
169
  # (see Defaults#increment)
157
170
  # @api public
158
171
  def increment(key, amount = 1, options = {})
159
- value = convert_for_increment(load(key, options)) + amount
172
+ value = Utils.to_int(load(key, options)) + amount
160
173
  store(key, value.to_s, options)
161
174
  value
162
175
  end
176
+ end
163
177
 
164
- protected
165
-
166
- def convert_for_increment(value)
167
- intvalue = value.to_i
168
- raise 'Tried to increment non integer value' unless value == nil || intvalue.to_s == value.to_s
169
- intvalue
178
+ # Implements simple create using key? and store.
179
+ #
180
+ # This is sufficient for non-shared stores or if atomicity is not required.
181
+ # @api private
182
+ module CreateSupport
183
+ # (see Default#create)
184
+ # @api public
185
+ def create(key, value, options = {})
186
+ if key? key
187
+ false
188
+ else
189
+ store(key, value, options)
190
+ true
191
+ end
170
192
  end
171
193
  end
172
194
 
@@ -1,7 +1,7 @@
1
1
  module Moneta
2
2
  # @api private
3
3
  class OptionMerger < Wrapper
4
- METHODS = [:key?, :load, :store, :delete, :increment, :clear].freeze
4
+ METHODS = [:key?, :load, :store, :create, :delete, :increment, :clear].freeze
5
5
 
6
6
  attr_reader :default_options
7
7
 
data/lib/moneta/proxy.rb CHANGED
@@ -22,6 +22,11 @@ module Moneta
22
22
  adapter.increment(key, amount, options)
23
23
  end
24
24
 
25
+ # (see Defaults#create)
26
+ def create(key, value, options = {})
27
+ adapter.create(key, value, options)
28
+ end
29
+
25
30
  # (see Defaults#close)
26
31
  def close
27
32
  adapter.close
@@ -31,9 +36,9 @@ module Moneta
31
36
  #
32
37
  # @param [Object] key
33
38
  # @param [Hash] options
34
- # @option options [Integer] :expires Update expiration time (See `Moneta::Expires`)
35
- # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
36
- # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
39
+ # @option options [Integer] :expires Update expiration time (See {Expires})
40
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
41
+ # @option options [String] :prefix Prefix key (See {Transformer})
37
42
  # @option options Other options as defined by the adapters or middleware
38
43
  # @return [Object] value
39
44
  # @api public
@@ -46,9 +51,9 @@ module Moneta
46
51
  # @param [Object] key
47
52
  # @param [Object] value
48
53
  # @param [Hash] options
49
- # @option options [Integer] :expires Set expiration time (See `Moneta::Expires`)
50
- # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
51
- # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
54
+ # @option options [Integer] :expires Set expiration time (See {Expires})
55
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
56
+ # @option options [String] :prefix Prefix key (See {Transformer})
52
57
  # @option options Other options as defined by the adapters or middleware
53
58
  # @return value
54
59
  # @api public
@@ -61,8 +66,8 @@ module Moneta
61
66
  # @param [Object] key
62
67
  # @return [Object] current value
63
68
  # @param [Hash] options
64
- # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
65
- # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
69
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
70
+ # @option options [String] :prefix Prefix key (See {Transformer})
66
71
  # @option options Other options as defined by the adapters or middleware
67
72
  # @api public
68
73
  def delete(key, options = {})
data/lib/moneta/server.rb CHANGED
@@ -6,12 +6,12 @@ module Moneta
6
6
  class Server
7
7
  # @param [Hash] options
8
8
  # @option options [Integer] :port (9000) TCP port
9
- # @option options [String] :file Alternative Unix socket file name
9
+ # @option options [String] :socket Alternative Unix socket file name
10
10
  def initialize(store, options = {})
11
11
  @store = store
12
12
  @server =
13
- if @file = options[:file]
14
- UNIXServer.open(@file)
13
+ if @socket = options[:socket]
14
+ UNIXServer.open(@socket)
15
15
  else
16
16
  TCPServer.open(options[:port] || DEFAULT_PORT)
17
17
  end
@@ -38,7 +38,7 @@ module Moneta
38
38
  mainloop
39
39
  end
40
40
  ensure
41
- File.unlink(@file) if @file
41
+ File.unlink(@socket) if @socket
42
42
  end
43
43
  end
44
44
 
@@ -58,8 +58,15 @@ module Moneta
58
58
  def mainloop
59
59
  client = accept
60
60
  handle(client) if client
61
+ rescue SignalException => ex
62
+ warn "Moneta::Server - #{ex.message}"
63
+ raise if ex.signo == 15 # SIGTERM
64
+ rescue IOError => ex
65
+ warn "Moneta::Server - #{ex.message}" unless ex.message =~ /closed/
66
+ @clients.delete(client) if client
67
+ @clients.reject!(&:closed?)
61
68
  rescue Exception => ex
62
- warn ex.message
69
+ warn "Moneta::Server - #{ex.message}"
63
70
  write(client, Error.new(ex.message)) if client
64
71
  end
65
72
 
@@ -85,7 +92,7 @@ module Moneta
85
92
  def handle(client)
86
93
  method, *args = read(client)
87
94
  case method
88
- when :key?, :load, :delete, :increment
95
+ when :key?, :load, :delete, :increment, :create
89
96
  write(client, @store.send(method, *args))
90
97
  when :store, :clear
91
98
  @store.send(method, *args)
data/lib/moneta/shared.rb CHANGED
@@ -14,7 +14,7 @@ module Moneta
14
14
  # @param [Hash] options
15
15
  # @option options [Integer] :port (9000) TCP port
16
16
  # @option options [String] :host Server hostname
17
- # @option options [String] :file Unix socket file name
17
+ # @option options [String] :socket Unix socket file name
18
18
  def initialize(options = {}, &block)
19
19
  @options = options
20
20
  @builder = Builder.new(&block)
@@ -38,8 +38,9 @@ module Moneta
38
38
  def wrap(*args)
39
39
  @adapter ||= Adapters::Client.new(@options)
40
40
  yield
41
- rescue Exception => ex
42
- warn "Failed to connect: #{ex.message}"
41
+ rescue Errno::ECONNREFUSED, Errno::ENOENT => ex
42
+ tries ||= 0
43
+ warn "Moneta::Shared - Failed to connect: #{ex.message}" if tries > 0
43
44
  begin
44
45
  # TODO: Implement this using forking (MRI) and threading (JRuby)
45
46
  # to get maximal performance
@@ -48,16 +49,11 @@ module Moneta
48
49
  @thread = Thread.new { @server.run }
49
50
  sleep 0.1 until @server.running?
50
51
  rescue Exception => ex
51
- warn "Failed to start server: #{ex.message}"
52
+ warn "Moneta::Shared - Failed to start server: #{ex.message}"
52
53
  @adapter.close if @adapter
53
54
  @adapter = nil
54
55
  end
55
- tries ||= 0
56
- if (tries += 1) > 2
57
- raise
58
- else
59
- retry
60
- end
56
+ (tries += 1) < 3 ? retry : raise
61
57
  end
62
58
  end
63
59
  end
@@ -0,0 +1,125 @@
1
+ module Moneta
2
+ # Base class for {Mutex} and {Semaphore}
3
+ # @api private
4
+ class SynchronizePrimitive
5
+ # Synchronize block
6
+ #
7
+ # @api public
8
+ # @yieldparam Synchronized block
9
+ # @return [Object] result of block
10
+ def synchronize
11
+ enter
12
+ yield
13
+ ensure
14
+ leave
15
+ end
16
+
17
+ # Try to enter critical section (nonblocking)
18
+ #
19
+ # @api public
20
+ # @return [Boolean] true if the lock was acquired
21
+ def try_enter
22
+ raise 'Already locked' if @locked
23
+ enter_primitive ? @locked = true : false
24
+ end
25
+ alias_method :try_lock, :try_enter
26
+
27
+ # Enter critical section (blocking)
28
+ #
29
+ # @api public
30
+ # @param [Number] timeout Maximum time to wait
31
+ # @param [Number] wait Sleep time between tries to acquire lock
32
+ # @return [Boolean] true if the lock was aquired
33
+ def enter(timeout = nil, wait = 0.01)
34
+ total = 0
35
+ while !timeout || total < timeout
36
+ return true if try_enter
37
+ sleep(wait)
38
+ total += wait
39
+ end
40
+ false
41
+ end
42
+ alias_method :lock, :enter
43
+
44
+ # Leave critical section
45
+ #
46
+ # @api public
47
+ def leave
48
+ raise 'Not locked' unless @locked
49
+ leave_primitive
50
+ @locked = false
51
+ nil
52
+ end
53
+ alias_method :unlock, :leave
54
+
55
+ # Is the lock acquired?
56
+ #
57
+ # @api public
58
+ def locked?
59
+ @locked
60
+ end
61
+ end
62
+
63
+ # Distributed/shared store-wide mutex
64
+ #
65
+ # @example Use `Moneta::Mutex`
66
+ # mutex = Moneta::Mutex.new(store, 'mutex')
67
+ # mutex.synchronize do
68
+ # # Synchronized access
69
+ # store['counter'] += 1
70
+ # end
71
+ #
72
+ # @api public
73
+ class Mutex < SynchronizePrimitive
74
+ # @param [Moneta store] store The store we want to lock
75
+ # @param [Object] lock Key of the lock entry
76
+ def initialize(store, lock)
77
+ @store, @lock = store, lock
78
+ end
79
+
80
+ protected
81
+
82
+ def enter_primitive
83
+ @store.create(@lock, '', :expires => false)
84
+ end
85
+
86
+ def leave_primitive
87
+ @store.delete(@lock)
88
+ end
89
+ end
90
+
91
+ # Distributed/shared store-wide semaphore
92
+ #
93
+ # @example Use `Moneta::Semaphore`
94
+ # semaphore = Moneta::Semaphore.new(store, 'semaphore', 2)
95
+ # semaphore.synchronize do
96
+ # # Synchronized access
97
+ # ...
98
+ # end
99
+ #
100
+ # @api public
101
+ class Semaphore < SynchronizePrimitive
102
+ # @param [Moneta store] store The store we want to lock
103
+ # @param [Object] counter Key of the counter entry
104
+ # @param [Fixnum] max Maximum number of threads which are allowed to enter the critical section
105
+ def initialize(store, counter, max = 1)
106
+ @store, @counter, @max = store, counter, max
107
+ @store.increment(@counter, 0, :expires => false) # Ensure that counter exists
108
+ end
109
+
110
+ protected
111
+
112
+ def enter_primitive
113
+ if @store.increment(@counter, 1) <= @max
114
+ true
115
+ else
116
+ @store.decrement(@counter)
117
+ false
118
+ end
119
+ end
120
+
121
+ def leave_primitive
122
+ @store.decrement(@counter)
123
+ end
124
+ end
125
+ end