oria 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.markdown +61 -5
- data/VERSION +1 -1
- data/benchmarks/mysql_table.sql +26 -0
- data/benchmarks/redis_v_oria.rb +33 -0
- data/benchmarks/sequel_v_oria.rb +39 -0
- data/benchmarks/sqlite_v_oria.rb +45 -0
- data/bin/oria +7 -4
- data/lib/oria/server.rb +17 -12
- data/oria.gemspec +17 -7
- metadata +7 -2
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/*
|
data/README.markdown
CHANGED
@@ -3,12 +3,12 @@ Oria
|
|
3
3
|
|
4
4
|
Oria (oh-rye-uh) is an in-memory, Ruby-based Key-Value Store. It's designed to handle moderate amounts of data quickly
|
5
5
|
and easily without causing deployment issues or server headaches. It uses EventMachine to provide a networked interface
|
6
|
-
to a semi-persistent
|
6
|
+
to a semi-persistent store and asynchronously writes the in-memory data to YAML files.
|
7
7
|
|
8
8
|
Installation
|
9
9
|
-
|
10
10
|
|
11
|
-
Oria is
|
11
|
+
Oria is provided as a Gem. Use the following command to install it:
|
12
12
|
|
13
13
|
gem install oria --source http://gemcutter.org
|
14
14
|
|
@@ -41,7 +41,7 @@ untested, so please test it heavily before deploying, and _report any issues you
|
|
41
41
|
Usage
|
42
42
|
-
|
43
43
|
|
44
|
-
Okay, now for the fun part. Oria behaves (mostly) like a Hash - you could say that it responds to 2/3 of @wycats' Moneta
|
44
|
+
Okay, now for the fun part. Oria behaves (mostly) like a Hash - you could say that it responds to 2/3 of [@wycats](http://github.com/wycats)' Moneta
|
45
45
|
plugin. Specifically, it responds to the following Hash methods:
|
46
46
|
|
47
47
|
[]=(value) Set a key to ... something.
|
@@ -117,6 +117,9 @@ Let's try it out:
|
|
117
117
|
Oria.app_key = "my_app_1"
|
118
118
|
Oria[:foo] #=> "bar"
|
119
119
|
|
120
|
+
That's it! I hope you enjoy Oria, and please let me know if you find any issues or have any trouble. As you will no doubt see from
|
121
|
+
the current version information, it's a very young project, and any contribution is welcome.
|
122
|
+
|
120
123
|
Dependencies
|
121
124
|
-
|
122
125
|
|
@@ -127,7 +130,60 @@ It also needs [EventMachine](http://github.com/eventmachine/eventmachine) to do
|
|
127
130
|
UDP sockets, and spent a lifetime on this. But EventMachine is seriously, seriously, seriously awesome, and works very well
|
128
131
|
without me writing an insane amount of code I couldn't write very well anyway. Check it out and see for yourself.
|
129
132
|
|
130
|
-
|
131
|
-
|
133
|
+
Warnings
|
134
|
+
-
|
135
|
+
|
136
|
+
Oria is weak in a few places. First, it forks all over the place with no regard for the consequences. Someday I'm going to upgrade it
|
137
|
+
to use Daemons, but not right now. In general, the forking is dangerous and clumsy.
|
138
|
+
|
139
|
+
Also, Oria's auto-start feature relies on `sleep`. In fact, Oria relies on `sleep` in more than one place. _This is terrible_ and I
|
140
|
+
want to fix it someday. But I also want to get the code out there so people can start breaking it and tell me where it breaks.
|
141
|
+
|
142
|
+
Which means: **please report any problems you have using the [Github issue tracking](http://github.com/flipsasser/oria/issues)!**
|
143
|
+
|
144
|
+
Benchmarks
|
145
|
+
-
|
146
|
+
|
147
|
+
I've run some benchmarks comparing Oria to Redis. It's not pretty:
|
148
|
+
|
149
|
+
user system total real
|
150
|
+
Redis (write): 0.050000 0.020000 0.070000 ( 0.115850)
|
151
|
+
Oria (write): 0.140000 0.110000 0.250000 ( 1.267912)
|
152
|
+
Redis (read): 0.070000 0.020000 0.090000 ( 0.145078)
|
153
|
+
Oria (read): 0.150000 0.110000 0.260000 ( 1.247791)
|
154
|
+
|
155
|
+
As you can see, Oria is about 10x slower than Redis on my development computer. Even worse, if you run the benchmark like so:
|
156
|
+
|
157
|
+
ruby redis_v_oria.rb 10000
|
158
|
+
|
159
|
+
Oria's server will fail to fulfill all of those requests. Scary. Clearly, it needs some serious improvement. Oria will never be
|
160
|
+
as performant as something like Redis - it's not meant to be (plus it's written in Ruby, not C). But it could use some reduction
|
161
|
+
in overhead, and any help is welcome.
|
162
|
+
|
163
|
+
But I knew Oria wouldn't compete with Redis. What about MySQL?
|
164
|
+
|
165
|
+
user system total real
|
166
|
+
MySQL (write): 0.270000 0.030000 0.300000 ( 0.445586)
|
167
|
+
Oria (write): 0.170000 0.120000 0.290000 ( 1.676674)
|
168
|
+
MySQL (read): 0.310000 0.020000 0.330000 ( 0.484944)
|
169
|
+
Oria (read): 0.120000 0.120000 0.240000 ( 1.616851)
|
170
|
+
|
171
|
+
Ew. Oria is consistently about 4x slower than MySQL. But check this out: I removed persistence, and here are the new benchmarks:
|
172
|
+
|
173
|
+
user system total real
|
174
|
+
Redis (write): 0.040000 0.020000 0.060000 ( 0.113882)
|
175
|
+
Oria (write): 0.130000 0.100000 0.230000 ( 0.396776)
|
176
|
+
Redis (read): 0.070000 0.020000 0.090000 ( 0.145068)
|
177
|
+
Oria (read): 0.130000 0.100000 0.230000 ( 0.395410)
|
178
|
+
|
179
|
+
That's getting competitive. How about MySQL?
|
180
|
+
|
181
|
+
user system total real
|
182
|
+
MySQL (write): 0.270000 0.030000 0.300000 ( 0.453413)
|
183
|
+
Oria (write): 0.150000 0.110000 0.260000 ( 0.430725)
|
184
|
+
MySQL (read): 0.320000 0.030000 0.350000 ( 0.484978)
|
185
|
+
Oria (read): 0.100000 0.100000 0.200000 ( 0.373431)
|
186
|
+
|
187
|
+
Oh snap! Oria outperforms MySQL when persistence is disabled. So I'll have to refactor the code.
|
132
188
|
|
133
189
|
Copyright (c) 2009 Flip Sasser, released under the MIT license
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
@@ -0,0 +1,26 @@
|
|
1
|
+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
2
|
+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
3
|
+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
4
|
+
/*!40101 SET NAMES utf8 */;
|
5
|
+
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
6
|
+
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
7
|
+
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
8
|
+
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
9
|
+
|
10
|
+
DROP TABLE IF EXISTS `oria_test`;
|
11
|
+
|
12
|
+
CREATE TABLE `oria_test` (
|
13
|
+
`id` int(11) NOT NULL AUTO_INCREMENT,
|
14
|
+
`key` varchar(32) DEFAULT NULL,
|
15
|
+
`value` varchar(128) DEFAULT NULL,
|
16
|
+
PRIMARY KEY (`id`),
|
17
|
+
UNIQUE KEY `key` (`key`)
|
18
|
+
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
|
19
|
+
|
20
|
+
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
21
|
+
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
22
|
+
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
23
|
+
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
24
|
+
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
25
|
+
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
26
|
+
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'redis'
|
3
|
+
require '../lib/oria'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
redis = Redis.new
|
7
|
+
n = (ARGV.shift || 1000).to_i
|
8
|
+
|
9
|
+
Benchmark.bm(15) do |bm|
|
10
|
+
bm.report("Redis (write):") do
|
11
|
+
n.times do
|
12
|
+
redis['foo'] = 'bar'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
bm.report("Oria (write):") do
|
17
|
+
n.times do
|
18
|
+
Oria['foo'] = 'bar'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
bm.report("Redis (read):") do
|
23
|
+
n.times do
|
24
|
+
foo = redis['foo']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
bm.report("Oria (read):") do
|
29
|
+
n.times do
|
30
|
+
foo = Oria['foo']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sequel'
|
3
|
+
require '../lib/oria'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
DB = Sequel.connect('mysql://root@localhost/oria_test')
|
7
|
+
n = (ARGV.shift || 1000).to_i
|
8
|
+
|
9
|
+
Benchmark.bm(15) do |bm|
|
10
|
+
bm.report("MySQL (write):") do
|
11
|
+
table = DB[:oria_test]
|
12
|
+
n.times do
|
13
|
+
if foo = table[:key => 'foo']
|
14
|
+
foo.update(:value => 'bar')
|
15
|
+
else
|
16
|
+
table.insert(:key => 'foo', :value => 'bar')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
bm.report("Oria (write):") do
|
22
|
+
n.times do
|
23
|
+
Oria['foo'] = 'bar'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
bm.report("MySQL (read):") do
|
28
|
+
table = DB[:oria_test]
|
29
|
+
n.times do
|
30
|
+
foo = table[:key => 'foo']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
bm.report("Oria (read):") do
|
35
|
+
n.times do
|
36
|
+
foo = Oria['foo']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sequel'
|
3
|
+
require '../lib/oria'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
DB = Sequel.sqlite
|
7
|
+
DB.create_table :oria_test do
|
8
|
+
primary_key :id
|
9
|
+
String :key
|
10
|
+
String :value
|
11
|
+
end
|
12
|
+
|
13
|
+
n = (ARGV.shift || 1000).to_i
|
14
|
+
|
15
|
+
Benchmark.bm(16) do |bm|
|
16
|
+
bm.report("SQLite3 (write):") do
|
17
|
+
table = DB[:oria_test]
|
18
|
+
n.times do
|
19
|
+
if foo = table[:key => 'foo']
|
20
|
+
foo.update(:value => 'bar')
|
21
|
+
else
|
22
|
+
table.insert(:key => 'foo', :value => 'bar')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
bm.report("Oria (write):") do
|
28
|
+
n.times do
|
29
|
+
Oria['foo'] = 'bar'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
bm.report("SQLite3 (read):") do
|
34
|
+
table = DB[:oria_test]
|
35
|
+
n.times do
|
36
|
+
foo = table[:key => 'foo']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
bm.report("Oria (read):") do
|
41
|
+
n.times do
|
42
|
+
foo = Oria['foo']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/bin/oria
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'optparse'
|
3
|
-
|
4
|
-
|
5
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'oria'))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'oria'
|
5
|
+
# require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'oria'))
|
6
6
|
|
7
7
|
module OriaCommand
|
8
8
|
def self.go
|
@@ -15,7 +15,7 @@ module OriaCommand
|
|
15
15
|
stop
|
16
16
|
start
|
17
17
|
else
|
18
|
-
puts parser
|
18
|
+
puts parser
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -29,6 +29,9 @@ module OriaCommand
|
|
29
29
|
opts.on('-h', '--host [IP]', 'The hostname or IP Oria should listen on.') do |host|
|
30
30
|
@options[:host] = port
|
31
31
|
end
|
32
|
+
opts.on('-d', '--debug', 'Log output to /tmp/oria.log') do |debug|
|
33
|
+
@options[:debug] = true
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
data/lib/oria/server.rb
CHANGED
@@ -3,10 +3,16 @@ require 'tmpdir'
|
|
3
3
|
module Oria
|
4
4
|
class Server < EventMachine::Connection
|
5
5
|
class << self
|
6
|
+
@@timer = nil
|
7
|
+
|
6
8
|
def debug?
|
7
9
|
@@debug
|
8
10
|
end
|
9
11
|
|
12
|
+
def log(value, app_key = nil)
|
13
|
+
logger.debug("#{"#{app_key}: " if app_key}#{value}") if debug?
|
14
|
+
end
|
15
|
+
|
10
16
|
def logger
|
11
17
|
require 'logger'
|
12
18
|
@@logger ||= Logger.new(log_file, 0, 100 * 1024 * 1024)
|
@@ -42,11 +48,14 @@ module Oria
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
|
-
def
|
46
|
-
@@
|
51
|
+
def store_hash(app_key)
|
52
|
+
@@timer.cancel if @@timer
|
53
|
+
@@timer = EventMachine::Timer.new(10) do
|
54
|
+
log "Writing changes to disk", app_key
|
47
55
|
File.open(yaml_store, 'w') do |store|
|
48
56
|
store.puts YAML.dump(@@servers)
|
49
57
|
end
|
58
|
+
@@timer = nil
|
50
59
|
end
|
51
60
|
end
|
52
61
|
|
@@ -69,11 +78,11 @@ module Oria
|
|
69
78
|
end
|
70
79
|
|
71
80
|
def post_init
|
72
|
-
log "Client connected"
|
81
|
+
Oria::Server.log "Client connected"
|
73
82
|
end
|
74
83
|
|
75
84
|
def receive_data(data)
|
76
|
-
log "Responding to #{data}"
|
85
|
+
Oria::Server.log "Responding to #{data}"
|
77
86
|
data = data.split(' ')
|
78
87
|
method = data.shift
|
79
88
|
data = JSON.parse(data.join(' '))
|
@@ -98,10 +107,12 @@ module Oria
|
|
98
107
|
end
|
99
108
|
if defined?(response)
|
100
109
|
response = JSON.generate({:response => response})
|
101
|
-
log "Sending response: #{response}"
|
110
|
+
Oria::Server.log "Sending response: #{response}"
|
111
|
+
Oria::Server.store_hash(@app_key)
|
102
112
|
send_data response
|
103
113
|
end
|
104
|
-
|
114
|
+
rescue JSON::ParserError
|
115
|
+
send_data "Invalid request"
|
105
116
|
end
|
106
117
|
|
107
118
|
def unbind
|
@@ -112,12 +123,6 @@ module Oria
|
|
112
123
|
@hash ||= @@servers[@app_key || 'default'] ||= {}
|
113
124
|
end
|
114
125
|
|
115
|
-
def log(value)
|
116
|
-
if Oria::Server.debug?
|
117
|
-
Oria::Server.logger.debug(value)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
126
|
def random_key
|
122
127
|
chars = ['a'..'z', 'A'..'Z', 0..9].map(&:to_a).flatten
|
123
128
|
max = [hash.length, 2].max
|
data/oria.gemspec
CHANGED
@@ -5,13 +5,17 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{oria}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Flip Sasser"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-23}
|
13
13
|
s.default_executable = %q{oria}
|
14
|
-
s.description = %q{
|
14
|
+
s.description = %q{
|
15
|
+
Oria (oh-rye-uh) is an in-memory, Ruby-based Key-Value store. It's designed to handle moderate amounts of data quickly
|
16
|
+
and easily without causing deployment issues or server headaches. It uses EventMachine to provide a networked interface
|
17
|
+
to a semi-persistent KVS and asynchronously writes the in-memory data to YAML files.
|
18
|
+
}
|
15
19
|
s.email = %q{flip@x451.com}
|
16
20
|
s.executables = ["oria"]
|
17
21
|
s.extra_rdoc_files = [
|
@@ -19,15 +23,21 @@ Gem::Specification.new do |s|
|
|
19
23
|
"README.markdown"
|
20
24
|
]
|
21
25
|
s.files = [
|
22
|
-
"
|
26
|
+
".gitignore",
|
27
|
+
"LICENSE",
|
23
28
|
"README.markdown",
|
24
29
|
"Rakefile",
|
25
30
|
"VERSION",
|
31
|
+
"benchmarks/mysql_table.sql",
|
32
|
+
"benchmarks/redis_v_oria.rb",
|
33
|
+
"benchmarks/sequel_v_oria.rb",
|
34
|
+
"benchmarks/sqlite_v_oria.rb",
|
26
35
|
"bin/oria",
|
27
36
|
"lib/oria.rb",
|
28
37
|
"lib/oria/client.rb",
|
29
38
|
"lib/oria/errors.rb",
|
30
39
|
"lib/oria/server.rb",
|
40
|
+
"oria.gemspec",
|
31
41
|
"spec/oria_spec.rb",
|
32
42
|
"spec/rcov.opts",
|
33
43
|
"spec/spec.opts",
|
@@ -49,14 +59,14 @@ Gem::Specification.new do |s|
|
|
49
59
|
|
50
60
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
61
|
s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
|
52
|
-
s.add_runtime_dependency(%q<json>, [">= 2.0
|
62
|
+
s.add_runtime_dependency(%q<json>, [">= 1.2.0"])
|
53
63
|
else
|
54
64
|
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
55
|
-
s.add_dependency(%q<json>, [">= 2.0
|
65
|
+
s.add_dependency(%q<json>, [">= 1.2.0"])
|
56
66
|
end
|
57
67
|
else
|
58
68
|
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
59
|
-
s.add_dependency(%q<json>, [">= 2.0
|
69
|
+
s.add_dependency(%q<json>, [">= 1.2.0"])
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oria
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Flip Sasser
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-23 00:00:00 -05:00
|
13
13
|
default_executable: oria
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,10 +42,15 @@ extra_rdoc_files:
|
|
42
42
|
- LICENSE
|
43
43
|
- README.markdown
|
44
44
|
files:
|
45
|
+
- .gitignore
|
45
46
|
- LICENSE
|
46
47
|
- README.markdown
|
47
48
|
- Rakefile
|
48
49
|
- VERSION
|
50
|
+
- benchmarks/mysql_table.sql
|
51
|
+
- benchmarks/redis_v_oria.rb
|
52
|
+
- benchmarks/sequel_v_oria.rb
|
53
|
+
- benchmarks/sqlite_v_oria.rb
|
49
54
|
- bin/oria
|
50
55
|
- lib/oria.rb
|
51
56
|
- lib/oria/client.rb
|