moneta 0.7.9 → 0.7.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.travis.yml +2 -2
  2. data/CHANGES +6 -0
  3. data/Gemfile +2 -0
  4. data/README.md +7 -4
  5. data/Rakefile +2 -2
  6. data/lib/moneta.rb +1 -0
  7. data/lib/moneta/adapters/activerecord.rb +1 -2
  8. data/lib/moneta/adapters/cassandra.rb +31 -26
  9. data/lib/moneta/adapters/cookie.rb +2 -2
  10. data/lib/moneta/adapters/couch.rb +5 -3
  11. data/lib/moneta/adapters/daybreak.rb +13 -9
  12. data/lib/moneta/adapters/dbm.rb +7 -3
  13. data/lib/moneta/adapters/file.rb +4 -3
  14. data/lib/moneta/adapters/fog.rb +5 -2
  15. data/lib/moneta/adapters/gdbm.rb +7 -3
  16. data/lib/moneta/adapters/hbase.rb +11 -9
  17. data/lib/moneta/adapters/kyotocabinet.rb +13 -8
  18. data/lib/moneta/adapters/leveldb.rb +9 -5
  19. data/lib/moneta/adapters/localmemcache.rb +7 -3
  20. data/lib/moneta/adapters/memcached/dalli.rb +16 -11
  21. data/lib/moneta/adapters/memcached/native.rb +20 -15
  22. data/lib/moneta/adapters/memory.rb +2 -1
  23. data/lib/moneta/adapters/mongo.rb +13 -8
  24. data/lib/moneta/adapters/pstore.rb +24 -21
  25. data/lib/moneta/adapters/redis.rb +14 -12
  26. data/lib/moneta/adapters/restclient.rb +10 -7
  27. data/lib/moneta/adapters/riak.rb +5 -1
  28. data/lib/moneta/adapters/sdbm.rb +7 -3
  29. data/lib/moneta/adapters/sequel.rb +13 -8
  30. data/lib/moneta/adapters/sqlite.rb +15 -10
  31. data/lib/moneta/adapters/tdb.rb +8 -4
  32. data/lib/moneta/adapters/tokyocabinet.rb +15 -10
  33. data/lib/moneta/adapters/tokyotyrant.rb +107 -0
  34. data/lib/moneta/cache.rb +17 -17
  35. data/lib/moneta/mixins.rb +7 -5
  36. data/lib/moneta/version.rb +1 -1
  37. data/lib/rack/moneta_store.rb +1 -1
  38. data/lib/rack/session/moneta.rb +6 -3
  39. data/script/benchmarks +28 -28
  40. data/script/generate-specs +96 -41
  41. data/script/memusage +40 -0
  42. data/script/start-services +1 -0
  43. data/spec/helper.rb +4 -1
  44. data/spec/moneta/adapter_tokyotyrant_spec.rb +30 -0
  45. data/spec/moneta/cache_file_memory_spec.rb +3 -3
  46. data/spec/moneta/cache_memory_null_spec.rb +1 -1
  47. data/spec/moneta/simple_tokyotyrant_spec.rb +155 -0
  48. data/spec/moneta/simple_tokyotyrant_with_expires_spec.rb +157 -0
  49. data/spec/monetaspecs.rb +79 -37
  50. data/spec/rack/moneta_store_spec.rb +1 -1
  51. data/spec/rack/session_moneta_spec.rb +27 -0
  52. metadata +10 -3
@@ -257,29 +257,31 @@ module Moneta
257
257
 
258
258
  # @api private
259
259
  module HashAdapter
260
+ attr_reader :backend
261
+
260
262
  # (see Proxy#key?)
261
263
  def key?(key, options = {})
262
- @hash.has_key?(key)
264
+ @backend.has_key?(key)
263
265
  end
264
266
 
265
267
  # (see Proxy#load)
266
268
  def load(key, options = {})
267
- @hash[key]
269
+ @backend[key]
268
270
  end
269
271
 
270
272
  # (see Proxy#store)
271
273
  def store(key, value, options = {})
