moneta 0.6.0 → 0.7.0
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.
- data/.gitignore +7 -0
- data/.travis.yml +39 -0
- data/Gemfile +61 -0
- data/LICENSE +2 -2
- data/README.md +450 -0
- data/Rakefile +29 -51
- data/SPEC.md +75 -0
- data/benchmarks/run.rb +195 -0
- data/lib/action_dispatch/middleware/session/moneta_store.rb +11 -0
- data/lib/active_support/cache/moneta_store.rb +55 -0
- data/lib/moneta.rb +121 -67
- data/lib/moneta/adapters/activerecord.rb +87 -0
- data/lib/moneta/adapters/cassandra.rb +91 -0
- data/lib/moneta/adapters/client.rb +69 -0
- data/lib/moneta/adapters/cookie.rb +35 -0
- data/lib/moneta/adapters/couch.rb +57 -0
- data/lib/moneta/adapters/datamapper.rb +75 -0
- data/lib/moneta/adapters/dbm.rb +25 -0
- data/lib/moneta/adapters/file.rb +79 -0
- data/lib/moneta/adapters/fog.rb +51 -0
- data/lib/moneta/adapters/gdbm.rb +25 -0
- data/lib/moneta/adapters/hbase.rb +101 -0
- data/lib/moneta/adapters/leveldb.rb +35 -0
- data/lib/moneta/adapters/localmemcache.rb +28 -0
- data/lib/moneta/adapters/lruhash.rb +85 -0
- data/lib/moneta/adapters/memcached.rb +11 -0
- data/lib/moneta/adapters/memcached_dalli.rb +69 -0
- data/lib/moneta/adapters/memcached_native.rb +70 -0
- data/lib/moneta/adapters/memory.rb +10 -0
- data/lib/moneta/adapters/mongo.rb +50 -0
- data/lib/moneta/adapters/null.rb +30 -0
- data/lib/moneta/adapters/pstore.rb +69 -0
- data/lib/moneta/adapters/redis.rb +68 -0
- data/lib/moneta/adapters/riak.rb +57 -0
- data/lib/moneta/adapters/sdbm.rb +35 -0
- data/lib/moneta/adapters/sequel.rb +79 -0
- data/lib/moneta/adapters/sqlite.rb +65 -0
- data/lib/moneta/adapters/tokyocabinet.rb +41 -0
- data/lib/moneta/adapters/yaml.rb +15 -0
- data/lib/moneta/base.rb +78 -0
- data/lib/moneta/builder.rb +39 -0
- data/lib/moneta/cache.rb +84 -0
- data/lib/moneta/expires.rb +71 -0
- data/lib/moneta/lock.rb +25 -0
- data/lib/moneta/logger.rb +61 -0
- data/lib/moneta/mixins.rb +65 -0
- data/lib/moneta/net.rb +18 -0
- data/lib/moneta/optionmerger.rb +39 -0
- data/lib/moneta/proxy.rb +86 -0
- data/lib/moneta/server.rb +81 -0
- data/lib/moneta/shared.rb +60 -0
- data/lib/moneta/stack.rb +78 -0
- data/lib/moneta/transformer.rb +159 -0
- data/lib/moneta/transformer/config.rb +42 -0
- data/lib/moneta/transformer/helper.rb +37 -0
- data/lib/moneta/version.rb +5 -0
- data/lib/moneta/wrapper.rb +33 -0
- data/lib/rack/cache/moneta.rb +93 -0
- data/lib/rack/moneta_cookies.rb +64 -0
- data/lib/rack/session/moneta.rb +63 -0
- data/moneta.gemspec +19 -0
- data/spec/action_dispatch/fixtures/session_autoload_test/foo.rb +10 -0
- data/spec/action_dispatch/session_moneta_store_spec.rb +196 -0
- data/spec/active_support/cache_moneta_store_spec.rb +197 -0
- data/spec/generate.rb +1489 -0
- data/spec/helper.rb +91 -0
- data/spec/moneta/adapter_activerecord_spec.rb +32 -0
- data/spec/moneta/adapter_cassandra_spec.rb +30 -0
- data/spec/moneta/adapter_client_spec.rb +19 -0
- data/spec/moneta/adapter_cookie_spec.rb +18 -0
- data/spec/moneta/adapter_couch_spec.rb +18 -0
- data/spec/moneta/adapter_datamapper_spec.rb +49 -0
- data/spec/moneta/adapter_dbm_spec.rb +18 -0
- data/spec/moneta/adapter_file_spec.rb +18 -0
- data/spec/moneta/adapter_fog_spec.rb +23 -0
- data/spec/moneta/adapter_gdbm_spec.rb +18 -0
- data/spec/moneta/adapter_hbase_spec.rb +18 -0
- data/spec/moneta/adapter_leveldb_spec.rb +18 -0
- data/spec/moneta/adapter_localmemcache_spec.rb +18 -0
- data/spec/moneta/adapter_lruhash_spec.rb +31 -0
- data/spec/moneta/adapter_memcached_dalli_spec.rb +30 -0
- data/spec/moneta/adapter_memcached_native_spec.rb +31 -0
- data/spec/moneta/adapter_memcached_spec.rb +30 -0
- data/spec/moneta/adapter_memory_spec.rb +39 -0
- data/spec/moneta/adapter_mongo_spec.rb +18 -0
- data/spec/moneta/adapter_pstore_spec.rb +21 -0
- data/spec/moneta/adapter_redis_spec.rb +30 -0
- data/spec/moneta/adapter_riak_spec.rb +22 -0
- data/spec/moneta/adapter_sdbm_spec.rb +18 -0
- data/spec/moneta/adapter_sequel_spec.rb +18 -0
- data/spec/moneta/adapter_sqlite_spec.rb +18 -0
- data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +18 -0
- data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +18 -0
- data/spec/moneta/adapter_yaml_spec.rb +21 -0
- data/spec/moneta/cache_file_memory_spec.rb +34 -0
- data/spec/moneta/cache_memory_null_spec.rb +23 -0
- data/spec/moneta/expires_file_spec.rb +76 -0
- data/spec/moneta/expires_memory_spec.rb +65 -0
- data/spec/moneta/lock_spec.rb +42 -0
- data/spec/moneta/null_adapter_spec.rb +26 -0
- data/spec/moneta/optionmerger_spec.rb +92 -0
- data/spec/moneta/proxy_expires_memory_spec.rb +55 -0
- data/spec/moneta/proxy_redis_spec.rb +23 -0
- data/spec/moneta/shared_spec.rb +30 -0
- data/spec/moneta/simple_activerecord_spec.rb +51 -0
- data/spec/moneta/simple_activerecord_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_cassandra_spec.rb +52 -0
- data/spec/moneta/simple_client_tcp_spec.rb +67 -0
- data/spec/moneta/simple_client_unix_spec.rb +53 -0
- data/spec/moneta/simple_couch_spec.rb +51 -0
- data/spec/moneta/simple_couch_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_datamapper_spec.rb +53 -0
- data/spec/moneta/simple_datamapper_with_expires_spec.rb +54 -0
- data/spec/moneta/simple_datamapper_with_repository_spec.rb +53 -0
- data/spec/moneta/simple_dbm_spec.rb +51 -0
- data/spec/moneta/simple_dbm_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_file_spec.rb +51 -0
- data/spec/moneta/simple_file_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_fog_spec.rb +56 -0
- data/spec/moneta/simple_fog_with_expires_spec.rb +58 -0
- data/spec/moneta/simple_gdbm_spec.rb +51 -0
- data/spec/moneta/simple_gdbm_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_hashfile_spec.rb +51 -0
- data/spec/moneta/simple_hashfile_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_hbase_spec.rb +51 -0
- data/spec/moneta/simple_hbase_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_leveldb_spec.rb +51 -0
- data/spec/moneta/simple_leveldb_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_localmemcache_spec.rb +51 -0
- data/spec/moneta/simple_localmemcache_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_lruhash_spec.rb +51 -0
- data/spec/moneta/simple_lruhash_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_memcached_dalli_spec.rb +52 -0
- data/spec/moneta/simple_memcached_native_spec.rb +52 -0
- data/spec/moneta/simple_memcached_spec.rb +52 -0
- data/spec/moneta/simple_memory_spec.rb +51 -0
- data/spec/moneta/simple_memory_with_compress_spec.rb +51 -0
- data/spec/moneta/simple_memory_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +37 -0
- data/spec/moneta/simple_memory_with_json_serializer_spec.rb +28 -0
- data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +35 -0
- data/spec/moneta/simple_memory_with_prefix_spec.rb +51 -0
- data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +51 -0
- data/spec/moneta/simple_mongo_spec.rb +51 -0
- data/spec/moneta/simple_mongo_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_null_spec.rb +36 -0
- data/spec/moneta/simple_pstore_spec.rb +51 -0
- data/spec/moneta/simple_pstore_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_redis_spec.rb +52 -0
- data/spec/moneta/simple_riak_spec.rb +55 -0
- data/spec/moneta/simple_riak_with_expires_spec.rb +56 -0
- data/spec/moneta/simple_sdbm_spec.rb +51 -0
- data/spec/moneta/simple_sdbm_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_sequel_spec.rb +51 -0
- data/spec/moneta/simple_sequel_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_sqlite_spec.rb +51 -0
- data/spec/moneta/simple_sqlite_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_tokyocabinet_spec.rb +51 -0
- data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +52 -0
- data/spec/moneta/simple_yaml_spec.rb +50 -0
- data/spec/moneta/simple_yaml_with_expires_spec.rb +51 -0
- data/spec/moneta/stack_file_memory_spec.rb +25 -0
- data/spec/moneta/stack_memory_file_spec.rb +24 -0
- data/spec/moneta/transformer_bencode_spec.rb +30 -0
- data/spec/moneta/transformer_bert_spec.rb +30 -0
- data/spec/moneta/transformer_bson_spec.rb +30 -0
- data/spec/moneta/transformer_bzip2_spec.rb +27 -0
- data/spec/moneta/transformer_json_spec.rb +30 -0
- data/spec/moneta/transformer_lzma_spec.rb +27 -0
- data/spec/moneta/transformer_lzo_spec.rb +27 -0
- data/spec/moneta/transformer_marshal_base64_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_escape_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_hmac_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_md5_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_md5_spread_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_prefix_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_rmd160_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_sha1_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_sha256_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_sha384_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_sha512_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_truncate_spec.rb +54 -0
- data/spec/moneta/transformer_marshal_uuencode_spec.rb +54 -0
- data/spec/moneta/transformer_msgpack_spec.rb +30 -0
- data/spec/moneta/transformer_ox_spec.rb +51 -0
- data/spec/moneta/transformer_quicklz_spec.rb +27 -0
- data/spec/moneta/transformer_snappy_spec.rb +27 -0
- data/spec/moneta/transformer_tnet_spec.rb +30 -0
- data/spec/moneta/transformer_yaml_spec.rb +51 -0
- data/spec/moneta/transformer_zlib_spec.rb +27 -0
- data/spec/monetaspecs.rb +2663 -0
- data/spec/rack/cache_moneta_spec.rb +355 -0
- data/spec/rack/moneta_cookies_spec.rb +81 -0
- data/spec/rack/session_moneta_spec.rb +305 -0
- metadata +359 -56
- data/README +0 -51
- data/TODO +0 -4
- data/lib/moneta/basic_file.rb +0 -111
- data/lib/moneta/berkeley.rb +0 -53
- data/lib/moneta/couch.rb +0 -63
- data/lib/moneta/datamapper.rb +0 -117
- data/lib/moneta/file.rb +0 -91
- data/lib/moneta/lmc.rb +0 -52
- data/lib/moneta/memcache.rb +0 -52
- data/lib/moneta/memory.rb +0 -11
- data/lib/moneta/mongodb.rb +0 -58
- data/lib/moneta/redis.rb +0 -49
- data/lib/moneta/rufus.rb +0 -41
- data/lib/moneta/s3.rb +0 -162
- data/lib/moneta/sdbm.rb +0 -33
- data/lib/moneta/tyrant.rb +0 -58
- data/lib/moneta/xattr.rb +0 -58
data/lib/moneta/net.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# @api private
|
|
3
|
+
module Net
|
|
4
|
+
DEFAULT_PORT = 9000
|
|
5
|
+
|
|
6
|
+
class Error < Exception; end
|
|
7
|
+
|
|
8
|
+
def read(io)
|
|
9
|
+
size = io.read(4).unpack('N').first
|
|
10
|
+
Marshal.load(io.read(size))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def write(io, o)
|
|
14
|
+
s = Marshal.dump(o)
|
|
15
|
+
io.write([s.bytesize].pack('N') << s)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# @api private
|
|
3
|
+
class OptionMerger < Wrapper
|
|
4
|
+
METHODS = [:key?, :load, :store, :delete, :increment, :clear].freeze
|
|
5
|
+
|
|
6
|
+
attr_reader :default_options
|
|
7
|
+
|
|
8
|
+
def initialize(adapter, options = {})
|
|
9
|
+
super(adapter, options)
|
|
10
|
+
|
|
11
|
+
@default_options = adapter.respond_to?(:default_options) ? adapter.default_options.dup : {}
|
|
12
|
+
|
|
13
|
+
if options.include?(:only)
|
|
14
|
+
raise ArgumentError, 'Either :only or :except is allowed' if options.include?(:except)
|
|
15
|
+
methods = [options.delete(:only)].compact.flatten
|
|
16
|
+
elsif options.include?(:except)
|
|
17
|
+
methods = METHODS - [options.delete(:except)].compact.flatten
|
|
18
|
+
else
|
|
19
|
+
methods = METHODS
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
methods.each do |method|
|
|
23
|
+
if oldopts = @default_options[method]
|
|
24
|
+
newopts = (@default_options[method] = oldopts.merge(options))
|
|
25
|
+
newopts[:prefix] = "#{oldopts[:prefix]}#{options[:prefix]}" if oldopts[:prefix] || options[:prefix]
|
|
26
|
+
else
|
|
27
|
+
@default_options[method] = options
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def wrap(method, *args)
|
|
33
|
+
options = args.last
|
|
34
|
+
options.merge!(@default_options[method]) if Hash === options && @default_options.include?(method)
|
|
35
|
+
yield
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
data/lib/moneta/proxy.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# Proxy base class
|
|
3
|
+
# @api public
|
|
4
|
+
class Proxy < Base
|
|
5
|
+
attr_reader :adapter
|
|
6
|
+
|
|
7
|
+
# Constructor
|
|
8
|
+
#
|
|
9
|
+
# @param [Moneta store] underlying adapter
|
|
10
|
+
# @param [Hash] options
|
|
11
|
+
def initialize(adapter, options = {})
|
|
12
|
+
@adapter = adapter
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Exists the value with key
|
|
16
|
+
#
|
|
17
|
+
# @param [Object] key
|
|
18
|
+
# @return [Boolean]
|
|
19
|
+
# @param [Hash] options
|
|
20
|
+
# @api public
|
|
21
|
+
def key?(key, options = {})
|
|
22
|
+
@adapter.key?(key, options)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Fetch value with key. Return nil if the key doesn't exist
|
|
26
|
+
#
|
|
27
|
+
# @param [Object] key
|
|
28
|
+
# @param [Hash] options
|
|
29
|
+
# @return [Object] value
|
|
30
|
+
# @api public
|
|
31
|
+
def load(key, options = {})
|
|
32
|
+
@adapter.load(key, options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Store value with key
|
|
36
|
+
#
|
|
37
|
+
# @param [Object] key
|
|
38
|
+
# @param [Object] value
|
|
39
|
+
# @param [Hash] options
|
|
40
|
+
# @return value
|
|
41
|
+
# @api public
|
|
42
|
+
def store(key, value, options = {})
|
|
43
|
+
@adapter.store(key, value, options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Delete the key from the store and return the current value
|
|
47
|
+
#
|
|
48
|
+
# @param [Object] key
|
|
49
|
+
# @return [Object] current value
|
|
50
|
+
# @param [Hash] options
|
|
51
|
+
# @api public
|
|
52
|
+
def delete(key, options = {})
|
|
53
|
+
@adapter.delete(key, options)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Atomically increment integer value with key
|
|
57
|
+
#
|
|
58
|
+
# Not every Moneta store implements this method,
|
|
59
|
+
# a NotImplementedError if it is not supported.
|
|
60
|
+
#
|
|
61
|
+
# @param [Object] key
|
|
62
|
+
# @param [Integer] amount
|
|
63
|
+
# @param [Hash] options
|
|
64
|
+
# @return [Object] value from store
|
|
65
|
+
# @api public
|
|
66
|
+
def increment(key, amount = 1, options = {})
|
|
67
|
+
@adapter.increment(key, amount, options)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Clear all keys in this store
|
|
71
|
+
#
|
|
72
|
+
# @param [Hash] options
|
|
73
|
+
# @return [void]
|
|
74
|
+
# @api public
|
|
75
|
+
def clear(options = {})
|
|
76
|
+
@adapter.clear(options)
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Close this store
|
|
81
|
+
# @api public
|
|
82
|
+
def close
|
|
83
|
+
@adapter.close
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
|
|
3
|
+
module Moneta
|
|
4
|
+
# Moneta server
|
|
5
|
+
# @api public
|
|
6
|
+
class Server
|
|
7
|
+
TIMEOUT = 1
|
|
8
|
+
include Net
|
|
9
|
+
|
|
10
|
+
# Constructor
|
|
11
|
+
#
|
|
12
|
+
# @param [Hash] options
|
|
13
|
+
#
|
|
14
|
+
# Options:
|
|
15
|
+
# * :port - TCP port (default 9000)
|
|
16
|
+
# * :file - Unix socket file name (default none)
|
|
17
|
+
def initialize(store, options = {})
|
|
18
|
+
@store = store
|
|
19
|
+
@server = options[:file] ? UNIXServer.open(options[:file]) :
|
|
20
|
+
TCPServer.open(options[:port] || DEFAULT_PORT)
|
|
21
|
+
@clients = [@server]
|
|
22
|
+
@running = true
|
|
23
|
+
@thread = Thread.new do
|
|
24
|
+
mainloop while @running
|
|
25
|
+
File.unlink(options[:file]) if options[:file]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def stop
|
|
30
|
+
if @thread
|
|
31
|
+
@running = false
|
|
32
|
+
@server.close
|
|
33
|
+
@server = nil
|
|
34
|
+
@thread.join
|
|
35
|
+
@thread = nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def mainloop
|
|
42
|
+
client = accept
|
|
43
|
+
handle(client) if client
|
|
44
|
+
rescue Exception => ex
|
|
45
|
+
puts "#{ex.message}\n#{ex.backtrace.join("\n")}"
|
|
46
|
+
write(client, Error.new(ex.message)) if client
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def accept
|
|
50
|
+
ios = IO.select(@clients, nil, @clients, TIMEOUT)
|
|
51
|
+
return nil unless ios
|
|
52
|
+
ios[2].each do |io|
|
|
53
|
+
io.close
|
|
54
|
+
@clients.delete(io)
|
|
55
|
+
end
|
|
56
|
+
ios[0].each do |io|
|
|
57
|
+
if io == @server
|
|
58
|
+
client = @server.accept
|
|
59
|
+
@clients << client if client
|
|
60
|
+
else
|
|
61
|
+
return io unless io.eof?
|
|
62
|
+
@clients.delete(io)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def handle(client)
|
|
69
|
+
method, *args = read(client)
|
|
70
|
+
case method
|
|
71
|
+
when :key?, :load, :delete, :increment
|
|
72
|
+
write(client, @store.send(method, *args))
|
|
73
|
+
when :store, :clear
|
|
74
|
+
@store.send(method, *args)
|
|
75
|
+
write(client, nil)
|
|
76
|
+
else
|
|
77
|
+
raise 'Invalid method call'
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# Shares a store between processes
|
|
3
|
+
#
|
|
4
|
+
# @example Share a store
|
|
5
|
+
# Moneta.build do
|
|
6
|
+
# use :Transformer, :key => :marshal, :value => :marshal
|
|
7
|
+
# use :Shared do
|
|
8
|
+
# adapter :GDBM, :file => 'shared.db'
|
|
9
|
+
# end
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
class Shared < Wrapper
|
|
14
|
+
# Constructor
|
|
15
|
+
#
|
|
16
|
+
# @param [Hash] options
|
|
17
|
+
#
|
|
18
|
+
# Options:
|
|
19
|
+
# * :port - TCP port (default 9000)
|
|
20
|
+
# * :host - Hostname (default empty)
|
|
21
|
+
# * :file - Unix socket file name (default none)
|
|
22
|
+
def initialize(options = {}, &block)
|
|
23
|
+
@options = options
|
|
24
|
+
@builder = Builder.new(&block)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def close
|
|
28
|
+
if @server
|
|
29
|
+
@server.stop
|
|
30
|
+
@server = nil
|
|
31
|
+
end
|
|
32
|
+
if @adapter
|
|
33
|
+
@adapter.close
|
|
34
|
+
@adapter = nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def wrap(*args)
|
|
41
|
+
tries ||= 0
|
|
42
|
+
@adapter ||= Adapters::Client.new(@options)
|
|
43
|
+
yield
|
|
44
|
+
rescue Exception => ex
|
|
45
|
+
puts "Failed to connect: #{ex.message}"
|
|
46
|
+
begin
|
|
47
|
+
@adapter = Lock.new(@builder.build.last)
|
|
48
|
+
@server = Server.new(@adapter, @options)
|
|
49
|
+
rescue Exception => ex
|
|
50
|
+
puts "Failed to start server: #{ex.message}"
|
|
51
|
+
@adapter = nil
|
|
52
|
+
end
|
|
53
|
+
if (tries += 1) > 2
|
|
54
|
+
raise
|
|
55
|
+
else
|
|
56
|
+
retry
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/moneta/stack.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# Combines multiple stores. Reads return the result from the first store,
|
|
3
|
+
# writes go to all stores.
|
|
4
|
+
#
|
|
5
|
+
# @example Add stack to chain
|
|
6
|
+
# Moneta.build do
|
|
7
|
+
# use(:Stack) do
|
|
8
|
+
# add { adapter :Redis }
|
|
9
|
+
# add { adapter :File, :dir => 'data' }
|
|
10
|
+
# add { adapter :File, :dir => 'replicate' }
|
|
11
|
+
# end
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# @api public
|
|
15
|
+
class Stack < Base
|
|
16
|
+
# @api private
|
|
17
|
+
class DSL
|
|
18
|
+
attr_reader :stack
|
|
19
|
+
|
|
20
|
+
def initialize(options, &block)
|
|
21
|
+
@stack = options[:stack].to_a
|
|
22
|
+
instance_eval(&block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add(store = nil, &block)
|
|
26
|
+
raise ArgumentError, 'Only argument or block allowed' if store && block
|
|
27
|
+
@stack << (store || Moneta.build(&block))
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attr_reader :stack
|
|
33
|
+
|
|
34
|
+
def initialize(options = {}, &block)
|
|
35
|
+
@stack = DSL.new(options, &block).stack
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def key?(key, options = {})
|
|
39
|
+
@stack.any? {|s| s.key?(key) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def load(key, options = {})
|
|
43
|
+
@stack.each do |s|
|
|
44
|
+
value = s.load(key, options)
|
|
45
|
+
return value if value
|
|
46
|
+
end
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def store(key, value, options = {})
|
|
51
|
+
@stack.each {|s| s.store(key, value, options) }
|
|
52
|
+
value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def delete(key, options = {})
|
|
56
|
+
@stack.inject(nil) do |value, s|
|
|
57
|
+
v = s.delete(key, options)
|
|
58
|
+
value || v
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def increment(key, amount = 1, options = {})
|
|
63
|
+
last = nil
|
|
64
|
+
@stack.each {|s| last = s.increment(key, amount, options) }
|
|
65
|
+
last
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def clear(options = {})
|
|
69
|
+
@stack.each {|s| s.clear }
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def close
|
|
74
|
+
@stack.each {|s| s.close }
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
module Moneta
|
|
2
|
+
# Transforms keys and values (Marshal, YAML, JSON, Base64, MD5, ...).
|
|
3
|
+
# You can bypass the transformer (e.g. serialization) by using the `:raw` option.
|
|
4
|
+
#
|
|
5
|
+
# @example Add transformer to chain
|
|
6
|
+
# Moneta.build do
|
|
7
|
+
# transformer :key => [:marshal, :escape], :value => [:marshal]
|
|
8
|
+
# adapter :File, :dir => 'data'
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# @example Bypass serialization
|
|
12
|
+
# store.store('key', 'value', :raw => true)
|
|
13
|
+
# store['key'] => Error
|
|
14
|
+
# store.load('key', :raw => true) => 'value'
|
|
15
|
+
#
|
|
16
|
+
# store['key'] = 'value'
|
|
17
|
+
# store.load('key', :raw => true) => "\x04\bI\"\nvalue\x06:\x06ET"
|
|
18
|
+
#
|
|
19
|
+
# @api public
|
|
20
|
+
class Transformer < Proxy
|
|
21
|
+
class << self
|
|
22
|
+
alias_method :original_new, :new
|
|
23
|
+
|
|
24
|
+
# Constructor
|
|
25
|
+
#
|
|
26
|
+
# @param [Moneta store] adapter The underlying store
|
|
27
|
+
# @param [Hash] options
|
|
28
|
+
#
|
|
29
|
+
# Options:
|
|
30
|
+
# * :key - List of key transformers in the order in which they should be applied
|
|
31
|
+
# * :value - List of value transformers in the order in which they should be applied
|
|
32
|
+
# * :prefix - Prefix string for key namespacing (Used by the :prefix key transformer)
|
|
33
|
+
# * :secret - HMAC secret to verify values (Used by the :hmac value transformer)
|
|
34
|
+
# * :maxlen - Maximum key length (Used by the :truncate key transformer)
|
|
35
|
+
# * :quiet - Disable error message
|
|
36
|
+
def new(adapter, options = {})
|
|
37
|
+
keys = [options[:key]].flatten.compact
|
|
38
|
+
values = [options[:value]].flatten.compact
|
|
39
|
+
raise ArgumentError, 'Option :key or :value is required' if keys.empty? && values.empty?
|
|
40
|
+
options[:prefix] ||= '' if keys.include?(:prefix)
|
|
41
|
+
name = class_name(options[:quiet] ? 'Quiet' : '', keys, values)
|
|
42
|
+
const_set(name, compile(options, keys, values)) unless const_defined?(name)
|
|
43
|
+
const_get(name).original_new(adapter, options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def compile(options, keys, values)
|
|
49
|
+
raise ArgumentError, 'Invalid key transformer chain' if KEY_TRANSFORMER !~ keys.map(&:inspect).join
|
|
50
|
+
raise ArgumentError, 'Invalid value transformer chain' if VALUE_TRANSFORMER !~ values.map(&:inspect).join
|
|
51
|
+
|
|
52
|
+
key = compile_transformer(keys, 'key')
|
|
53
|
+
|
|
54
|
+
klass = Class.new(self)
|
|
55
|
+
klass.class_eval <<-end_eval, __FILE__, __LINE__
|
|
56
|
+
def initialize(adapter, options = {})
|
|
57
|
+
super
|
|
58
|
+
#{compile_initializer('key', keys)}
|
|
59
|
+
#{compile_initializer('value', values)}
|
|
60
|
+
end
|
|
61
|
+
def key?(key, options = {})
|
|
62
|
+
@adapter.key?(#{key}, options)
|
|
63
|
+
end
|
|
64
|
+
def increment(key, amount = 1, options = {})
|
|
65
|
+
@adapter.increment(#{key}, amount, options)
|
|
66
|
+
end
|
|
67
|
+
end_eval
|
|
68
|
+
|
|
69
|
+
if values.empty?
|
|
70
|
+
klass.class_eval <<-end_eval, __FILE__, __LINE__
|
|
71
|
+
def load(key, options = {})
|
|
72
|
+
options.delete(:raw)
|
|
73
|
+
@adapter.load(#{key}, options)
|
|
74
|
+
end
|
|
75
|
+
def store(key, value, options = {})
|
|
76
|
+
options.delete(:raw)
|
|
77
|
+
@adapter.store(#{key}, value, options)
|
|
78
|
+
end
|
|
79
|
+
def delete(key, options = {})
|
|
80
|
+
options.delete(:raw)
|
|
81
|
+
@adapter.delete(#{key}, options)
|
|
82
|
+
end
|
|
83
|
+
end_eval
|
|
84
|
+
else
|
|
85
|
+
dump = compile_transformer(values, 'value')
|
|
86
|
+
load = compile_transformer(values.reverse, 'value', 1)
|
|
87
|
+
|
|
88
|
+
klass.class_eval <<-end_eval, __FILE__, __LINE__
|
|
89
|
+
def load(key, options = {})
|
|
90
|
+
raw = options.delete(:raw)
|
|
91
|
+
value = @adapter.load(#{key}, options)
|
|
92
|
+
begin
|
|
93
|
+
return #{load} if value && !raw
|
|
94
|
+
rescue Exception => ex
|
|
95
|
+
#{options[:quiet] ? '' : 'puts "Tried to load invalid value: #{ex.message}"'}
|
|
96
|
+
end
|
|
97
|
+
value
|
|
98
|
+
end
|
|
99
|
+
def store(key, value, options = {})
|
|
100
|
+
raw = options.delete(:raw)
|
|
101
|
+
@adapter.store(#{key}, raw ? value : #{dump}, options)
|
|
102
|
+
value
|
|
103
|
+
end
|
|
104
|
+
def delete(key, options = {})
|
|
105
|
+
raw = options.delete(:raw)
|
|
106
|
+
value = @adapter.delete(#{key}, options)
|
|
107
|
+
begin
|
|
108
|
+
return #{load} if value && !raw
|
|
109
|
+
rescue Exception => ex
|
|
110
|
+
#{options[:quiet] ? '' : 'puts "Tried to delete invalid value: #{ex.message}"'}
|
|
111
|
+
end
|
|
112
|
+
value
|
|
113
|
+
end
|
|
114
|
+
end_eval
|
|
115
|
+
end
|
|
116
|
+
klass
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Compile option initializer
|
|
120
|
+
def compile_initializer(type, transformers)
|
|
121
|
+
transformers.map do |name|
|
|
122
|
+
t = TRANSFORMER[name]
|
|
123
|
+
(t[1].to_s + t[2].to_s).scan(/@\w+/).uniq.map do |opt|
|
|
124
|
+
"raise ArgumentError, \"Option #{opt[1..-1]} is required for #{name} #{type} transformer\" unless #{opt} = options[:#{opt[1..-1]}]\n"
|
|
125
|
+
end
|
|
126
|
+
end.join("\n")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Compile transformer validator regular expression
|
|
130
|
+
def compile_validator(s)
|
|
131
|
+
Regexp.new(s.gsub(/\w+/) do
|
|
132
|
+
'(' + TRANSFORMER.select {|k,v| v.first.to_s == $& }.map {|v| ":#{v.first}" }.join('|') + ')'
|
|
133
|
+
end.gsub(/\s+/, '').sub(/\A/, '\A').sub(/\Z/, '\Z'))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Returned compiled transformer code string
|
|
137
|
+
def compile_transformer(transformer, var, i = 2)
|
|
138
|
+
transformer.inject(var) do |value, name|
|
|
139
|
+
raise ArgumentError, "Unknown transformer #{name}" unless t = TRANSFORMER[name]
|
|
140
|
+
require t[3] if t[3]
|
|
141
|
+
code = t[i]
|
|
142
|
+
if t[0] == :serialize && var == 'key'
|
|
143
|
+
"(tmp = #{value}; String === tmp ? tmp : #{code.gsub('value', 'tmp')})"
|
|
144
|
+
else
|
|
145
|
+
code.gsub('value', value)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def class_name(prefix, keys, values)
|
|
151
|
+
prefix << (keys.empty? ? '' : keys.map(&:to_s).map(&:capitalize).join << 'Key') <<
|
|
152
|
+
(values.empty? ? '' : values.map(&:to_s).map(&:capitalize).join << 'Value')
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
require 'moneta/transformer/helper'
|
|
159
|
+
require 'moneta/transformer/config'
|