moneta 0.7.9 → 0.7.10

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.
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