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/Rakefile
CHANGED
@@ -1,60 +1,38 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
require 'date'
|
6
|
-
|
7
|
-
GEM = "moneta"
|
8
|
-
GEM_VERSION = "0.6.0"
|
9
|
-
AUTHOR = "Yehuda Katz"
|
10
|
-
EMAIL = "wycats@gmail.com"
|
11
|
-
HOMEPAGE = "http://www.yehudakatz.com"
|
12
|
-
SUMMARY = "A unified interface to key/value stores"
|
13
|
-
|
14
|
-
spec = Gem::Specification.new do |s|
|
15
|
-
s.name = GEM
|
16
|
-
s.version = GEM_VERSION
|
17
|
-
s.platform = Gem::Platform::RUBY
|
18
|
-
s.has_rdoc = true
|
19
|
-
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
20
|
-
s.summary = SUMMARY
|
21
|
-
s.description = s.summary
|
22
|
-
s.author = AUTHOR
|
23
|
-
s.email = EMAIL
|
24
|
-
s.homepage = HOMEPAGE
|
25
|
-
|
26
|
-
# Uncomment this to add a dependency
|
27
|
-
# s.add_dependency "foo"
|
28
|
-
|
29
|
-
s.require_path = 'lib'
|
30
|
-
s.autorequire = GEM
|
31
|
-
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
|
1
|
+
begin
|
2
|
+
require 'bundler'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
rescue Exception
|
32
5
|
end
|
33
6
|
|
34
|
-
|
35
|
-
pkg.gem_spec = spec
|
36
|
-
end
|
7
|
+
task :test => %w(test:parallel test:non_parallel)
|
37
8
|
|
38
|
-
|
39
|
-
|
40
|
-
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
41
|
-
end
|
9
|
+
# memcached and redis specs cannot be used in parallel
|
10
|
+
# because of flushing and namespace lacking in redis
|
42
11
|
|
43
|
-
|
44
|
-
task :
|
45
|
-
|
46
|
-
|
12
|
+
namespace :test do
|
13
|
+
task :parallel do
|
14
|
+
if defined?(JRUBY_VERSION)
|
15
|
+
puts 'No tests executed in parallel in JRuby'
|
16
|
+
else
|
17
|
+
specs = Dir['spec/*/*_spec.rb'].reject {|s| s =~ /memcached|redis|client|shared|riak/ }
|
18
|
+
sh("parallel_rspec -m 5 #{specs.join(' ')}")
|
19
|
+
end
|
47
20
|
end
|
48
|
-
end
|
49
21
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if ENV["TASK"]
|
55
|
-
ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
|
22
|
+
task :non_parallel do
|
23
|
+
if defined?(JRUBY_VERSION)
|
24
|
+
# Run all tests in jruby non-parallel
|
25
|
+
sh('rspec spec/*/*_spec.rb')
|
56
26
|
else
|
57
|
-
|
27
|
+
specs = Dir['spec/*/*_spec.rb'].select {|s| s =~ /memcached|redis|client|shared|riak/ }
|
28
|
+
sh("rspec #{specs.join(' ')}")
|
58
29
|
end
|
59
30
|
end
|
60
|
-
end
|
31
|
+
end
|
32
|
+
|
33
|
+
task :benchmarks do
|
34
|
+
Dir.chdir('benchmarks')
|
35
|
+
ruby('run.rb')
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :test
|
data/SPEC.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Moneta Specification
|
2
|
+
|
3
|
+
The purpose of the moneta specification is to create a general-purpose API for interacting with key-value stores. In general, libraries that need to interact with key-value stores should be able to specify that they can use any "moneta-compliant store".
|
4
|
+
|
5
|
+
# Moneta Executable Specs
|
6
|
+
|
7
|
+
Moneta ships with a set of executable specs which you can use to verify spec-compliance with your moneta adapter.
|
8
|
+
|
9
|
+
# Requirements for a Moneta Adapter
|
10
|
+
|
11
|
+
(See RFC 2119 for use of MUST, SHOULD, MAY, MUST NOT, and SHOULD NOT)
|
12
|
+
|
13
|
+
A Moneta adapter must expose a class with the following characteristics:
|
14
|
+
|
15
|
+
## Class Methods
|
16
|
+
|
17
|
+
### <code>new(options[Hash] => {}) => Object</code>
|
18
|
+
|
19
|
+
Return an instance of the moneta adapter, with the instance methods listed below. The <code>options</code> hash is a required parameter, and the adapter may specify whatever additional requirements it needs to properly instantiate it.
|
20
|
+
|
21
|
+
## Instance Methods
|
22
|
+
|
23
|
+
### <code>\[\](key[Object]) => Object</code>
|
24
|
+
|
25
|
+
Return the value stored in the key-value-store under the provided key. Adapters MUST return a duplicate of the original value, and consumers should expect that adapters might serialize and deserialize the key and value. As a result, both the key and value MUST be objects that can be serialized using Ruby's Marshal system.
|
26
|
+
|
27
|
+
### <code>\[\]=(key[Object], value[Object]) => Object(value)</code>
|
28
|
+
|
29
|
+
Store the value in the key-value-store under the provided key. Adapters MAY serialize the value using Ruby's Marshal system, and MUST NOT store a reference to the original value in the store, unless Ruby disallows duplication of the original value. Adapters SHOULD NOT simply call <code>dup</code> on the value, unless the value stores no references to other Object. For example, an adapter MAY store a <code>dup</code> of a String, but SHOULD NOT store a <code>dup</code> of <code>["hello", "world"]</code>.
|
30
|
+
|
31
|
+
### <code>fetch(key[Object], options[Hash] => {}, &block) => Object</code>
|
32
|
+
|
33
|
+
Return the value stored in the key-value-store under the provided key. If no value is stored under the provided key, the adapter MUST yield to the block, and return the value. The adapter MUST NOT store the value returned from the block in the key-value-store.
|
34
|
+
|
35
|
+
### <code>fetch(key[Object], value[Object], options[Hash] => {}) => Object</code>
|
36
|
+
|
37
|
+
Return the value stored in the key-value-store under the provided key. If no value is stored under the provided key, the adapter MUST return the default value provided. The adapter MUST NOT store the default value in the key-value-store.
|
38
|
+
|
39
|
+
### <code>delete(key[Object], options[Hash] => {}) => Object</code>
|
40
|
+
|
41
|
+
Delete the value stored in the key-value-store for the key provided, and return the value previously stored there. After this operation, the key-value-store MUST behave as though no value was stored for the provided key.
|
42
|
+
|
43
|
+
### <code>key?(key[Object], options[Hash] => {}) => [TrueClass, FalseClass]</code>
|
44
|
+
|
45
|
+
Determine whether a value exists in the key-value-store for the key provided. If a value exists, the adapter MUST return <code>true</code>. Otherwise, the adapter MUST return <code>false</code>.
|
46
|
+
|
47
|
+
### <code>store(key[Object], value[Object], options[Hash] => {}) => Object(value)</code>
|
48
|
+
|
49
|
+
Behaves the same as <code>[]=</code>, but allows the client to send additional options which can be specified by the adapter (and which may be specified by extensions to this specification).
|
50
|
+
|
51
|
+
### <code>increment(key[Object], amount[Integer] = 1, options[Hash] => {}) => Integer(value)</code>
|
52
|
+
|
53
|
+
Increments a value atomically. This method is not supported by all stores and might raise a <code>NotImplementedError</code>.
|
54
|
+
|
55
|
+
### <code>clear(options[Hash] => {})</code>
|
56
|
+
|
57
|
+
Completely empty all keys and values from the key-value-store. Adapters MAY allow a namespace during initialization, which can scope this operation to a particular subset of keys. After calling <code>clear</code>, a <code>[]</code> operation MUST return nil for every possible key, and a <code>key?</code> query MUST return false for every possible key.
|
58
|
+
|
59
|
+
# Additional Options Hashes
|
60
|
+
|
61
|
+
The following methods may all take an additional Hash as a final argument. This allows the client to send additional options which can be specified by the adapter (and which may be specified by extensions to this specification).
|
62
|
+
|
63
|
+
* fetch
|
64
|
+
* load
|
65
|
+
* store
|
66
|
+
* delete
|
67
|
+
* key?
|
68
|
+
* increment
|
69
|
+
* clear
|
70
|
+
|
71
|
+
In the case of methods with optional arguments, the Hash MUST be provided as the final argument. Keys in this Hash MUST be Symbols.
|
72
|
+
|
73
|
+
# Atomicity
|
74
|
+
|
75
|
+
The base Moneta specification does not specify any atomicity guarantees. However, extensions to this spec may specify extensions that define additional guarantees for any of the defined operations.
|
data/benchmarks/run.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
require 'benchmark'
|
5
|
+
require 'moneta'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'dm-core'
|
9
|
+
DataMapper.setup(:default, :adapter => :in_memory)
|
10
|
+
rescue LoadError => ex
|
11
|
+
puts "Failed to load DataMapper - #{ex.message}"
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
server = Moneta::Server.new(Moneta.new(:Memory))
|
16
|
+
rescue
|
17
|
+
puts "Failed to start Moneta server - #{ex.message}"
|
18
|
+
end
|
19
|
+
|
20
|
+
class Array
|
21
|
+
def random_index
|
22
|
+
rand(size)
|
23
|
+
end
|
24
|
+
|
25
|
+
def random_value
|
26
|
+
self[random_index]
|
27
|
+
end
|
28
|
+
|
29
|
+
def random_subset(n)
|
30
|
+
(1..n).map{|x| random_value }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
stores = {
|
35
|
+
:ActiveRecord => { :connection => { :adapter => 'sqlite3', :database => 'bench.activerecord' } },
|
36
|
+
:Cassandra => {},
|
37
|
+
:Client => {},
|
38
|
+
:Couch => {},
|
39
|
+
:DBM => { :file => 'bench.dbm' },
|
40
|
+
:DataMapper => { :setup => 'sqlite3:bench.datamapper' },
|
41
|
+
:File => { :dir => 'bench.file' },
|
42
|
+
:GDBM => { :file => 'bench.gdbm' },
|
43
|
+
:HBase => {},
|
44
|
+
:HBase => {},
|
45
|
+
:HashFile => { :dir => 'bench.hashfile' },
|
46
|
+
:LRUHash => {},
|
47
|
+
:LevelDB => { :dir => 'bench.leveldb' },
|
48
|
+
:LocalMemCache => { :file => 'bench.lmc' },
|
49
|
+
:MemcachedDalli => {},
|
50
|
+
:MemcachedNative => {},
|
51
|
+
:Memory => {},
|
52
|
+
:Mongo => {},
|
53
|
+
:PStore => { :file => 'bench.pstore' },
|
54
|
+
:Redis => {},
|
55
|
+
:Riak => {},
|
56
|
+
:SDBM => { :file => 'bench.sdbm' },
|
57
|
+
:Sequel => { :db => 'sqlite:/' },
|
58
|
+
:Sqlite => { :file => 'bench.sqlite' },
|
59
|
+
:YAML => { :file => 'bench.yaml' },
|
60
|
+
}
|
61
|
+
|
62
|
+
stats, keys, data, errors, summary = {}, [], [], [], []
|
63
|
+
dict = 'ABCDEFGHIJKLNOPQRSTUVWXYZabcdefghijklnopqrstuvwxyz123456789'.split('')
|
64
|
+
vlen_min, vlen_max, vlen_total, vlen_average = 99999, 0, 0, 0
|
65
|
+
klen_min, klen_max, klen_total, klen_average = 99999, 0, 0, 0
|
66
|
+
|
67
|
+
RUNS = 3
|
68
|
+
KEYS = 100
|
69
|
+
MIN_KEY_SIZE = 3
|
70
|
+
MAX_KEY_SIZE = 64
|
71
|
+
MIN_VALUE_SIZE = 1
|
72
|
+
MAX_VALUE_SIZE = 1024 * 10
|
73
|
+
|
74
|
+
puts '======================================================================'
|
75
|
+
puts 'Comparison of write/read between Moneta Stores'
|
76
|
+
puts '======================================================================'
|
77
|
+
|
78
|
+
stores.each do |name, options|
|
79
|
+
begin
|
80
|
+
cache = Moneta.new(name, options.dup)
|
81
|
+
cache['test'] = 'test'
|
82
|
+
rescue Exception => ex
|
83
|
+
puts "#{name} not benchmarked - #{ex.message}"
|
84
|
+
stores.delete(name)
|
85
|
+
ensure
|
86
|
+
cache.close if cache
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
puts 'Data loading...'
|
91
|
+
KEYS.times do |x|
|
92
|
+
klen = rand(MAX_KEY_SIZE - MIN_KEY_SIZE) + MIN_KEY_SIZE
|
93
|
+
vlen = rand(MAX_VALUE_SIZE - MIN_VALUE_SIZE) + MIN_VALUE_SIZE
|
94
|
+
|
95
|
+
key = dict.random_subset(klen).join
|
96
|
+
value = dict.random_subset(vlen).join
|
97
|
+
keys << key
|
98
|
+
data << [key, value]
|
99
|
+
|
100
|
+
vlen_min = value.size if value.size < vlen_min
|
101
|
+
vlen_max = value.size if value.size > vlen_max
|
102
|
+
vlen_total = vlen_total + value.size
|
103
|
+
|
104
|
+
klen_min = key.size if key.size < klen_min
|
105
|
+
klen_max = key.size if key.size > klen_max
|
106
|
+
klen_total = klen_total + key.size
|
107
|
+
end
|
108
|
+
vlen_average = vlen_total / KEYS
|
109
|
+
|
110
|
+
puts '----------------------------------------------------------------------'
|
111
|
+
puts "Total keys: #{keys.size}, unique: #{keys.uniq.size}"
|
112
|
+
puts '----------------------------------------------------------------------'
|
113
|
+
puts ' Minimum Maximum Total Average xps '
|
114
|
+
puts '----------------------------------------------------------------------'
|
115
|
+
puts 'Key Length % 10i % 10i % 10i % 10i ' % [klen_min, klen_max, klen_total, klen_average]
|
116
|
+
puts 'Value Length % 10i % 10i % 10i % 10i ' % [vlen_min, vlen_max, vlen_total, vlen_average]
|
117
|
+
|
118
|
+
stores.each do |name, options|
|
119
|
+
begin
|
120
|
+
puts '======================================================================'
|
121
|
+
puts name
|
122
|
+
puts '----------------------------------------------------------------------'
|
123
|
+
cache = Moneta.new(name, options.dup)
|
124
|
+
|
125
|
+
stats[name] = {
|
126
|
+
:writes => [],
|
127
|
+
:reads => [],
|
128
|
+
:totals => [],
|
129
|
+
:averages => [],
|
130
|
+
}
|
131
|
+
|
132
|
+
RUNS.times do |round|
|
133
|
+
cache.clear
|
134
|
+
print "[#{round + 1}] W"
|
135
|
+
m1 = Benchmark.measure do
|
136
|
+
KEYS.times do
|
137
|
+
key, value = data.random_value
|
138
|
+
cache[key] = value
|
139
|
+
end
|
140
|
+
end
|
141
|
+
stats[name][:writes] << m1.real
|
142
|
+
print 'R '
|
143
|
+
m2 = Benchmark.measure do
|
144
|
+
KEYS.times do
|
145
|
+
key, value = data.random_value
|
146
|
+
res = cache[key]
|
147
|
+
errors << [name, key, value, res] unless res == value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
stats[name][:reads] << m2.real
|
151
|
+
stats[name][:totals] << (m1.real + m2.real)
|
152
|
+
stats[name][:averages] << (m1.real + m2.real)
|
153
|
+
end
|
154
|
+
puts ''
|
155
|
+
puts '----------------------------------------------------------------------'
|
156
|
+
puts ' Minimum Maximum Total Average xps '
|
157
|
+
puts '----------------------------------------------------------------------'
|
158
|
+
tcmin, tcmax, tctot, tcavg = 99999, 0, 0, 0
|
159
|
+
[:writes, :reads].each do |sname|
|
160
|
+
cmin, cmax, ctot, cavg = 99999, 0, 0, 0
|
161
|
+
stats[name][sname].each do |val|
|
162
|
+
cmin = val if val < cmin
|
163
|
+
tcmin = val if val < tcmin
|
164
|
+
cmax = val if val > cmax
|
165
|
+
tcmax = val if val > tcmax
|
166
|
+
ctot = ctot + val
|
167
|
+
tctot = tctot + val
|
168
|
+
end
|
169
|
+
cavg = ctot / RUNS
|
170
|
+
puts '%-14.14s % 10.4f % 10.4f % 10.4f % 10.4f % 10.4f ' % ["#{name} #{sname}", cmin, cmax, ctot, cavg, KEYS / cavg]
|
171
|
+
end
|
172
|
+
tcavg = tctot / (RUNS * 2)
|
173
|
+
puts '%-14.14s % 10.4f % 10.4f % 10.4f % 10.4f % 10.4f ' % ["#{name} avgs", tcmin, tcmax, tctot, tcavg, KEYS / tcavg]
|
174
|
+
summary << [name, tcmin, tcmax, tctot, tcavg, KEYS / tcavg]
|
175
|
+
rescue Exception => ex
|
176
|
+
puts "Failed to benchmark #{name} - #{ex.message}"
|
177
|
+
ensure
|
178
|
+
cache.close if cache
|
179
|
+
end
|
180
|
+
end
|
181
|
+
puts '----------------------------------------------------------------------'
|
182
|
+
if errors.size > 0
|
183
|
+
puts "Errors : #{errors.size}"
|
184
|
+
# puts errors.inspect
|
185
|
+
else
|
186
|
+
puts 'No errors in reading!'
|
187
|
+
end
|
188
|
+
puts '======================================================================'
|
189
|
+
puts "Summary: #{RUNS} runs, #{KEYS} keys"
|
190
|
+
puts '======================================================================'
|
191
|
+
puts ' Minimum Maximum Total Average xps '
|
192
|
+
puts '----------------------------------------------------------------------'
|
193
|
+
summary.each do |sry|
|
194
|
+
puts '%-14.14s % 10.4f % 10.4f % 10.4f % 10.4f % 10.4f ' % sry
|
195
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
module Cache
|
3
|
+
class MonetaStore < Store
|
4
|
+
def initialize(options = nil)
|
5
|
+
raise ArgumentError, 'Option :store is required' unless @store = options.delete(:store)
|
6
|
+
@store = ::Moneta.new(@store, :expires => true) if Symbol === @store
|
7
|
+
super(options)
|
8
|
+
extend Strategy::LocalCache
|
9
|
+
end
|
10
|
+
|
11
|
+
def increment(key, amount = 1, options = nil)
|
12
|
+
instrument(:increment, key, :amount => amount) do
|
13
|
+
@store.increment(key, amount, moneta_options(options))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def decrement(key, amount = 1, options = nil)
|
18
|
+
instrument(:decrement, key, :amount => amount) do
|
19
|
+
@store.increment(key, -amount, moneta_options(options))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear(options = nil)
|
24
|
+
instrument(:clear, nil, nil) do
|
25
|
+
@store.clear(moneta_options(options))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def read_entry(key, options)
|
32
|
+
entry = @store.load(key, moneta_options(options))
|
33
|
+
entry && (ActiveSupport::Cache::Entry === entry ? entry : ActiveSupport::Cache::Entry.new(entry))
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_entry(key, entry, options)
|
37
|
+
@store.store(key, entry, moneta_options(options))
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_entry(key, options)
|
42
|
+
@store.delete(key, moneta_options(options))
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def moneta_options(options)
|
49
|
+
options ||= {}
|
50
|
+
options[:expires] = options.delete(:expires_in).to_i if options.include?(:expires_in)
|
51
|
+
options
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/moneta.rb
CHANGED
@@ -1,76 +1,130 @@
|
|
1
1
|
module Moneta
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
|
-
def fetch(key, default = nil, &blk)
|
21
|
-
check_expired(key)
|
22
|
-
super
|
23
|
-
end
|
24
|
-
|
25
|
-
def delete(key)
|
26
|
-
check_expired(key)
|
27
|
-
super
|
28
|
-
end
|
2
|
+
autoload :Base, 'moneta/base'
|
3
|
+
autoload :Builder, 'moneta/builder'
|
4
|
+
autoload :Cache, 'moneta/cache'
|
5
|
+
autoload :Expires, 'moneta/expires'
|
6
|
+
autoload :Lock, 'moneta/lock'
|
7
|
+
autoload :Logger, 'moneta/logger'
|
8
|
+
autoload :Mixins, 'moneta/mixins'
|
9
|
+
autoload :Net, 'moneta/net'
|
10
|
+
autoload :OptionMerger, 'moneta/optionmerger'
|
11
|
+
autoload :Proxy, 'moneta/proxy'
|
12
|
+
autoload :Server, 'moneta/server'
|
13
|
+
autoload :Shared, 'moneta/shared'
|
14
|
+
autoload :Stack, 'moneta/stack'
|
15
|
+
autoload :Transformer, 'moneta/transformer'
|
16
|
+
autoload :Wrapper, 'moneta/wrapper'
|
29
17
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
18
|
+
module Adapters
|
19
|
+
autoload :ActiveRecord, 'moneta/adapters/activerecord'
|
20
|
+
autoload :Cassandra, 'moneta/adapters/cassandra'
|
21
|
+
autoload :Client, 'moneta/adapters/client'
|
22
|
+
autoload :Cookie, 'moneta/adapters/cookie'
|
23
|
+
autoload :Couch, 'moneta/adapters/couch'
|
24
|
+
autoload :DataMapper, 'moneta/adapters/datamapper'
|
25
|
+
autoload :DBM, 'moneta/adapters/dbm'
|
26
|
+
autoload :File, 'moneta/adapters/file'
|
27
|
+
autoload :Fog, 'moneta/adapters/fog'
|
28
|
+
autoload :GDBM, 'moneta/adapters/gdbm'
|
29
|
+
autoload :HBase, 'moneta/adapters/hbase'
|
30
|
+
autoload :LevelDB, 'moneta/adapters/leveldb'
|
31
|
+
autoload :LocalMemCache, 'moneta/adapters/localmemcache'
|
32
|
+
autoload :LRUHash, 'moneta/adapters/lruhash'
|
33
|
+
autoload :Memcached, 'moneta/adapters/memcached'
|
34
|
+
autoload :MemcachedDalli, 'moneta/adapters/memcached_dalli'
|
35
|
+
autoload :MemcachedNative, 'moneta/adapters/memcached_native'
|
36
|
+
autoload :Memory, 'moneta/adapters/memory'
|
37
|
+
autoload :Mongo, 'moneta/adapters/mongo'
|
38
|
+
autoload :Null, 'moneta/adapters/null'
|
39
|
+
autoload :PStore, 'moneta/adapters/pstore'
|
40
|
+
autoload :Redis, 'moneta/adapters/redis'
|
41
|
+
autoload :Riak, 'moneta/adapters/riak'
|
42
|
+
autoload :SDBM, 'moneta/adapters/sdbm'
|
43
|
+
autoload :Sequel, 'moneta/adapters/sequel'
|
44
|
+
autoload :Sqlite, 'moneta/adapters/sqlite'
|
45
|
+
autoload :TokyoCabinet, 'moneta/adapters/tokyocabinet'
|
46
|
+
autoload :YAML, 'moneta/adapters/yaml'
|
46
47
|
end
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
# Create new Moneta store with default proxies
|
50
|
+
# which works in most cases if you don't want fine
|
51
|
+
# control over the proxy chain. It uses Marshal on the
|
52
|
+
# keys and values. Use Moneta#build if you want to have fine control!
|
53
|
+
#
|
54
|
+
# @param [Symbol] name Name of adapter (See Moneta::Adapters)
|
55
|
+
# @param [Hash] options
|
56
|
+
#
|
57
|
+
# Options:
|
58
|
+
# * :expires - If true or integer, ensure that store supports expiration by inserting
|
59
|
+
# Moneta::Expires if the underlying adapter doesn't support it natively
|
60
|
+
# * :threadsafe - If true, ensure that the store is thread safe by inserting Moneta::Lock
|
61
|
+
# * :logger - If true or Hash, add logger to chain (Hash is passed to logger as options)
|
62
|
+
# * :compress - If true, compress value with zlib, or specify custom compress, e.g. :quicklz
|
63
|
+
# * :serializer - Serializer used for key and value, disable with nil (default :marshal)
|
64
|
+
# * :key_serializer - Serializer used for key, disable with nil (default options[:serializer] if not provided)
|
65
|
+
# * :value_serializer - Serializer used for key, disable with nil (default options[:serializer] if not provided)
|
66
|
+
# * :prefix - Key prefix used for namespacing (default none)
|
67
|
+
# * All other options passed to the adapter
|
68
|
+
#
|
69
|
+
# Supported adapters:
|
70
|
+
# * :HashFile (Store which spreads the entries using a md5 hash, e.g. cache/42/391dd7535aebef91b823286ac67fcd)
|
71
|
+
# * :File (normal file store)
|
72
|
+
# * :Memcached (Memcached store)
|
73
|
+
# * ... (All other adapters from Moneta::Adapters)
|
74
|
+
def self.new(name, options = {})
|
75
|
+
expires = options.delete(:expires)
|
76
|
+
logger = options.delete(:logger)
|
77
|
+
threadsafe = options.delete(:threadsafe)
|
78
|
+
compress = options.delete(:compress)
|
79
|
+
serializer = options.include?(:serializer) ? options.delete(:serializer) : :marshal
|
80
|
+
key_serializer = options.include?(:key_serializer) ? options.delete(:key_serializer) : serializer
|
81
|
+
value_serializer = options.include?(:value_serializer) ? options.delete(:value_serializer) : serializer
|
82
|
+
transformer = { :key => [key_serializer, :prefix], :value => [value_serializer], :prefix => options.delete(:prefix) }
|
83
|
+
transformer[:value] << (Symbol === compress ? compress : :zlib) if compress
|
84
|
+
raise ArgumentError, 'Name must be Symbol' unless Symbol === name
|
85
|
+
case name
|
86
|
+
when :Sequel, :ActiveRecord, :Couch, :DataMapper
|
87
|
+
# Sequel accept only base64 keys and values
|
88
|
+
# FIXME: Couch should work only with :marshal but this raises an error on 1.9
|
89
|
+
transformer[:key] << :base64
|
90
|
+
transformer[:value] << :base64
|
91
|
+
when :Memcached, :MemcachedDalli, :MemcachedNative
|
92
|
+
# Memcached accept only base64 keys, expires already supported
|
93
|
+
options[:expires] = expires if Integer === expires
|
94
|
+
expires = false
|
95
|
+
transformer[:key] << :base64
|
96
|
+
when :PStore, :YAML, :Null
|
97
|
+
# For PStore and YAML only the key has to be a string
|
98
|
+
transformer.delete(:value) if transformer[:value] == [:marshal]
|
99
|
+
when :HashFile
|
100
|
+
# Use spreading hashes
|
101
|
+
transformer[:key] << :md5 << :spread
|
102
|
+
name = :File
|
103
|
+
when :File
|
104
|
+
# Use escaping
|
105
|
+
transformer[:key] << :escape
|
106
|
+
when :Cassandra, :Redis
|
107
|
+
# Expires already supported
|
108
|
+
options[:expires] = expires if Integer === expires
|
109
|
+
expires = false
|
56
110
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
111
|
+
build do
|
112
|
+
use :Logger, Hash === logger ? logger : {} if logger
|
113
|
+
use :Expires, :expires => (Integer === expires ? expires : nil) if expires
|
114
|
+
use :Transformer, transformer
|
115
|
+
use :Lock if threadsafe
|
116
|
+
adapter name, options
|
63
117
|
end
|
64
118
|
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
119
|
+
|
120
|
+
# Build your own store chain!
|
121
|
+
#
|
122
|
+
# @example Moneta builder
|
123
|
+
# Moneta.build do
|
124
|
+
# use :Expires
|
125
|
+
# adapter :Memory
|
126
|
+
# end
|
127
|
+
def self.build(&block)
|
128
|
+
Builder.new(&block).build.last
|
75
129
|
end
|
76
130
|
end
|