perobs 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/perobs/BTree.rb +33 -13
- data/lib/perobs/BTreeBlob.rb +3 -2
- data/lib/perobs/BTreeDB.rb +4 -3
- data/lib/perobs/BTreeNode.rb +107 -78
- data/lib/perobs/BTreeNodeLink.rb +10 -0
- data/lib/perobs/BigArray.rb +19 -1
- data/lib/perobs/BigArrayNode.rb +13 -9
- data/lib/perobs/BigHash.rb +8 -24
- data/lib/perobs/BigTree.rb +14 -1
- data/lib/perobs/BigTreeNode.rb +2 -2
- data/lib/perobs/Cache.rb +31 -6
- data/lib/perobs/EquiBlobsFile.rb +12 -1
- data/lib/perobs/FlatFile.rb +197 -45
- data/lib/perobs/FlatFileBlobHeader.rb +20 -5
- data/lib/perobs/FlatFileDB.rb +8 -4
- data/lib/perobs/FuzzyStringMatcher.rb +192 -0
- data/lib/perobs/Hash.rb +4 -0
- data/lib/perobs/IDListPageFile.rb +1 -2
- data/lib/perobs/ObjectBase.rb +1 -1
- data/lib/perobs/PersistentObjectCache.rb +7 -4
- data/lib/perobs/SpaceManager.rb +273 -0
- data/lib/perobs/SpaceTree.rb +1 -1
- data/lib/perobs/Store.rb +67 -25
- data/lib/perobs/version.rb +1 -1
- data/perobs.gemspec +2 -2
- data/test/BTree_spec.rb +1 -0
- data/test/BigArray_spec.rb +53 -6
- data/test/BigHash_spec.rb +8 -0
- data/test/FlatFileDB_spec.rb +108 -3
- data/test/FuzzyStringMatcher_spec.rb +171 -0
- data/test/LegacyDBs/LegacyDB.rb +4 -0
- data/test/SpaceManager_spec.rb +176 -0
- data/test/Store_spec.rb +2 -5
- metadata +12 -6
data/lib/perobs/SpaceTree.rb
CHANGED
@@ -54,7 +54,7 @@ module PEROBS
|
|
54
54
|
|
55
55
|
# Benchmark runs showed a cache size of 128 to be a good compromise
|
56
56
|
# between read and write performance trade-offs and memory consumption.
|
57
|
-
@cache = PersistentObjectCache.new(
|
57
|
+
@cache = PersistentObjectCache.new(256, -1, SpaceTreeNode, self)
|
58
58
|
end
|
59
59
|
|
60
60
|
# Open the SpaceTree file.
|
data/lib/perobs/Store.rb
CHANGED
@@ -46,8 +46,9 @@ require 'perobs/ConsoleProgressMeter'
|
|
46
46
|
# PErsistent Ruby OBject Store
|
47
47
|
module PEROBS
|
48
48
|
|
49
|
-
Statistics = Struct.new(:in_memory_objects, :root_objects,
|
50
|
-
:marked_objects, :swept_objects
|
49
|
+
Statistics = Struct.new(:in_memory_objects, :root_objects, :zombie_objects,
|
50
|
+
:marked_objects, :swept_objects,
|
51
|
+
:created_objects, :collected_objects)
|
51
52
|
|
52
53
|
# PEROBS::Store is a persistent storage system for Ruby objects. Regular
|
53
54
|
# Ruby objects are transparently stored in a back-end storage and retrieved
|
@@ -109,6 +110,7 @@ module PEROBS
|
|
109
110
|
class Store
|
110
111
|
|
111
112
|
attr_reader :db, :cache, :class_map
|
113
|
+
attr_writer :root_objects
|
112
114
|
|
113
115
|
# Create a new Store.
|
114
116
|
# @param data_base [String] the name of the database
|
@@ -143,6 +145,9 @@ module PEROBS
|
|
143
145
|
# It defaults to ProgressMeter which only logs into
|
144
146
|
# the log. Use ConsoleProgressMeter or a derived
|
145
147
|
# class for more fancy progress reporting.
|
148
|
+
# :no_root_objects : Create a new store without root objects. This only
|
149
|
+
# makes sense if you want to copy the objects of
|
150
|
+
# another store into this store.
|
146
151
|
def initialize(data_base, options = {})
|
147
152
|
# Create a backing store handler
|
148
153
|
@progressmeter = (options[:progressmeter] ||= ProgressMeter.new)
|
@@ -155,25 +160,32 @@ module PEROBS
|
|
155
160
|
# List of PEROBS objects that are currently available as Ruby objects
|
156
161
|
# hashed by their ID.
|
157
162
|
@in_memory_objects = {}
|
163
|
+
# List of objects that were destroyed already but were still found in
|
164
|
+
# the in_memory_objects list. _collect has not yet been called for them.
|
165
|
+
@zombie_objects = {}
|
158
166
|
|
159
167
|
# This objects keeps some counters of interest.
|
160
168
|
@stats = Statistics.new
|
169
|
+
@stats[:created_objects] = 0
|
170
|
+
@stats[:collected_objects] = 0
|
161
171
|
|
162
172
|
# The Cache reduces read and write latencies by keeping a subset of the
|
163
173
|
# objects in memory.
|
164
174
|
@cache = Cache.new(options[:cache_bits] || 16)
|
165
175
|
|
166
176
|
# The named (global) objects IDs hashed by their name
|
167
|
-
unless
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
"
|
177
|
+
unless options[:no_root_objects]
|
178
|
+
unless (@root_objects = object_by_id(0))
|
179
|
+
PEROBS.log.debug "Initializing the PEROBS store"
|
180
|
+
# The root object hash always has the object ID 0.
|
181
|
+
@root_objects = _construct_po(Hash, 0)
|
182
|
+
# Mark the root_objects object as modified.
|
183
|
+
@cache.cache_write(@root_objects)
|
184
|
+
end
|
185
|
+
unless @root_objects.is_a?(Hash)
|
186
|
+
PEROBS.log.fatal "Database corrupted: Root objects must be a Hash " +
|
187
|
+
"but is a #{@root_objects.class}"
|
188
|
+
end
|
177
189
|
end
|
178
190
|
end
|
179
191
|
|
@@ -185,7 +197,9 @@ module PEROBS
|
|
185
197
|
sync
|
186
198
|
|
187
199
|
# Create a new store with the specified directory and options.
|
188
|
-
|
200
|
+
new_options = options.clone
|
201
|
+
new_options[:no_root_objects] = true
|
202
|
+
new_db = Store.new(dir, new_options)
|
189
203
|
# Clear the cache.
|
190
204
|
new_db.sync
|
191
205
|
# Copy all objects of the existing store to the new store.
|
@@ -196,6 +210,7 @@ module PEROBS
|
|
196
210
|
obj._sync
|
197
211
|
i += 1
|
198
212
|
end
|
213
|
+
new_db.root_objects = new_db.object_by_id(0)
|
199
214
|
PEROBS.log.debug "Copied #{i} objects into new database at #{dir}"
|
200
215
|
# Flush the new store and close it.
|
201
216
|
new_db.exit
|
@@ -203,7 +218,6 @@ module PEROBS
|
|
203
218
|
true
|
204
219
|
end
|
205
220
|
|
206
|
-
|
207
221
|
# Close the store and ensure that all in-memory objects are written out to
|
208
222
|
# the storage backend. The Store object is no longer usable after this
|
209
223
|
# method was called.
|
@@ -216,10 +230,22 @@ module PEROBS
|
|
216
230
|
end
|
217
231
|
@cache.flush if @cache
|
218
232
|
@db.close if @db
|
219
|
-
@db = @class_map = @in_memory_objects = @stats = @cache = @root_objects =
|
220
|
-
nil
|
221
|
-
end
|
222
233
|
|
234
|
+
GC.start
|
235
|
+
if @stats
|
236
|
+
unless @stats[:created_objects] == @stats[:collected_objects] +
|
237
|
+
@in_memory_objects.length
|
238
|
+
PEROGS.log.fatal "Created objects count " +
|
239
|
+
"(#{@stats[:created_objects]})" +
|
240
|
+
" is not equal to the collected count " +
|
241
|
+
"(#{@stats[:collected_objects]}) + in_memory_objects count " +
|
242
|
+
"(#{@in_memory_objects.length})"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
@db = @class_map = @in_memory_objects = @zombie_objects =
|
247
|
+
@stats = @cache = @root_objects = nil
|
248
|
+
end
|
223
249
|
|
224
250
|
# You need to call this method to create new PEROBS objects that belong to
|
225
251
|
# this Store.
|
@@ -255,8 +281,8 @@ module PEROBS
|
|
255
281
|
# deletes the entire database.
|
256
282
|
def delete_store
|
257
283
|
@db.delete_database
|
258
|
-
@db = @class_map = @in_memory_objects = @
|
259
|
-
nil
|
284
|
+
@db = @class_map = @in_memory_objects = @zombie_objects =
|
285
|
+
@stats = @cache = @root_objects = nil
|
260
286
|
end
|
261
287
|
|
262
288
|
# Store the provided object under the given name. Use this to make the
|
@@ -358,10 +384,10 @@ module PEROBS
|
|
358
384
|
rescue RangeError => e
|
359
385
|
# Due to a race condition the object can still be in the
|
360
386
|
# @in_memory_objects list but has been collected already by the Ruby
|
361
|
-
# GC. In that case we need to load it again.
|
362
|
-
#
|
363
|
-
#
|
364
|
-
@in_memory_objects.delete(id)
|
387
|
+
# GC. In that case we need to load it again. The _collect() call
|
388
|
+
# will happen much later, potentially after we have registered a new
|
389
|
+
# object with the same ID.
|
390
|
+
@zombie_objects[id] = @in_memory_objects.delete(id)
|
365
391
|
end
|
366
392
|
end
|
367
393
|
|
@@ -510,7 +536,16 @@ module PEROBS
|
|
510
536
|
# @param obj [BasicObject] Object to register
|
511
537
|
# @param id [Integer] object ID
|
512
538
|
def _register_in_memory(obj, id)
|
539
|
+
unless obj.is_a?(ObjectBase)
|
540
|
+
PEROBS.log.fatal "You can only register ObjectBase objects"
|
541
|
+
end
|
542
|
+
if @in_memory_objects.include?(id)
|
543
|
+
PEROBS.log.fatal "The Store::_in_memory_objects list already " +
|
544
|
+
"contains an object for ID #{id}"
|
545
|
+
end
|
546
|
+
|
513
547
|
@in_memory_objects[id] = obj.object_id
|
548
|
+
@stats[:created_objects] += 1
|
514
549
|
end
|
515
550
|
|
516
551
|
# Remove the object from the in-memory list. This is an internal method
|
@@ -520,6 +555,10 @@ module PEROBS
|
|
520
555
|
def _collect(id, ruby_object_id)
|
521
556
|
if @in_memory_objects[id] == ruby_object_id
|
522
557
|
@in_memory_objects.delete(id)
|
558
|
+
@stats[:collected_objects] += 1
|
559
|
+
elsif @zombie_objects[id] == ruby_object_id
|
560
|
+
@zombie_objects.delete(id)
|
561
|
+
@stats[:collected_objects] += 1
|
523
562
|
end
|
524
563
|
end
|
525
564
|
|
@@ -527,6 +566,7 @@ module PEROBS
|
|
527
566
|
def statistics
|
528
567
|
@stats.in_memory_objects = @in_memory_objects.length
|
529
568
|
@stats.root_objects = @root_objects.length
|
569
|
+
@stats.zombie_objects = @zombie_objects.length
|
530
570
|
|
531
571
|
@stats
|
532
572
|
end
|
@@ -556,8 +596,10 @@ module PEROBS
|
|
556
596
|
# Sweep phase of a mark-and-sweep garbage collector. It will remove all
|
557
597
|
# unmarked objects from the store.
|
558
598
|
def sweep
|
559
|
-
@stats.swept_objects = @db.delete_unmarked_objects
|
560
|
-
|
599
|
+
@stats.swept_objects = @db.delete_unmarked_objects do |id|
|
600
|
+
@cache.evict(id)
|
601
|
+
end
|
602
|
+
GC.start
|
561
603
|
PEROBS.log.debug "#{@stats.swept_objects} objects collected"
|
562
604
|
@stats.swept_objects
|
563
605
|
end
|
data/lib/perobs/version.rb
CHANGED
data/perobs.gemspec
CHANGED
@@ -16,9 +16,9 @@ GEM_SPEC = Gem::Specification.new do |spec|
|
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
|
-
spec.required_ruby_version = '>=2.
|
19
|
+
spec.required_ruby_version = '>=2.4'
|
20
20
|
|
21
21
|
spec.add_development_dependency 'bundler', '~> 2.3'
|
22
22
|
spec.add_development_dependency 'yard', '~>0.9.12'
|
23
|
-
spec.add_development_dependency 'rake', '~>
|
23
|
+
spec.add_development_dependency 'rake', '~> 12.3.3'
|
24
24
|
end
|
data/test/BTree_spec.rb
CHANGED
data/test/BigArray_spec.rb
CHANGED
@@ -32,7 +32,7 @@ require 'spec_helper'
|
|
32
32
|
require 'perobs'
|
33
33
|
require 'perobs/BigArray'
|
34
34
|
|
35
|
-
NODE_ENTRIES =
|
35
|
+
NODE_ENTRIES = 6
|
36
36
|
|
37
37
|
describe PEROBS::BigArray do
|
38
38
|
|
@@ -59,12 +59,16 @@ describe PEROBS::BigArray do
|
|
59
59
|
expect(@a.length).to eq(0)
|
60
60
|
expect(@a.check).to be true
|
61
61
|
expect(@a[0]).to be nil
|
62
|
+
expect(@a.first).to be nil
|
63
|
+
expect(@a.last).to be nil
|
62
64
|
end
|
63
65
|
|
64
66
|
it 'should append the first element' do
|
65
67
|
@a << 0
|
66
68
|
expect(@a.empty?).to be false
|
67
69
|
expect(@a[0]).to eq(0)
|
70
|
+
expect(@a.first).to eq(0)
|
71
|
+
expect(@a.last).to eq(0)
|
68
72
|
expect(@a.length).to eq(1)
|
69
73
|
expect(@a.check).to be true
|
70
74
|
end
|
@@ -75,6 +79,8 @@ describe PEROBS::BigArray do
|
|
75
79
|
expect(@a.check).to be true
|
76
80
|
expect(@a.length).to eq(i + 1)
|
77
81
|
end
|
82
|
+
expect(@a.first).to eq(0)
|
83
|
+
expect(@a.last).to eq(10 * NODE_ENTRIES - 1)
|
78
84
|
end
|
79
85
|
|
80
86
|
it 'should insert at 0' do
|
@@ -111,7 +117,7 @@ describe PEROBS::BigArray do
|
|
111
117
|
|
112
118
|
it 'should support the [] operator' do
|
113
119
|
expect(@a[0]).to be nil
|
114
|
-
expect
|
120
|
+
expect(@a[-1]).to be nil
|
115
121
|
@a[0] = 0
|
116
122
|
expect(@a[0]).to eq(0)
|
117
123
|
1.upto(3 * NODE_ENTRIES) do |i|
|
@@ -124,7 +130,7 @@ describe PEROBS::BigArray do
|
|
124
130
|
0.upto(3 * NODE_ENTRIES) do |i|
|
125
131
|
expect(@a[-3 * NODE_ENTRIES + i - 1]).to eq(i)
|
126
132
|
end
|
127
|
-
expect
|
133
|
+
expect(@a[-3 * NODE_ENTRIES - 2]).to be nil
|
128
134
|
(3 * NODE_ENTRIES + 1).upto(4 * NODE_ENTRIES) do |i|
|
129
135
|
expect(@a[i]).to be nil
|
130
136
|
end
|
@@ -142,7 +148,7 @@ describe PEROBS::BigArray do
|
|
142
148
|
expect(@a.length).to eq(0)
|
143
149
|
expect(@a.check).to be true
|
144
150
|
|
145
|
-
n =
|
151
|
+
n = 5 * NODE_ENTRIES
|
146
152
|
0.upto(n) { |i| @a.insert(i, i) }
|
147
153
|
0.upto(n) do |i|
|
148
154
|
expect(@a.delete_at(0)).to eql(i)
|
@@ -155,20 +161,52 @@ describe PEROBS::BigArray do
|
|
155
161
|
expect(@a.check).to be true
|
156
162
|
end
|
157
163
|
|
158
|
-
n =
|
164
|
+
n = 15 * NODE_ENTRIES
|
159
165
|
0.upto(n - 1) { |i| @a.insert(i, i) }
|
160
166
|
expect(@a.delete_at(n + 2)).to be nil
|
161
167
|
expect(@a.delete_at(-(n + 2))).to be nil
|
162
168
|
expect(@a.size).to eql(n)
|
163
169
|
|
164
170
|
n.times do |i|
|
165
|
-
|
171
|
+
idx = rand(@a.size)
|
172
|
+
@a.delete_at(idx)
|
166
173
|
expect(@a.size).to be (n - 1 - i)
|
167
174
|
expect(@a.check).to be true
|
168
175
|
end
|
169
176
|
expect(@a.size).to eql(0)
|
170
177
|
end
|
171
178
|
|
179
|
+
it 'should fill the gaps' do
|
180
|
+
1.upto(4) do |i|
|
181
|
+
idx = i * NODE_ENTRIES * NODE_ENTRIES
|
182
|
+
@a[idx] = idx
|
183
|
+
expect(@a[idx - 1]).to be nil
|
184
|
+
expect(@a[idx + 1]).to be nil
|
185
|
+
expect(@a.check).to be true
|
186
|
+
end
|
187
|
+
expect(@a[0]).to be nil
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should insert after a gap' do
|
191
|
+
ref = []
|
192
|
+
10.times do |i|
|
193
|
+
idx = 10 + i * 3
|
194
|
+
@a[idx] = idx
|
195
|
+
ref[idx] = idx
|
196
|
+
expect(@a[idx]).to eql(idx)
|
197
|
+
expect(@a.check).to be true
|
198
|
+
end
|
199
|
+
10.times do |i|
|
200
|
+
idx = i * 5
|
201
|
+
@a[idx] = idx
|
202
|
+
ref[idx] = idx
|
203
|
+
expect(@a[idx]).to eql(idx)
|
204
|
+
expect(@a.check).to be true
|
205
|
+
end
|
206
|
+
expect(@a.check).to be true
|
207
|
+
expect(@a.to_a).to eql(ref)
|
208
|
+
end
|
209
|
+
|
172
210
|
it 'should iterate over all values' do
|
173
211
|
n = 3 * NODE_ENTRIES
|
174
212
|
0.upto(n) { |i| @a.insert(i, i) }
|
@@ -191,6 +229,15 @@ describe PEROBS::BigArray do
|
|
191
229
|
end
|
192
230
|
end
|
193
231
|
|
232
|
+
it 'should insert at the beginning' do
|
233
|
+
(5 * NODE_ENTRIES).downto(0) do |i|
|
234
|
+
@a.insert(0, i)
|
235
|
+
end
|
236
|
+
expect(@a.check).to be true
|
237
|
+
a = Array.new(5 * NODE_ENTRIES + 1) { |i| i }
|
238
|
+
expect(@a.to_a).to eq(a)
|
239
|
+
end
|
240
|
+
|
194
241
|
it 'should persist the data' do
|
195
242
|
db_name = generate_db_name(__FILE__ + "_persist")
|
196
243
|
store = PEROBS::Store.new(db_name)
|
data/test/BigHash_spec.rb
CHANGED
@@ -72,6 +72,13 @@ describe PEROBS::Hash do
|
|
72
72
|
expect(@h.keys).to eql([ 'foo' ])
|
73
73
|
end
|
74
74
|
|
75
|
+
it 'should store a few objects' do
|
76
|
+
20.times do |i|
|
77
|
+
@h["bar#{i}"] = "foo#{i}"
|
78
|
+
end
|
79
|
+
expect(@h.size).to eql(20)
|
80
|
+
end
|
81
|
+
|
75
82
|
it 'should return nil for unknown objects' do
|
76
83
|
expect(@h['bar']).to be_nil
|
77
84
|
end
|
@@ -127,6 +134,7 @@ describe PEROBS::Hash do
|
|
127
134
|
end
|
128
135
|
expect(h.check).to be true
|
129
136
|
expect(h.length).to eql(n)
|
137
|
+
expect(store.check).to eql(0)
|
130
138
|
store.exit
|
131
139
|
|
132
140
|
store = PEROBS::Store.new(db_name)
|
data/test/FlatFileDB_spec.rb
CHANGED
@@ -71,7 +71,7 @@ describe PEROBS::FlatFileDB do
|
|
71
71
|
expect { db2.open }.to raise_error(PEROBS::FatalError)
|
72
72
|
end
|
73
73
|
|
74
|
-
it 'should do a version upgrade' do
|
74
|
+
it 'should do a version upgrade from version 3' do
|
75
75
|
# Close the store
|
76
76
|
@store.exit
|
77
77
|
src_dir = File.join(File.dirname(__FILE__), 'LegacyDBs', 'version_3')
|
@@ -82,6 +82,21 @@ describe PEROBS::FlatFileDB do
|
|
82
82
|
capture_io { expect(db.check).to be true }
|
83
83
|
end
|
84
84
|
|
85
|
+
it 'should do a version upgrade from version 4.1' do
|
86
|
+
# Close the store
|
87
|
+
@store.exit
|
88
|
+
src_dir = File.join(File.dirname(__FILE__), 'LegacyDBs', 'version_4.1')
|
89
|
+
FileUtils.cp_r(Dir.glob(src_dir + '/*'), @db_dir)
|
90
|
+
|
91
|
+
db = LegacyDB.new(@db_dir)
|
92
|
+
capture_io { db.open }
|
93
|
+
capture_io { expect(db.repair).to eql(0) }
|
94
|
+
expect(File.exist?(File.join(@db_dir, 'space_index.blobs'))).to be true
|
95
|
+
expect(File.exist?(File.join(@db_dir, 'space_list.blobs'))).to be true
|
96
|
+
expect(File.exist?(File.join(@db_dir, 'database_spaces.blobs'))).to be false
|
97
|
+
capture_io { expect(db.check).to be true }
|
98
|
+
end
|
99
|
+
|
85
100
|
it 'should refuse a version downgrade' do
|
86
101
|
# Close the store
|
87
102
|
@store.exit
|
@@ -119,7 +134,7 @@ describe PEROBS::FlatFileDB do
|
|
119
134
|
expect(store['o'].b).to eql(42)
|
120
135
|
end
|
121
136
|
|
122
|
-
it 'should
|
137
|
+
it 'should discard a corrupted blob inside the database.blobs file' do
|
123
138
|
@store.exit
|
124
139
|
|
125
140
|
db = PEROBS::FlatFileDB.new(@db_dir)
|
@@ -142,7 +157,7 @@ describe PEROBS::FlatFileDB do
|
|
142
157
|
f.close
|
143
158
|
|
144
159
|
db.open
|
145
|
-
expect(db.check_db).to eql(
|
160
|
+
expect(db.check_db).to eql(1)
|
146
161
|
expect(db.check_db(true)).to eql(1)
|
147
162
|
db.close
|
148
163
|
db = PEROBS::FlatFileDB.new(@db_dir, { :log => $stderr,
|
@@ -160,5 +175,95 @@ describe PEROBS::FlatFileDB do
|
|
160
175
|
db.close
|
161
176
|
end
|
162
177
|
|
178
|
+
it 'should discard a corrupted blob at the end of the database.blobs file' do
|
179
|
+
@store.exit
|
180
|
+
|
181
|
+
db = PEROBS::FlatFileDB.new(@db_dir)
|
182
|
+
db_file = File.join(@db_dir, 'database.blobs')
|
183
|
+
db.open
|
184
|
+
0.upto(5) do |i|
|
185
|
+
db.put_object("#{i + 1}:#{'X' * (i + 1) * 30}$", i + 1)
|
186
|
+
end
|
187
|
+
db.close
|
188
|
+
|
189
|
+
f = File.truncate(db_file, File.size(db_file) - 20)
|
190
|
+
|
191
|
+
db.open
|
192
|
+
expect(db.check_db).to eql(2)
|
193
|
+
expect(db.check_db(true)).to eql(2)
|
194
|
+
db.close
|
195
|
+
db = PEROBS::FlatFileDB.new(@db_dir, { :log => $stderr,
|
196
|
+
:log_level => Logger::ERROR })
|
197
|
+
db.open
|
198
|
+
expect(db.check_db).to eql(0)
|
199
|
+
|
200
|
+
0.upto(4) do |i|
|
201
|
+
expect(db.get_object(i + 1)).to eql("#{i + 1}:#{'X' * (i + 1) * 30}$")
|
202
|
+
end
|
203
|
+
expect(db.get_object(6)).to be_nil
|
204
|
+
db.close
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should discard a corrupted header at the end of the database.blobs file' do
|
208
|
+
@store.exit
|
209
|
+
|
210
|
+
db = PEROBS::FlatFileDB.new(@db_dir)
|
211
|
+
db_file = File.join(@db_dir, 'database.blobs')
|
212
|
+
db.open
|
213
|
+
0.upto(5) do |i|
|
214
|
+
db.put_object("#{i + 1}:#{'X' * (i + 1) * 30}$", i + 1)
|
215
|
+
end
|
216
|
+
db.close
|
217
|
+
|
218
|
+
f = File.truncate(db_file, File.size(db_file) - 200)
|
219
|
+
|
220
|
+
db.open
|
221
|
+
expect(db.check_db).to eql(1)
|
222
|
+
expect(db.check_db(true)).to eql(1)
|
223
|
+
db.close
|
224
|
+
db = PEROBS::FlatFileDB.new(@db_dir, { :log => $stderr,
|
225
|
+
:log_level => Logger::ERROR })
|
226
|
+
db.open
|
227
|
+
expect(db.check_db).to eql(0)
|
228
|
+
|
229
|
+
0.upto(4) do |i|
|
230
|
+
expect(db.get_object(i + 1)).to eql("#{i + 1}:#{'X' * (i + 1) * 30}$")
|
231
|
+
end
|
232
|
+
expect(db.get_object(6)).to be_nil
|
233
|
+
db.close
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should handle a lost blob at the end of the database.blobs file' do
|
237
|
+
@store.exit
|
238
|
+
|
239
|
+
db = PEROBS::FlatFileDB.new(@db_dir)
|
240
|
+
db_file = File.join(@db_dir, 'database.blobs')
|
241
|
+
db.open
|
242
|
+
0.upto(5) do |i|
|
243
|
+
db.put_object("#{i + 1}:#{'X' * (i + 1) * 30}$", i + 1)
|
244
|
+
end
|
245
|
+
db.close
|
246
|
+
|
247
|
+
# This exactly removes the last blob (#6)
|
248
|
+
f = File.truncate(db_file, File.size(db_file) - 210)
|
249
|
+
|
250
|
+
db.open
|
251
|
+
expect(db.check_db).to eql(1)
|
252
|
+
# The repair won't find the missing blob since the blob file is without
|
253
|
+
# errors.
|
254
|
+
expect(db.check_db(true)).to eql(0)
|
255
|
+
db.close
|
256
|
+
db = PEROBS::FlatFileDB.new(@db_dir, { :log => $stderr,
|
257
|
+
:log_level => Logger::ERROR })
|
258
|
+
db.open
|
259
|
+
expect(db.check_db).to eql(0)
|
260
|
+
|
261
|
+
0.upto(4) do |i|
|
262
|
+
expect(db.get_object(i + 1)).to eql("#{i + 1}:#{'X' * (i + 1) * 30}$")
|
263
|
+
end
|
264
|
+
expect(db.get_object(6)).to be_nil
|
265
|
+
db.close
|
266
|
+
end
|
267
|
+
|
163
268
|
end
|
164
269
|
|