moneta 0.7.17 → 0.7.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +15 -9
- data/CHANGES +12 -1
- data/CONTRIBUTORS +2 -2
- data/Gemfile +3 -0
- data/README.md +30 -5
- data/Rakefile +1 -1
- data/lib/active_support/cache/moneta_store.rb +5 -2
- data/lib/moneta/adapters/couch.rb +63 -5
- data/lib/moneta/adapters/file.rb +29 -12
- data/lib/moneta/adapters/fog.rb +1 -0
- data/lib/moneta/adapters/mongo.rb +74 -22
- data/lib/moneta/adapters/sqlite.rb +6 -5
- data/lib/moneta/pool.rb +28 -5
- data/lib/moneta/transformer/config.rb +37 -34
- data/lib/moneta/version.rb +1 -1
- data/script/contributors +7 -0
- data/script/generate-specs +89 -30
- data/script/install-bundle +1 -1
- data/script/start-services +6 -12
- data/script/wait-services +15 -0
- data/spec/active_support/cache_moneta_store_spec.rb +3 -3
- data/spec/moneta/adapter_couch_spec.rb +14 -6
- data/spec/moneta/adapter_memory_spec.rb +29 -0
- data/spec/moneta/adapter_mongo_spec.rb +7 -0
- data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +7 -0
- data/spec/moneta/adapter_pstore_spec.rb +42 -0
- data/spec/moneta/expires_file_spec.rb +4 -0
- data/spec/moneta/expires_memory_spec.rb +29 -0
- data/spec/moneta/expires_memory_with_default_expires_spec.rb +29 -0
- data/spec/moneta/lock_spec.rb +29 -0
- data/spec/moneta/null_adapter_spec.rb +13 -0
- data/spec/moneta/proxy_expires_memory_spec.rb +29 -0
- data/spec/moneta/simple_activerecord_spec.rb +42 -0
- data/spec/moneta/simple_activerecord_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_cassandra_spec.rb +42 -0
- data/spec/moneta/simple_client_tcp_spec.rb +42 -0
- data/spec/moneta/simple_client_unix_spec.rb +42 -0
- data/spec/moneta/simple_couch_spec.rb +45 -2
- data/spec/moneta/simple_couch_with_expires_spec.rb +46 -2
- data/spec/moneta/simple_datamapper_spec.rb +42 -0
- data/spec/moneta/simple_datamapper_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_datamapper_with_repository_spec.rb +42 -0
- data/spec/moneta/simple_daybreak_spec.rb +42 -0
- data/spec/moneta/simple_daybreak_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_dbm_spec.rb +42 -0
- data/spec/moneta/simple_dbm_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_file_spec.rb +42 -0
- data/spec/moneta/simple_file_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_fog_spec.rb +42 -0
- data/spec/moneta/simple_fog_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_gdbm_spec.rb +42 -0
- data/spec/moneta/simple_gdbm_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_hashfile_spec.rb +42 -0
- data/spec/moneta/simple_hashfile_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_hbase_spec.rb +42 -0
- data/spec/moneta/simple_hbase_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_kyotocabinet_spec.rb +42 -0
- data/spec/moneta/simple_kyotocabinet_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_leveldb_spec.rb +42 -0
- data/spec/moneta/simple_leveldb_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_localmemcache_spec.rb +42 -0
- data/spec/moneta/simple_localmemcache_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_lruhash_spec.rb +29 -0
- data/spec/moneta/simple_lruhash_with_expires_spec.rb +29 -0
- data/spec/moneta/simple_memcached_dalli_spec.rb +42 -0
- data/spec/moneta/simple_memcached_native_spec.rb +42 -0
- data/spec/moneta/simple_memcached_spec.rb +42 -0
- data/spec/moneta/simple_memory_spec.rb +29 -0
- data/spec/moneta/simple_memory_with_compress_spec.rb +29 -0
- data/spec/moneta/simple_memory_with_expires_spec.rb +29 -0
- data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +6 -0
- data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +8 -0
- data/spec/moneta/simple_memory_with_prefix_spec.rb +29 -0
- data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +29 -0
- data/spec/moneta/simple_mongo_spec.rb +42 -0
- data/spec/moneta/simple_null_spec.rb +16 -0
- data/spec/moneta/simple_pstore_spec.rb +42 -0
- data/spec/moneta/simple_pstore_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_redis_spec.rb +42 -0
- data/spec/moneta/simple_restclient_spec.rb +42 -0
- data/spec/moneta/simple_riak_spec.rb +42 -0
- data/spec/moneta/simple_riak_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_sdbm_spec.rb +42 -0
- data/spec/moneta/simple_sdbm_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_sequel_spec.rb +42 -0
- data/spec/moneta/simple_sequel_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_sqlite_spec.rb +42 -0
- data/spec/moneta/simple_sqlite_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_tdb_spec.rb +42 -0
- data/spec/moneta/simple_tdb_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_tokyocabinet_spec.rb +42 -0
- data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_tokyotyrant_spec.rb +42 -0
- data/spec/moneta/simple_tokyotyrant_with_expires_spec.rb +42 -0
- data/spec/moneta/simple_yaml_spec.rb +42 -0
- data/spec/moneta/simple_yaml_with_expires_spec.rb +42 -0
- data/spec/moneta/transformer_bzip2_spec.rb +3 -0
- data/spec/moneta/transformer_key_inspect_spec.rb +6 -0
- data/spec/moneta/transformer_key_marshal_spec.rb +29 -0
- data/spec/moneta/transformer_key_to_s_spec.rb +6 -0
- data/spec/moneta/transformer_key_yaml_spec.rb +29 -0
- data/spec/moneta/transformer_lz4_spec.rb +3 -0
- data/spec/moneta/transformer_lzma_spec.rb +3 -0
- data/spec/moneta/transformer_lzo_spec.rb +3 -0
- data/spec/moneta/transformer_marshal_base64_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_city128_spec.rb +152 -0
- data/spec/moneta/transformer_marshal_city32_spec.rb +152 -0
- data/spec/moneta/transformer_marshal_city64_spec.rb +152 -0
- data/spec/moneta/transformer_marshal_escape_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_hmac_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_md5_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_md5_spread_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_prefix_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_qp_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_rmd160_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_sha1_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_sha256_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_sha384_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_sha512_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_truncate_spec.rb +29 -0
- data/spec/moneta/transformer_marshal_uuencode_spec.rb +29 -0
- data/spec/moneta/transformer_ox_spec.rb +29 -0
- data/spec/moneta/transformer_quicklz_spec.rb +3 -0
- data/spec/moneta/transformer_snappy_spec.rb +3 -0
- data/spec/moneta/transformer_value_marshal_spec.rb +29 -0
- data/spec/moneta/transformer_value_yaml_spec.rb +29 -0
- data/spec/moneta/transformer_yaml_spec.rb +29 -0
- data/spec/moneta/transformer_zlib_spec.rb +3 -0
- data/spec/moneta/weak_create_spec.rb +2 -1
- data/spec/moneta/weak_increment_spec.rb +2 -1
- data/spec/monetaspecs.rb +29879 -6167
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40e5bf4f97796468cef521c2b103f72d7be29811
|
4
|
+
data.tar.gz: d9ab4368e38146049f4e92a0cf2337b2148fcf10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fadbaee29f91f2259b44cf7140d64e3ab12196ee2e29c6c9ccc5db2518b0a06a4db0d81f654e7625dceaa3ead6a7636aeb2240d9cff0bd17161b2f1865a6f19
|
7
|
+
data.tar.gz: f1751faff2cef9302fa0b3125e421e6632fa580978ab548fb13afd53f7dc37fe0e586821a657b3c79298a44b9ba66ccf68edacbf6efcc89e3b134176dfa2b7c9
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -5,15 +5,16 @@ rvm:
|
|
5
5
|
- 1.8.7
|
6
6
|
- jruby-19mode
|
7
7
|
- jruby-18mode
|
8
|
-
|
9
|
-
|
8
|
+
- rbx-19mode
|
9
|
+
- rbx-18mode
|
10
10
|
before_install:
|
11
11
|
- script/kill-travis
|
12
12
|
#- script/install-kyotocabinet
|
13
|
-
- sudo apt-get install -qq libtokyocabinet8 libtokyocabinet-dev liblzo2-dev libtdb-dev tokyotyrant
|
13
|
+
- sudo apt-get install -qq libtokyocabinet8 libtokyocabinet-dev liblzo2-dev libtdb-dev libleveldb-dev tokyotyrant
|
14
14
|
- script/start-services
|
15
15
|
- script/install-bundle
|
16
16
|
- script/upload-bundle
|
17
|
+
- script/wait-services
|
17
18
|
install: 'echo "Bundle installed"'
|
18
19
|
before_script:
|
19
20
|
- mysql -e 'create database moneta;'
|
@@ -21,13 +22,18 @@ before_script:
|
|
21
22
|
- mysql -e 'create database moneta_activerecord2;'
|
22
23
|
env:
|
23
24
|
global:
|
24
|
-
- secure: "
|
25
|
+
- secure: "dtM4n7FP8P0UI9Iq+nsvQ7/yfDqsxhfCO9i8zMxm/f9Kxj5Z/4C7jsXsLA+e\n/7FZ9+ld2QjPSPU0LUiDpj/z81bxyZHwqocQ7Nb0DVvO3JRHpr4/iBQQQHd3\n0jvou3mRbu5mBlUjf1/ALaZA+b+vcnsF9fd86UnkY+ChriylGnM="
|
25
26
|
matrix:
|
26
|
-
- "TASK=test TEST_GROUP=1/
|
27
|
-
- "TASK=test TEST_GROUP=2/
|
28
|
-
- "TASK=test TEST_GROUP=3/
|
29
|
-
- "TASK=test TEST_GROUP=4/
|
30
|
-
- "TASK=test TEST_GROUP=5/
|
27
|
+
- "TASK=test TEST_GROUP=1/10"
|
28
|
+
- "TASK=test TEST_GROUP=2/10"
|
29
|
+
- "TASK=test TEST_GROUP=3/10"
|
30
|
+
- "TASK=test TEST_GROUP=4/10"
|
31
|
+
- "TASK=test TEST_GROUP=5/10"
|
32
|
+
- "TASK=test TEST_GROUP=6/10"
|
33
|
+
- "TASK=test TEST_GROUP=7/10"
|
34
|
+
- "TASK=test TEST_GROUP=8/10"
|
35
|
+
- "TASK=test TEST_GROUP=9/10"
|
36
|
+
- "TASK=test TEST_GROUP=10/10"
|
31
37
|
- "TASK=test TEST_GROUP=unstable"
|
32
38
|
- "TASK=benchmarks CONFIG=uniform_small"
|
33
39
|
- "TASK=benchmarks CONFIG=uniform_medium"
|
data/CHANGES
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
-
|
1
|
+
0.7.18
|
2
|
+
|
3
|
+
* Adapters::File#increment and #create fixed on JRuby
|
4
|
+
* Adapters::Couch and Adapters::Mongo can store hashes directly as documents.
|
5
|
+
It is not necessary to serialize values as strings anymore.
|
6
|
+
* Adapters::Couch#create added
|
7
|
+
* Pool thread safety improved
|
8
|
+
* Transformer: Add CityHash
|
9
|
+
|
10
|
+
0.7.17
|
11
|
+
|
12
|
+
* Transformer: LZ4 compression added
|
2
13
|
|
3
14
|
0.7.16
|
4
15
|
|
data/CONTRIBUTORS
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
Adrian Madrid <aemadrid@gmail.com>
|
2
2
|
Alejandro Crosa <acrosa@sharing.local>
|
3
3
|
Anthony Eden <anthonyeden@gmail.com>
|
4
|
-
Hendrik Beskow <hendrik-github@beskow.de>
|
5
4
|
Benjamin Yu <benjaminlyu@gmail.com>
|
6
5
|
Ben Schwarz <ben.schwarz@gmail.com>
|
7
6
|
Daniel Mendler <mail@daniel-mendler.de>
|
@@ -9,7 +8,7 @@ Derek Kastner <dkastner@gmail.com>
|
|
9
8
|
Dylan Egan <me@dylanegan.com>
|
10
9
|
Hampton Catlin <hcatlin@gmail.com>
|
11
10
|
Hannes Georg <hannes.georg@googlemail.com>
|
12
|
-
|
11
|
+
Hendrik Beskow <hendrik-github@beskow.de>
|
13
12
|
Jari Bakken <jari.bakken@gmail.com>
|
14
13
|
Jeremy Voorhis <jvoorhis@gmail.com>
|
15
14
|
Jon Crosby <jon@joncrosby.me>
|
@@ -17,6 +16,7 @@ lakshan <lakshan@web2media.net>
|
|
17
16
|
Piotr Murach <pmurach@gmail.com>
|
18
17
|
Potapov Sergey <blake131313@gmail.com>
|
19
18
|
Quin Hoxie <quin@aboutus.org>
|
19
|
+
Scott Wadden <scott.wadden@gmail.com>
|
20
20
|
Tom Meier <ozmeier@yahoo.co.uk>
|
21
21
|
Xavier Shay <xavier@rhnh.net>
|
22
22
|
Yehuda Katz <wycats@gmail.com>
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/moneta.png)](http://rubygems.org/gems/moneta) [![Build Status](https://secure.travis-ci.org/minad/moneta.png?branch=master)](http://travis-ci.org/minad/moneta) [![Dependency Status](https://gemnasium.com/minad/moneta.png?travis)](https://gemnasium.com/minad/moneta) [![Code Climate](https://codeclimate.com/github/minad/moneta.png)](https://codeclimate.com/github/minad/moneta)
|
4
4
|
|
5
|
-
Moneta provides a standard interface for interacting with various kinds of key/value stores.
|
5
|
+
Moneta provides a standard interface for interacting with various kinds of key/value stores. Moneta supports the well-known
|
6
|
+
NoSQL and document based stores.
|
7
|
+
|
8
|
+
A short overview of the features:
|
6
9
|
|
7
10
|
* Supports a lot of backends with consistent behaviour (See below)
|
8
11
|
* Allows a full configuration of the serialization -> compression -> adapter stack using proxies (Similar to [Rack middlewares](http://rack.github.com/))
|
@@ -170,14 +173,14 @@ __NOTE:__ <a name="backend-matrix">The backend matrix</a> is much more readable
|
|
170
173
|
|
171
174
|
<tr><td>DataMapper</td><td>dm-core, dm-migrations</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://datamapper.org/">DataMapper</a> ORM</td></tr>
|
172
175
|
|
176
|
+
<tr><td>Couch</td><td>faraday, multi_json</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://couchdb.apache.org/">CouchDB</a> database</td></tr>
|
177
|
+
|
173
178
|
<tr><td>HBase</td><td>hbaserb</td><td style="text-align:center;background:#55F">?</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://hbase.apache.org/">HBase</a> database</td></tr>
|
174
179
|
|
175
180
|
<tr><td>Cassandra</td><td>cassandra</td><td style="text-align:center;background:#55F">?</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://cassandra.apache.org/">Cassandra</a> distributed database</td></tr>
|
176
181
|
|
177
182
|
<tr><td>LocalMemCache</td><td>localmemcache</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://localmemcache.rubyforge.org/">LocalMemCache</a> database</td></tr>
|
178
183
|
|
179
|
-
<tr><td>Couch</td><td>faraday, multi_json</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://couchdb.apache.org/">CouchDB</a> database</td></tr>
|
180
|
-
|
181
184
|
<tr><td>Fog</td><td>fog</td><td style="text-align:center;background:#55F">?</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://fog.io/">Fog</a> cloud store</td></tr>
|
182
185
|
|
183
186
|
<tr><td>Riak</td><td>riak-client</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#5F5">✓</td><td><a href="http://docs.basho.com/">Riak</a> database</td></tr>
|
@@ -258,7 +261,7 @@ Supported value compressors:
|
|
258
261
|
|
259
262
|
Special transformers:
|
260
263
|
|
261
|
-
* Digests (MD5, Shas, ...)
|
264
|
+
* Digests (MD5, Shas, CityHash, ...)
|
262
265
|
* Add prefix to keys (`:prefix`)
|
263
266
|
* HMAC to verify values (`:hmac`, useful for `Rack::MonetaCookies`)
|
264
267
|
|
@@ -312,10 +315,16 @@ Moneta does not support iteration or partial matches.
|
|
312
315
|
|
313
316
|
### Creating a Store
|
314
317
|
|
315
|
-
There is a simple interface to create a store using `Moneta.new
|
318
|
+
There is a simple interface to create a store using `Moneta.new`. You will
|
319
|
+
get automatic key and value serialization which is provided by `Moneta::Transformer`.
|
320
|
+
This allows you to store arbitrary Ruby objects. You can tune some options
|
321
|
+
when you call `Moneta.new`. However for very fine tuning use `Moneta.build`.
|
316
322
|
|
317
323
|
~~~ ruby
|
318
324
|
store = Moneta.new(:Memcached, :server => 'localhost:11211')
|
325
|
+
store['key'] = 'value'
|
326
|
+
store['hash_key'] = {:a => 1, :b => 2}
|
327
|
+
store['object_key'] = MarshallableRubyObject.new
|
319
328
|
~~~
|
320
329
|
|
321
330
|
If you want to have control over the proxies, you have to use `Moneta.build`:
|
@@ -335,6 +344,22 @@ store = Moneta.build do
|
|
335
344
|
end
|
336
345
|
~~~
|
337
346
|
|
347
|
+
You can also directly access the underlying adapters if you don't want
|
348
|
+
to use the Moneta stack.
|
349
|
+
|
350
|
+
~~~ ruby
|
351
|
+
db = Moneta::Adapters::File.new(:dir => 'directory')
|
352
|
+
db['key'] = {:a => 1, :b => 2} # This will fail since you can only store Strings
|
353
|
+
|
354
|
+
# However for Mongo and Couch this works
|
355
|
+
# The hash will be mapped directly to a Mongo/Couch document.
|
356
|
+
db = Moneta::Adapters::Couch.new
|
357
|
+
db['key'] = {:a => 1, :b => 2}
|
358
|
+
|
359
|
+
db = Moneta::Adapters::Mongo.new
|
360
|
+
db['key'] = {:a => 1, :b => 2}
|
361
|
+
~~~
|
362
|
+
|
338
363
|
### Expiration
|
339
364
|
|
340
365
|
The Cassandra, Memcached, Redis and Mongo backends support expiration natively.
|
data/Rakefile
CHANGED
@@ -10,18 +10,21 @@ module ActiveSupport
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def increment(key, amount = 1, options = nil)
|
13
|
+
options = merged_options(options)
|
13
14
|
instrument(:increment, key, :amount => amount) do
|
14
|
-
@store.increment(key, amount, moneta_options(options))
|
15
|
+
@store.increment(namespaced_key(key, options), amount, moneta_options(options))
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
19
|
def decrement(key, amount = 1, options = nil)
|
20
|
+
options = merged_options(options)
|
19
21
|
instrument(:decrement, key, :amount => amount) do
|
20
|
-
@store.increment(key, -amount, moneta_options(options))
|
22
|
+
@store.increment(namespaced_key(key, options), -amount, moneta_options(options))
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
def clear(options = nil)
|
27
|
+
options = merged_options(options)
|
25
28
|
instrument(:clear, nil, nil) do
|
26
29
|
@store.clear(moneta_options(options))
|
27
30
|
end
|
@@ -4,18 +4,31 @@ require 'multi_json'
|
|
4
4
|
module Moneta
|
5
5
|
module Adapters
|
6
6
|
# CouchDB backend
|
7
|
+
#
|
8
|
+
# You can store hashes directly using this adapter.
|
9
|
+
#
|
10
|
+
# @example Store hashes
|
11
|
+
# db = Moneta::Adapters::Mongo.new
|
12
|
+
# db['key'] = {a: 1, b: 2}
|
13
|
+
#
|
7
14
|
# @api public
|
8
15
|
class Couch
|
9
16
|
include Defaults
|
10
17
|
|
11
18
|
attr_reader :backend
|
12
19
|
|
20
|
+
supports :create
|
21
|
+
|
13
22
|
# @param [Hash] options
|
14
23
|
# @option options [String] :host ('127.0.0.1') Couch host
|
15
24
|
# @option options [String] :port (5984) Couch port
|
16
25
|
# @option options [String] :db ('moneta') Couch database
|
26
|
+
# @option options [String] :value_field ('value') Document field to store value
|
27
|
+
# @option options [String] :type_field ('type') Document field to store value type
|
17
28
|
# @option options [Faraday connection] :backend Use existing backend instance
|
18
29
|
def initialize(options = {})
|
30
|
+
@value_field = options[:value_field] || 'value'
|
31
|
+
@type_field = options[:type_field] || 'type'
|
19
32
|
url = "http://#{options[:host] || '127.0.0.1'}:#{options[:port] || 5984}/#{options[:db] || 'moneta'}"
|
20
33
|
@backend = options[:backend] || ::Faraday.new(:url => url)
|
21
34
|
create_db
|
@@ -29,15 +42,14 @@ module Moneta
|
|
29
42
|
# (see Proxy#load)
|
30
43
|
def load(key, options = {})
|
31
44
|
response = @backend.get(key)
|
32
|
-
response.status == 200 ?
|
45
|
+
response.status == 200 ? body_to_value(response.body) : nil
|
33
46
|
end
|
34
47
|
|
35
48
|
# (see Proxy#store)
|
36
49
|
def store(key, value, options = {})
|
37
50
|
response = @backend.head(key)
|
38
|
-
|
39
|
-
|
40
|
-
response = @backend.put(key, MultiJson.dump(doc), 'Content-Type' => 'application/json')
|
51
|
+
body = value_to_body(value, response.status == 200 && response['etag'][1..-2])
|
52
|
+
response = @backend.put(key, body, 'Content-Type' => 'application/json')
|
41
53
|
raise "HTTP error #{response.status}" unless response.status == 201
|
42
54
|
value
|
43
55
|
rescue
|
@@ -49,7 +61,7 @@ module Moneta
|
|
49
61
|
def delete(key, options = {})
|
50
62
|
response = @backend.get(key)
|
51
63
|
if response.status == 200
|
52
|
-
value =
|
64
|
+
value = body_to_value(response.body)
|
53
65
|
response = @backend.delete("#{key}?rev=#{response['etag'][1..-2]}")
|
54
66
|
raise "HTTP error #{response.status}" unless response.status == 200
|
55
67
|
value
|
@@ -66,8 +78,54 @@ module Moneta
|
|
66
78
|
self
|
67
79
|
end
|
68
80
|
|
81
|
+
# (see Proxy#create)
|
82
|
+
def create(key, value, options = {})
|
83
|
+
body = value_to_body(value, nil)
|
84
|
+
response = @backend.put(key, body, 'Content-Type' => 'application/json')
|
85
|
+
case response.status
|
86
|
+
when 201
|
87
|
+
true
|
88
|
+
when 409
|
89
|
+
false
|
90
|
+
else
|
91
|
+
raise "HTTP error #{response.status}"
|
92
|
+
end
|
93
|
+
rescue
|
94
|
+
tries ||= 0
|
95
|
+
(tries += 1) < 10 ? retry : raise
|
96
|
+
end
|
97
|
+
|
69
98
|
private
|
70
99
|
|
100
|
+
def body_to_value(body)
|
101
|
+
doc = MultiJson.load(body)
|
102
|
+
case doc[@type_field]
|
103
|
+
when 'Hash'
|
104
|
+
doc = doc.dup
|
105
|
+
doc.delete('_id')
|
106
|
+
doc.delete('_rev')
|
107
|
+
doc.delete(@type_field)
|
108
|
+
doc
|
109
|
+
else
|
110
|
+
doc[@value_field]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def value_to_body(value, rev)
|
115
|
+
case value
|
116
|
+
when Hash
|
117
|
+
doc = value.merge(@type_field => 'Hash')
|
118
|
+
when String
|
119
|
+
doc = { @value_field => value, @type_field => 'String' }
|
120
|
+
when Float, Fixnum
|
121
|
+
doc = { @value_field => value, @type_field => 'Number' }
|
122
|
+
else
|
123
|
+
raise ArgumentError, "Invalid value type: #{value.class}"
|
124
|
+
end
|
125
|
+
doc['_rev'] = rev if rev
|
126
|
+
MultiJson.dump(doc)
|
127
|
+
end
|
128
|
+
|
71
129
|
def create_db
|
72
130
|
response = @backend.put '', ''
|
73
131
|
raise "HTTP error #{response.status}" unless response.status == 201 || response.status == 412
|
data/lib/moneta/adapters/file.rb
CHANGED
@@ -66,24 +66,41 @@ module Moneta
|
|
66
66
|
FileUtils.mkpath(::File.dirname(path))
|
67
67
|
::File.open(path, ::File::RDWR | ::File::CREAT) do |f|
|
68
68
|
Thread.pass until f.flock(::File::LOCK_EX)
|
69
|
-
content =
|
69
|
+
content = f.read
|
70
70
|
amount += Utils.to_int(content) unless content.empty?
|
71
|
-
|
71
|
+
content = amount.to_s
|
72
|
+
f.pos = 0
|
73
|
+
f.write(content)
|
74
|
+
f.truncate(content.bytesize)
|
72
75
|
amount
|
73
76
|
end
|
74
77
|
end
|
75
78
|
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
# HACK: The implementation using File::EXCL is not atomic under JRuby 1.7.4
|
80
|
+
# See https://github.com/jruby/jruby/issues/827
|
81
|
+
if defined?(JRUBY_VERSION)
|
82
|
+
# (see Proxy#create)
|
83
|
+
def create(key, value, options = {})
|
84
|
+
path = store_path(key)
|
85
|
+
FileUtils.mkpath(::File.dirname(path))
|
86
|
+
# Call native java.io.File#createNewFile
|
87
|
+
return false unless ::Java::JavaIo::File.new(path).createNewFile
|
88
|
+
::File.open(path, 'wb+') {|f| f.write(value) }
|
89
|
+
true
|
90
|
+
end
|
91
|
+
else
|
92
|
+
# (see Proxy#create)
|
93
|
+
def create(key, value, options = {})
|
94
|
+
path = store_path(key)
|
95
|
+
FileUtils.mkpath(::File.dirname(path))
|
96
|
+
::File.open(path, ::File::WRONLY | ::File::CREAT | ::File::EXCL) do |f|
|
97
|
+
f.binmode
|
98
|
+
f.write(value)
|
99
|
+
end
|
100
|
+
true
|
101
|
+
rescue Errno::EEXIST
|
102
|
+
false
|
83
103
|
end
|
84
|
-
true
|
85
|
-
rescue Errno::EEXIST
|
86
|
-
false
|
87
104
|
end
|
88
105
|
|
89
106
|
protected
|
data/lib/moneta/adapters/fog.rb
CHANGED
@@ -7,6 +7,12 @@ module Moneta
|
|
7
7
|
# Supports expiration, documents will be automatically removed starting
|
8
8
|
# with mongodb >= 2.2 (see {http://docs.mongodb.org/manual/tutorial/expire-data/}).
|
9
9
|
#
|
10
|
+
# You can store hashes directly using this adapter.
|
11
|
+
#
|
12
|
+
# @example Store hashes
|
13
|
+
# db = Moneta::Adapters::Mongo.new
|
14
|
+
# db['key'] = {a: 1, b: 2}
|
15
|
+
#
|
10
16
|
# @api public
|
11
17
|
class Mongo
|
12
18
|
include Defaults
|
@@ -23,11 +29,18 @@ module Moneta
|
|
23
29
|
# @option options [Integer] :port (MongoDB default port) MongoDB server port
|
24
30
|
# @option options [String] :db ('moneta') MongoDB database
|
25
31
|
# @option options [Integer] :expires Default expiration time
|
32
|
+
# @option options [String] :expires_field ('expiresAt') Document field to store expiration time
|
33
|
+
# @option options [String] :value_field ('value') Document field to store value
|
34
|
+
# @option options [String] :type_field ('type') Document field to store value type
|
26
35
|
# @option options [::Mongo::MongoClient] :backend Use existing backend instance
|
36
|
+
# @option options Other options passed to `Mongo::MongoClient#new`
|
27
37
|
def initialize(options = {})
|
28
38
|
self.default_expires = options.delete(:expires)
|
29
39
|
collection = options.delete(:collection) || 'moneta'
|
30
40
|
db = options.delete(:db) || 'moneta'
|
41
|
+
@expires_field = options.delete(:expires_field) || 'expiresAt'
|
42
|
+
@value_field = options.delete(:value_field) || 'value'
|
43
|
+
@type_field = options.delete(:type_field) || 'type'
|
31
44
|
@backend = options[:backend] ||
|
32
45
|
begin
|
33
46
|
host = options.delete(:host) || '127.0.0.1'
|
@@ -40,7 +53,7 @@ module Moneta
|
|
40
53
|
db.authenticate(user, password, true) if user && password
|
41
54
|
@collection = db.collection(collection)
|
42
55
|
if @backend.server_version >= '2.2'
|
43
|
-
@collection.ensure_index([[
|
56
|
+
@collection.ensure_index([[@expires_field, ::Mongo::ASCENDING]], :expireAfterSeconds => 0)
|
44
57
|
else
|
45
58
|
warn 'Moneta::Adapters::Mongo - You are using MongoDB version < 2.2, expired documents will not be deleted'
|
46
59
|
end
|
@@ -48,26 +61,22 @@ module Moneta
|
|
48
61
|
|
49
62
|
# (see Proxy#load)
|
50
63
|
def load(key, options = {})
|
51
|
-
key =
|
64
|
+
key = to_binary(key)
|
52
65
|
doc = @collection.find_one('_id' => key)
|
53
|
-
if doc && (!doc[
|
66
|
+
if doc && (!doc[@expires_field] || doc[@expires_field] >= Time.now)
|
54
67
|
expires = expires_at(options, nil)
|
55
68
|
@collection.update({ '_id' => key },
|
56
|
-
#
|
57
|
-
{ '$set' => {
|
58
|
-
doc
|
69
|
+
# @expires_field must be a Time object (BSON date datatype)
|
70
|
+
{ '$set' => { @expires_field => expires || nil } }) if expires != nil
|
71
|
+
doc_to_value(doc)
|
59
72
|
end
|
60
73
|
end
|
61
74
|
|
62
75
|
# (see Proxy#store)
|
63
76
|
def store(key, value, options = {})
|
64
|
-
key =
|
65
|
-
intvalue = value.to_i
|
77
|
+
key = to_binary(key)
|
66
78
|
@collection.update({ '_id' => key },
|
67
|
-
|
68
|
-
'value' => intvalue.to_s == value ? intvalue : ::BSON::Binary.new(value),
|
69
|
-
# expiresAt must be a Time object (BSON date datatype)
|
70
|
-
'expiresAt' => expires_at(options) || nil },
|
79
|
+
value_to_doc(key, value, options),
|
71
80
|
{ :upsert => true })
|
72
81
|
value
|
73
82
|
end
|
@@ -75,26 +84,22 @@ module Moneta
|
|
75
84
|
# (see Proxy#delete)
|
76
85
|
def delete(key, options = {})
|
77
86
|
value = load(key, options)
|
78
|
-
@collection.remove('_id' =>
|
87
|
+
@collection.remove('_id' => to_binary(key)) if value
|
79
88
|
value
|
80
89
|
end
|
81
90
|
|
82
91
|
# (see Proxy#increment)
|
83
92
|
def increment(key, amount = 1, options = {})
|
84
|
-
@collection.find_and_modify(:query => { '_id' =>
|
85
|
-
:update => { '$inc' => {
|
93
|
+
@collection.find_and_modify(:query => { '_id' => to_binary(key) },
|
94
|
+
:update => { '$inc' => { @value_field => amount } },
|
86
95
|
:new => true,
|
87
|
-
:upsert => true)[
|
96
|
+
:upsert => true)[@value_field]
|
88
97
|
end
|
89
98
|
|
90
99
|
# (see Proxy#create)
|
91
100
|
def create(key, value, options = {})
|
92
|
-
key =
|
93
|
-
|
94
|
-
@collection.insert('_id' => key,
|
95
|
-
'value' => intvalue.to_s == value ? intvalue : ::BSON::Binary.new(value),
|
96
|
-
# expiresAt must be a Time object (BSON date datatype)
|
97
|
-
'expiresAt' => expires_at(options) || nil)
|
101
|
+
key = to_binary(key)
|
102
|
+
@collection.insert(value_to_doc(key, value, options))
|
98
103
|
true
|
99
104
|
rescue ::Mongo::OperationFailure
|
100
105
|
# FIXME: This catches too many errors
|
@@ -113,6 +118,53 @@ module Moneta
|
|
113
118
|
@backend.close
|
114
119
|
nil
|
115
120
|
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def doc_to_value(doc)
|
125
|
+
case doc[@type_field]
|
126
|
+
when 'Hash'
|
127
|
+
doc = doc.dup
|
128
|
+
doc.delete('_id')
|
129
|
+
doc.delete(@type_field)
|
130
|
+
doc.delete(@expires_field)
|
131
|
+
doc
|
132
|
+
when 'Number'
|
133
|
+
doc[@value_field]
|
134
|
+
else
|
135
|
+
doc[@value_field].to_s
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def value_to_doc(key, value, options)
|
140
|
+
case value
|
141
|
+
when Hash
|
142
|
+
value.merge('_id' => key,
|
143
|
+
@type_field => 'Hash',
|
144
|
+
# @expires_field must be a Time object (BSON date datatype)
|
145
|
+
@expires_field => expires_at(options) || nil)
|
146
|
+
when Float, Fixnum
|
147
|
+
{ '_id' => key,
|
148
|
+
@type_field => 'Number',
|
149
|
+
@value_field => value,
|
150
|
+
# @expires_field must be a Time object (BSON date datatype)
|
151
|
+
@expires_field => expires_at(options) || nil }
|
152
|
+
when String
|
153
|
+
intvalue = value.to_i
|
154
|
+
{ '_id' => key,
|
155
|
+
@type_field => 'String',
|
156
|
+
@value_field => intvalue.to_s == value ? intvalue : to_binary(value),
|
157
|
+
# @expires_field must be a Time object (BSON date datatype)
|
158
|
+
@expires_field => expires_at(options) || nil }
|
159
|
+
else
|
160
|
+
raise ArgumentError, "Invalid value type: #{value.class}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def to_binary(s)
|
165
|
+
s = s.dup if s.frozen? # HACK: BSON::Binary needs unfrozen string
|
166
|
+
::BSON::Binary.new(s)
|
167
|
+
end
|
116
168
|
end
|
117
169
|
end
|
118
170
|
end
|