daybreak 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/LICENSE +2 -2
- data/README +1 -3
- data/Rakefile +6 -9
- data/daybreak.gemspec +4 -4
- data/lib/daybreak.rb +3 -5
- data/lib/daybreak/db.rb +308 -114
- data/lib/daybreak/format.rb +52 -0
- data/lib/daybreak/queue.rb +107 -0
- data/lib/daybreak/serializer.rb +39 -0
- data/lib/daybreak/version.rb +3 -2
- data/script/bench +95 -0
- data/script/converter +390 -0
- data/test/test.rb +251 -57
- data/test/test_helper.rb +0 -3
- metadata +12 -11
- data/lib/daybreak/record.rb +0 -62
- data/lib/daybreak/writer.rb +0 -127
- data/test/bench.rb +0 -28
- data/test/compare.rb +0 -47
data/lib/daybreak/writer.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
module Daybreak
|
2
|
-
# Writer's handle the actually fiddly task of committing data to disk.
|
3
|
-
# They have a Worker instance that writes in a select loop.
|
4
|
-
class Writer
|
5
|
-
# Open up the file, ready it for binary and nonblocking writing.
|
6
|
-
def initialize(file)
|
7
|
-
@file = file
|
8
|
-
open!
|
9
|
-
@worker = Worker.new(@fd)
|
10
|
-
end
|
11
|
-
|
12
|
-
# Send a record to the workers queue.
|
13
|
-
def write(record)
|
14
|
-
@worker.enqueue record
|
15
|
-
end
|
16
|
-
|
17
|
-
# Finish writing
|
18
|
-
def finish!
|
19
|
-
@worker.finish!
|
20
|
-
end
|
21
|
-
|
22
|
-
# Flush pending commits, and restart the worker.
|
23
|
-
def flush!
|
24
|
-
@worker.flush!
|
25
|
-
end
|
26
|
-
|
27
|
-
# Finish writing and close the file descriptor.
|
28
|
-
def close!
|
29
|
-
finish!
|
30
|
-
@fd.close
|
31
|
-
end
|
32
|
-
|
33
|
-
# Truncate the file.
|
34
|
-
def truncate!
|
35
|
-
finish!
|
36
|
-
@fd.truncate(0)
|
37
|
-
@fd.pos = 0
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def open!
|
43
|
-
@fd = File.open @file, 'ab'
|
44
|
-
|
45
|
-
if defined?(Fcntl::O_NONBLOCK)
|
46
|
-
f = @fd.fcntl(Fcntl::F_GETFL, 0)
|
47
|
-
@fd.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | f)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Workers handle the actual fiddly bits of asynchronous io and
|
52
|
-
# and handle background writes.
|
53
|
-
class Worker
|
54
|
-
def initialize(fd)
|
55
|
-
@queue = Queue.new
|
56
|
-
@fd = fd
|
57
|
-
@thread = Thread.new { work }
|
58
|
-
at_exit { finish! }
|
59
|
-
end
|
60
|
-
|
61
|
-
# Queue up a write to be committed later.
|
62
|
-
def enqueue(record)
|
63
|
-
@queue << record
|
64
|
-
end
|
65
|
-
|
66
|
-
# Loop and block if we don't have work to do or if
|
67
|
-
# the file isn't ready for another write just yet.
|
68
|
-
def work
|
69
|
-
buf, finished = '', false
|
70
|
-
until finished && buf.empty?
|
71
|
-
record = @queue.pop
|
72
|
-
if record
|
73
|
-
buf << Record.serialize(record)
|
74
|
-
else
|
75
|
-
finished = true
|
76
|
-
end
|
77
|
-
read, write = IO.select [], [@fd]
|
78
|
-
if write and fd = write.first
|
79
|
-
lock(fd) { buf = try_write fd, buf }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
@fd.flush
|
83
|
-
end
|
84
|
-
|
85
|
-
# Try and write the buffer to the file via non blocking file writes.
|
86
|
-
# If the write fails try again.
|
87
|
-
def try_write(fd, buf)
|
88
|
-
if defined?(Fcntl::O_NONBLOCK)
|
89
|
-
s = fd.write_nonblock(buf)
|
90
|
-
else
|
91
|
-
s = fd.write(buf)
|
92
|
-
end
|
93
|
-
if s < buf.length
|
94
|
-
buf = buf[s..-1] # didn't finish
|
95
|
-
else
|
96
|
-
buf = ""
|
97
|
-
end
|
98
|
-
buf
|
99
|
-
rescue Errno::EAGAIN
|
100
|
-
buf
|
101
|
-
end
|
102
|
-
|
103
|
-
# Lock a file with the type <tt>lock</tt>
|
104
|
-
def lock(fd)
|
105
|
-
fd.flock File::LOCK_EX
|
106
|
-
begin
|
107
|
-
yield
|
108
|
-
ensure
|
109
|
-
fd.flock File::LOCK_UN
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# finish! and start up another worker thread.
|
114
|
-
def flush!
|
115
|
-
finish!
|
116
|
-
@thread = Thread.new { work }
|
117
|
-
true
|
118
|
-
end
|
119
|
-
|
120
|
-
# Push a nil through the queue and block until the write loop is finished.
|
121
|
-
def finish!
|
122
|
-
@queue.push nil
|
123
|
-
@thread.join
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/test/bench.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__)) + '/test_helper.rb'
|
2
|
-
|
3
|
-
describe "benchmarks" do
|
4
|
-
before do
|
5
|
-
@db = Daybreak::DB.new DB_PATH
|
6
|
-
1000.times {|i| @db[i] = i }
|
7
|
-
@db.flush!
|
8
|
-
end
|
9
|
-
|
10
|
-
bench_performance_constant "keys with sync" do |n|
|
11
|
-
n.times {|i| @db.set(i, 'i' * i, true) }
|
12
|
-
end
|
13
|
-
|
14
|
-
bench_performance_constant "inserting keys" do |n|
|
15
|
-
n.times {|i| @db[i] = 'i' * i }
|
16
|
-
end
|
17
|
-
|
18
|
-
bench_performance_constant "reading keys" do |n|
|
19
|
-
n.times {|i| assert_equal i % 1000, @db[i % 1000] }
|
20
|
-
end
|
21
|
-
|
22
|
-
after do
|
23
|
-
@db.empty!
|
24
|
-
@db.close!
|
25
|
-
File.unlink(DB_PATH)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
data/test/compare.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__)) + '/test_helper.rb'
|
2
|
-
require 'pstore'
|
3
|
-
|
4
|
-
describe "compare with pstore" do
|
5
|
-
before do
|
6
|
-
@pstore = PStore.new(File.join(HERE, "test.pstore"))
|
7
|
-
end
|
8
|
-
|
9
|
-
bench_performance_constant "pstore bulk performance" do |n|
|
10
|
-
@pstore.transaction do
|
11
|
-
n.times do |i|
|
12
|
-
@pstore[i] = 'i' * i
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
after do
|
18
|
-
File.unlink File.join(HERE, "test.pstore")
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
require 'dbm'
|
23
|
-
|
24
|
-
describe "compare with dbm" do
|
25
|
-
before do
|
26
|
-
@dbm = DBM.open(File.join(HERE, "test-dbm"), 666, DBM::WRCREAT)
|
27
|
-
1000.times {|i| @dbm[i.to_s] = i }
|
28
|
-
end
|
29
|
-
|
30
|
-
bench_performance_constant "DBM write performance" do |n|
|
31
|
-
n.times do |i|
|
32
|
-
@dbm[i.to_s] = 'i' * i
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
bench_performance_constant "DBM read performance" do |n|
|
37
|
-
n.times do |i|
|
38
|
-
assert_equal (i % 1000).to_s, @dbm[(i % 1000).to_s]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
after do
|
43
|
-
@dbm.close
|
44
|
-
|
45
|
-
File.unlink File.join(HERE, "test-dbm.db")
|
46
|
-
end
|
47
|
-
end
|