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