272
- @hash[key] = value
274
+ @backend[key] = value
273
275
  end
274
276
 
275
277
  # (see Proxy#delete)
276
278
  def delete(key, options = {})
277
- @hash.delete(key)
279
+ @backend.delete(key)
278
280
  end
279
281
 
280
282
  # (see Proxy#clear)
281
283
  def clear(options = {})
282
- @hash.clear
284
+ @backend.clear
283
285
  self
284
286
  end
285
287
  end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '0.7.9'
4
+ VERSION = '0.7.10'
5
5
  end
@@ -38,7 +38,7 @@ module Rack
38
38
  end
39
39
 
40
40
  def call(env)
41
- env['rack.moneta_store'] = @cache ? ::Moneta::Cache.new(:cache => ::Moneta::Adapters::Memory.new, :backend => @store) : @store
41
+ env['rack.moneta_store'] = @cache ? ::Moneta::Cache.new(:cache => ::Moneta::Adapters::Memory.new, :adapter => @store) : @store
42
42
  @app.call(env)
43
43
  end
44
44
  end
@@ -17,6 +17,7 @@ module Rack
17
17
  raise ArgumentError, 'Block or option :store is required' unless @pool = options[:store]
18
18
  @pool = ::Moneta.new(@pool, :expires => true) if Symbol === @pool
19
19
  end
20
+ @pool = ::Moneta::WeakCreate.new(@pool) unless @pool.supports?(:create)
20
21
  @mutex = Mutex.new
21
22
  end
22
23
 
@@ -30,8 +31,10 @@ module Rack
30
31
  def get_session(env, sid)
31
32
  with_lock(env) do
32
33
  unless sid && session = @pool[sid]
33
- sid, session = generate_sid, {}
34
- @pool[sid] = session
34
+ session = {}
35
+ begin
36
+ sid = generate_sid
37
+ end until @pool.create(sid, session)
35
38
  end
36
39
  [sid, session]
37
40
  end
@@ -40,7 +43,7 @@ module Rack
40
43
  def set_session(env, session_id, new_session, options)
41
44
  with_lock(env) do
42
45
  @pool.store(session_id, new_session,
43
- options[:expire_after] ? {:expires => options[:expire_after]} : {})
46
+ options[:expire_after] ? { :expires => options[:expire_after] } : {})
44
47
  session_id
45
48
  end
46
49
  end
@@ -31,10 +31,10 @@ class MonetaBenchmarks
31
31
  FileUtils.mkpath(DIR)
32
32
 
33
33
  STORES = {
34
- # SDBM is unstable
34
+ # SDBM is unstable, the rest is too slow
35
35
  # :SDBM => { :file => "#{DIR}/sdbm" },
36
- # YAML is so fucking slow
37
36
  # :YAML => { :file => "#{DIR}/yaml" },
37
+ # :RestClient => { :url => 'http://localhost:8808/' },
38
38
  :ActiveRecord => { :connection => { :adapter => 'sqlite3', :database => ':memory:' } },
39
39
  :Cassandra => {},
40
40
  :Client => {},
@@ -56,12 +56,12 @@ class MonetaBenchmarks
56
56
  :Mongo => {},
57
57
  :PStore => { :file => "#{DIR}/pstore" },
58
58
  :Redis => {},
59
- :RestClient => { :url => 'http://localhost:8808/' },
60
59
  :Riak => {},
61
60
  :Sequel => { :db => 'sqlite:/' },
62
61
  :Sqlite => { :file => ':memory:' },
63
62
  :TDB => { :file => "#{DIR}/tdb" },
64
63
  :TokyoCabinet => { :file => 'tokyocabinet' },
64
+ :TokyoTyrant => {},
65
65
  }
66
66
 
