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