juno 0.1.0 → 0.1.1
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.
- 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
|
|