juno 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +2 -5
- data/Gemfile +21 -8
- data/README.md +3 -1
- data/{unsupported/benchmarks.rb → benchmarks/run.rb} +20 -83
- data/lib/juno.rb +4 -4
- data/lib/juno/activerecord.rb +2 -5
- data/lib/juno/base.rb +4 -0
- data/{unsupported → lib/juno}/cassandra.rb +11 -11
- data/lib/juno/datamapper.rb +1 -1
- data/{unsupported → lib/juno}/fog.rb +7 -19
- data/lib/juno/null.rb +23 -0
- data/lib/juno/redis.rb +13 -1
- data/lib/juno/sequel.rb +3 -6
- data/lib/juno/stack.rb +41 -0
- data/lib/juno/version.rb +1 -1
- data/test/helper.rb +160 -130
- data/test/{test_active_record.rb → test_activerecord.rb} +2 -5
- data/{unsupported → test}/test_cassandra.rb +1 -1
- data/test/test_couch.rb +1 -1
- data/test/test_datamapper.rb +2 -2
- data/test/test_dbm.rb +1 -1
- data/test/test_expires.rb +1 -2
- data/test/test_file.rb +1 -1
- data/test/test_fog.rb +17 -0
- data/test/test_gdbm.rb +1 -1
- data/test/test_hashfile.rb +1 -1
- data/test/test_localmemcache.rb +1 -1
- data/test/test_memcached.rb +1 -2
- data/test/test_memcached_dalli.rb +1 -2
- data/test/test_memcached_native.rb +1 -2
- data/test/test_memory.rb +1 -1
- data/test/test_mongodb.rb +1 -1
- data/test/test_null.rb +9 -0
- data/test/test_proxy.rb +1 -1
- data/test/test_pstore.rb +1 -1
- data/test/test_redis.rb +1 -1
- data/test/test_riak.rb +1 -1
- data/test/test_sdbm.rb +1 -1
- data/test/test_sequel.rb +4 -4
- data/test/test_sqlite.rb +1 -1
- data/test/test_stack.rb +10 -0
- data/test/test_tokyocabinet.rb +1 -1
- data/test/test_yaml.rb +1 -1
- metadata +20 -13
- data/unsupported/test_rackspace.rb +0 -15
- data/unsupported/test_s3.rb +0 -15
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,7 +2,7 @@ rvm:
|
|
2
2
|
- 1.8.7
|
3
3
|
- 1.9.3
|
4
4
|
# - ruby-head
|
5
|
-
|
5
|
+
- jruby
|
6
6
|
- rbx-18mode
|
7
7
|
- rbx-19mode
|
8
8
|
services:
|
@@ -18,8 +18,5 @@ before_install:
|
|
18
18
|
- memcached -d -p 22122
|
19
19
|
matrix:
|
20
20
|
allow_failures:
|
21
|
-
- rvm: 1.8.7
|
22
21
|
# - rvm: ruby-head
|
23
|
-
- rvm:
|
24
|
-
- rvm: rbx-19mode
|
25
|
-
|
22
|
+
- rvm: jruby
|
data/Gemfile
CHANGED
@@ -1,19 +1,32 @@
|
|
1
1
|
source :rubygems
|
2
2
|
gemspec
|
3
3
|
|
4
|
+
if RUBY_VERSION > '1.9'
|
5
|
+
# HACK - Juno::DataMapper and CouchRest don't work currently on 1.8
|
6
|
+
gem 'datamapper'
|
7
|
+
gem 'dm-sqlite-adapter'
|
8
|
+
gem 'couchrest'
|
9
|
+
end
|
10
|
+
|
11
|
+
gem 'fog'
|
4
12
|
gem 'activerecord'
|
5
|
-
gem 'sqlite3'
|
6
13
|
gem 'redis'
|
7
|
-
gem 'datamapper'
|
8
|
-
gem 'dm-sqlite-adapter'
|
9
|
-
gem 'ripple'
|
10
|
-
gem 'tokyocabinet'
|
11
14
|
gem 'mongo'
|
12
|
-
gem 'couchrest'
|
13
15
|
gem 'sequel'
|
14
16
|
gem 'dalli'
|
15
|
-
gem '
|
17
|
+
gem 'json' # Ripple/Riak needs json
|
18
|
+
gem 'ripple'
|
19
|
+
|
20
|
+
if defined?(JRUBY_VERSION)
|
21
|
+
gem 'jdbc-sqlite3'
|
22
|
+
gem 'activerecord-jdbc-adapter'
|
23
|
+
gem 'activerecord-jdbcsqlite3-adapter'
|
24
|
+
else
|
25
|
+
gem 'tokyocabinet'
|
26
|
+
gem 'memcached'
|
27
|
+
gem 'sqlite3'
|
28
|
+
end
|
29
|
+
|
16
30
|
#gem 'cassandra'
|
17
31
|
#gem 'localmemcache'
|
18
|
-
#gem 'fog'
|
19
32
|
#gem 'tokyotyrant'
|
data/README.md
CHANGED
@@ -27,6 +27,8 @@ Out of the box, it supports:
|
|
27
27
|
* LocalMemCache
|
28
28
|
* Sequel
|
29
29
|
* Sqlite3
|
30
|
+
* Fog cloud storage (Amazon S3, Rackspace, ...)
|
31
|
+
* Cassandra
|
30
32
|
|
31
33
|
The Juno API is purposely extremely similar to the Hash API. In order so support an
|
32
34
|
identical API across stores, it does not support iteration or partial matches.
|
@@ -61,7 +63,7 @@ The API
|
|
61
63
|
Proxy store & Expiry
|
62
64
|
====================
|
63
65
|
|
64
|
-
The memcached
|
66
|
+
The memcached and redis backends supports expires values directly:
|
65
67
|
|
66
68
|
```ruby
|
67
69
|
cache = Juno::Memcached.new
|
@@ -1,6 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'benchmark'
|
3
|
-
require
|
3
|
+
require 'juno'
|
4
|
+
require 'dm-core'
|
5
|
+
|
6
|
+
DataMapper.setup(:default, :adapter => :in_memory)
|
4
7
|
|
5
8
|
# Hacked arrays
|
6
9
|
# Array modifications
|
@@ -30,27 +33,26 @@ class HackedArray < Array
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
require "../lib/juno"
|
34
|
-
require "juno/memcache"
|
35
|
-
require "juno/tyrant"
|
36
|
-
require "juno/berkeley"
|
37
|
-
|
38
|
-
|
39
36
|
stores = {
|
40
37
|
'Redis' => { },
|
41
|
-
'
|
42
|
-
'
|
43
|
-
'MongoDB' => { :host => 'localhost', :port => 27017, :db => 'juno_bench' },
|
44
|
-
'
|
45
|
-
'
|
46
|
-
'
|
38
|
+
'MemcachedDalli' => { :server => "localhost:11211", :namespace => 'juno_dalli' },
|
39
|
+
'MemcachedNative' => { :server => "localhost:11211", :namespace => 'juno_native' },
|
40
|
+
#'MongoDB' => { :host => 'localhost', :port => 27017, :db => 'juno_bench' },
|
41
|
+
'LocalMemCache' => { :file => "bench.lmc" },
|
42
|
+
'DBM' => { :file => "bench.dbm" },
|
43
|
+
# 'SDBM' => { :file => "bench.sdbm" },
|
44
|
+
'GDBM' => { :file => "bench.gdbm" },
|
45
|
+
'Sqlite' => { :file => ":memory:" },
|
47
46
|
'Memory' => { },
|
47
|
+
'YAML' => { :file => "bench.yaml" },
|
48
|
+
'PStore' => { :file => "bench.pstore" },
|
49
|
+
'File' => { :dir => "bench.file" },
|
50
|
+
'HashFile' => { :dir => "bench.hashfile" },
|
48
51
|
'DataMapper' => { :setup => "sqlite3::memory:" },
|
52
|
+
'ActiveRecord' => { :db => "sqlite:/" },
|
53
|
+
'ActiveRecord' => { :connection => { :adapter => 'sqlite3', :database => ':memory:' } },
|
54
|
+
'Sequel' => { :db => "sqlite:/" },
|
49
55
|
# 'Couch' => {:db => "couch_test"},
|
50
|
-
'TC (Tyrant)' =>
|
51
|
-
{:name => "test.tieredtyrant", :backup => Juno::Tyrant.new(:host => "localhost", :port => 1978), :class_name => "TieredCache"},
|
52
|
-
'TC (Memcached)' =>
|
53
|
-
{:name => "test.tieredmc", :backup => Juno::Memcache.new(:server => "localhost:11211", :namespace => "various"), :class_name => "TieredCache"}
|
54
56
|
}
|
55
57
|
|
56
58
|
stats, keys, data, errors, summary = {}, [], HackedArray.new, HackedArray.new, HackedArray.new
|
@@ -90,66 +92,12 @@ puts " Minimum Maximum Total Average xps "
|
|
90
92
|
puts "----------------------------------------------------------------------"
|
91
93
|
puts "Lenght Stats % 10i % 10i % 10i % 10i " % [vlen_min, vlen_max, vlen_ttl, vlen_avg]
|
92
94
|
|
93
|
-
module Juno
|
94
|
-
class TieredCache
|
95
|
-
include Juno::Defaults
|
96
|
-
|
97
|
-
def initialize(options)
|
98
|
-
@bdb = Juno::Berkeley.new(:file => File.join(File.dirname(__FILE__), options[:name]))
|
99
|
-
@mc = options[:backup]
|
100
|
-
# @mc = Juno::Tyrant.new(:host => "localhost", :port => 1978)
|
101
|
-
# @mc = Juno::Memcache.new(:server => "localhost:11211", :namespace => options[:name])
|
102
|
-
end
|
103
|
-
|
104
|
-
def [](key)
|
105
|
-
val = @bdb[key]
|
106
|
-
unless val
|
107
|
-
@bdb[key] = val if val = @mc[key]
|
108
|
-
end
|
109
|
-
val
|
110
|
-
end
|
111
|
-
|
112
|
-
def []=(key, val)
|
113
|
-
@bdb[key] = val
|
114
|
-
@mc[key] = val
|
115
|
-
end
|
116
|
-
|
117
|
-
def store(key, value, options = {})
|
118
|
-
@bdb.store(key, value, options)
|
119
|
-
@mc.store(key, value, options)
|
120
|
-
end
|
121
|
-
|
122
|
-
def delete(key)
|
123
|
-
bdb_val = @bdb.delete(key)
|
124
|
-
mc_val = @mc.delete(key)
|
125
|
-
bdb_val || mc_val
|
126
|
-
end
|
127
|
-
|
128
|
-
def clear
|
129
|
-
@mc.clear
|
130
|
-
@bdb.clear
|
131
|
-
end
|
132
|
-
|
133
|
-
def update_key(name, options)
|
134
|
-
@mc.update_key(name, options)
|
135
|
-
@bdb.update_key(name, options)
|
136
|
-
end
|
137
|
-
|
138
|
-
def key?(key)
|
139
|
-
@bdb.key?(key) || @mc.key?(key)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
95
|
|
144
96
|
stores.each do |name, options|
|
145
97
|
cname = options.delete(:class_name) || name
|
146
98
|
puts "======================================================================"
|
147
99
|
puts name
|
148
100
|
puts "----------------------------------------------------------------------"
|
149
|
-
begin
|
150
|
-
require "../lib/juno/#{cname.downcase}"
|
151
|
-
rescue LoadError
|
152
|
-
end
|
153
101
|
klass = Juno.const_get(cname)
|
154
102
|
@cache = klass.new(options)
|
155
103
|
stats[name] = {
|
@@ -164,7 +112,7 @@ stores.each do |name, options|
|
|
164
112
|
m1 = Benchmark.measure do
|
165
113
|
n.times do
|
166
114
|
key, value = data.random
|
167
|
-
|
115
|
+
|
168
116
|
@cache[key] = value
|
169
117
|
end
|
170
118
|
end
|
@@ -221,14 +169,3 @@ end
|
|
221
169
|
puts "======================================================================"
|
222
170
|
puts "THE END"
|
223
171
|
puts "======================================================================"
|
224
|
-
|
225
|
-
#======================================================================
|
226
|
-
#Summary :: 3 runs, 1000 keys
|
227
|
-
#======================================================================
|
228
|
-
# Minimum Maximum Total Average xps
|
229
|
-
#----------------------------------------------------------------------
|
230
|
-
#MemcacheDB 0.6202 2.7850 7.0099 1.1683 855.9366
|
231
|
-
#Memcached 0.4483 0.6563 3.3251 0.5542 1804.4385
|
232
|
-
#Redis 0.3282 0.5221 2.2965 0.3828 2612.6444
|
233
|
-
#MongoDB 0.6660 1.0539 5.1667 0.8611 1161.2745
|
234
|
-
#======================================================================
|
data/lib/juno.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
module Juno
|
2
2
|
autoload :ActiveRecord, 'juno/activerecord'
|
3
3
|
autoload :Base, 'juno/base'
|
4
|
-
|
4
|
+
autoload :Cassandra, 'juno/cassandra'
|
5
5
|
autoload :Couch, 'juno/couch'
|
6
6
|
autoload :DataMapper, 'juno/datamapper'
|
7
7
|
autoload :DBM, 'juno/dbm'
|
8
8
|
autoload :Expires, 'juno/expires'
|
9
9
|
autoload :File, 'juno/file'
|
10
|
-
|
11
|
-
#autoload :S3, 'juno/fog'
|
12
|
-
#autoload :Rackspace, 'juno/fog'
|
10
|
+
autoload :Fog, 'juno/fog'
|
13
11
|
autoload :GDBM, 'juno/gdbm'
|
14
12
|
autoload :HashFile, 'juno/hashfile'
|
15
13
|
autoload :LocalMemCache, 'juno/localmemcache'
|
@@ -18,12 +16,14 @@ module Juno
|
|
18
16
|
autoload :MemcachedNative, 'juno/memcached_native'
|
19
17
|
autoload :Memory, 'juno/memory'
|
20
18
|
autoload :MongoDB, 'juno/mongodb'
|
19
|
+
autoload :Null, 'juno/null'
|
21
20
|
autoload :Proxy, 'juno/proxy'
|
22
21
|
autoload :PStore, 'juno/pstore'
|
23
22
|
autoload :Redis, 'juno/redis'
|
24
23
|
autoload :Riak, 'juno/riak'
|
25
24
|
autoload :SDBM, 'juno/sdbm'
|
26
25
|
autoload :Sequel, 'juno/sequel'
|
26
|
+
autoload :Stack, 'juno/stack'
|
27
27
|
autoload :Sqlite, 'juno/sqlite'
|
28
28
|
autoload :TokyoCabinet, 'juno/tokyocabinet'
|
29
29
|
#autoload :TokyoTyrant, 'juno/tokyotyrant'
|
data/lib/juno/activerecord.rb
CHANGED
@@ -16,12 +16,9 @@ module Juno
|
|
16
16
|
c
|
17
17
|
end
|
18
18
|
@table.establish_connection(options[:connection]) if options[:connection]
|
19
|
-
end
|
20
|
-
|
21
|
-
def migrate
|
22
19
|
@table.connection.create_table @table.table_name do |t|
|
23
|
-
t.
|
24
|
-
t.
|
20
|
+
t.binary 'key', :primary => :true
|
21
|
+
t.binary 'value'
|
25
22
|
end unless @table.table_exists?
|
26
23
|
end
|
27
24
|
|
data/lib/juno/base.rb
CHANGED
@@ -9,30 +9,30 @@ module Juno
|
|
9
9
|
options[:keyspace] ||= 'Juno'
|
10
10
|
options[:host] ||= '127.0.0.1'
|
11
11
|
options[:port] ||= 9160
|
12
|
-
@client = ::Cassandra.new(options[:keyspace], "#{options[:host]}:#{options[:port]}")
|
13
12
|
@column_family = options[:column_family] || :Juno
|
13
|
+
@client = ::Cassandra.new(options[:keyspace], "#{options[:host]}:#{options[:port]}")
|
14
14
|
end
|
15
15
|
|
16
16
|
def key?(key, options = {})
|
17
|
-
|
18
|
-
@client.exists?(@column_family, key)
|
17
|
+
@client.exists?(@column_family, key_for(key))
|
19
18
|
end
|
20
19
|
|
21
20
|
def [](key)
|
22
|
-
|
23
|
-
deserialize(
|
21
|
+
value = @client.get(@column_family, key_for(key))
|
22
|
+
value ? deserialize(value['value']) : nil
|
24
23
|
end
|
25
24
|
|
26
25
|
def delete(key, options = {})
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
if value = self[key]
|
27
|
+
@client.remove(@column_family, key_for(key))
|
28
|
+
value
|
29
|
+
end
|
31
30
|
end
|
32
31
|
|
33
32
|
def store(key, value, options = {})
|
34
|
-
|
35
|
-
|
33
|
+
@client.insert(@column_family, key_for(key),
|
34
|
+
{'value' => serialize(value)}, :ttl => options[:expires])
|
35
|
+
value
|
36
36
|
end
|
37
37
|
|
38
38
|
def clear(options = {})
|
data/lib/juno/datamapper.rb
CHANGED
@@ -12,7 +12,7 @@ module Juno
|
|
12
12
|
def initialize(options = {})
|
13
13
|
raise 'No option :setup specified' unless options[:setup]
|
14
14
|
@repository = options.delete(:repository) || :juno
|
15
|
-
Store.storage_names[@repository] = options.delete(:table) || :juno
|
15
|
+
Store.storage_names[@repository] = (options.delete(:table) || :juno).to_s
|
16
16
|
::DataMapper.setup(@repository, options[:setup])
|
17
17
|
context { Store.auto_upgrade! }
|
18
18
|
end
|
@@ -3,13 +3,13 @@ require 'fog'
|
|
3
3
|
module Juno
|
4
4
|
class Fog < Base
|
5
5
|
def initialize(options = {})
|
6
|
-
|
7
|
-
|
8
|
-
@directory =
|
6
|
+
raise 'No option :dir specified' unless dir = options.delete(:dir)
|
7
|
+
storage = ::Fog::Storage.new(options)
|
8
|
+
@directory = storage.directories.create(:key => dir)
|
9
9
|
end
|
10
10
|
|
11
11
|
def key?(key, options = {})
|
12
|
-
|
12
|
+
!!@directory.files.head(key_for(key))
|
13
13
|
end
|
14
14
|
|
15
15
|
def [](key)
|
@@ -21,13 +21,15 @@ module Juno
|
|
21
21
|
def delete(key, options = {})
|
22
22
|
value = get(key)
|
23
23
|
if value
|
24
|
+
body = deserialize(value.body)
|
24
25
|
value.destroy
|
25
|
-
|
26
|
+
body
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
30
|
def store(key, value, options = {})
|
30
31
|
@directory.files.create(:key => key_for(key), :body => serialize(value))
|
32
|
+
value
|
31
33
|
end
|
32
34
|
|
33
35
|
def clear(options = {})
|
@@ -43,18 +45,4 @@ module Juno
|
|
43
45
|
@directory.files.get(key_for(key))
|
44
46
|
end
|
45
47
|
end
|
46
|
-
|
47
|
-
class S3 < Fog
|
48
|
-
def initialize(options = {})
|
49
|
-
options[:cloud] = ::Fog::AWS::S3
|
50
|
-
super
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class Rackspace < Fog
|
55
|
-
def initialize(options = {})
|
56
|
-
options[:cloud] = ::Fog::Rackspace::Files
|
57
|
-
super
|
58
|
-
end
|
59
|
-
end
|
60
48
|
end
|
data/lib/juno/null.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Juno
|
2
|
+
class Null < Base
|
3
|
+
def key?(key, options = {})
|
4
|
+
false
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](key)
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def store(key, value, options = {})
|
12
|
+
value
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(key, options = {})
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear(options = {})
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/juno/redis.rb
CHANGED
@@ -10,6 +10,14 @@ module Juno
|
|
10
10
|
@store.exists(key_for(key))
|
11
11
|
end
|
12
12
|
|
13
|
+
def fetch(key, value = nil, options = {})
|
14
|
+
result = super
|
15
|
+
if result && expires = options[:expires]
|
16
|
+
@store.expire(key_for(key), expires)
|
17
|
+
end
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
13
21
|
def [](key)
|
14
22
|
deserialize(@store.get(key_for(key)))
|
15
23
|
end
|
@@ -22,7 +30,11 @@ module Juno
|
|
22
30
|
end
|
23
31
|
|
24
32
|
def store(key, value, options = {})
|
25
|
-
|
33
|
+
key = key_for(key)
|
34
|
+
@store.set(key, serialize(value))
|
35
|
+
if expires = options[:expires]
|
36
|
+
@store.expire(key, expires)
|
37
|
+
end
|
26
38
|
value
|
27
39
|
end
|
28
40
|
|