67
67
  CONFIGS = {
@@ -188,31 +188,31 @@ class MonetaBenchmarks
188
188
  end
189
189
  end
190
190
 
191
- parallel do
192
- begin
193
- require 'rack'
194
- require 'webrick'
195
- require 'rack/moneta_rest'
196
-
197
- # Keep webrick quiet
198
- ::WEBrick::HTTPServer.class_eval do
199
- def access_log(config, req, res); end
200
- end
201
- ::WEBrick::BasicLog.class_eval do
202
- def log(level, data); end
203
- end
204
-
205
- Rack::Server.start(:app => Rack::Builder.app do
206
- use Rack::Lint
207
- run Rack::MonetaRest.new(:store => :Memory)
208
- end,
209
- :environment => :none,
210
- :server => :webrick,
211
- :Port => 8808)
212
- rescue Exception => ex
213
- puts "\e[31mFailed to start Rack server - #{ex.message}\e[0m"
214
- end
215
- end
191
+ # parallel do
192
+ # begin
193
+ # require 'rack'
194
+ # require 'webrick'
195
+ # require 'rack/moneta_rest'
196
+
197
+ # # Keep webrick quiet
198
+ # ::WEBrick::HTTPServer.class_eval do
199
+ # def access_log(config, req, res); end
200
+ # end
201
+ # ::WEBrick::BasicLog.class_eval do
202
+ # def log(level, data); end
203
+ # end
204
+
205
+ # Rack::Server.start(:app => Rack::Builder.app do
206
+ # use Rack::Lint
207
+ # run Rack::MonetaRest.new(:store => :Memory)
208
+ # end,
209
+ # :environment => :none,
210
+ # :server => :webrick,
211
+ # :Port => 8808)
212
+ # rescue Exception => ex
213
+ # puts "\e[31mFailed to start Rack server - #{ex.message}\e[0m"
214
+ # end
215
+ # end
216
216
 
217
217
  sleep 1 # Wait for servers
218
218
  end
@@ -330,6 +330,15 @@ end
330
330
  :options => ':file => File.join(make_tempdir, "simple_tokyocabinet_with_expires"), :expires => true',
331
331
  :specs => STANDARD_SPECS.without_multiprocess.with_expires
332
332
  },
