moneta 1.4.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +418 -0
  3. data/CHANGES +4 -0
  4. data/Gemfile +1 -1
  5. data/README.md +16 -13
  6. data/lib/moneta/pool.rb +26 -6
  7. data/lib/moneta/version.rb +1 -1
  8. data/spec/active_support/cache_moneta_store_spec.rb +13 -13
  9. data/spec/helper.rb +14 -1
  10. data/spec/moneta/adapters/activerecord/adapter_activerecord_existing_connection_spec.rb +3 -1
  11. data/spec/moneta/adapters/activerecord/adapter_activerecord_spec.rb +15 -7
  12. data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +5 -2
  13. data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +5 -2
  14. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_spec.rb +3 -3
  15. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_with_default_expires_spec.rb +2 -2
  16. data/spec/moneta/adapters/datamapper/adapter_datamapper_spec.rb +25 -8
  17. data/spec/moneta/adapters/datamapper/standard_datamapper_spec.rb +2 -2
  18. data/spec/moneta/adapters/datamapper/standard_datamapper_with_expires_spec.rb +2 -2
  19. data/spec/moneta/adapters/datamapper/standard_datamapper_with_repository_spec.rb +2 -2
  20. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_spec.rb +13 -3
  21. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_spec.rb +13 -3
  22. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +1 -1
  23. data/spec/moneta/adapters/redis/adapter_redis_spec.rb +13 -3
  24. data/spec/moneta/adapters/redis/standard_redis_spec.rb +8 -1
  25. data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +4 -4
  26. data/spec/moneta/adapters/sequel/helper.rb +10 -5
  27. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +1 -1
  28. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +1 -1
  29. data/spec/moneta/adapters/sqlite/adapter_sqlite_spec.rb +1 -1
  30. data/spec/moneta/adapters/sqlite/standard_sqlite_spec.rb +1 -1
  31. data/spec/moneta/adapters/sqlite/standard_sqlite_with_expires_spec.rb +1 -1
  32. data/spec/moneta/proxies/pool/pool_spec.rb +31 -3
  33. metadata +7 -15
  34. data/.travis.yml +0 -146
  35. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_with_default_expires_spec.rb +0 -15
  36. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_with_default_expires_spec.rb +0 -15
  37. data/spec/moneta/adapters/redis/adapter_redis_with_default_expires_spec.rb +0 -10
  38. data/spec/moneta/proxies/proxy/proxy_redis_spec.rb +0 -13
data/lib/moneta/pool.rb CHANGED
@@ -87,6 +87,7 @@ module Moneta
87
87
  @waiting_since = [] if @timeout
88
88
  @last_checkout = nil
89
89
  @stopping = false
90
+ @idle_time = nil
90
91
 
91
92
  # Launch the manager thread
92
93
  @thread = run
@@ -126,10 +127,16 @@ module Moneta
126
127
  populate_stores
127
128
 
128
129
  until @stopping && @stores.empty?
130
+ loop_start = Time.now
131
+
129
132
  # Block until a message arrives, or until we time out for some reason
130
- if request = pop
131
- handle_request(request)
132
- end
133
+ request = pop
134
+
135
+ # Record how long we were idle, for stats purposes
136
+ @idle_time = Time.now - loop_start
137
+
138
+ # If a message arrived, handle it
139
+ handle_request(request) if request
133
140
 
134
141
  # Handle any stale checkout requests
135
142
  handle_timed_out_requests
@@ -186,7 +193,7 @@ module Moneta
186
193
  # @return [Integer, nil]
187
194
  def timeout
188
195
  # Time to wait before there will be stores that should be closed
189
- ttl = if @ttl && @last_checkout && !@available.empty?
196
+ ttl = if @ttl && @last_checkout && stores_available? && stores_unneeded?
190
197
  [@ttl - (Time.now - @last_checkout), 0].max
191
198
  end
192
199
 
@@ -199,6 +206,18 @@ module Moneta
199
206
  [ttl, timeout].compact.min
200
207
  end
201
208
 
209
+ def stores_available?
210
+ !@available.empty?
211
+ end
212
+
213
+ def stores_unneeded?
214
+ @stores.length > @min
215
+ end
216
+
217
+ def stores_maxed?
218
+ @max != nil && @stores.length == @max
219
+ end
220
+
202
221
  def pop
203
222
  @mutex.synchronize do
204
223
  @resource.wait(@mutex, timeout) if @inbox.empty?
