moneta 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +15 -0
- data/README.md +160 -50
- data/Rakefile +11 -2
- data/SPEC.md +7 -2
- data/lib/moneta.rb +7 -1
- data/lib/moneta/adapters/activerecord.rb +27 -3
- data/lib/moneta/adapters/cassandra.rb +1 -1
- data/lib/moneta/adapters/client.rb +8 -2
- data/lib/moneta/adapters/cookie.rb +1 -1
- data/lib/moneta/adapters/couch.rb +2 -1
- data/lib/moneta/adapters/datamapper.rb +16 -0
- data/lib/moneta/adapters/daybreak.rb +19 -1
- data/lib/moneta/adapters/file.rb +12 -0
- data/lib/moneta/adapters/hbase.rb +1 -2
- data/lib/moneta/adapters/lruhash.rb +4 -1
- data/lib/moneta/adapters/memcached.rb +7 -3
- data/lib/moneta/adapters/memcached/dalli.rb +8 -2
- data/lib/moneta/adapters/memcached/native.rb +10 -3
- data/lib/moneta/adapters/memory.rb +1 -0
- data/lib/moneta/adapters/mongo.rb +32 -5
- data/lib/moneta/adapters/pstore.rb +13 -2
- data/lib/moneta/adapters/redis.rb +19 -0
- data/lib/moneta/adapters/restclient.rb +1 -1
- data/lib/moneta/adapters/sequel.rb +20 -6
- data/lib/moneta/adapters/sqlite.rb +13 -1
- data/lib/moneta/adapters/tokyocabinet.rb +5 -0
- data/lib/moneta/cache.rb +10 -0
- data/lib/moneta/expires.rb +19 -22
- data/lib/moneta/lock.rb +2 -2
- data/lib/moneta/mixins.rb +33 -11
- data/lib/moneta/optionmerger.rb +1 -1
- data/lib/moneta/proxy.rb +13 -8
- data/lib/moneta/server.rb +13 -6
- data/lib/moneta/shared.rb +6 -10
- data/lib/moneta/synchronize.rb +125 -0
- data/lib/moneta/transformer.rb +50 -42
- data/lib/moneta/transformer/config.rb +34 -32
- data/lib/moneta/utils.rb +20 -0
- data/lib/moneta/version.rb +1 -1
- data/lib/moneta/weak.rb +17 -0
- data/lib/moneta/wrapper.rb +5 -0
- data/lib/rack/moneta_cookies.rb +2 -2
- data/lib/rack/moneta_store.rb +4 -4
- data/script/benchmarks +3 -9
- data/script/generate-specs +278 -41
- data/script/install-bundle +2 -2
- data/spec/moneta/adapter_activerecord_spec.rb +1 -0
- data/spec/moneta/adapter_cassandra_spec.rb +1 -0
- data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +1 -0
- data/spec/moneta/adapter_client_spec.rb +1 -0
- data/spec/moneta/adapter_cookie_spec.rb +1 -0
- data/spec/moneta/adapter_couch_spec.rb +1 -0
- data/spec/moneta/adapter_datamapper_spec.rb +1 -0
- data/spec/moneta/adapter_daybreak_spec.rb +1 -0
- data/spec/moneta/adapter_dbm_spec.rb +1 -0
- data/spec/moneta/adapter_file_spec.rb +1 -0
- data/spec/moneta/adapter_fog_spec.rb +1 -0
- data/spec/moneta/adapter_gdbm_spec.rb +1 -1
- data/spec/moneta/adapter_hbase_spec.rb +1 -0
- data/spec/moneta/adapter_leveldb_spec.rb +1 -0
- data/spec/moneta/adapter_localmemcache_spec.rb +1 -0
- data/spec/moneta/adapter_lruhash_spec.rb +1 -0
- data/spec/moneta/adapter_memcached_dalli_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_native_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_spec.rb +2 -0
- data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_memory_spec.rb +1 -0
- data/spec/moneta/adapter_mongo_spec.rb +2 -0
- data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_pstore_spec.rb +1 -0
- data/spec/moneta/adapter_redis_spec.rb +2 -0
- data/spec/moneta/adapter_redis_with_default_expires_spec.rb +2 -0
- data/spec/moneta/adapter_restclient_spec.rb +1 -0
- data/spec/moneta/adapter_riak_spec.rb +1 -0
- data/spec/moneta/adapter_sdbm_spec.rb +1 -0
- data/spec/moneta/adapter_sequel_spec.rb +1 -0
- data/spec/moneta/adapter_sqlite_spec.rb +1 -0
- data/spec/moneta/adapter_tdb_spec.rb +1 -0
- data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -0
- data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -0
- data/spec/moneta/adapter_yaml_spec.rb +1 -0
- data/spec/moneta/cache_file_memory_spec.rb +1 -0
- data/spec/moneta/cache_memory_null_spec.rb +1 -0
- data/spec/moneta/expires_file_spec.rb +3 -1
- data/spec/moneta/expires_memory_spec.rb +2 -0
- data/spec/moneta/expires_memory_with_default_expires_spec.rb +2 -0
- data/spec/moneta/lock_spec.rb +1 -0
- data/spec/moneta/mutex_spec.rb +71 -0
- data/spec/moneta/null_adapter_spec.rb +1 -0
- data/spec/moneta/optionmerger_spec.rb +5 -7
- data/spec/moneta/pool_spec.rb +1 -0
- data/spec/moneta/proxy_expires_memory_spec.rb +2 -0
- data/spec/moneta/proxy_redis_spec.rb +2 -0
- data/spec/moneta/semaphore_spec.rb +84 -0
- data/spec/moneta/{shared_spec.rb → shared_tcp_spec.rb} +4 -3
- data/spec/moneta/shared_unix_spec.rb +37 -0
- data/spec/moneta/simple_activerecord_spec.rb +1 -0
- data/spec/moneta/simple_activerecord_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_cassandra_spec.rb +1 -0
- data/spec/moneta/simple_client_tcp_spec.rb +1 -0
- data/spec/moneta/simple_client_unix_spec.rb +3 -2
- data/spec/moneta/simple_couch_spec.rb +1 -0
- data/spec/moneta/simple_couch_with_expires_spec.rb +2 -1
- data/spec/moneta/simple_datamapper_spec.rb +1 -0
- data/spec/moneta/simple_datamapper_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -0
- data/spec/moneta/simple_daybreak_spec.rb +1 -0
- data/spec/moneta/simple_daybreak_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_dbm_spec.rb +1 -0
- data/spec/moneta/simple_dbm_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_file_spec.rb +1 -0
- data/spec/moneta/simple_file_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_fog_spec.rb +1 -0
- data/spec/moneta/simple_fog_with_expires_spec.rb +2 -1
- data/spec/moneta/simple_gdbm_spec.rb +1 -0
- data/spec/moneta/simple_gdbm_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_hashfile_spec.rb +1 -0
- data/spec/moneta/simple_hashfile_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_hbase_spec.rb +1 -0
- data/spec/moneta/simple_hbase_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_leveldb_spec.rb +1 -0
- data/spec/moneta/simple_leveldb_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_localmemcache_spec.rb +1 -0
- data/spec/moneta/simple_localmemcache_with_expires_spec.rb +2 -1
- data/spec/moneta/simple_lruhash_spec.rb +1 -0
- data/spec/moneta/simple_lruhash_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_memcached_dalli_spec.rb +2 -0
- data/spec/moneta/simple_memcached_native_spec.rb +2 -0
- data/spec/moneta/simple_memcached_spec.rb +2 -0
- data/spec/moneta/simple_memory_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_compress_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -0
- data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -0
- data/spec/moneta/simple_mongo_spec.rb +2 -0
- data/spec/moneta/simple_null_spec.rb +1 -0
- data/spec/moneta/simple_pstore_spec.rb +1 -0
- data/spec/moneta/simple_pstore_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_redis_spec.rb +2 -0
- data/spec/moneta/simple_restclient_spec.rb +1 -0
- data/spec/moneta/simple_riak_spec.rb +1 -0
- data/spec/moneta/simple_riak_with_expires_spec.rb +2 -1
- data/spec/moneta/simple_sdbm_spec.rb +1 -0
- data/spec/moneta/simple_sdbm_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_sequel_spec.rb +1 -0
- data/spec/moneta/simple_sequel_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_sqlite_spec.rb +1 -0
- data/spec/moneta/simple_sqlite_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_tdb_spec.rb +1 -0
- data/spec/moneta/simple_tdb_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_tokyocabinet_spec.rb +1 -0
- data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +3 -1
- data/spec/moneta/simple_yaml_spec.rb +1 -0
- data/spec/moneta/simple_yaml_with_expires_spec.rb +3 -1
- data/spec/moneta/stack_file_memory_spec.rb +1 -0
- data/spec/moneta/stack_memory_file_spec.rb +1 -0
- data/spec/moneta/transformer_bencode_spec.rb +1 -0
- data/spec/moneta/transformer_bert_spec.rb +1 -0
- data/spec/moneta/transformer_bson_spec.rb +1 -0
- data/spec/moneta/transformer_bzip2_spec.rb +1 -0
- data/spec/moneta/transformer_json_spec.rb +1 -0
- data/spec/moneta/transformer_key_inspect_spec.rb +73 -0
- data/spec/moneta/transformer_key_marshal_spec.rb +1 -0
- data/spec/moneta/transformer_key_to_s_spec.rb +1 -0
- data/spec/moneta/transformer_key_yaml_spec.rb +1 -0
- data/spec/moneta/transformer_lzma_spec.rb +1 -0
- data/spec/moneta/transformer_lzo_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_base64_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_escape_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_md5_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -0
- data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -0
- data/spec/moneta/transformer_msgpack_spec.rb +1 -0
- data/spec/moneta/transformer_ox_spec.rb +1 -0
- data/spec/moneta/transformer_quicklz_spec.rb +1 -0
- data/spec/moneta/transformer_snappy_spec.rb +1 -0
- data/spec/moneta/transformer_tnet_spec.rb +1 -0
- data/spec/moneta/transformer_value_marshal_spec.rb +1 -0
- data/spec/moneta/transformer_value_yaml_spec.rb +1 -0
- data/spec/moneta/transformer_yaml_spec.rb +1 -0
- data/spec/moneta/transformer_zlib_spec.rb +1 -0
- data/spec/moneta/weak_create_spec.rb +114 -0
- data/spec/moneta/weak_increment_spec.rb +114 -0
- data/spec/monetaspecs.rb +75 -2
- data/spec/rack/moneta_cookies_spec.rb +1 -1
- metadata +20 -4
data/CHANGES
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
0.7.8
|
|
2
|
+
|
|
3
|
+
* Adapters::Memcached: switched to Dalli by default
|
|
4
|
+
* Adapters::Daybreak: add option :sync to load and store
|
|
5
|
+
* Adapters::LRUHash: add option :max_count
|
|
6
|
+
* Adapters::Mongo: add options :user and :password
|
|
7
|
+
* Adapters::Mongo: Correctly close connection
|
|
8
|
+
* Adapters::Redis: Correctly close connection
|
|
9
|
+
* Transformer: add inspect key transformer
|
|
10
|
+
* Added #create method to atomically create entries
|
|
11
|
+
* Added WeakCreate and WeakIncrement proxies
|
|
12
|
+
* Added Mutex and Semaphore synchronization primitives for
|
|
13
|
+
shared/distributed database locks
|
|
14
|
+
* Rename unix socket options from :file to :socket
|
|
15
|
+
|
|
1
16
|
0.7.6
|
|
2
17
|
|
|
3
18
|
* Adapters::Daybreak: api changed
|
data/README.md
CHANGED
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
Moneta provides a standard interface for interacting with various kinds of key/value stores. A short overview of the features:
|
|
6
6
|
|
|
7
|
-
* Supports a lot of backends (See below)
|
|
7
|
+
* Supports a lot of backends with consistent behaviour (See below)
|
|
8
8
|
* Allows a full configuration of the serialization -> compression -> adapter stack using proxies (Similar to [Rack middlewares](http://rack.github.com/))
|
|
9
9
|
* Configurable serialization via `Moneta::Transformer` proxy (Marshal/JSON/YAML and many more)
|
|
10
10
|
* Configurable value compression via `Moneta::Transformer` proxy (Zlib, Snappy, LZMA, ...)
|
|
11
11
|
* Configurable key transformation via `Moneta::Transformer` proxy
|
|
12
12
|
* Expiration for all stores (Added via proxy `Moneta::Expires` if not supported natively)
|
|
13
|
-
* Atomic
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* Atomic operations
|
|
14
|
+
* Atomic incrementation and decrementation for most stores (Method `#increment` and `#decrement`)
|
|
15
|
+
* Atomic creation of entries (Method `#create`)
|
|
16
|
+
* Shared/distributed database-wide synchronization primitives `Moneta::Mutex` and `Moneta::Semaphore`
|
|
17
|
+
* Includes a simple pure-ruby key/value server (`Moneta::Server`) and client (`Moneta::Adapters::Client`)
|
|
18
|
+
* Integration with [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/)/[Rack-Cache](https://github.com/rtomayko/rack-cache), [Sinatra](http://sinatrarb.com/) and [Ramaze](http://ramaze.net/).
|
|
16
19
|
|
|
17
20
|
If you are not yet convinced, you might ask why? What are the goals of the project?
|
|
18
21
|
|
|
@@ -21,11 +24,43 @@ same for template languages.
|
|
|
21
24
|
* Make it easy to compare different key/value stores and benchmark them
|
|
22
25
|
* To hide a lot of different and maybe complex APIs behind one well-designed and simple Moneta API
|
|
23
26
|
* Give people a starting point or example code to start working with their favourite key/value store. Feel free to copy code, please mention Moneta then :)
|
|
24
|
-
* Create a reusable piece of code, since similar things are solved over and over again ([Rails](http://rubyonrails.org/ brings its own cache stores, and many frameworks do the same...)
|
|
27
|
+
* Create a reusable piece of code, since similar things are solved over and over again ([Rails](http://rubyonrails.org/) brings its own cache stores, and many frameworks do the same...)
|
|
25
28
|
* See also http://yehudakatz.com/2009/02/12/whats-the-point/
|
|
26
29
|
|
|
27
30
|
Moneta is tested thoroughly using [Travis-CI](http://travis-ci.org/minad/moneta).
|
|
28
31
|
|
|
32
|
+
## Getting started
|
|
33
|
+
|
|
34
|
+
Install Moneta via Rubygems
|
|
35
|
+
|
|
36
|
+
~~~
|
|
37
|
+
$ gem install moneta
|
|
38
|
+
~~~
|
|
39
|
+
|
|
40
|
+
or add it to your Gemfile
|
|
41
|
+
|
|
42
|
+
~~~ ruby
|
|
43
|
+
gem 'moneta'
|
|
44
|
+
~~~
|
|
45
|
+
|
|
46
|
+
Now you are ready to go:
|
|
47
|
+
|
|
48
|
+
~~~ ruby
|
|
49
|
+
require 'moneta'
|
|
50
|
+
|
|
51
|
+
# Create a simple file store
|
|
52
|
+
store = Moneta.new(:File, :dir => 'moneta')
|
|
53
|
+
|
|
54
|
+
# Store some entries
|
|
55
|
+
store['key'] = 'value'
|
|
56
|
+
|
|
57
|
+
# Read entry
|
|
58
|
+
store.key?('key') # returns true
|
|
59
|
+
store['key'] # returns 'value'
|
|
60
|
+
|
|
61
|
+
store.close
|
|
62
|
+
~~~
|
|
63
|
+
|
|
29
64
|
## Links
|
|
30
65
|
|
|
31
66
|
* Source: <http://github.com/minad/moneta>
|
|
@@ -36,7 +71,7 @@ Moneta is tested thoroughly using [Travis-CI](http://travis-ci.org/minad/moneta)
|
|
|
36
71
|
|
|
37
72
|
## Supported backends
|
|
38
73
|
|
|
39
|
-
Out of the box, it supports the following backends:
|
|
74
|
+
Out of the box, it supports the following backends. Use the backend name symbol in the Moneta constructor (e.g. `Moneta.new(:Memory)`).
|
|
40
75
|
|
|
41
76
|
* Memory:
|
|
42
77
|
* In-memory store (`:Memory`)
|
|
@@ -83,49 +118,51 @@ to upgrade to a real key/value store.
|
|
|
83
118
|
### Backend feature matrix
|
|
84
119
|
|
|
85
120
|
<table>
|
|
86
|
-
<thead style="font-weight:bold"><tr><th>Adapter</th><th>Required gems</th><th>Multi-thread safe<sup>[1]</sup></th><th>Multi-process safe<sup>[2]</sup></th><th>Atomic increment</th><th>Native expires<sup>[3]</sup></th><th>Persistent</th><th>Description</th></tr></thead>
|
|
121
|
+
<thead style="font-weight:bold"><tr><th>Adapter</th><th>Required gems</th><th>Multi-thread safe<sup>[1]</sup></th><th>Multi-process safe<sup>[2]</sup></th><th>Atomic increment<sup>[8]</sup></th><th>Atomic create<sup>[9]</sup></th><th>Native expires<sup>[3]</sup></th><th>Persistent</th><th>Description</th></tr></thead>
|
|
87
122
|
<tbody>
|
|
88
|
-
<tr><td>ActiveRecord</td><td>activerecord</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="https://rubygems.org/gems/activerecord">ActiveRecord</a> ORM</td></tr>
|
|
89
|
-
<tr><td>Cassandra</td><td>cassandra</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:green">✓</td><td><a href="http://cassandra.apache.org/">Cassandra</a> distributed database</td></tr>
|
|
90
|
-
<tr><td>Client</td><td>-</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:blue">?<sup>[5]</sup></td><td style="color:blue">?<sup>[5]</sup></td><td style="color:blue">?<sup>[5]</sup></td><td>Moneta client adapter</td></tr>
|
|
91
|
-
<tr><td>Cookie</td><td>-</td><td style="color:red">✗</td><td style="color:blue">(✓)<sup>[6]</sup></td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td>Cookie in memory store</td></tr>
|
|
92
|
-
<tr><td>Couch</td><td>couchrest</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://couchdb.apache.org/">CouchDB</a> database</td></tr>
|
|
93
|
-
<tr><td>DataMapper</td><td>dm-core, dm-migrations</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://datamapper.org/">DataMapper</a> ORM</td></tr>
|
|
94
|
-
<tr><td>Daybreak</td><td>daybreak</td><td style="color:red">✗</td><td style="color:blue">(✓)<sup>[7]</sup></td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td>Incredibly fast pure-ruby key/value store <a href="http://propublica.github.com/daybreak/">Daybreak</a></td></tr>
|
|
95
|
-
<tr><td>DBM</td><td>-</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/dbm/rdoc/DBM.html">Berkeley DB</a></td></tr>
|
|
96
|
-
<tr><td>File</td><td>-</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td>File store</td></tr>
|
|
97
|
-
<tr><td>Fog</td><td>fog</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://fog.io/">Fog</a> cloud store</td></tr>
|
|
98
|
-
<tr><td>GDBM</td><td>-</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/gdbm/rdoc/GDBM.html">GDBM</a> database</td></tr>
|
|
99
|
-
<tr><td>HBase</td><td>hbase</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://hbase.apache.org/">HBase</a> database</td></tr>
|
|
100
|
-
<tr><td>LevelDB</td><td>leveldb</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://code.google.com/p/leveldb/">LevelDB</a> database</td></tr>
|
|
101
|
-
<tr><td>LocalMemCache</td><td>localmemcache</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://localmemcache.rubyforge.org/">LocalMemCache</a> database</td></tr>
|
|
102
|
-
<tr><td>LRUHash</td><td>-</td><td style="color:red">✗</td><td style="color:blue">(✓)<sup>[6]</sup></td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td>LRU memory store</td></tr>
|
|
103
|
-
<tr><td>Memcached</td><td>dalli or memcached</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗<sup>[4]</sup></td><td><a href="http://memcached.org/">Memcached</a> database</td></tr>
|
|
104
|
-
<tr><td>MemcachedDalli</td><td>dalli</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗<sup>[4]</sup></td><td><a href="http://memcached.org/">Memcached</a> database with Dalli library</td></tr>
|
|
105
|
-
<tr><td>MemcachedNative</td><td>memcached</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗<sup>[4]</sup></td><td>Memcached database with native library</td></tr>
|
|
106
|
-
<tr><td>Memory</td><td>-</td><td style="color:red">✗</td><td style="color:blue">(✓)<sup>[6]</sup></td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td>Memory store</td></tr>
|
|
107
|
-
<tr><td>Mongo</td><td>mongo</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td><a href="http://www.mongodb.org/">MongoDB</a> database</td></tr>
|
|
108
|
-
<tr><td>Null</td><td>-</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:red">✗</td><td>No database</td></tr>
|
|
109
|
-
<tr><td>PStore</td><td>-</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://ruby-doc.org/stdlib/libdoc/pstore/rdoc/PStore.html">PStore</a> store</td></tr>
|
|
110
|
-
<tr><td>Redis</td><td>redis</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td><a href="http://redis.io/">Redis</a> database</td></tr>
|
|
111
|
-
<tr><td>RestClient</td><td>-</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:blue">?<sup>[5]</sup></td><td>Moneta REST client adapter</td></tr>
|
|
112
|
-
<tr><td>Riak</td><td>riak-client</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://docs.basho.com/">Riak</a> database</td></tr>
|
|
113
|
-
<tr><td>SDBM</td><td>-</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/sdbm/rdoc/SDBM.html">SDBM</a> database</td></tr>
|
|
114
|
-
<tr><td>Sequel</td><td>sequel</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://sequel.rubyforge.org/">Sequel</a> ORM</td></tr>
|
|
115
|
-
<tr><td>Sqlite</td><td>sqlite3</td><td style="color:blue">?</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://sqlite.org/">Sqlite3</a> database</td></tr>
|
|
116
|
-
<tr><td>TDB</td><td>tdb</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://tdb.samba.org/">TDB</a> database</td></tr>
|
|
117
|
-
<tr><td>TokyoCabinet</td><td>tokoycabinet</td><td style="color:red">✗</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://fallabs.com/tokyocabinet/">TokyoCabinet</a> database</td></tr>
|
|
118
|
-
<tr><td>YAML</td><td>-</td><td style="color:red">✗</td><td style="color:green">✓</td><td style="color:green">✓</td><td style="color:red">✗</td><td style="color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/YAML/Store.html">YAML</a> store</td></tr>
|
|
123
|
+
<tr><td>ActiveRecord</td><td>activerecord</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="https://rubygems.org/gems/activerecord">ActiveRecord</a> ORM</td></tr>
|
|
124
|
+
<tr><td>Cassandra</td><td>cassandra</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td><a href="http://cassandra.apache.org/">Cassandra</a> distributed database</td></tr>
|
|
125
|
+
<tr><td>Client</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:blue">?<sup>[5]</sup></td><td style="text-align:center;color:blue">?<sup>[5]</sup></td><td style="text-align:center;color:blue">?<sup>[5]</sup></td><td style="text-align:center;color:blue">?<sup>[5]</sup></td><td>Moneta client adapter</td></tr>
|
|
126
|
+
<tr><td>Cookie</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:blue">(✓)<sup>[6]</sup></td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td>Cookie in memory store</td></tr>
|
|
127
|
+
<tr><td>Couch</td><td>couchrest</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://couchdb.apache.org/">CouchDB</a> database</td></tr>
|
|
128
|
+
<tr><td>DataMapper</td><td>dm-core, dm-migrations</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://datamapper.org/">DataMapper</a> ORM</td></tr>
|
|
129
|
+
<tr><td>Daybreak</td><td>daybreak</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:blue">(✓)<sup>[7]</sup></td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td>Incredibly fast pure-ruby key/value store <a href="http://propublica.github.com/daybreak/">Daybreak</a></td></tr>
|
|
130
|
+
<tr><td>DBM</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/dbm/rdoc/DBM.html">Berkeley DB</a></td></tr>
|
|
131
|
+
<tr><td>File</td><td>-</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td>File store</td></tr>
|
|
132
|
+
<tr><td>Fog</td><td>fog</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://fog.io/">Fog</a> cloud store</td></tr>
|
|
133
|
+
<tr><td>GDBM</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/gdbm/rdoc/GDBM.html">GDBM</a> database</td></tr>
|
|
134
|
+
<tr><td>HBase</td><td>hbase</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://hbase.apache.org/">HBase</a> database</td></tr>
|
|
135
|
+
<tr><td>LevelDB</td><td>leveldb</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://code.google.com/p/leveldb/">LevelDB</a> database</td></tr>
|
|
136
|
+
<tr><td>LocalMemCache</td><td>localmemcache</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://localmemcache.rubyforge.org/">LocalMemCache</a> database</td></tr>
|
|
137
|
+
<tr><td>LRUHash</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:blue">(✓)<sup>[6]</sup></td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td>LRU memory store</td></tr>
|
|
138
|
+
<tr><td>Memcached</td><td>dalli or memcached</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗<sup>[4]</sup></td><td><a href="http://memcached.org/">Memcached</a> database</td></tr>
|
|
139
|
+
<tr><td>MemcachedDalli</td><td>dalli</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗<sup>[4]</sup></td><td><a href="http://memcached.org/">Memcached</a> database with Dalli library</td></tr>
|
|
140
|
+
<tr><td>MemcachedNative</td><td>memcached</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗<sup>[4]</sup></td><td>Memcached database with native library</td></tr>
|
|
141
|
+
<tr><td>Memory</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:blue">(✓)<sup>[6]</sup></td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td>Memory store</td></tr>
|
|
142
|
+
<tr><td>Mongo</td><td>mongo</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td><a href="http://www.mongodb.org/">MongoDB</a> database</td></tr>
|
|
143
|
+
<tr><td>Null</td><td>-</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td>No database</td></tr>
|
|
144
|
+
<tr><td>PStore</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://ruby-doc.org/stdlib/libdoc/pstore/rdoc/PStore.html">PStore</a> store</td></tr>
|
|
145
|
+
<tr><td>Redis</td><td>redis</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td><a href="http://redis.io/">Redis</a> database</td></tr>
|
|
146
|
+
<tr><td>RestClient</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:blue">?<sup>[5]</sup></td><td>Moneta REST client adapter</td></tr>
|
|
147
|
+
<tr><td>Riak</td><td>riak-client</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://docs.basho.com/">Riak</a> database</td></tr>
|
|
148
|
+
<tr><td>SDBM</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/sdbm/rdoc/SDBM.html">SDBM</a> database</td></tr>
|
|
149
|
+
<tr><td>Sequel</td><td>sequel</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://sequel.rubyforge.org/">Sequel</a> ORM</td></tr>
|
|
150
|
+
<tr><td>Sqlite</td><td>sqlite3</td><td style="text-align:center;color:blue">?</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://sqlite.org/">Sqlite3</a> database</td></tr>
|
|
151
|
+
<tr><td>TDB</td><td>tdb</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://tdb.samba.org/">TDB</a> database</td></tr>
|
|
152
|
+
<tr><td>TokyoCabinet</td><td>tokoycabinet</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://fallabs.com/tokyocabinet/">TokyoCabinet</a> database</td></tr>
|
|
153
|
+
<tr><td>YAML</td><td>-</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:green">✓</td><td style="text-align:center;color:red">✗</td><td style="text-align:center;color:green">✓</td><td><a href="http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/YAML/Store.html">YAML</a> store</td></tr>
|
|
119
154
|
</tbody>
|
|
120
155
|
</table>
|
|
121
156
|
|
|
122
157
|
* [1]: Make adapters thread-safe by using `Moneta::Lock` or by passing the option `:threadsafe => true` to `Moneta#new`. There is also `Moneta::Pool` which can be used to share a store between multiple threads if the store is multi-process safe. I recommend to add the option `:threadsafe` to ensure thread-safety since for example under JRuby and Rubinius even the basic datastructures are not thread safe due to the lack of a global interpreter lock (GIL). This differs from MRI where some adapters might appear thread safe already but only due to the GIL.
|
|
123
158
|
* [2]: Share a Moneta store between multiple processes using `Moneta::Shared` (See below).
|
|
124
159
|
* [3]: Add expiration support by using `Moneta::Expires` or by passing the option `:expires => true` to `Moneta#new`.
|
|
125
|
-
* [4]: There are some servers which use the memcached protocol but which are persistent (e.g. MemcacheDB, Kai, IronCache
|
|
160
|
+
* [4]: There are some servers which use the memcached protocol but which are persistent (e.g. [MemcacheDB](http://memcachedb.org/), [Kai](http://sourceforge.net/apps/mediawiki/kai), [IronCache](http://dev.iron.io/cache/reference/memcache/))
|
|
126
161
|
* [5]: Depends on server
|
|
127
162
|
* [6]: Store is multi-process safe because it is an in-memory store, values are not shared between multiple processes
|
|
128
163
|
* [7]: Store is multi-process safe, but not synchronized automatically between multiple processes
|
|
164
|
+
* [8]: If a store provides atomic increment it can be used with `Moneta::Semaphore`. You can add weak `#increment` using the `Moneta::WeakIncrement` proxy.
|
|
165
|
+
* [8]: If a store provides atomic creation it can be used with `Moneta::Mutex`. You can add weak `#create` using the `Moneta::WeakCreate` proxy.
|
|
129
166
|
|
|
130
167
|
## Proxies
|
|
131
168
|
|
|
@@ -141,6 +178,7 @@ add additional features to storage backends:
|
|
|
141
178
|
* `Moneta::Pool` to create a pool of stores as a means of making the store thread safe. Add it in the builder using `use(:Pool) {}`.
|
|
142
179
|
* `Moneta::Logger` to log database accesses. Add it in the builder using `use :Logger`.
|
|
143
180
|
* `Moneta::Shared` to share a store between multiple processes. Add it in the builder using `use(:Shared) {}`.
|
|
181
|
+
* `Moneta::WeakIncrement` and `Moneta::WeakCreate` to add `#create` and `#increment` support without atomicity (weak) to stores which don't support it.
|
|
144
182
|
|
|
145
183
|
### Serializers and compressors (`Moneta::Transformer`)
|
|
146
184
|
|
|
@@ -173,7 +211,7 @@ Special transformers:
|
|
|
173
211
|
## Moneta API
|
|
174
212
|
|
|
175
213
|
The Moneta API is purposely extremely similar to the Hash API with a few minor additions.
|
|
176
|
-
There are the additional methods `#load`, `#increment`, `#decrement` and `#close`. Every method takes also a optional
|
|
214
|
+
There are the additional methods `#load`, `#increment`, `#decrement`, `#create` and `#close`. Every method takes also a optional
|
|
177
215
|
option hash. In order so support an identical API across stores, Moneta does not support iteration or partial matches.
|
|
178
216
|
|
|
179
217
|
~~~
|
|
@@ -197,13 +235,16 @@ option hash. In order so support an identical API across stores, Moneta does not
|
|
|
197
235
|
|
|
198
236
|
#key?(key, options = {}) true if the key exists, false if it does not.
|
|
199
237
|
|
|
200
|
-
#increment(key, amount = 1, options = {}) increment numeric value. This is
|
|
238
|
+
#increment(key, amount = 1, options = {}) increment numeric value. This is an atomic operation
|
|
201
239
|
which is not supported by all stores. Returns current value.
|
|
202
240
|
|
|
203
|
-
#decrement(key, amount = 1, options = {}) increment numeric value. This is
|
|
241
|
+
#decrement(key, amount = 1, options = {}) increment numeric value. This is an atomic operation
|
|
204
242
|
which is not supported by all stores. Returns current value.
|
|
205
243
|
This is just syntactic sugar for incrementing with a negative value.
|
|
206
244
|
|
|
245
|
+
#create(key, value, options = {}) create entry. This is an atomic operation which is not supported by all stores.
|
|
246
|
+
Returns true if the value was created.
|
|
247
|
+
|
|
207
248
|
#clear(options = {}) clear all keys in this store.
|
|
208
249
|
|
|
209
250
|
#close close database connection.
|
|
@@ -275,7 +316,9 @@ cache = Moneta.build do
|
|
|
275
316
|
end
|
|
276
317
|
~~~
|
|
277
318
|
|
|
278
|
-
###
|
|
319
|
+
### Atomic operations
|
|
320
|
+
|
|
321
|
+
#### Atomic incrementation and raw access
|
|
279
322
|
|
|
280
323
|
The stores support the `#increment` which allows atomic increments of unsigned integer values. If you increment
|
|
281
324
|
a non existing value, it will be created. If you increment a non integer value an exception will be raised.
|
|
@@ -326,6 +369,69 @@ counters['counter'] = '10'
|
|
|
326
369
|
counters.increment('counter') # returns 11
|
|
327
370
|
~~~
|
|
328
371
|
|
|
372
|
+
#### Atomic create
|
|
373
|
+
|
|
374
|
+
The stores support the `#create` which allows atomic creation of entries. `#create` returns true
|
|
375
|
+
if the value was created.
|
|
376
|
+
|
|
377
|
+
~~~ ruby
|
|
378
|
+
store.create('key', 'value') # returns true
|
|
379
|
+
store.create('key', 'other value') # returns false
|
|
380
|
+
~~~
|
|
381
|
+
|
|
382
|
+
#### Shared/distributed synchronization primitives
|
|
383
|
+
|
|
384
|
+
Moneta provides shared/distributed synchronization primitives which are shared database-wide between
|
|
385
|
+
all clients.
|
|
386
|
+
|
|
387
|
+
* `Moneta::Mutex`
|
|
388
|
+
|
|
389
|
+
~~~ ruby
|
|
390
|
+
mutex = Moneta::Mutex.new(store, 'mutex_key')
|
|
391
|
+
|
|
392
|
+
mutex.synchronize do
|
|
393
|
+
mutex.locked? # returns true
|
|
394
|
+
|
|
395
|
+
# Synchronized access to counter
|
|
396
|
+
store['counter'] += 1
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
begin
|
|
400
|
+
mutex.lock
|
|
401
|
+
mutex.locked? # returns true
|
|
402
|
+
...
|
|
403
|
+
ensure
|
|
404
|
+
mutex.unlock
|
|
405
|
+
end
|
|
406
|
+
~~~
|
|
407
|
+
|
|
408
|
+
* `Moneta::Semaphore`
|
|
409
|
+
|
|
410
|
+
~~~ ruby
|
|
411
|
+
semaphore = Moneta::Semaphore.new(store, 'semaphore_counter', max_concurrent)
|
|
412
|
+
|
|
413
|
+
semaphore.synchronize do
|
|
414
|
+
semaphore.locked? # returns true
|
|
415
|
+
...
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
begin
|
|
419
|
+
semaphore.enter
|
|
420
|
+
semaphore.locked? # returns true
|
|
421
|
+
...
|
|
422
|
+
ensure
|
|
423
|
+
semaphore.leave
|
|
424
|
+
end
|
|
425
|
+
~~~
|
|
426
|
+
|
|
427
|
+
#### Weak atomic operations
|
|
428
|
+
|
|
429
|
+
If an underlying adapter doesn't provide atomic `#create` or `#increment` and `#decrement` you can
|
|
430
|
+
use the proxies `Moneta::WeakIncrement` and `Moneta::WeakCreate` to add support without atomicity.
|
|
431
|
+
|
|
432
|
+
But then you have to ensure that the store is not shared by multiple processes and thread-safety is
|
|
433
|
+
provided by `Moneta::Lock`.
|
|
434
|
+
|
|
329
435
|
### Syntactic sugar and option merger
|
|
330
436
|
|
|
331
437
|
For raw data access as described before the class `Moneta::OptionMerger` is used. It works like this:
|
|
@@ -367,7 +473,7 @@ compressed_store['key'] = 'value will be compressed'
|
|
|
367
473
|
|
|
368
474
|
## Framework Integration
|
|
369
475
|
|
|
370
|
-
Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist integration classes for [Rails](http://rubyonrails.org/)
|
|
476
|
+
Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist integration classes for [Rails](http://rubyonrails.org/) and [Rack](http://rack.github.com/)/[Rack-Cache](https://github.com/rtomayko/rack-cache). You can also use all the Rack middlewares together with Rails and the [Sinatra](http://sinatrarb.com/) framework. There exist the following integration classes:
|
|
371
477
|
|
|
372
478
|
* Rack, Rails and Sinatra
|
|
373
479
|
* `Rack::Session::Moneta` is a Rack middleware to use Moneta for storing sessions
|
|
@@ -378,6 +484,9 @@ Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist in
|
|
|
378
484
|
* Rails
|
|
379
485
|
* `ActionDispatch::Session::MonetaStore` is a Rails middleware to use Moneta for storing sessions
|
|
380
486
|
* `ActiveSupport::Cache::MonetaStore` is a Rails cache implementation which uses a Moneta store as backend
|
|
487
|
+
* Ramaze
|
|
488
|
+
* `Ramaze::Cache::Moneta` is integrated into the [Ramaze](http://ramaze.net/) project and allows Ramaze to use
|
|
489
|
+
Moneta as caching store
|
|
381
490
|
|
|
382
491
|
### Rack
|
|
383
492
|
|
|
@@ -410,9 +519,9 @@ caching if you add the option `:cache => true`. Use it in your `config.ru` like
|
|
|
410
519
|
# Add Rack::MonetaStore somewhere in your rack stack
|
|
411
520
|
use Rack::MonetaStore, :Memory, :cache => true
|
|
412
521
|
|
|
413
|
-
run lambda
|
|
522
|
+
run lambda { |env|
|
|
414
523
|
env['rack.moneta_store'] # is a Moneta store with per-request caching
|
|
415
|
-
|
|
524
|
+
}
|
|
416
525
|
|
|
417
526
|
# Pass it a block like the one passed to Moneta.build
|
|
418
527
|
use Rack::MonetaStore do
|
|
@@ -420,9 +529,9 @@ use Rack::MonetaStore do
|
|
|
420
529
|
adapter :Cookie
|
|
421
530
|
end
|
|
422
531
|
|
|
423
|
-
run lambda
|
|
532
|
+
run lambda { |env|
|
|
424
533
|
env['rack.moneta_store'] # is a Moneta store without caching
|
|
425
|
-
|
|
534
|
+
}
|
|
426
535
|
~~~
|
|
427
536
|
|
|
428
537
|
#### REST server
|
|
@@ -474,7 +583,7 @@ to use all the transformers on the cookies (e.g. `:prefix`, `:marshal` and `:hma
|
|
|
474
583
|
require 'rack/moneta_cookies'
|
|
475
584
|
|
|
476
585
|
use Rack::MonetaCookies, :domain => 'example.com', :path => '/path'
|
|
477
|
-
run lambda
|
|
586
|
+
run lambda { |env|
|
|
478
587
|
req = Rack::Request.new(env)
|
|
479
588
|
req.cookies #=> is now a Moneta store!
|
|
480
589
|
env['rack.request.cookie_hash'] #=> is now a Moneta store!
|
|
@@ -482,7 +591,7 @@ run lambda do |env|
|
|
|
482
591
|
req.cookies['key'] = 'value' #=> sets 'key'
|
|
483
592
|
req.cookies.delete('key') #=> removes 'key'
|
|
484
593
|
[200, {}, []]
|
|
485
|
-
|
|
594
|
+
}
|
|
486
595
|
~~~
|
|
487
596
|
|
|
488
597
|
### Rails
|
|
@@ -588,6 +697,7 @@ on top of the different stores.
|
|
|
588
697
|
|
|
589
698
|
* [Horcrux](https://github.com/technoweenie/horcrux): Used at github, supports batch operations but only Memcached backend
|
|
590
699
|
* [ActiveSupport::Cache::Store](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html): The Rails cache store abstraction
|
|
700
|
+
* [Padrino::Cache::Store](http://www.padrinorb.com/api/Padrino/Cache/Store.html): The Padrino cache store abstraction
|
|
591
701
|
* [ToyStore](https://github.com/jnunemaker/toystore): ORM mapper for key/value stores
|
|
592
702
|
* [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
|
|
593
703
|
|
data/Rakefile
CHANGED
|
@@ -24,9 +24,18 @@ task :test do
|
|
|
24
24
|
# QuickLZ is also not maintained on Github, but on Bitbucket
|
|
25
25
|
# and I don't know where the issue tracker is.
|
|
26
26
|
#
|
|
27
|
-
# * Cassandra
|
|
27
|
+
# * Cassandra show spurious failures
|
|
28
|
+
#
|
|
29
|
+
# * action_dispatch cannot be required for an unknown reason
|
|
28
30
|
if ENV['TEST_GROUP']
|
|
29
|
-
|
|
31
|
+
# Shuffle specs to ensure equal distribution over the test groups
|
|
32
|
+
# We have to shuffle with the same seed every time because rake is started
|
|
33
|
+
# multiple times!
|
|
34
|
+
old_seed = srand(42)
|
|
35
|
+
specs.shuffle!
|
|
36
|
+
srand(old_seed)
|
|
37
|
+
|
|
38
|
+
unstable = specs.select {|s| s =~ /quicklz|cassandra|action_dispatch/ }
|
|
30
39
|
specs -= unstable
|
|
31
40
|
end
|
|
32
41
|
|
data/SPEC.md
CHANGED
|
@@ -43,12 +43,17 @@ Behaves the same as <code>[]=</code>, but allows the client to send additional o
|
|
|
43
43
|
### <code>increment(key[Object], amount[Integer] = 1, options[Hash] => {}) => Integer(value)</code>
|
|
44
44
|
|
|
45
45
|
Increments a value atomically. This method is not supported by all stores and might raise a <code>NotImplementedError</code>.
|
|
46
|
-
This method MUST accept negative
|
|
46
|
+
This method MUST accept negative amounts, but the result MUST be unsigned.
|
|
47
47
|
|
|
48
48
|
### <code>decrement(key[Object], amount[Integer] = 1, options[Hash] => {}) => Integer(value)</code>
|
|
49
49
|
|
|
50
50
|
Decrements a value atomically. This method is not supported by all stores and might raise a <code>NotImplementedError</code>.
|
|
51
|
-
This method MUST accept negative
|
|
51
|
+
This method MUST accept negative amounts, but the result MUST be unsigned.
|
|
52
|
+
|
|
53
|
+
### <code>create(key[Object], value[Object], options[Hash] => {}) => [TrueClass, FalseClass]</code>
|
|
54
|
+
|
|
55
|
+
Creates a value atomically. This method is not supported by all stores and might raise a <code>NotImplementedError</code>.
|
|
56
|
+
It MUST return true if the value was created.
|
|
52
57
|
|
|
53
58
|
### <code>clear(options[Hash] => {})</code>
|
|
54
59
|
|
data/lib/moneta.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Moneta
|
|
2
2
|
autoload :Builder, 'moneta/builder'
|
|
3
3
|
autoload :Cache, 'moneta/cache'
|
|
4
|
+
autoload :CreateSupport, 'moneta/mixins'
|
|
4
5
|
autoload :Defaults, 'moneta/mixins'
|
|
5
6
|
autoload :ExpiresSupport, 'moneta/mixins'
|
|
6
7
|
autoload :Expires, 'moneta/expires'
|
|
@@ -8,15 +9,20 @@ module Moneta
|
|
|
8
9
|
autoload :IncrementSupport, 'moneta/mixins'
|
|
9
10
|
autoload :Lock, 'moneta/lock'
|
|
10
11
|
autoload :Logger, 'moneta/logger'
|
|
12
|
+
autoload :Mutex, 'moneta/synchronize'
|
|
11
13
|
autoload :Net, 'moneta/mixins'
|
|
12
14
|
autoload :OptionMerger, 'moneta/optionmerger'
|
|
13
15
|
autoload :OptionSupport, 'moneta/mixins'
|
|
14
16
|
autoload :Pool, 'moneta/pool'
|
|
15
17
|
autoload :Proxy, 'moneta/proxy'
|
|
18
|
+
autoload :Semaphore, 'moneta/synchronize'
|
|
16
19
|
autoload :Server, 'moneta/server'
|
|
17
20
|
autoload :Shared, 'moneta/shared'
|
|
18
21
|
autoload :Stack, 'moneta/stack'
|
|
19
22
|
autoload :Transformer, 'moneta/transformer'
|
|
23
|
+
autoload :Utils, 'moneta/utils'
|
|
24
|
+
autoload :WeakCreate, 'moneta/weak'
|
|
25
|
+
autoload :WeakIncrement, 'moneta/weak'
|
|
20
26
|
autoload :Wrapper, 'moneta/wrapper'
|
|
21
27
|
|
|
22
28
|
module Adapters
|
|
@@ -63,7 +69,7 @@ module Moneta
|
|
|
63
69
|
# @param [Hash] options
|
|
64
70
|
# @return [Moneta store] newly created Moneta store
|
|
65
71
|
# @option options [Boolean/Integer] :expires Ensure that store supports expiration by inserting
|
|
66
|
-
#
|
|
72
|
+
# {Expires} if the underlying adapter doesn't support it natively
|
|
67
73
|
# and set default expiration time
|
|
68
74
|
# @option options [Boolean] :threadsafe (false) Ensure that the store is thread safe by inserting Moneta::Lock
|
|
69
75
|
# @option options [Boolean/Hash] :logger (false) Add logger to proxy stack (Hash is passed to logger as options)
|
|
@@ -6,7 +6,6 @@ module Moneta
|
|
|
6
6
|
# @api public
|
|
7
7
|
class ActiveRecord
|
|
8
8
|
include Defaults
|
|
9
|
-
include IncrementSupport
|
|
10
9
|
|
|
11
10
|
def self.tables
|
|
12
11
|
@tables ||= {}
|
|
@@ -26,7 +25,16 @@ module Moneta
|
|
|
26
25
|
c.primary_key = :k
|
|
27
26
|
c
|
|
28
27
|
end
|
|
29
|
-
|
|
28
|
+
|
|
29
|
+
if options[:connection]
|
|
30
|
+
begin
|
|
31
|
+
@table.establish_connection(options[:connection])
|
|
32
|
+
rescue
|
|
33
|
+
tries ||= 0
|
|
34
|
+
(tries += 1) < 3 ? retry : raise
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
unless @table.table_exists?
|
|
31
39
|
@table.connection.create_table(@table.table_name, :id => false) do |t|
|
|
32
40
|
# Do not use binary columns (Issue #17)
|
|
@@ -54,6 +62,9 @@ module Moneta
|
|
|
54
62
|
record.v = value
|
|
55
63
|
record.save
|
|
56
64
|
value
|
|
65
|
+
rescue
|
|
66
|
+
tries ||= 0
|
|
67
|
+
(tries += 1) < 10 ? retry : raise
|
|
57
68
|
end
|
|
58
69
|
|
|
59
70
|
# (see Proxy#delete)
|
|
@@ -67,12 +78,25 @@ module Moneta
|
|
|
67
78
|
# (see Proxy#increment)
|
|
68
79
|
def increment(key, amount = 1, options = {})
|
|
69
80
|
record = @table.where(:k => key).lock.first_or_initialize
|
|
70
|
-
value =
|
|
81
|
+
value = Utils.to_int(record.v) + amount
|
|
71
82
|
record.v = value.to_s
|
|
72
83
|
record.save
|
|
73
84
|
value
|
|
74
85
|
end
|
|
75
86
|
|
|
87
|
+
# (see Proxy#create)
|
|
88
|
+
def create(key, value, options = {})
|
|
89
|
+
record = @table.new
|
|
90
|
+
record.k = key
|
|
91
|
+
record.v = value
|
|
92
|
+
record.save
|
|
93
|
+
true
|
|
94
|
+
rescue
|
|
95
|
+
# FIXME: This catches too many errors
|
|
96
|
+
# it should only catch a not-unique-exception
|
|
97
|
+
false
|
|
98
|
+
end
|
|
99
|
+
|
|
76
100
|
# (see Proxy#clear)
|
|
77
101
|
def clear(options = {})
|
|
78
102
|
@table.delete_all
|