333
+ 'simple_tokyotyrant' => {
334
+ :store => :TokyoTyrant,
335
+ :specs => STANDARD_SPECS
336
+ },
337
+ 'simple_tokyotyrant_with_expires' => {
338
+ :store => :TokyoTyrant,
339
+ :options => ':expires => true',
340
+ :specs => STANDARD_SPECS.with_expires
341
+ },
333
342
  'simple_kyotocabinet' => {
334
343
  :store => :KyotoCabinet,
335
344
  :options => ':file => File.join(make_tempdir, "simple_kyotocabinet.kch")',
@@ -545,18 +554,18 @@ end},
545
554
  'cache_file_memory' => {
546
555
  :build => %{Moneta.build do
547
556
  use(:Cache) do
548
- backend { adapter :File, :dir => File.join(make_tempdir, "cache_file_memory") }
557
+ adapter { adapter :File, :dir => File.join(make_tempdir, "cache_file_memory") }
549
558
  cache { adapter :Memory }
550
559
  end
551
560
  end},
552
561
  :specs => ADAPTER_SPECS.returnsame,
553
562
  :tests => %{
554
563
  it 'stores loaded values in cache' do
555
- store.backend['foo'] = 'bar'
564
+ store.adapter['foo'] = 'bar'
556
565
  store.cache['foo'].should be_nil
557
566
  store['foo'].should == 'bar'
558
567
  store.cache['foo'].should == 'bar'
559
- store.backend.delete('foo')
568
+ store.adapter.delete('foo')
560
569
  store['foo'].should == 'bar'
561
570
  store.delete('foo')
562
571
  store['foo'].should be_nil
@@ -566,7 +575,7 @@ end
566
575
  'cache_memory_null' => {
567
576
  :build => %{Moneta.build do
568
577
  use(:Cache) do
569
- backend(Moneta::Adapters::Memory.new)
578
+ adapter(Moneta::Adapters::Memory.new)
570
579
  cache(Moneta::Adapters::Null.new)
571
580
  end
572
581
  end},
@@ -1301,6 +1310,10 @@ end}
1301
1310
  :build => 'Moneta::Adapters::TokyoCabinet.new(:file => File.join(make_tempdir, "adapter_tokyocabinet_hdb"), :type => :hdb)',
1302
1311
  :specs => ADAPTER_SPECS.without_multiprocess
1303
1312
  },
1313
+ 'adapter_tokyotyrant' => {
1314
+ :build => 'Moneta::Adapters::TokyoTyrant.new',
1315
+ :specs => ADAPTER_SPECS
1316
+ },
1304
1317
  'adapter_yaml' => {
1305
1318
  :build => 'Moneta::Adapters::YAML.new(:file => File.join(make_tempdir, "adapter_yaml"))',
1306
1319
  :specs => STANDARD_SPECS.simplevalues_only.simplekeys_only.without_transform
@@ -1705,146 +1718,188 @@ SPECS['multiprocess'] = %{it 'supports access by multiple instances/processes' d
1705
1718
  store2.close
1706
1719
  end}
1707
1720
 
1708
- SPECS['expires'] = %{it 'supports expires on store and #[]' do
1709
- store.store('key1', 'val1', :expires => 2)
1721
+ SPECS['expires'] = %{it 'supports expires on store and []', :retry => 3 do
1722
+ store.store('key1', 'val1', :expires => 3)
1710
1723
  store['key1'].should == 'val1'
1711
1724
  sleep 1
1712
1725
  store['key1'].should == 'val1'
1713
- sleep 2
1726
+ sleep 3
1714
1727
  store['key1'].should be_nil
1715
1728
  end
1716
1729
 
1717
- it 'supports 0 as no-expires on store and #[]' do
1730
+ it 'supports strict expires on store and []' do
1731
+ store.store('key1', 'val1', :expires => 2)
1732
+ store['key1'].should == 'val1'
1733
+ sleep 3 # Sleep 3 seconds because after 2 seconds the value can still exist!
1734
+ store['key1'].should be_nil
1735
+ end
1736
+
1737
+ it 'supports expires on store and fetch', :retry => 3 do
1738
+ store.store('key1', 'val1', :expires => 3)
1739
+ store.fetch('key1').should == 'val1'
1740
+ sleep 1
1741
+ store.fetch('key1').should == 'val1'
1742
+ sleep 3
1743
+ store.fetch('key1').should be_nil
1744
+ end
1745
+
1746
+ it 'supports strict expires on store and fetch' do
1747
+ store.store('key1', 'val1', :expires => 2)
1748
+ store.fetch('key1').should == 'val1'
1749
+ sleep 3 # Sleep 3 seconds because after 2 seconds the value can still exist!
1750
+ store.fetch('key1').should be_nil
1751
+ end
1752
+
1753
+ it 'supports 0 as no-expires on store and []' do
1718
1754
  store.store('key1', 'val1', :expires => 0)
1719
1755
  store['key1'].should == 'val1'
1720
1756
  sleep 2
1721
1757
  store['key1'].should == 'val1'
1722
1758
  end
1723
1759
 
1724
- it 'supports false as no-expires on store and #[]' do
1760
+ it 'supports false as no-expires on store and []' do
1725
1761
  store.store('key1', 'val1', :expires => false)
1726
1762
  store['key1'].should == 'val1'
1727
1763
  sleep 2
1728
1764
  store['key1'].should == 'val1'
1729
1765
  end
1730
1766
 
1731
- it 'supports expires on store and load' do
1732
- store.store('key1', 'val1', :expires => 2)
1767
+ it 'supports expires on store and load', :retry => 3 do
1768
+ store.store('key1', 'val1', :expires => 3)
1733
1769
  store.load('key1').should == 'val1'
1734
1770
  sleep 1
1735
1771
  store.load('key1').should == 'val1'
1736
- sleep 2
1772
+ sleep 3
1737
1773
  store.load('key1').should be_nil
1738
1774
  end
1739
1775
 
1740
- it 'supports expires on store and key?' do
1776
+ it 'supports strict expires on store and load' do
1741
1777
  store.store('key1', 'val1', :expires => 2)
1778
+ store.load('key1').should == 'val1'
1779
+ sleep 3 # Sleep 3 seconds because after 2 seconds the value can still exist!
1780
+ store.load('key1').should be_nil
1781
+ end
1782
+
1783
+ it 'supports expires on store and key?', :retry => 3 do
1784
+ store.store('key1', 'val1', :expires => 3)
1742
1785
  store.key?('key1').should be_true
1743
1786
  sleep 1
1744
1787
  store.key?('key1').should be_true
1745
- sleep 2
1788
+ sleep 3
1746
1789
  store.key?('key1').should be_false
1747
1790
  end
1748
1791
 
1749
- it 'supports updating the expiration time in load' do
1750
- store.store('key2', 'val2', :expires => 2)
1792
+ it 'supports strict expires on store and key?' do
1793
+ store.store('key1', 'val1', :expires => 2)
1794
+ store.key?('key1').should be_true
1795
+ sleep 3 # Sleep 3 seconds because after 2 seconds the value can still exist!
1796
+ store.key?('key1').should be_false
1797
+ end
1798
+
1799
+ it 'supports updating the expiration time in load', :retry => 3 do
1800
+ store.store('key2', 'val2', :expires => 3)
1751
1801
  store['key2'].should == 'val2'
1752
1802
  sleep 1
1753
- store.load('key2', :expires => 3).should == 'val2'
1803
+ store.load('key2', :expires => 5).should == 'val2'
1754
1804
  store['key2'].should == 'val2'
1755
- sleep 2
1805
+ sleep 3
1756
1806
  store['key2'].should == 'val2'
1757
- sleep 2
1807
+ sleep 3
1758
1808
  store['key2'].should be_nil
1759
1809
  end
1760
1810
 
1761
1811
  it 'supports 0 as no-expires in load' do
1762
1812
  store.store('key1', 'val1', :expires => 2)
1763
1813
  store.load('key1', :expires => 0).should == 'val1'
1764
- sleep 2
1814
+ sleep 3
1765
1815
  store.load('key1').should == 'val1'
1766
1816
  end
1767
1817
 
1768
1818
  it 'supports false as no-expires in load' do
1769
1819
  store.store('key1', 'val1', :expires => 2)
1770
1820
  store.load('key1', :expires => false).should == 'val1'
1771
- sleep 2
1821
+ sleep 3
1772
1822
  store.load('key1').should == 'val1'
1773
1823
  end
1774
1824
 
1775
- it 'supports updating the expiration time in key?' do
1776
- store.store('key2', 'val2', :expires => 2)
1825
+ it 'supports updating the expiration time in key?', :retry => 3 do
1826
+ store.store('key2', 'val2', :expires => 3)
1777
1827
  store['key2'].should == 'val2'
1778
1828
  sleep 1
1779
- store.key?('key2', :expires => 3).should be_true
1829
+ store.key?('key2', :expires => 5).should be_true
1780
1830
  store['key2'].should == 'val2'
1781
- sleep 2
1831
+ sleep 3
1782
1832
  store['key2'].should == 'val2'
1783
- sleep 2
1833
+ sleep 3
1784
1834
  store['key2'].should be_nil
1785
1835
  end
1786
1836
 
1787
1837
  it 'supports 0 as no-expires in key?' do
1788
1838
  store.store('key1', 'val1', :expires => 2)
1789
1839
  store.key?('key1', :expires => 0).should be_true
1790
- sleep 2
1840
+ sleep 3
1791
1841
  store['key1'].should == 'val1'
1792
1842
  end
1793
1843
 
1794
1844
  it 'supports false as no-expires in key?' do
1795
1845
  store.store('key1', 'val1', :expires => 2)
1796
1846
  store.key?('key1', :expires => false ).should be_true
1797
- sleep 2
1847
+ sleep 3
1798
1848
  store['key1'].should == 'val1'
1799
1849
  end
1800
1850
 
1801
- it 'supports updating the expiration time in fetch' do
1802
- store.store('key1', 'val1', :expires => 2)
1851
+ it 'supports updating the expiration time in fetch', :retry => 3 do
1852
+ store.store('key1', 'val1', :expires => 3)
1803
1853
  store['key1'].should == 'val1'
1804
1854
  sleep 1
1805
- store.fetch('key1', nil, :expires => 3).should == 'val1'
1855
+ store.fetch('key1', nil, :expires => 5).should == 'val1'
1806
1856
  store['key1'].should == 'val1'
1807
- sleep 2
1857
+ sleep 3
1808
1858
  store['key1'].should == 'val1'
1809
- sleep 2
1859
+ sleep 3
1810
1860
  store['key1'].should be_nil
1811
1861
  end
1812
1862
 
1813
1863
  it 'supports 0 as no-expires in fetch' do
1814
1864
  store.store('key1', 'val1', :expires => 2)
1815
1865
  store.fetch('key1', nil, :expires => 0).should == 'val1'
1816
- sleep 2
1866
+ sleep 3
1817
1867
  store.load('key1').should == 'val1'
1818
1868
  end
1819
1869
 
1820
1870
  it 'supports false as no-expires in fetch' do
1821
1871
  store.store('key1', 'val1', :expires => 2)
1822
1872
  store.fetch('key1', nil, :expires => false).should == 'val1'
1823
- sleep 2
1873
+ sleep 3
1824
1874
  store.load('key1').should == 'val1'
1825
1875
  end
1826
1876
 
1827
- it 'respects expires in delete' do
1877
+ it 'strictly respects expires in delete' do
1828
1878
  store.store('key2', 'val2', :expires => 2)
1829
1879
  store['key2'].should == 'val2'
1880
+ sleep 3 # Sleep 3 seconds because after 2 seconds the value can still exist!
1881
+ store.delete('key2').should be_nil
1882
+ end
1883
+
1884
+ it 'respects expires in delete', :retry => 3 do
1885
+ store.store('key2', 'val2', :expires => 3)
1886
+ store['key2'].should == 'val2'
1830
1887
  sleep 1
1831
1888
  store['key2'].should == 'val2'
1832
- sleep 2
1889
+ sleep 3
1833
1890
  store.delete('key2').should be_nil
1834
1891
  end
1835
1892
 
1836
1893
  it 'supports the #expires syntactic sugar' do
1837
1894
  store.store('persistent_key', 'persistent_value', :expires => 0)
1838
- store.expires(2).store('key2', 'val2')
1839
- store['key2'].should == 'val2'
1840
- sleep 1
1895
+ store.expires(1).store('key2', 'val2')
1841
1896
  store['key2'].should == 'val2'
1842
1897
  sleep 2
1843
1898
  store.delete('key2').should be_nil
1844
1899
  store['persistent_key'].should == 'persistent_value'
1845
1900
  end
1846
1901
 
1847
- it 'supports false as no-expires on store and #[]' do
1902
+ it 'supports false as no-expires on store and []' do
1848
1903
  store.store('key1', 'val1', :expires => false)
1849
1904
  store['key1'].should == 'val1'
1850
1905
  sleep 2
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ def memusage
6
+ `pmap #{$$} | tail -1`[10..-1].strip.to_i
7
+ end
8
+
9
+ def shrink
10
+ last = memusage
11
+ loop do
12
+ GC.start
13
+ sleep 1
14
+ m = memusage
15
+ break if m == last
16
+ last = m
17
+ end
18
+ end
19
+
20
+ $last_memusage = 0
21
+
22
+ def stats
23
+ shrink
24
+ m = memusage
25
+ delta = m - $last_memusage
26
+ $last_memusage = m
27
+ puts "# #{m}K #{delta >= 0 ? '+' : ''}#{delta}K"
28
+ end
29
+
30
+ stats
31
+
32
+ %q{require 'moneta'
33
+ Moneta.new(:Memory)
34
+ Moneta.new(:File, :dir => 'filestore')
35
+ Moneta.new(:MemcachedNative)
36
+ Moneta.new(:MemcachedDalli)}.each_line do |line|
37
+ puts line
38
+ eval(line)
39
+ stats
40
+ end