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/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
rvm:
|
2
|
+
- 1.8.7
|
3
|
+
- 1.9.3
|
4
|
+
# - ruby-head
|
5
|
+
- jruby
|
6
|
+
- rbx-18mode
|
7
|
+
- rbx-19mode
|
8
|
+
services:
|
9
|
+
- riak
|
10
|
+
- couchdb
|
11
|
+
- redis-server
|
12
|
+
- cassandra
|
13
|
+
- memcached
|
14
|
+
- mongodb
|
15
|
+
before_install:
|
16
|
+
- sudo apt-get install -qq libtokyocabinet8 libtokyocabinet-dev liblzo2-dev
|
17
|
+
env:
|
18
|
+
- "TASK=test:parallel"
|
19
|
+
- "TASK=test:non_parallel"
|
20
|
+
- "TASK=benchmarks"
|
21
|
+
matrix:
|
22
|
+
allow_failures:
|
23
|
+
# - rvm: ruby-head
|
24
|
+
- rvm: jruby
|
25
|
+
- rvm: rbx-18mode
|
26
|
+
- rvm: rbx-19mode
|
27
|
+
# Parallel tests do not work on jruby
|
28
|
+
exclude:
|
29
|
+
- rvm: jruby
|
30
|
+
env: "TASK=test:parallel"
|
31
|
+
- rvm: 1.8.7
|
32
|
+
env: "TASK=benchmarks"
|
33
|
+
- rvm: jruby
|
34
|
+
env: "TASK=benchmarks"
|
35
|
+
- rvm: rbx-18mode
|
36
|
+
env: "TASK=benchmarks"
|
37
|
+
- rvm: rbx-19mode
|
38
|
+
env: "TASK=benchmarks"
|
39
|
+
script: "bundle exec rake $TASK"
|
data/Gemfile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
source :rubygems
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
def alternatives(gems)
|
5
|
+
if defined?(JRUBY_VERSION)
|
6
|
+
[gems[:jruby]].flatten.compact.each {|g| gem g }
|
7
|
+
else
|
8
|
+
[gems[:mri]].flatten.compact.each {|g| gem g }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Testing
|
13
|
+
gem 'rake'
|
14
|
+
gem 'rspec'
|
15
|
+
gem 'parallel_tests'
|
16
|
+
|
17
|
+
# Serializer used by Transformer
|
18
|
+
gem 'tnetstring'
|
19
|
+
gem 'bencode'
|
20
|
+
gem 'multi_json'
|
21
|
+
alternatives :mri => 'bson_ext', :jruby => 'bson'
|
22
|
+
alternatives :mri => 'ox'
|
23
|
+
alternatives :mri => 'msgpack', :jruby => 'msgpack-jruby'
|
24
|
+
alternatives :mri => 'bert'
|
25
|
+
|
26
|
+
# Compressors used by Transformer
|
27
|
+
alternatives :mri => 'bzip2-ruby'
|
28
|
+
alternatives :mri => 'ruby-lzma'
|
29
|
+
alternatives :mri => 'lzoruby'
|
30
|
+
alternatives :mri => 'snappy'
|
31
|
+
# QuickLZ segfaults because of an assertion, fix this before activating it again
|
32
|
+
# alternatives :mri => 'qlzruby'
|
33
|
+
|
34
|
+
# Backends
|
35
|
+
gem 'dm-core'
|
36
|
+
gem 'dm-migrations'
|
37
|
+
gem 'dm-sqlite-adapter'
|
38
|
+
gem 'fog'
|
39
|
+
gem 'activerecord', '>= 3.2.9'
|
40
|
+
gem 'redis'
|
41
|
+
gem 'mongo'
|
42
|
+
gem 'couchrest'
|
43
|
+
gem 'sequel'
|
44
|
+
gem 'dalli'
|
45
|
+
gem 'riak-client'
|
46
|
+
gem 'cassandra'
|
47
|
+
#gem 'hbaserb'
|
48
|
+
#gem 'localmemcache'
|
49
|
+
alternatives :mri => 'leveldb-ruby'
|
50
|
+
alternatives :mri => 'tokyocabinet'
|
51
|
+
alternatives :mri => 'memcached', :jruby => 'jruby-memcached'
|
52
|
+
alternatives :mri => 'sqlite3', :jruby => %w(jdbc-sqlite3 activerecord-jdbc-adapter activerecord-jdbcsqlite3-adapter)
|
53
|
+
alternatives :jruby => %w(ffi gdbm) # gdbm for jruby needs ffi
|
54
|
+
|
55
|
+
# Rack integration testing
|
56
|
+
gem 'rack'
|
57
|
+
gem 'rack-cache'
|
58
|
+
|
59
|
+
# Rails integration testing
|
60
|
+
gem 'actionpack'
|
61
|
+
gem 'minitest'
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2009 Yehuda Katz
|
1
|
+
Copyright (c) 2009 Yehuda Katz, 2012 Daniel Mendler
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,450 @@
|
|
1
|
+
# Moneta: A unified interface for key/value stores
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/minad/moneta.png?branch=master)](http://travis-ci.org/minad/moneta) [![Dependency Status](https://gemnasium.com/minad/moneta.png?travis)](https://gemnasium.com/minad/moneta) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/minad/moneta)
|
4
|
+
|
5
|
+
Moneta provides a standard interface for interacting with various kinds of key/value stores. Moneta is very feature rich:
|
6
|
+
|
7
|
+
* Supports a lot of backends (See below)
|
8
|
+
* Supports proxies (Similar to [Rack middlewares](http://rack.github.com/))
|
9
|
+
* Custom serialization via `Moneta::Transformer` proxy (Marshal/JSON/YAML and many more)
|
10
|
+
* Custom key transformation via `Moneta::Transformer` proxy
|
11
|
+
* Value compression via `Moneta::Transformer` proxy (Zlib, Snappy, LZMA, ...)
|
12
|
+
* Expiration for all stores (Added via proxy `Moneta::Expires` if not supported natively)
|
13
|
+
* Atomic incrementation and decrementation for most stores (Method `#increment`)
|
14
|
+
* Includes a very simple key/value server (`Moneta::Server`) and client (`Moneta::Adapters::Client`)
|
15
|
+
* Integration with [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/) as cookie and session store and [Rack-Cache](https://github.com/rtomayko/rack-cache)
|
16
|
+
|
17
|
+
Moneta is tested thoroughly using [Travis-CI](http://travis-ci.org/minad/moneta).
|
18
|
+
|
19
|
+
## Links
|
20
|
+
|
21
|
+
* Source: <http://github.com/minad/moneta>
|
22
|
+
* Bugs: <http://github.com/minad/moneta/issues>
|
23
|
+
* API documentation:
|
24
|
+
* Latest Gem: <http://rubydoc.info/gems/moneta/frames>
|
25
|
+
* GitHub master: <http://rubydoc.info/github/minad/moneta/master/frames>
|
26
|
+
|
27
|
+
## Supported backends
|
28
|
+
|
29
|
+
Out of the box, it supports the following backends:
|
30
|
+
|
31
|
+
* Memory:
|
32
|
+
* In-memory store (`:Memory`)
|
33
|
+
* LRU hash - prefer this over :Memory! (`:LRUHash`)
|
34
|
+
* LocalMemCache (`:LocalMemCache`)
|
35
|
+
* Memcached store (`:Memcached`, `:MemcachedNative` and `:MemcachedDalli`)
|
36
|
+
* Relational Databases:
|
37
|
+
* DataMapper (`:DataMapper`)
|
38
|
+
* ActiveRecord (`:ActiveRecord`)
|
39
|
+
* Sequel (`:Sequel`)
|
40
|
+
* Sqlite3 (`:Sqlite`)
|
41
|
+
* Filesystem:
|
42
|
+
* PStore (`:PStore`)
|
43
|
+
* YAML store (`:YAML`)
|
44
|
+
* Filesystem directory store (`:File`)
|
45
|
+
* Filesystem directory store which spreads files in subdirectories using md5 hash (`:HashFile`)
|
46
|
+
* Key/value databases:
|
47
|
+
* Berkeley DB (`:DBM`)
|
48
|
+
* Cassandra (`:Cassandra`)
|
49
|
+
* GDBM (`:GDBM`)
|
50
|
+
* HBase (`:HBase`)
|
51
|
+
* LevelDB (`:LevelDB`)
|
52
|
+
* Redis (`:Redis`)
|
53
|
+
* Riak (`:Riak`)
|
54
|
+
* SDBM (`:SDBM`)
|
55
|
+
* TokyoCabinet (`:TokyoCabinet`)
|
56
|
+
* Document databases:
|
57
|
+
* CouchDB (`:Couch`)
|
58
|
+
* MongoDB (`:Mongo`)
|
59
|
+
* Other
|
60
|
+
* Moneta key/value server client (`:Client` works with `Moneta::Server`)
|
61
|
+
* Fog cloud storage which supports Amazon S3, Rackspace, etc. (`:Fog`)
|
62
|
+
* Storage which doesn't store anything (`:Null`)
|
63
|
+
|
64
|
+
Some of the backends are not exactly based on key/value stores, e.g. the relational ones. These
|
65
|
+
are useful if you already use the corresponding backend in your application. You get a key/value
|
66
|
+
store for free then without installing any additional services and you still have the possibility
|
67
|
+
to upgrade to a real key/value store.
|
68
|
+
|
69
|
+
## Proxies
|
70
|
+
|
71
|
+
In addition it supports proxies (Similar to [Rack middlewares](http://rack.github.com/)) which
|
72
|
+
add additional features to storage backends:
|
73
|
+
|
74
|
+
* `Moneta::Proxy` and `Moneta::Wrapper` proxy base classes
|
75
|
+
* `Moneta::Expires` to add expiration support to stores which don't support it natively. Add it in the builder using `use :Expires`.
|
76
|
+
* `Moneta::Stack` to stack multiple stores (Read returns result from first where the key is found, writes go to all stores). Add it in the builder using `use :Stack`.
|
77
|
+
* `Moneta::Transformer` transforms keys and values (Marshal, YAML, JSON, Base64, MD5, ...). Add it in the builder using `use :Transformer`.
|
78
|
+
* `Moneta::Cache` combine two stores, one as backend and one as cache (e.g. `Moneta::Adapters::File` + `Moneta::Adapters::Memory`). Add it in the builder using `use :Cache`.
|
79
|
+
* `Moneta::Lock` to make store thread safe. Add it in the builder using `use :Lock`.
|
80
|
+
* `Moneta::Logger` to log database accesses. Add it in the builder using `use :Logger`.
|
81
|
+
* `Moneta::Shared` to share a store between multiple processes. Add it in the builder using `use :Shared`.
|
82
|
+
|
83
|
+
## Supported serializers and compressors (`Moneta::Transformer`)
|
84
|
+
|
85
|
+
Supported serializers:
|
86
|
+
|
87
|
+
* BEncode (`:bencode`)
|
88
|
+
* BERT (`:bert`)
|
89
|
+
* BSON (`:bson`)
|
90
|
+
* JSON (`:json`)
|
91
|
+
* Marshal (`:marshal`)
|
92
|
+
* MessagePack (`:msgpack`)
|
93
|
+
* Ox (`:ox`)
|
94
|
+
* TNetStrings (`:tnet`)
|
95
|
+
* YAML (`:yaml`)
|
96
|
+
|
97
|
+
Supported value compressors:
|
98
|
+
|
99
|
+
* LZMA (`:lzma`)
|
100
|
+
* LZO (`:lzo`)
|
101
|
+
* Snappy (`:snappy`)
|
102
|
+
* QuickLZ (`:quicklz`)
|
103
|
+
* Zlib (`:zlib`)
|
104
|
+
|
105
|
+
Special transformers:
|
106
|
+
|
107
|
+
* Digests (MD5, Shas, ...)
|
108
|
+
* Add prefix to keys (`:prefix`)
|
109
|
+
* HMAC to verify values (`:hmac`, useful for `Rack::MonetaCookies`)
|
110
|
+
|
111
|
+
## Moneta API
|
112
|
+
|
113
|
+
~~~
|
114
|
+
#initialize(options) options differs per-store, and is used to set up the store.
|
115
|
+
|
116
|
+
#[](key) retrieve a key. If the key is not available, return nil.
|
117
|
+
|
118
|
+
#load(key, options = {}) retrieve a key. If the key is not available, return nil.
|
119
|
+
|
120
|
+
#fetch(key, options = {}, &block) retrieve a key. If the key is not available, execute the
|
121
|
+
block and return its return value.
|
122
|
+
|
123
|
+
#fetch(key, value, options = {}) retrieve a key. If the key is not available, return the value,
|
124
|
+
|
125
|
+
#[]=(key, value) set a value for a key. If the key is already used, clobber it.
|
126
|
+
keys set using []= will never expire.
|
127
|
+
|
128
|
+
#store(key, value, options = {}) same as []=, but you can supply options.
|
129
|
+
|
130
|
+
#delete(key, options = {}) delete the key from the store and return the current value.
|
131
|
+
|
132
|
+
#key?(key, options = {}) true if the key exists, false if it does not.
|
133
|
+
|
134
|
+
#increment(key, amount = 1, options = {}) increment numeric value. This is a atomic operation
|
135
|
+
which is not supported by all stores. Returns current value.
|
136
|
+
|
137
|
+
#clear(options = {}) clear all keys in this store.
|
138
|
+
|
139
|
+
#close close database connection.
|
140
|
+
~~~
|
141
|
+
|
142
|
+
The Moneta API is purposely extremely similar to the Hash API. In order so support an
|
143
|
+
identical API across stores, it does not support iteration or partial matches.
|
144
|
+
|
145
|
+
### Creating a Store
|
146
|
+
|
147
|
+
There is a simple interface to create a store using `Moneta.new`:
|
148
|
+
|
149
|
+
~~~ ruby
|
150
|
+
store = Moneta.new(:Memcached, :server => 'localhost:11211')
|
151
|
+
~~~
|
152
|
+
|
153
|
+
If you want to have control over the proxies, you have to use `Moneta.build`:
|
154
|
+
|
155
|
+
~~~ ruby
|
156
|
+
store = Moneta.build do
|
157
|
+
# Adds expires proxy
|
158
|
+
use :Expires
|
159
|
+
# Transform key using Marshal and Base64 and value using Marshal
|
160
|
+
use :Transformer, :key => [:marshal, :base64], :value => :marshal
|
161
|
+
# Memory backend
|
162
|
+
adapter :Memory
|
163
|
+
end
|
164
|
+
~~~
|
165
|
+
|
166
|
+
### Expiration
|
167
|
+
|
168
|
+
The Cassandra, Memcached and Redis backends supports expires values directly:
|
169
|
+
|
170
|
+
~~~ ruby
|
171
|
+
cache = Moneta::Adapters::Memcached.new
|
172
|
+
|
173
|
+
# Or using the builder...
|
174
|
+
cache = Moneta.build do
|
175
|
+
adapter :Memcached
|
176
|
+
end
|
177
|
+
|
178
|
+
# Expires in 60 seconds
|
179
|
+
cache.store(key, value, :expires => 60)
|
180
|
+
|
181
|
+
# Update expires time if value is found
|
182
|
+
cache.load(key, :expires => 30)
|
183
|
+
cache.key?(key, :expires => 30)
|
184
|
+
~~~
|
185
|
+
|
186
|
+
You can add the expires feature to other backends using the Expires proxy:
|
187
|
+
|
188
|
+
~~~ ruby
|
189
|
+
# Using the :expires option
|
190
|
+
cache = Moneta.new(:File, :dir => '...', :expires => true)
|
191
|
+
|
192
|
+
# or manually by using the proxy...
|
193
|
+
cache = Moneta::Expires.new(Moneta::Adapters::File.new(:dir => '...'))
|
194
|
+
|
195
|
+
# or using the builder...
|
196
|
+
cache = Moneta.build do
|
197
|
+
use :Expires
|
198
|
+
adapter :File, :dir => '...'
|
199
|
+
end
|
200
|
+
~~~
|
201
|
+
|
202
|
+
### Incrementation and raw access
|
203
|
+
|
204
|
+
The stores support the `#increment` which allows atomic increments of unsigned integer values. If you increment
|
205
|
+
a non existing value, it will be created. If you increment a non integer value an exception will be raised.
|
206
|
+
|
207
|
+
~~~ ruby
|
208
|
+
store.increment('counter') => 1 # counter created
|
209
|
+
store.increment('counter') => 2
|
210
|
+
store.increment('counter', -1) => 1
|
211
|
+
store.increment('counter', 13) => 14
|
212
|
+
store.increment('counter', 0) => 14
|
213
|
+
store['name'] = 'Moneta'
|
214
|
+
store.increment('name') => Exception
|
215
|
+
~~~
|
216
|
+
|
217
|
+
If you want to access the counter value you have to use raw access to the datastore. This is only important
|
218
|
+
if you have a `Moneta::Transformer` somewhere in your proxy chain which transforms the values e.g. with `Marshal`.
|
219
|
+
|
220
|
+
~~~ ruby
|
221
|
+
store.increment('counter') => 1 # counter created
|
222
|
+
store.load('counter', :raw => true) => '1'
|
223
|
+
|
224
|
+
store.store('counter', '10', :raw => true)
|
225
|
+
store.increment('counter') => 11
|
226
|
+
~~~
|
227
|
+
|
228
|
+
Fortunately there is a nicer way to do this using some syntactic sugar!
|
229
|
+
|
230
|
+
~~~ ruby
|
231
|
+
store.increment('counter') => 1 # counter created
|
232
|
+
store.raw['counter'] => '1'
|
233
|
+
store.raw.load('counter') => '1'
|
234
|
+
|
235
|
+
store.raw['counter'] = '10'
|
236
|
+
store.increment('counter') => 11
|
237
|
+
~~~
|
238
|
+
|
239
|
+
You can also keep the `raw` store in a variable and use it like this:
|
240
|
+
|
241
|
+
~~~ ruby
|
242
|
+
counters = store.raw
|
243
|
+
|
244
|
+
counters.increment('counter') => 1 # counter created
|
245
|
+
counters['counter'] => '1'
|
246
|
+
counters.load('counter') => '1'
|
247
|
+
|
248
|
+
counters['counter'] = '10'
|
249
|
+
counters.increment('counter') => 11
|
250
|
+
~~~
|
251
|
+
|
252
|
+
Stores which support incrementation (you have to use `Moneta::Lock` if you want to use the store in a multithreading environment.)
|
253
|
+
|
254
|
+
* ActiveRecord
|
255
|
+
* File
|
256
|
+
* HBase
|
257
|
+
* LRUHash
|
258
|
+
* LevelDB
|
259
|
+
* Memcached
|
260
|
+
* Memory
|
261
|
+
* Redis
|
262
|
+
* SDBM/DBM/GDBM
|
263
|
+
* Sequel
|
264
|
+
* Sqlite
|
265
|
+
* TokyoCabinet
|
266
|
+
* YAML/PStore
|
267
|
+
|
268
|
+
Stores which don't support incrementation:
|
269
|
+
|
270
|
+
* Cassandra
|
271
|
+
* Couch
|
272
|
+
* DataMapper
|
273
|
+
* Fog
|
274
|
+
* LocalMemCache
|
275
|
+
* Mongo
|
276
|
+
* Riak
|
277
|
+
|
278
|
+
### Syntactic sugar and option merger
|
279
|
+
|
280
|
+
For raw data access as described before the class `Moneta::OptionMerger` is used. It works like this:
|
281
|
+
|
282
|
+
~~~ ruby
|
283
|
+
# All methods after `with` get the options passed
|
284
|
+
store.with(:raw => true).load('key')
|
285
|
+
|
286
|
+
# You can also specify the methods
|
287
|
+
store.with(:raw => true, :only => :load).load('key')
|
288
|
+
store.with(:raw => true, :except => [:key?, :increment]).load('key')
|
289
|
+
|
290
|
+
# Syntactic sugar for raw access
|
291
|
+
store.raw.load('key')
|
292
|
+
|
293
|
+
# Access substore where all keys get a prefix
|
294
|
+
substore = store.prefix('sub')
|
295
|
+
substore['key'] = 'value'
|
296
|
+
store['key'] => nil
|
297
|
+
store['subkey'] => 'value'
|
298
|
+
|
299
|
+
# Set expiration time for all keys
|
300
|
+
short_lived_store = long_lived_store.expires(60)
|
301
|
+
short_lived_store['key'] = 'value'
|
302
|
+
~~~
|
303
|
+
|
304
|
+
## Framework Integration
|
305
|
+
|
306
|
+
Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist integration classes for [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/) and [Rack-Cache](https://github.com/rtomayko/rack-cache).
|
307
|
+
|
308
|
+
### Rack session store
|
309
|
+
|
310
|
+
Use Moneta as a [Rack](http://rack.github.com/) session store:
|
311
|
+
|
312
|
+
~~~ ruby
|
313
|
+
require 'rack/session/moneta'
|
314
|
+
|
315
|
+
# Use only the adapter name
|
316
|
+
use Rack::Session::Moneta, :store => :Redis
|
317
|
+
|
318
|
+
# Use Moneta.new
|
319
|
+
use Rack::Session::Moneta, :store => Moneta.new(:Memory, :expires => true)
|
320
|
+
|
321
|
+
# Use the Moneta builder
|
322
|
+
use Rack::Session::Moneta do
|
323
|
+
use :Expires
|
324
|
+
adapter :Memory
|
325
|
+
end
|
326
|
+
~~~
|
327
|
+
|
328
|
+
### Rack cache
|
329
|
+
|
330
|
+
Use Moneta as a [Rack-Cache](https://github.com/rtomayko/rack-cache) store:
|
331
|
+
|
332
|
+
~~~ ruby
|
333
|
+
require 'rack/cache/moneta'
|
334
|
+
|
335
|
+
use Rack::Cache,
|
336
|
+
:metastore => 'moneta://Memory?expires=true',
|
337
|
+
:entitystore => 'moneta://Memory?expires=true'
|
338
|
+
|
339
|
+
# Or used named Moneta stores
|
340
|
+
Rack::Cache::Moneta['named_metastore'] = Moneta.build do
|
341
|
+
use :Expires
|
342
|
+
adapter :Memory
|
343
|
+
end
|
344
|
+
use Rack::Cache,
|
345
|
+
:metastore => 'moneta://named_metastore',
|
346
|
+
:entity_store => 'moneta://named_entitystore'
|
347
|
+
~~~
|
348
|
+
|
349
|
+
### Rack cookies
|
350
|
+
|
351
|
+
Use Moneta to store cookies in [Rack](http://rack.github.com/). It uses the `Moneta::Adapters::Cookie`. You might
|
352
|
+
wonder what the purpose of this store or Rack middleware is: It makes it possible
|
353
|
+
to use all the transformers on the cookies (e.g. `:prefix`, `:marshal` and `:hmac` for value verification).
|
354
|
+
|
355
|
+
~~~ ruby
|
356
|
+
require 'rack/moneta_cookies'
|
357
|
+
|
358
|
+
use Rack::MonetaCookies, :domain => 'example.com', :path => '/path'
|
359
|
+
run lambda do |env|
|
360
|
+
req = Rack::Request.new(env)
|
361
|
+
req.cookies #=> is now a Moneta store!
|
362
|
+
env['rack.request.cookie_hash'] #=> is now a Moneta store!
|
363
|
+
req.cookies['key'] #=> retrieves 'key'
|
364
|
+
req.cookies['key'] = 'value' #=> sets 'key'
|
365
|
+
req.cookies.delete('key') #=> removes 'key'
|
366
|
+
[200, {}, []]
|
367
|
+
end
|
368
|
+
~~~
|
369
|
+
|
370
|
+
### Rails session store
|
371
|
+
|
372
|
+
Add the session store in your application configuration `config/environments/*.rb`.
|
373
|
+
|
374
|
+
~~~ ruby
|
375
|
+
require 'moneta'
|
376
|
+
|
377
|
+
# Only by adapter name
|
378
|
+
config.cache_store :moneta_store, :store => :Memory
|
379
|
+
|
380
|
+
# Use Moneta.new
|
381
|
+
config.cache_store :moneta_store, :store => Moneta.new(:Memory)
|
382
|
+
|
383
|
+
# Use the Moneta builder
|
384
|
+
config.cache_store :moneta_store, :store => Moneta.build do
|
385
|
+
use :Expires
|
386
|
+
adapter :Memory
|
387
|
+
end
|
388
|
+
~~~
|
389
|
+
|
390
|
+
### Rails cache store
|
391
|
+
|
392
|
+
Add the cache store in your application configuration `config/environments/*.rb`. Unfortunately the
|
393
|
+
Moneta cache store doesn't support matchers. If you need these features use a different server-specific implementation.
|
394
|
+
|
395
|
+
~~~ ruby
|
396
|
+
require 'moneta'
|
397
|
+
|
398
|
+
# Only by adapter name
|
399
|
+
config.cache_store :moneta_store, :store => :Memory
|
400
|
+
|
401
|
+
# Use Moneta.new
|
402
|
+
config.cache_store :moneta_store, :store => Moneta.new(:Memory)
|
403
|
+
|
404
|
+
# Use the Moneta builder
|
405
|
+
config.cache_store :moneta_store, :store => Moneta.build do
|
406
|
+
use :Expires
|
407
|
+
adapter :Memory
|
408
|
+
end
|
409
|
+
~~~
|
410
|
+
|
411
|
+
## Advanced - Build your own key value server
|
412
|
+
|
413
|
+
You can use Moneta to build your own key/value server which is shared between
|
414
|
+
multiple processes. If you run the following code in two different processes,
|
415
|
+
they will share the same data which will also be persistet in the database `shared.db`.
|
416
|
+
|
417
|
+
~~~ ruby
|
418
|
+
require 'moneta'
|
419
|
+
|
420
|
+
store = Moneta.build do
|
421
|
+
use :Transformer, :key => :marshal, :value => :marshal
|
422
|
+
use :Shared do
|
423
|
+
use :Cache do
|
424
|
+
cache do
|
425
|
+
adapter :LRUHash
|
426
|
+
end
|
427
|
+
backend do
|
428
|
+
adapter :GDBM, :file => 'shared.db'
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
~~~
|
434
|
+
|
435
|
+
## More information
|
436
|
+
|
437
|
+
* http://yehudakatz.com/2009/02/12/whats-the-point/
|
438
|
+
* http://yehudakatz.com/2009/02/12/initial-release-of-moneta-unified-keyvalue-store-api/
|
439
|
+
|
440
|
+
## Alternatives
|
441
|
+
|
442
|
+
* [Horcrux](https://github.com/technoweenie/horcrux): Used at github, supports batch operations but only Memcached backend
|
443
|
+
* [ToyStore](https://github.com/jnunemaker/toystore): ORM mapper for key/value stores
|
444
|
+
* [ToyStore Adapter](https://github.com/jnunemaker/adapter): Adapter to key/value stores used by ToyStore, Moneta can be used directly with the ToyStore Memory adapter
|
445
|
+
|
446
|
+
## Authors
|
447
|
+
|
448
|
+
* Daniel Mendler
|
449
|
+
* Hannes Georg
|
450
|
+
* Originally by Yehuda Katz and contributors
|