moneta 1.2.1 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +1 -1
- data/.travis.yml +10 -4
- data/CHANGES +9 -0
- data/Gemfile +7 -5
- data/README.md +9 -6
- data/feature_matrix.yaml +2 -1
- data/lib/moneta/adapters/client.rb +56 -19
- data/lib/moneta/adapters/couch.rb +5 -0
- data/lib/moneta/adapters/mongo/moped.rb +4 -1
- data/lib/moneta/builder.rb +2 -2
- data/lib/moneta/lock.rb +6 -1
- data/lib/moneta/pool.rb +12 -0
- data/lib/moneta/proxy.rb +1 -1
- data/lib/moneta/server.rb +215 -61
- data/lib/moneta/shared.rb +13 -7
- data/lib/moneta/transformer.rb +50 -8
- data/lib/moneta/transformer/config.rb +59 -40
- data/lib/moneta/version.rb +1 -1
- data/moneta.gemspec +2 -2
- data/script/benchmarks +6 -1
- data/script/contributors +1 -2
- data/script/start-couchdb +27 -0
- data/script/start-hbase +2 -2
- data/script/start-services +3 -3
- data/spec/features/store.rb +3 -3
- data/spec/features/transform_value.rb +27 -21
- data/spec/helper.rb +52 -53
- data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +1 -1
- data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/cassandra/standard_cassandra_spec.rb +1 -1
- data/spec/moneta/adapters/client/adapter_client_spec.rb +6 -6
- data/spec/moneta/adapters/client/client_helper.rb +24 -0
- data/spec/moneta/adapters/client/standard_client_tcp_spec.rb +8 -8
- data/spec/moneta/adapters/client/standard_client_unix_spec.rb +23 -7
- data/spec/moneta/adapters/couch/adapter_couch_spec.rb +1 -1
- data/spec/moneta/adapters/couch/standard_couch_spec.rb +2 -2
- data/spec/moneta/adapters/couch/standard_couch_with_expires_spec.rb +2 -2
- data/spec/moneta/adapters/daybreak/standard_daybreak_spec.rb +1 -1
- data/spec/moneta/adapters/daybreak/standard_daybreak_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/dbm/standard_dbm_spec.rb +1 -1
- data/spec/moneta/adapters/dbm/standard_dbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/file/standard_file_spec.rb +2 -2
- data/spec/moneta/adapters/file/standard_file_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/gdbm/standard_gdbm_spec.rb +1 -1
- data/spec/moneta/adapters/gdbm/standard_gdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/kyotocabinet/adapter_kyotocabinet_spec.rb +1 -1
- data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_spec.rb +2 -2
- data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_with_expires_spec.rb +2 -2
- data/spec/moneta/adapters/leveldb/standard_leveldb_spec.rb +1 -1
- data/spec/moneta/adapters/leveldb/standard_leveldb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/lmdb/standard_lmdb_spec.rb +1 -1
- data/spec/moneta/adapters/lmdb/standard_lmdb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/lruhash/standard_lruhash_spec.rb +1 -1
- data/spec/moneta/adapters/lruhash/standard_lruhash_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_compress_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_key_serializer_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_serializer_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_value_serializer_spec.rb +2 -2
- data/spec/moneta/adapters/memory/standard_memory_with_prefix_spec.rb +39 -2
- data/spec/moneta/adapters/memory/standard_memory_with_snappy_compress_spec.rb +2 -2
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +4 -3
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +5 -3
- data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +4 -2
- data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +5 -3
- data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +3 -2
- data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +5 -3
- data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +2 -2
- data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +2 -2
- data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +2 -2
- data/spec/moneta/adapters/pstore/standard_pstore_spec.rb +1 -1
- data/spec/moneta/adapters/pstore/standard_pstore_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/redis/standard_redis_spec.rb +1 -1
- data/spec/moneta/adapters/sdbm/standard_sdbm_spec.rb +1 -1
- data/spec/moneta/adapters/sdbm/standard_sdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +1 -1
- data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/sqlite/standard_sqlite_spec.rb +1 -1
- data/spec/moneta/adapters/sqlite/standard_sqlite_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/tdb/standard_tdb_spec.rb +1 -1
- data/spec/moneta/adapters/tdb/standard_tdb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_spec.rb +1 -1
- data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/yaml/standard_yaml_spec.rb +1 -1
- data/spec/moneta/adapters/yaml/standard_yaml_with_expires_spec.rb +1 -1
- data/spec/moneta/builder_spec.rb +22 -0
- data/spec/moneta/proxies/expires/expires_file_spec.rb +1 -1
- data/spec/moneta/proxies/shared/shared_tcp_spec.rb +14 -4
- data/spec/moneta/proxies/shared/shared_unix_spec.rb +4 -4
- data/spec/moneta/proxies/transformer/transformer_bencode_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_bert_spec.rb +3 -3
- data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +2 -2
- data/spec/moneta/proxies/transformer/transformer_json_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_key_marshal_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_key_yaml_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_base64_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_hex_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_hmac_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_prefix_base64_spec.rb +33 -0
- data/spec/moneta/proxies/transformer/transformer_marshal_prefix_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_qp_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_urlsafe_base64_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_uuencode_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_msgpack_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_ox_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_php_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_tnet_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_yaml_spec.rb +2 -2
- data/spec/moneta/proxies/weak_each_key/weak_each_key_spec.rb +0 -2
- data/spec/support/mongo_helper.rb +12 -0
- metadata +18 -12
- data/script/reconfigure-couchdb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9aebec0b5bcf8b12d295aff540c30c453e88883e5d5d498f92f3666adcbf4eeb
|
4
|
+
data.tar.gz: f62cbb548556e6d4a36e0465edb468a7421262620469d7329c34cb7d160553bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9544cff0b2b3550776646d83131b8c7db4c3a9e79083ddb56af23a4cffaa9ce5a3de4a8c1db2db3571e768fe00c409692c3a2787ac9e7e8312a3f145d36f270
|
7
|
+
data.tar.gz: 96cf85c80a0dbb86c820351e711470f873139e6544ec450e427a5cba92cf23f615bedd7f2ff5fda7eca8f005631e0dbcb5e79550ef001234b6d231fcaa71c924
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
dist: xenial
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
+
- 2.7
|
4
5
|
- 2.6
|
5
6
|
- 2.5
|
6
7
|
- 2.4
|
7
8
|
- 2.3
|
8
|
-
- 2.
|
9
|
-
- jruby-9.2
|
9
|
+
- jruby-9.2.9.0
|
10
10
|
- rbx-3
|
11
11
|
services:
|
12
12
|
- mysql
|
@@ -26,7 +26,6 @@ addons:
|
|
26
26
|
key_url: https://packagecloud.io/basho/riak/gpgkey
|
27
27
|
packages:
|
28
28
|
- cassandra
|
29
|
-
- couchdb
|
30
29
|
- libkyotocabinet-dev
|
31
30
|
- libleveldb-dev
|
32
31
|
- liblzo2-dev
|
@@ -36,6 +35,7 @@ addons:
|
|
36
35
|
- riak
|
37
36
|
postgresql: '9.6'
|
38
37
|
before_install:
|
38
|
+
- gem install bundler
|
39
39
|
- script/start-services
|
40
40
|
cache:
|
41
41
|
bundler: true
|
@@ -47,6 +47,10 @@ before_script:
|
|
47
47
|
- psql -c 'create database moneta1;' -U postgres
|
48
48
|
- psql -c 'create extension hstore;' -U postgres moneta1
|
49
49
|
- psql -c 'create database moneta2;' -U postgres
|
50
|
+
# FIXME: remove this once moneta no longer generates hundreds of warnings
|
51
|
+
# in Ruby 2.7
|
52
|
+
- if echo $RUBY_VERSION | grep -q 'ruby-2.7'; then export RUBYOPT='-W0'; fi
|
53
|
+
- export
|
50
54
|
env:
|
51
55
|
matrix:
|
52
56
|
- SCRIPT='script/parallel-tests ~unstable --
|
@@ -120,6 +124,8 @@ matrix:
|
|
120
124
|
- rvm: rbx-3
|
121
125
|
- env: SCRIPT='script/parallel-tests unstable'
|
122
126
|
exclude:
|
127
|
+
- rvm: 2.6
|
128
|
+
env: SCRIPT='rubocop lib'
|
123
129
|
- rvm: 2.5
|
124
130
|
env: SCRIPT='rubocop lib'
|
125
131
|
- rvm: 2.4
|
@@ -128,7 +134,7 @@ matrix:
|
|
128
134
|
env: SCRIPT='rubocop lib'
|
129
135
|
- rvm: 2.2
|
130
136
|
env: SCRIPT='rubocop lib'
|
131
|
-
- rvm: jruby-9.2
|
137
|
+
- rvm: jruby-9.2.9.0
|
132
138
|
env: SCRIPT='rubocop lib'
|
133
139
|
- rvm: rbx-3
|
134
140
|
env: SCRIPT='rubocop lib'
|
data/CHANGES
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
1.3.0
|
2
|
+
|
3
|
+
* Transformer - add :each_key support (#170)
|
4
|
+
* Server - add :each_key support, use non-blocking IO (#165)
|
5
|
+
* Builder - dup options before passing to adapter/proxy (#174)
|
6
|
+
* Adapter::Couch - add HTTP basic auth support
|
7
|
+
* Support MRI 2.7.0 (#172)
|
8
|
+
* Minimum required MRI version is now 2.3.0 (#172)
|
9
|
+
|
1
10
|
1.2.1
|
2
11
|
|
3
12
|
* Transformer - fix :escape transformer deserialize implementation (#168)
|
data/Gemfile
CHANGED
@@ -23,7 +23,7 @@ group :msgpack do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# Compressors used by Transformer
|
26
|
-
gem 'rbzip2', '
|
26
|
+
gem 'rbzip2', '>= 0.3.0', group: :bzip2
|
27
27
|
gem 'lz4-ruby', platforms: :ruby, group: :lz4
|
28
28
|
gem 'ruby-lzma', platforms: :ruby, group: :lzma
|
29
29
|
gem 'lzoruby', platforms: :ruby, group: :lzo
|
@@ -37,8 +37,8 @@ gem 'cityhash', platforms: :ruby, group: :city
|
|
37
37
|
gem 'daybreak', group: :daybreak
|
38
38
|
gem 'activerecord', '~> 5.2', group: :activerecord
|
39
39
|
gem 'redis', '~> 4.0.0', group: :redis
|
40
|
-
gem 'mongo', '
|
41
|
-
gem 'moped', '>= 2
|
40
|
+
gem 'mongo', '>= 2', group: :mongo_official
|
41
|
+
gem 'moped', '>= 2', group: :mongo_moped
|
42
42
|
gem 'sequel', group: :sequel
|
43
43
|
gem 'dalli', group: :memcached_dalli
|
44
44
|
gem 'riak-client', group: :riak
|
@@ -50,7 +50,7 @@ gem 'tdb', platforms: :ruby, group: :tdb
|
|
50
50
|
gem 'leveldb-ruby', platforms: :ruby, group: :leveldb
|
51
51
|
gem 'lmdb', platforms: :mri, group: :lmdb
|
52
52
|
gem 'tokyocabinet', platforms: :ruby, group: :tokyocabinet
|
53
|
-
gem 'kyotocabinet-ruby-reanimated', platforms: :
|
53
|
+
gem 'kyotocabinet-ruby-reanimated', platforms: [:ruby_23, :ruby_24, :ruby_25, :ruby_26], group: :kyotocabinet
|
54
54
|
gem 'memcached', platforms: :ruby, group: :memcached_native
|
55
55
|
gem 'jruby-memcached', platforms: :jruby, group: :memcached_native
|
56
56
|
gem 'activerecord-jdbch2-adapter', platforms: :jruby, group: :h2, github: 'jruby/activerecord-jdbc-adapter', glob: 'activerecord-jdbch2-adapter/*.gemspec', branch: '52-stable'
|
@@ -94,7 +94,9 @@ end
|
|
94
94
|
|
95
95
|
# Rails integration testing
|
96
96
|
group :rails do
|
97
|
-
|
97
|
+
git 'https://github.com/rails/rails.git', branch: '5-2-stable' do
|
98
|
+
gem 'actionpack'
|
99
|
+
end
|
98
100
|
gem 'minitest', '~> 5.0'
|
99
101
|
end
|
100
102
|
|
data/README.md
CHANGED
@@ -214,7 +214,7 @@ __NOTE:__ <a name="backend-matrix"></a>The backend matrix is much more readable
|
|
214
214
|
|
215
215
|
<tr><th colspan="2">Network clients</th><th colspan="12"></th></tr>
|
216
216
|
|
217
|
-
<tr><td>Client</td><td>-</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:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#
|
217
|
+
<tr><td>Client</td><td>-</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:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#55F">?<sup>13</sup></td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td>Moneta client adapter</td></tr>
|
218
218
|
|
219
219
|
<tr><td>RestClient</td><td>-</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:#F44">✗</td><td style="text-align:center;background:#F44">✗</td><td style="text-align:center;background:#55F">?<sup>13</sup></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>Moneta REST client adapter</td></tr>
|
220
220
|
|
@@ -913,12 +913,15 @@ Person.adapter :memory, Moneta.new(:Redis)
|
|
913
913
|
|
914
914
|
## Testing and Benchmarks
|
915
915
|
|
916
|
-
Testing is done using [Travis-CI](http://travis-ci.org/moneta-rb/moneta).
|
916
|
+
Testing is done using [Travis-CI](http://travis-ci.org/moneta-rb/moneta).
|
917
|
+
Currently we support MRI Ruby >= 2.3.0 and the JRuby >= 9.2.9.0.
|
917
918
|
|
918
|
-
Benchmarks for each store are done on
|
919
|
-
|
920
|
-
|
921
|
-
|
919
|
+
Benchmarks for each store are done on
|
920
|
+
[Travis-CI](http://travis-ci.org/moneta-rb/moneta) for each build. Take a look
|
921
|
+
there to compare the speed of the different key value stores for different
|
922
|
+
key/value sizes and size distributions. Feel free to add your own
|
923
|
+
configurations! The impact of Moneta should be minimal since it is only a thin
|
924
|
+
layer on top of the different stores.
|
922
925
|
|
923
926
|
|
924
927
|
------
|
data/feature_matrix.yaml
CHANGED
@@ -220,13 +220,14 @@ backends:
|
|
220
220
|
- adapter: Client
|
221
221
|
platforms: [ MRI, JRuby ]
|
222
222
|
features: [multiprocess]
|
223
|
-
unknown: [ increment, create, expires, persist ]
|
223
|
+
unknown: [ increment, create, expires, persist, each_key ]
|
224
224
|
description: "Moneta client adapter"
|
225
225
|
notes:
|
226
226
|
increment: depends on server
|
227
227
|
create: depends on server
|
228
228
|
expires: depends on server
|
229
229
|
persist: depends on server
|
230
|
+
each_key: depends on server
|
230
231
|
- adapter: RestClient
|
231
232
|
platforms: [ MRI, JRuby ]
|
232
233
|
features: [ multiprocess ]
|
@@ -23,44 +23,44 @@ module Moneta
|
|
23
23
|
# (see Proxy#key?)
|
24
24
|
def key?(key, options = {})
|
25
25
|
write(:key?, key, options)
|
26
|
-
|
26
|
+
read_msg
|
27
27
|
end
|
28
28
|
|
29
29
|
# (see Proxy#load)
|
30
30
|
def load(key, options = {})
|
31
31
|
write(:load, key, options)
|
32
|
-
|
32
|
+
read_msg
|
33
33
|
end
|
34
34
|
|
35
35
|
# (see Proxy#store)
|
36
36
|
def store(key, value, options = {})
|
37
37
|
write(:store, key, value, options)
|
38
|
-
|
38
|
+
read_msg
|
39
39
|
value
|
40
40
|
end
|
41
41
|
|
42
42
|
# (see Proxy#delete)
|
43
43
|
def delete(key, options = {})
|
44
44
|
write(:delete, key, options)
|
45
|
-
|
45
|
+
read_msg
|
46
46
|
end
|
47
47
|
|
48
48
|
# (see Proxy#increment)
|
49
49
|
def increment(key, amount = 1, options = {})
|
50
50
|
write(:increment, key, amount, options)
|
51
|
-
|
51
|
+
read_msg
|
52
52
|
end
|
53
53
|
|
54
54
|
# (see Proxy#create)
|
55
55
|
def create(key, value, options = {})
|
56
56
|
write(:create, key, value, options)
|
57
|
-
|
57
|
+
read_msg
|
58
58
|
end
|
59
59
|
|
60
60
|
# (see Proxy#clear)
|
61
61
|
def clear(options = {})
|
62
62
|
write(:clear, options)
|
63
|
-
|
63
|
+
read_msg
|
64
64
|
self
|
65
65
|
end
|
66
66
|
|
@@ -70,12 +70,43 @@ module Moneta
|
|
70
70
|
nil
|
71
71
|
end
|
72
72
|
|
73
|
+
# (see Proxy#each_key)
|
74
|
+
def each_key
|
75
|
+
raise NotImplementedError, 'each_key is not supported' unless supports?(:each_key)
|
76
|
+
return enum_for(:each_key) unless block_given?
|
77
|
+
|
78
|
+
begin
|
79
|
+
write(:each_key)
|
80
|
+
yield_break = false
|
81
|
+
|
82
|
+
loop do
|
83
|
+
write('NEXT')
|
84
|
+
|
85
|
+
# A StopIteration error will be raised by this call if the server
|
86
|
+
# reached the end of the enumeration. This will stop the loop
|
87
|
+
# automatically.
|
88
|
+
result = read_msg
|
89
|
+
|
90
|
+
# yield_break will be true in the ensure block (below) if anything
|
91
|
+
# happened during the yield to stop further enumeration.
|
92
|
+
yield_break = true
|
93
|
+
yield result
|
94
|
+
yield_break = false
|
95
|
+
end
|
96
|
+
ensure
|
97
|
+
write('BREAK') if yield_break
|
98
|
+
read_msg # nil return from each_key
|
99
|
+
end
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
73
104
|
# (see Default#features)
|
74
105
|
def features
|
75
106
|
@features ||=
|
76
107
|
begin
|
77
108
|
write(:features)
|
78
|
-
|
109
|
+
read_msg.freeze
|
79
110
|
end
|
80
111
|
end
|
81
112
|
|
@@ -86,18 +117,24 @@ module Moneta
|
|
86
117
|
@socket.write([s.bytesize].pack('N') << s)
|
87
118
|
end
|
88
119
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
120
|
+
# JRuby doesn't support socket#recv with flags
|
121
|
+
if defined?(JRUBY_VERSION)
|
122
|
+
def read(bytes)
|
123
|
+
received = @socket.read(bytes)
|
124
|
+
raise EOFError, "Server closed socket" unless received && received.bytesize == bytes
|
125
|
+
received
|
126
|
+
end
|
127
|
+
else
|
128
|
+
def read(bytes)
|
129
|
+
received = @socket.recv(bytes, Socket::MSG_WAITALL)
|
130
|
+
raise EOFError, "Server closed socket" unless received && received.bytesize == bytes
|
131
|
+
received
|
132
|
+
end
|
133
|
+
end
|
100
134
|
|
135
|
+
def read_msg
|
136
|
+
size = read(4).unpack('N').first
|
137
|
+
result = Marshal.load(read(size))
|
101
138
|
raise result if Exception === result
|
102
139
|
result
|
103
140
|
end
|
@@ -39,6 +39,8 @@ module Moneta
|
|
39
39
|
# @option options [String] :scheme ('http') HTTP scheme to use
|
40
40
|
# @option options [String] :value_field ('value') Document field to store value
|
41
41
|
# @option options [String] :type_field ('type') Document field to store value type
|
42
|
+
# @option options [String] :login Login name to use for HTTP basic authentication
|
43
|
+
# @option options [String] :password Password to use for HTTP basic authentication
|
42
44
|
# @option options [Symbol] :adapter Adapter to use with Faraday
|
43
45
|
# @option options [Faraday::Connecton] :backend Use existing backend instance
|
44
46
|
# @option options Other options passed to {Faraday::new} (unless
|
@@ -46,6 +48,8 @@ module Moneta
|
|
46
48
|
def initialize(options = {})
|
47
49
|
@value_field = options.delete(:value_field) || 'value'
|
48
50
|
@type_field = options.delete(:type_field) || 'type'
|
51
|
+
login = options.delete(:login)
|
52
|
+
password = options.delete(:password)
|
49
53
|
@backend = options.delete(:backend) || begin
|
50
54
|
host = options.delete(:host) || '127.0.0.1'
|
51
55
|
port = options.delete(:port) || 5984
|
@@ -56,6 +60,7 @@ module Moneta
|
|
56
60
|
end
|
57
61
|
::Faraday.new("#{scheme}://#{host}:#{port}/#{db}", options, &block)
|
58
62
|
end
|
63
|
+
@backend.basic_auth(login, password) if login && password
|
59
64
|
@rev_cache = Moneta.build do
|
60
65
|
use :Lock
|
61
66
|
adapter :LRUHash
|
@@ -44,7 +44,10 @@ module Moneta
|
|
44
44
|
@backend.use(db)
|
45
45
|
@backend.login(user, password) if user && password
|
46
46
|
@collection = @backend[collection]
|
47
|
-
if @backend.command(buildinfo: 1)['version'] >= '
|
47
|
+
if @backend.command(buildinfo: 1)['version'] >= '3.0'
|
48
|
+
# Moped creates indexes in the system.indexes collection which is not writable anymore since Mongo v3
|
49
|
+
warn 'Moneta::Adapters::MongoMoped - You are using the unmaintained Moped gem, expired documents will not be deleted'
|
50
|
+
elsif @backend.command(buildinfo: 1)['version'] >= '2.2'
|
48
51
|
@collection.indexes.create({ @expires_field => 1 }, expireAfterSeconds: 0)
|
49
52
|
else
|
50
53
|
warn 'Moneta::Adapters::Mongo - You are using MongoDB version < 2.2, expired documents will not be deleted'
|
data/lib/moneta/builder.rb
CHANGED
@@ -17,12 +17,12 @@ module Moneta
|
|
17
17
|
adapter = @proxies.first
|
18
18
|
if Array === adapter
|
19
19
|
klass, options, block = adapter
|
20
|
-
adapter = new_proxy(klass, options, &block)
|
20
|
+
adapter = new_proxy(klass, options.dup, &block)
|
21
21
|
check_arity(klass, adapter, 1)
|
22
22
|
end
|
23
23
|
@proxies[1..-1].inject([adapter]) do |result, proxy|
|
24
24
|
klass, options, block = proxy
|
25
|
-
proxy = new_proxy(klass, result.last, options, &block)
|
25
|
+
proxy = new_proxy(klass, result.last, options.dup, &block)
|
26
26
|
check_arity(klass, proxy, 2)
|
27
27
|
result << proxy
|
28
28
|
end
|
data/lib/moneta/lock.rb
CHANGED
@@ -15,6 +15,7 @@ module Moneta
|
|
15
15
|
protected
|
16
16
|
|
17
17
|
def wrap(name, *args, &block)
|
18
|
+
self.locks ||= Set.new
|
18
19
|
if locked?
|
19
20
|
yield
|
20
21
|
else
|
@@ -22,8 +23,12 @@ module Moneta
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
26
|
+
def locks=(locks)
|
27
|
+
Thread.current.thread_variable_set('Moneta::Lock', locks)
|
28
|
+
end
|
29
|
+
|
25
30
|
def locks
|
26
|
-
Thread.current
|
31
|
+
Thread.current.thread_variable_get('Moneta::Lock')
|
27
32
|
end
|
28
33
|
|
29
34
|
def lock!(&block)
|
data/lib/moneta/pool.rb
CHANGED
@@ -298,6 +298,18 @@ module Moneta
|
|
298
298
|
# by the manager after the ttl
|
299
299
|
def close; end
|
300
300
|
|
301
|
+
def each_key(&block)
|
302
|
+
wrap(:each_key) do
|
303
|
+
raise NotImplementedError, "each_key is not supported on this proxy" \
|
304
|
+
unless supports? :each_key
|
305
|
+
|
306
|
+
return enum_for(:each_key) { adapter ? adapter.each_key.size : check_out! { adapter.each_key.size } } unless block_given?
|
307
|
+
|
308
|
+
adapter.each_key(&block)
|
309
|
+
self
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
301
313
|
# Tells the manager to close all stores. It will not be possible to use
|
302
314
|
# the store after this.
|
303
315
|
def stop
|
data/lib/moneta/proxy.rb
CHANGED
@@ -22,7 +22,7 @@ module Moneta
|
|
22
22
|
raise NotImplementedError, "each_key is not supported on this proxy" \
|
23
23
|
unless supports? :each_key
|
24
24
|
|
25
|
-
return enum_for(:each_key) unless block_given?
|
25
|
+
return enum_for(:each_key) { adapter.each_key.size } unless block_given?
|
26
26
|
adapter.each_key(&block)
|
27
27
|
self
|
28
28
|
end
|
data/lib/moneta/server.rb
CHANGED
@@ -4,6 +4,154 @@ module Moneta
|
|
4
4
|
# Moneta server to be used together with Moneta::Adapters::Client
|
5
5
|
# @api public
|
6
6
|
class Server
|
7
|
+
TIMEOUT = 1
|
8
|
+
MAXSIZE = 0x100000
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
class Connection
|
12
|
+
def initialize(io, store)
|
13
|
+
@io = io
|
14
|
+
@store = store
|
15
|
+
@fiber = Fiber.new { run }
|
16
|
+
end
|
17
|
+
|
18
|
+
def resume(result = nil)
|
19
|
+
@fiber.resume result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# The return value of this function will be sent to the reactor.
|
25
|
+
#
|
26
|
+
# @return [:closed,Exception]
|
27
|
+
def run
|
28
|
+
catch :closed do
|
29
|
+
loop { write_dispatch(read_msg) }
|
30
|
+
end
|
31
|
+
:closed
|
32
|
+
rescue => ex
|
33
|
+
ex
|
34
|
+
ensure
|
35
|
+
@io.close unless @io.closed?
|
36
|
+
end
|
37
|
+
|
38
|
+
def dispatch(method, args)
|
39
|
+
case method
|
40
|
+
when :key?, :load, :delete, :increment, :create, :features
|
41
|
+
@store.public_send(method, *args)
|
42
|
+
when :store, :clear
|
43
|
+
@store.public_send(method, *args)
|
44
|
+
nil
|
45
|
+
when :each_key
|
46
|
+
yield_each(@store.each_key)
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
rescue => ex
|
50
|
+
ex
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_dispatch(msg)
|
54
|
+
method, *args = msg
|
55
|
+
result = dispatch(method, args)
|
56
|
+
write(result)
|
57
|
+
end
|
58
|
+
|
59
|
+
def read_msg
|
60
|
+
size = read(4).unpack('N').first
|
61
|
+
throw :closed, 'Message too big' if size > MAXSIZE
|
62
|
+
Marshal.load(read(size))
|
63
|
+
end
|
64
|
+
|
65
|
+
def read(len)
|
66
|
+
buffer = ''
|
67
|
+
loop do
|
68
|
+
begin
|
69
|
+
case received = @io.recv_nonblock(len)
|
70
|
+
when '', nil
|
71
|
+
throw :closed, 'Closed during read'
|
72
|
+
else
|
73
|
+
buffer << received
|
74
|
+
len -= received.bytesize
|
75
|
+
end
|
76
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
77
|
+
yield_to_reactor(:read)
|
78
|
+
rescue Errno::ECONNRESET
|
79
|
+
throw :closed, 'Closed during read'
|
80
|
+
rescue IOError => ex
|
81
|
+
if ex.message =~ /closed stream/
|
82
|
+
throw :closed, 'Closed during read'
|
83
|
+
else
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
break if len == 0
|
88
|
+
end
|
89
|
+
buffer
|
90
|
+
end
|
91
|
+
|
92
|
+
def write(obj)
|
93
|
+
buffer = pack(obj)
|
94
|
+
until buffer.empty?
|
95
|
+
begin
|
96
|
+
len = sendmsg(buffer)
|
97
|
+
buffer = buffer.byteslice(len...buffer.length)
|
98
|
+
rescue IO::WaitWritable, Errno::EINTR
|
99
|
+
yield_to_reactor(:write)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
# Detect support for socket#sendmsg_nonblock
|
106
|
+
Socket.new(Socket::AF_INET, Socket::SOCK_STREAM).tap do |socket|
|
107
|
+
begin
|
108
|
+
socket.sendmsg_nonblock('probe')
|
109
|
+
rescue Errno::EPIPE, Errno::ENOTCONN
|
110
|
+
def sendmsg(msg)
|
111
|
+
@io.sendmsg_nonblock(msg)
|
112
|
+
end
|
113
|
+
rescue NotImplementedError
|
114
|
+
def sendmsg(msg)
|
115
|
+
@io.write_nonblock(msg)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def yield_to_reactor(mode = :read)
|
121
|
+
if Fiber.yield(mode) == :close
|
122
|
+
throw :closed, 'Closed by reactor'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def pack(obj)
|
127
|
+
s = Marshal.dump(obj)
|
128
|
+
[s.bytesize].pack('N') << s
|
129
|
+
end
|
130
|
+
|
131
|
+
def yield_each(enumerator)
|
132
|
+
received_break = false
|
133
|
+
loop do
|
134
|
+
case msg = read_msg
|
135
|
+
when %w{NEXT}
|
136
|
+
# This will raise a StopIteration at the end of the enumeration,
|
137
|
+
# which will exit the loop.
|
138
|
+
write(enumerator.next)
|
139
|
+
when %w{BREAK}
|
140
|
+
# This is received when the client wants to stop the enumeration.
|
141
|
+
received_break = true
|
142
|
+
break
|
143
|
+
else
|
144
|
+
# Otherwise, the client is attempting to call another method within
|
145
|
+
# an `each` block.
|
146
|
+
write_dispatch(msg)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
ensure
|
150
|
+
# This tells the client to stop enumerating
|
151
|
+
write(StopIteration.new("Server initiated stop")) unless received_break
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
7
155
|
# @param [Hash] options
|
8
156
|
# @option options [Integer] :port (9000) TCP port
|
9
157
|
# @option options [String] :socket Alternative Unix socket file name
|
@@ -11,7 +159,9 @@ module Moneta
|
|
11
159
|
@store = store
|
12
160
|
@server = start(options)
|
13
161
|
@ios = [@server]
|
14
|
-
@
|
162
|
+
@reads = @ios.dup
|
163
|
+
@writes = []
|
164
|
+
@connections = {}
|
15
165
|
@running = false
|
16
166
|
end
|
17
167
|
|
@@ -26,94 +176,89 @@ module Moneta
|
|
26
176
|
#
|
27
177
|
# @note This method blocks!
|
28
178
|
def run
|
29
|
-
raise 'Already running' if
|
179
|
+
raise 'Already running' if running?
|
30
180
|
@stop = false
|
31
181
|
@running = true
|
32
182
|
begin
|
33
183
|
mainloop until @stop
|
34
184
|
ensure
|
35
|
-
|
36
|
-
@
|
185
|
+
@running = false
|
186
|
+
@server.close unless @server.closed?
|
187
|
+
@ios
|
188
|
+
.reject { |io| io == @server }
|
189
|
+
.each { |io| close_connection(io) }
|
190
|
+
File.unlink(@socket) if @socket rescue nil
|
37
191
|
end
|
38
192
|
end
|
39
193
|
|
40
194
|
# Stop the server
|
41
195
|
def stop
|
42
|
-
raise 'Not running' unless
|
196
|
+
raise 'Not running' unless running?
|
43
197
|
@stop = true
|
44
198
|
@server.close
|
45
|
-
|
199
|
+
nil
|
46
200
|
end
|
47
201
|
|
48
202
|
private
|
49
203
|
|
50
|
-
TIMEOUT = 1
|
51
|
-
MAXSIZE = 0x100000
|
52
|
-
|
53
204
|
def mainloop
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
if client = @server.accept
|
62
|
-
@ios << client
|
63
|
-
@clients[client] = ''
|
64
|
-
end
|
65
|
-
elsif io.closed? || io.eof?
|
66
|
-
delete_client(io)
|
67
|
-
else
|
68
|
-
handle(io, @clients[io] << io.readpartial(0xFFFF))
|
69
|
-
end
|
205
|
+
if ready = IO.select(@reads, @writes, @ios, TIMEOUT)
|
206
|
+
reads, writes, errors = ready
|
207
|
+
errors.each { |io| close_connection(io) }
|
208
|
+
|
209
|
+
@reads -= reads
|
210
|
+
reads.each do |io|
|
211
|
+
io == @server ? accept_connection : resume(io)
|
70
212
|
end
|
213
|
+
|
214
|
+
@writes -= writes
|
215
|
+
writes.each { |io| resume(io) }
|
71
216
|
end
|
72
|
-
rescue SignalException =>
|
73
|
-
warn "Moneta::Server - #{
|
74
|
-
|
75
|
-
|
217
|
+
rescue SignalException => signal
|
218
|
+
warn "Moneta::Server - received #{signal}"
|
219
|
+
case signal.signo
|
220
|
+
when Signal.list['INT'], Signal.list['TERM']
|
221
|
+
@stop = true # graceful exit
|
222
|
+
end
|
223
|
+
rescue IOError => ex
|
224
|
+
# We get a lot of these "closed stream" errors, which we ignore
|
225
|
+
raise unless ex.message =~ /closed stream/
|
226
|
+
rescue Errno::EBADF => ex
|
76
227
|
warn "Moneta::Server - #{ex.message}"
|
77
228
|
end
|
78
229
|
|
79
|
-
def
|
230
|
+
def accept_connection
|
231
|
+
io = @server.accept
|
232
|
+
@connections[io] = Connection.new(io, @store)
|
233
|
+
@ios << io
|
234
|
+
resume(io)
|
235
|
+
ensure
|
236
|
+
@reads << @server
|
237
|
+
end
|
238
|
+
|
239
|
+
def delete_connection(io)
|
80
240
|
@ios.delete(io)
|
81
|
-
@
|
241
|
+
@reads.delete(io)
|
242
|
+
@writes.delete(io)
|
82
243
|
end
|
83
244
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
245
|
+
def close_connection(io)
|
246
|
+
delete_connection(io)
|
247
|
+
@connections.delete(io).resume(:close)
|
87
248
|
end
|
88
249
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
when :key?, :load, :delete, :increment, :create
|
101
|
-
io.write(pack(@store.send(method, *args)))
|
102
|
-
when :features
|
103
|
-
# all features except each_key are supported
|
104
|
-
io.write(pack(@store.features - [:each_key]))
|
105
|
-
when :store, :clear
|
106
|
-
@store.send(method, *args)
|
107
|
-
io.write(@nil ||= pack(nil))
|
108
|
-
else
|
109
|
-
raise 'Invalid method call'
|
250
|
+
def resume(io)
|
251
|
+
case result = @connections[io].resume
|
252
|
+
when :closed # graceful exit
|
253
|
+
delete_connection(io)
|
254
|
+
when Exception # messy exit
|
255
|
+
delete_connection(io)
|
256
|
+
raise result
|
257
|
+
when :read
|
258
|
+
@reads << io
|
259
|
+
when :write
|
260
|
+
@writes << io
|
110
261
|
end
|
111
|
-
rescue IOError => ex
|
112
|
-
warn "Moneta::Server - #{ex.message}" unless ex.message =~ /closed/
|
113
|
-
delete_client(io)
|
114
|
-
rescue => ex
|
115
|
-
warn "Moneta::Server - #{ex.message}"
|
116
|
-
io.write(pack(Exception.new(ex.message)))
|
117
262
|
end
|
118
263
|
|
119
264
|
def start(options)
|
@@ -133,5 +278,14 @@ module Moneta
|
|
133
278
|
TCPServer.open(options[:host] || '127.0.0.1', options[:port] || 9000)
|
134
279
|
end
|
135
280
|
end
|
281
|
+
|
282
|
+
def stats
|
283
|
+
{
|
284
|
+
connections: @connections.length,
|
285
|
+
reading: @reads.length,
|
286
|
+
writing: @writes.length,
|
287
|
+
total: @ios.length
|
288
|
+
}
|
289
|
+
end
|
136
290
|
end
|
137
291
|
end
|