daybreak 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/daybreak/db.rb +30 -4
- data/lib/daybreak/record.rb +31 -9
- data/lib/daybreak/version.rb +1 -1
- data/test/test.rb +34 -0
- metadata +2 -2
data/lib/daybreak/db.rb
CHANGED
@@ -28,8 +28,7 @@ module Daybreak
|
|
28
28
|
# @param [Boolean] sync if true, sync this value immediately
|
29
29
|
def []=(key, value, sync = false)
|
30
30
|
key = key.to_s
|
31
|
-
|
32
|
-
flush! if sync
|
31
|
+
write key, value, sync
|
33
32
|
@table[key] = value
|
34
33
|
end
|
35
34
|
alias_method :set, :"[]="
|
@@ -41,6 +40,21 @@ module Daybreak
|
|
41
40
|
set key, value, true
|
42
41
|
end
|
43
42
|
|
43
|
+
# Delete a key from the database
|
44
|
+
# @param [#to_s] key the key of the storage slot in the database
|
45
|
+
# @param [Boolean] sync if true, sync this deletion immediately
|
46
|
+
def delete(key, sync = false)
|
47
|
+
key = key.to_s
|
48
|
+
write key, '', sync, true
|
49
|
+
@table.delete key
|
50
|
+
end
|
51
|
+
|
52
|
+
# delete! immediately deletes the key on disk.
|
53
|
+
# @param [#to_s] key the key of the storage slot in the database
|
54
|
+
def delete!(key)
|
55
|
+
delete key, true
|
56
|
+
end
|
57
|
+
|
44
58
|
# Retrieve a value at key from the database. If the default value was specified
|
45
59
|
# when this database was created, that value will be set and returned. Aliased
|
46
60
|
# as <tt>get</tt>.
|
@@ -112,6 +126,7 @@ module Daybreak
|
|
112
126
|
@writer.truncate!
|
113
127
|
reset!
|
114
128
|
end
|
129
|
+
alias_method :clear, :empty!
|
115
130
|
|
116
131
|
# Force all queued commits to be written to disk.
|
117
132
|
def flush!
|
@@ -138,7 +153,7 @@ module Daybreak
|
|
138
153
|
copy_db = self.class.new tmp_file.path
|
139
154
|
|
140
155
|
# Copy the database key by key into the temporary table
|
141
|
-
each do |key
|
156
|
+
each do |key|
|
142
157
|
copy_db.set(key, get(key))
|
143
158
|
end
|
144
159
|
copy_db.close!
|
@@ -161,8 +176,19 @@ module Daybreak
|
|
161
176
|
# call this again.
|
162
177
|
def read!
|
163
178
|
@reader.read do |record|
|
164
|
-
|
179
|
+
if record.deleted?
|
180
|
+
@table.delete record.key
|
181
|
+
else
|
182
|
+
@table[record.key] = parse(record.data)
|
183
|
+
end
|
165
184
|
end
|
166
185
|
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def write(key, value, sync = false, delete = false)
|
190
|
+
@writer.write(Record.new(key, serialize(value), delete))
|
191
|
+
flush! if sync
|
192
|
+
end
|
167
193
|
end
|
168
194
|
end
|
data/lib/daybreak/record.rb
CHANGED
@@ -9,11 +9,19 @@ module Daybreak
|
|
9
9
|
class CorruptDataError < Exception; end
|
10
10
|
include Locking
|
11
11
|
|
12
|
+
# The mask a record uses to check for deletion.
|
13
|
+
DELETION_MASK = (1 << 31)
|
14
|
+
|
12
15
|
attr_accessor :key, :data
|
13
16
|
|
14
|
-
def initialize(key = nil, data = nil)
|
17
|
+
def initialize(key = nil, data = nil, deleted = false)
|
15
18
|
@key = key
|
16
19
|
@data = data
|
20
|
+
if deleted
|
21
|
+
@deleted = DELETION_MASK
|
22
|
+
else
|
23
|
+
@deleted = 0
|
24
|
+
end
|
17
25
|
end
|
18
26
|
|
19
27
|
# Read a record from an open io source, check the CRC, and set <tt>@key</tt>
|
@@ -21,8 +29,8 @@ module Daybreak
|
|
21
29
|
# @param [#read] io an IO instance to read from
|
22
30
|
def read(io)
|
23
31
|
lock io do
|
24
|
-
@key =
|
25
|
-
@data =
|
32
|
+
@key = read_key(io)
|
33
|
+
@data = read_data(io)
|
26
34
|
crc = io.read(4)
|
27
35
|
raise CorruptDataError, "CRC mismatch #{crc} should be #{crc_string}" unless crc == crc_string
|
28
36
|
end
|
@@ -42,24 +50,38 @@ module Daybreak
|
|
42
50
|
new.read(io)
|
43
51
|
end
|
44
52
|
|
53
|
+
def deleted?
|
54
|
+
@deleted > 0
|
55
|
+
end
|
56
|
+
|
45
57
|
private
|
46
58
|
|
47
59
|
def byte_string
|
48
|
-
@byte_string ||= part(@key) + part(@data)
|
60
|
+
@byte_string ||= part(@key, @key.bytesize + @deleted) + part(@data, @data.bytesize)
|
49
61
|
end
|
50
62
|
|
51
63
|
def crc_string
|
52
64
|
[Zlib.crc32(byte_string, 0)].pack('N')
|
53
65
|
end
|
54
66
|
|
55
|
-
def
|
67
|
+
def read_data(io)
|
68
|
+
io.read read32(io)
|
69
|
+
end
|
70
|
+
|
71
|
+
def read_key(io)
|
72
|
+
masked = read32 io
|
73
|
+
@deleted = masked & DELETION_MASK
|
74
|
+
length = masked & (DELETION_MASK - 1)
|
75
|
+
io.read length
|
76
|
+
end
|
77
|
+
|
78
|
+
def read32(io)
|
56
79
|
raw = io.read(4)
|
57
|
-
|
58
|
-
io.read(length)
|
80
|
+
raw.unpack('N')[0]
|
59
81
|
end
|
60
82
|
|
61
|
-
def part(data)
|
62
|
-
[
|
83
|
+
def part(data, length)
|
84
|
+
[length].pack('N') + data
|
63
85
|
end
|
64
86
|
end
|
65
87
|
end
|
data/lib/daybreak/version.rb
CHANGED
data/test/test.rb
CHANGED
@@ -77,6 +77,40 @@ describe "database functions" do
|
|
77
77
|
assert_equal nil, db2['19']
|
78
78
|
end
|
79
79
|
|
80
|
+
it "should compact subclassed dbs" do
|
81
|
+
class StringDB < Daybreak::DB
|
82
|
+
def serialize(it)
|
83
|
+
it.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse(it)
|
87
|
+
it
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
db = StringDB.new 'string.db'
|
92
|
+
db[1] = 'one'
|
93
|
+
db[2] = 'two'
|
94
|
+
db.delete 2
|
95
|
+
db.compact!
|
96
|
+
assert_equal db[1], 'one'
|
97
|
+
assert_equal db[2], nil
|
98
|
+
db.empty!
|
99
|
+
db.close!
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should handle deletions" do
|
103
|
+
@db[1] = 'one'
|
104
|
+
@db[2] = 'two'
|
105
|
+
@db.delete 'two'
|
106
|
+
assert !@db.has_key?('two')
|
107
|
+
assert_equal @db['two'], nil
|
108
|
+
|
109
|
+
db2 = Daybreak::DB.new DB_PATH
|
110
|
+
assert !db2.has_key?('two')
|
111
|
+
assert_equal db2['two'], nil
|
112
|
+
end
|
113
|
+
|
80
114
|
after do
|
81
115
|
@db.empty!
|
82
116
|
@db.close!
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daybreak
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|