@@ -218,7 +237,7 @@ module Moneta
218
237
  reply.resolve(ShutdownError.new("Shutting down"))
219
238
  elsif !@available.empty?
220
239
  reply.resolve(@available.pop)
221
- elsif !@max || @stores.length < @max
240
+ elsif !stores_maxed?
222
241
  begin
223
242
  reply.resolve(add_store)
224
243
  rescue => e
@@ -258,7 +277,8 @@ module Moneta
258
277
  waiting: @waiting.length,
259
278
  longest_wait: @timeout && !@waiting_since.empty? ? @waiting_since.first.dup : nil,
260
279
  stopping: @stopping,
261
- last_checkout: @last_checkout && @last_checkout.dup)
280
+ last_checkout: @last_checkout && @last_checkout.dup,
281
+ idle_time: @idle_time.dup)
262
282
  end
263
283
 
264
284
  def handle_request(request)
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '1.4.1'.freeze
4
+ VERSION = '1.4.2'.freeze
5
5
  end
@@ -74,7 +74,7 @@ describe "cache_moneta_store" do
74
74
  end
75
75
  expect(result['rabbit']).to eq rabbit
76
76
  expect(result['irish whisky']).to eq 'irish whisky was missing'
77
- expect(store.fetch 'irish whisky').to eq 'irish whisky was missing'
77
+ expect(store.fetch('irish whisky')).to eq 'irish whisky was missing'
78
78
  end
79
79
  end
80
80
 
@@ -88,9 +88,9 @@ describe "cache_moneta_store" do
88
88
 
89
89
  it 'writes multiple values with expiration time' do
90
90
  store.write_multi({
91
- 'rabbit' => white_rabbit,
92
- 'irish whisky' => 'Jameson'
93
- }, expires_in: 0.2.second)
91
+ 'rabbit' => white_rabbit,
92
+ 'irish whisky' => 'Jameson'
93
+ }, expires_in: 0.2.second)
94
94
 
95
95
  expect(store.read_multi('rabbit', 'irish whisky')).to eq \
96
96
  'rabbit' => white_rabbit,
@@ -234,23 +234,23 @@ describe "cache_moneta_store" do
234
234
  end
235
235
 
236
236
  context "with :Memory store" do
237
- let(:store){ described_class.new(store: :Memory) }
237
+ let(:store) { described_class.new(store: :Memory) }
238
238
  include_examples :moneta_store
239
239
  end
240
240
 
241
241
  context "with existing :Memory store" do
242
- let(:store){ described_class.new(store: ::Moneta.new(:Memory)) }
242
+ let(:store) { described_class.new(store: ::Moneta.new(:Memory)) }
243
243
  include_examples :moneta_store
244
244
  end
245
245
 
246
- context "with Redis store" do
247
- let(:store) {described_class.new(store: :Redis) }
246
+ context "with Redis store", adapter: :Redis do
247
+ let(:store) { described_class.new(store: :Redis) }
248
248
  include_examples :moneta_store
249
249
  end
250
250
  end
251
251
 
252
252
  describe ActiveSupport::Cache::MemoryStore do
253
- let(:store){ described_class.new }
253
+ let(:store) { described_class.new }
254
254
 
255
255
  include_examples :basic_store
256
256
  include_examples :expiry
@@ -258,8 +258,8 @@ describe "cache_moneta_store" do
258
258
  include_examples :basic_instrumentation
259
259
  end
260
260
 
261
- describe ActiveSupport::Cache::MemCacheStore do
262
- let(:store){ described_class.new('127.0.0.1:11213') }
261
+ describe ActiveSupport::Cache::MemCacheStore, memcached: true do
262
+ let(:store) { described_class.new('127.0.0.1:11213') }
263
263
 
264
264
  include_context :start_memcached, 11213
265
265
 
@@ -270,8 +270,8 @@ describe "cache_moneta_store" do
270
270
  include_examples :increment_decrement_instrumentation
271
271
  end
272
272
 
273
- describe ActiveSupport::Cache::RedisCacheStore do
274
- let(:store){ described_class.new(url: 'redis:///3') }
273
+ describe ActiveSupport::Cache::RedisCacheStore, redis: true do
274
+ let(:store) { described_class.new(url: "redis:///3") }
275
275
 
276
276
  include_examples :basic_store
277
277
  include_examples :expiry
data/spec/helper.rb CHANGED
@@ -213,11 +213,18 @@ ADAPTER_SPECS = MonetaSpecs.new(
213
213
  :create, :features, :store_large, :not_each_key],
