moneta 0.7.6 → 0.7.8

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 (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