214
214
  key: %w(string path),
215
215
  value: %w(string path binary))
216
+
217
+ NATIVE_EXPIRY_SPECS = MonetaSpecs.new(
218
+ specs: [:create, :expires, :create_expires],
219
+ key: %w(string path),
220
+ value: %w(string path binary))
221
+
216
222
  STANDARD_SPECS = MonetaSpecs.new(
217
223
  specs: [:null, :store, :returndifferent,
218
224
  :marshallable_key, :marshallable_value, :transform_value, :increment,
219
225
  :concurrent_increment, :concurrent_create, :persist, :multiprocess, :create,
220
226
  :features, :store_large, :not_each_key])
227
+
221
228
  TRANSFORMER_SPECS = MonetaSpecs.new(
222
229
  specs: [:null, :store, :returndifferent,
223
230
  :transform_value, :increment, :create, :features, :store_large,
@@ -260,18 +267,24 @@ module MonetaHelpers
260
267
 
261
268
  # Used by tests that rely on MySQL. These env vars can be used if you
262
269
  # want to run the tests but don't want to grant root access to moneta
270
+ let(:mysql_host) { ENV['MYSQL_HOST'] || 'localhost' }
271
+ let(:mysql_port) { ENV['MYSQL_TCP_PORT'] || '3306' }
263
272
  let(:mysql_username) { ENV['MONETA_MYSQL_USERNAME'] || 'root' }
264
273
  let(:mysql_password) { ENV['MONETA_MYSQL_PASSWORD'] }
265
274
  let(:mysql_database1) { ENV['MONETA_MYSQL_DATABASE1'] || 'moneta' }
266
275
  let(:mysql_database2) { ENV['MONETA_MYSQL_DATABASE2'] || 'moneta2' }
267
276
 
268
- let(:postgres_username) { ENV['MONETA_POSTGRES_USERNAME'] || 'postgres' }
277
+ let(:postgres_username) { ENV['PGUSER'] || 'postgres' }
278
+ let(:postgres_password) { ENV['PGPASSWORD'] }
269
279
  let(:postgres_database1) { ENV['MONETA_POSTGRES_DATABSASE1'] || 'moneta1' }
270
280
  let(:postgres_database2) { ENV['MONETA_POSTGRES_DATABSASE1'] || 'moneta2' }
271
281
 
272
282
  let(:couch_login) { ENV['COUCH_LOGIN'] || 'admin' }
273
283
  let(:couch_password) { ENV['COUCH_PASSWORD'] || 'password' }
274
284
 
285
+ let(:redis_host) { ENV.fetch('REDIS_HOST', 'localhost') }
286
+ let(:redis_port) { ENV.fetch('REDIS_PORT', '6379') }
287
+
275
288
  before do
276
289
  store = new_store
277
290
  store.clear
@@ -1,4 +1,4 @@
1
- describe 'adapter_activerecord_existing_connection', adapter: :ActiveRecord do
1
+ describe 'adapter_activerecord_existing_connection', adapter: :ActiveRecord, mysql: true do
2
2
  before :all do
3
3
  require 'active_record'
4
4
  end
@@ -8,6 +8,8 @@ describe 'adapter_activerecord_existing_connection', adapter: :ActiveRecord do
8
8
  ActiveRecord::Base.configurations = {
9
9
  default_env => {
10
10
  'adapter' => (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'),
11
+ 'host' => mysql_host,
12
+ 'port' => mysql_port,
11
13
  'database' => mysql_database1,
12
14
  'username' => mysql_username,
13
15
  'password' => mysql_password
@@ -58,32 +58,39 @@ describe 'adapter_activerecord', adapter: :ActiveRecord do
58
58
  end
59
59
  end
60
60
 
61
- context "with MySQL" do
61
+ context "with MySQL", mysql: true do
62
62
  let(:connection1) do
63
63
  {
64
64
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'),
65
+ host: mysql_host,
66
+ port: mysql_port,
65
67
  database: mysql_database1,
66
- username: mysql_username
68
+ username: mysql_username,
69
+ password: mysql_password
67
70
  }
68
71
  end
69
72
 
70
73
  let(:connection2) do
71
74
  {
72
75
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'),
76
+ host: mysql_host,
77
+ port: mysql_port,
73
78
  database: mysql_database2,
74
- username: mysql_username
79
+ username: mysql_username,
80
+ password: mysql_password
75
81
  }
76
82
  end
77
83
 
78
84
  include_examples :adapter_activerecord, activerecord_specs
79
85
  end
80
86
 
81
- context "with PostgreSQL" do
87
+ context "with PostgreSQL", postgres: true do
82
88
  let(:connection1) do
83
89
  {
84
90
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcpostgresql' : 'postgresql'),
85
91
  database: postgres_database1,
86
- username: postgres_username
92
+ username: postgres_username,
93
+ password: postgres_password
87
94
  }
88
95
  end
89
96
 
@@ -91,14 +98,15 @@ describe 'adapter_activerecord', adapter: :ActiveRecord do
91
98
  {
92
99
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcpostgresql' : 'postgresql'),
93
100
  database: postgres_database2,
94
- username: postgres_username
101
+ username: postgres_username,
102
+ password: postgres_password
95
103
  }
96
104
  end
97
105
 
98
106
  include_examples :adapter_activerecord, activerecord_specs
99
107
  end
100
108
 
101
- context "with SQLite" do
109
+ context "with SQLite", sqlite: true do
102
110
  let(:connection1) do
103
111
  {
104
112
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3'),
@@ -1,11 +1,14 @@
1
- describe "standard_activerecord", adapter: :ActiveRecord do
1
+ describe "standard_activerecord", adapter: :ActiveRecord, mysql: true do
2
2
  moneta_store :ActiveRecord do
3
3
  {
4
4
  table: 'standard_activerecord',
5
5
  connection: {
6
6
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'),
7
+ host: mysql_host,
8
+ port: mysql_port,
7
9
  database: mysql_database1,
8
- username: mysql_username
10
+ username: mysql_username,
11
+ password: mysql_password
9
12
  }
10
13
  }
11
14
  end
@@ -1,4 +1,4 @@
1
- describe "standard_activerecord_with_expires", adapter: :ActiveRecord do
1
+ describe "standard_activerecord_with_expires", adapter: :ActiveRecord, mysql: true do
2
2
  let(:t_res) { 0.125 }
3
3
  let(:min_ttl) { t_res }
4
4
  use_timecop
@@ -8,8 +8,11 @@ describe "standard_activerecord_with_expires", adapter: :ActiveRecord do
8
8
  table: 'standard_activerecord_with_expires',
9
9
  connection: {
10
10
  adapter: (defined?(JRUBY_VERSION) ? 'jdbcmysql' : 'mysql2'),
11
+ host: mysql_host,
12
+ port: mysql_port,
11
13
  database: mysql_database1,
12
- username: mysql_username
14
+ username: mysql_username,
15
+ password: mysql_password
13
16
  },
14
17
  expires: true
15
18
  }
@@ -23,7 +23,7 @@ describe 'adapter_activesupportcache', adapter: :ActiveSupportCache do
23
23
  include_examples :adapter_activesupportcache
24
24
  end
25
25
 
26
- context 'using MemCacheStore' do
26
+ context 'using MemCacheStore', memcached: true do
27
27
  let(:t_res) { 1 }
28
28
  let(:min_ttl) { 2 }
29
29
  use_timecop
@@ -34,12 +34,12 @@ describe 'adapter_activesupportcache', adapter: :ActiveSupportCache do
34
34
  include_examples :adapter_activesupportcache
35
35
  end
36
36
 
37
- context 'using RedisCacheStore' do
37
+ context 'using RedisCacheStore', redis: true do
38
38
  let(:t_res) { 1 }
39
39
  let(:min_ttl) { t_res }
40
40
  use_timecop
41
41
 
42
- let(:backend) { ActiveSupport::Cache::RedisCacheStore.new(url: 'redis:///1') }
42
+ let(:backend) { ActiveSupport::Cache::RedisCacheStore.new(url: "redis://#{redis_host}:#{redis_port}/1") }
43
43
  include_examples :adapter_activesupportcache
44
44
  end
45
45
 
@@ -23,7 +23,7 @@ describe 'adapter_activesupportcache_with_default_expires', adapter: :ActiveSupp
23
23
  include_examples :adapter_activesupportcache_with_default_expires
24
24
  end
25
25
 
26
- context 'using MemCacheStore' do
26
+ context 'using MemCacheStore', memcached: true do
27
27
  let(:t_res) { 1 }
28
28
  let(:min_ttl) { 2 }
29
29
  use_timecop
@@ -39,7 +39,7 @@ describe 'adapter_activesupportcache_with_default_expires', adapter: :ActiveSupp
39
39
  let(:min_ttl) { t_res }
40
40
  use_timecop
41
41
 
42
- let(:backend) { ActiveSupport::Cache::RedisCacheStore.new(url: 'redis:///2') }
42
+ let(:backend) { ActiveSupport::Cache::RedisCacheStore.new(url: "redis://#{redis_host}:#{redis_port}/2") }
43
43
  include_examples :adapter_activesupportcache_with_default_expires
44
44
  end
45
45
 
@@ -1,22 +1,32 @@
1
- describe 'adapter_datamapper', broken: defined?(JRUBY_VERSION), adapter: :DataMapper do
1
+ describe 'adapter_datamapper', broken: defined?(JRUBY_VERSION), adapter: :DataMapper, mysql: true do
2
2
  before :all do
3
3
  require 'dm-core'
4
4
 
5
5
  # DataMapper needs default repository to be setup
6
6
  DataMapper.setup(:default, adapter: :in_memory)
7
7
  end
8
-
8
+
9
9
  moneta_build do
10
- Moneta::Adapters::DataMapper.new(setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}", table: "adapter_datamapper")
10
+ Moneta::Adapters::DataMapper.new(
11
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
12
+ table: "adapter_datamapper"
13
+ )
11
14
  end
12
15
 
13
16
  moneta_specs ADAPTER_SPECS.without_increment.with_values(:nil).without_values(:binary)
14
-
17
+
15
18
  it 'does not cross contaminate when storing' do
16
- first = Moneta::Adapters::DataMapper.new(setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}", table: "datamapper_first")
19
+ first = Moneta::Adapters::DataMapper.new(
20
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
21
+ table: "datamapper_first"
22
+ )
17
23
  first.clear
18
24
 
19
- second = Moneta::Adapters::DataMapper.new(repository: :sample, setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}", table: "datamapper_second")
25
+ second = Moneta::Adapters::DataMapper.new(
26
+ repository: :sample,
27
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
28
+ table: "datamapper_second"
29
+ )
20
30
  second.clear
21
31
 
22
32
  first['key'] = 'value'
@@ -27,10 +37,17 @@ describe 'adapter_datamapper', broken: defined?(JRUBY_VERSION), adapter: :DataMa
27
37
  end
28
38
 
29
39
  it 'does not cross contaminate when deleting' do
30
- first = Moneta::Adapters::DataMapper.new(setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}", table: "datamapper_first")
40
+ first = Moneta::Adapters::DataMapper.new(
41
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
42
+ table: "datamapper_first"
43
+ )
31
44
  first.clear
32
45
 
33
- second = Moneta::Adapters::DataMapper.new(repository: :sample, setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}", table: "datamapper_second")
46
+ second = Moneta::Adapters::DataMapper.new(
47
+ repository: :sample,
48
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
49
+ table: "datamapper_second"
50
+ )
34
51
  second.clear
35
52
 
36
53
  first['key'] = 'value'
@@ -1,4 +1,4 @@
1
- describe "standard_datamapper", broken: defined?(JRUBY_VERSION), adapter: :DataMapper do
1
+ describe "standard_datamapper", broken: defined?(JRUBY_VERSION), adapter: :DataMapper, mysql: true do
2
2
  before :all do
3
3
  require 'dm-core'
4
4
 
@@ -8,7 +8,7 @@ describe "standard_datamapper", broken: defined?(JRUBY_VERSION), adapter: :DataM
8
8
 
9
9
  moneta_store :DataMapper do
10
10
  {
11
- setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}",
11
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
12
12
  table: "simple_datamapper"
13
13
  }
14
14
  end
@@ -1,4 +1,4 @@
1
- describe "standard_datamapper_with_expires", broken: defined?(JRUBY_VERSION), adapter: :DataMapper do
1
+ describe "standard_datamapper_with_expires", broken: defined?(JRUBY_VERSION), adapter: :DataMapper, mysql: true do
2
2
  let(:t_res) { 0.125 }
3
3
  let(:min_ttl) { t_res }
4
4
  use_timecop
@@ -12,7 +12,7 @@ describe "standard_datamapper_with_expires", broken: defined?(JRUBY_VERSION), ad
12
12
 
13
13
  moneta_store :DataMapper do
14
14
  {
15
- setup: "mysql://#{mysql_username}:#{mysql_password}@localhost/#{mysql_database1}",
15
+ setup: "mysql://#{mysql_username}:#{mysql_password}@#{mysql_host}:#{mysql_port}/#{mysql_database1}",
16
16
  table: "simple_datamapper_with_expires",
17
17
  expires: true
18
18
  }