perobs 3.0.1 → 4.3.0

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.
Files changed (75) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +19 -18
  3. data/lib/perobs.rb +2 -0
  4. data/lib/perobs/Array.rb +68 -21
  5. data/lib/perobs/BTree.rb +110 -54
  6. data/lib/perobs/BTreeBlob.rb +14 -13
  7. data/lib/perobs/BTreeDB.rb +11 -10
  8. data/lib/perobs/BTreeNode.rb +551 -197
  9. data/lib/perobs/BTreeNodeCache.rb +10 -8
  10. data/lib/perobs/BTreeNodeLink.rb +11 -1
  11. data/lib/perobs/BigArray.rb +285 -0
  12. data/lib/perobs/BigArrayNode.rb +1002 -0
  13. data/lib/perobs/BigHash.rb +246 -0
  14. data/lib/perobs/BigTree.rb +197 -0
  15. data/lib/perobs/BigTreeNode.rb +873 -0
  16. data/lib/perobs/Cache.rb +47 -22
  17. data/lib/perobs/ClassMap.rb +2 -2
  18. data/lib/perobs/ConsoleProgressMeter.rb +61 -0
  19. data/lib/perobs/DataBase.rb +4 -3
  20. data/lib/perobs/DynamoDB.rb +62 -20
  21. data/lib/perobs/EquiBlobsFile.rb +174 -59
  22. data/lib/perobs/FNV_Hash_1a_64.rb +54 -0
  23. data/lib/perobs/FlatFile.rb +536 -242
  24. data/lib/perobs/FlatFileBlobHeader.rb +120 -84
  25. data/lib/perobs/FlatFileDB.rb +58 -27
  26. data/lib/perobs/FuzzyStringMatcher.rb +175 -0
  27. data/lib/perobs/Hash.rb +129 -35
  28. data/lib/perobs/IDList.rb +144 -0
  29. data/lib/perobs/IDListPage.rb +107 -0
  30. data/lib/perobs/IDListPageFile.rb +180 -0
  31. data/lib/perobs/IDListPageRecord.rb +142 -0
  32. data/lib/perobs/LockFile.rb +3 -0
  33. data/lib/perobs/Object.rb +28 -20
  34. data/lib/perobs/ObjectBase.rb +53 -10
  35. data/lib/perobs/PersistentObjectCache.rb +142 -0
  36. data/lib/perobs/PersistentObjectCacheLine.rb +99 -0
  37. data/lib/perobs/ProgressMeter.rb +97 -0
  38. data/lib/perobs/SpaceManager.rb +273 -0
  39. data/lib/perobs/SpaceTree.rb +63 -47
  40. data/lib/perobs/SpaceTreeNode.rb +134 -115
  41. data/lib/perobs/SpaceTreeNodeLink.rb +1 -1
  42. data/lib/perobs/StackFile.rb +1 -1
  43. data/lib/perobs/Store.rb +180 -70
  44. data/lib/perobs/version.rb +1 -1
  45. data/perobs.gemspec +4 -4
  46. data/test/Array_spec.rb +48 -39
  47. data/test/BTreeDB_spec.rb +2 -2
  48. data/test/BTree_spec.rb +50 -1
  49. data/test/BigArray_spec.rb +261 -0
  50. data/test/BigHash_spec.rb +152 -0
  51. data/test/BigTreeNode_spec.rb +153 -0
  52. data/test/BigTree_spec.rb +259 -0
  53. data/test/EquiBlobsFile_spec.rb +105 -5
  54. data/test/FNV_Hash_1a_64_spec.rb +59 -0
  55. data/test/FlatFileDB_spec.rb +199 -15
  56. data/test/FuzzyStringMatcher_spec.rb +261 -0
  57. data/test/Hash_spec.rb +27 -16
  58. data/test/IDList_spec.rb +77 -0
  59. data/test/LegacyDBs/LegacyDB.rb +155 -0
  60. data/test/LegacyDBs/version_3/class_map.json +1 -0
  61. data/test/LegacyDBs/version_3/config.json +1 -0
  62. data/test/LegacyDBs/version_3/database.blobs +0 -0
  63. data/test/LegacyDBs/version_3/database_spaces.blobs +0 -0
  64. data/test/LegacyDBs/version_3/index.blobs +0 -0
  65. data/test/LegacyDBs/version_3/version +1 -0
  66. data/test/LockFile_spec.rb +9 -6
  67. data/test/Object_spec.rb +5 -5
  68. data/test/SpaceManager_spec.rb +176 -0
  69. data/test/SpaceTree_spec.rb +27 -9
  70. data/test/Store_spec.rb +353 -206
  71. data/test/perobs_spec.rb +7 -3
  72. data/test/spec_helper.rb +9 -4
  73. metadata +59 -16
  74. data/lib/perobs/SpaceTreeNodeCache.rb +0 -76
  75. data/lib/perobs/TreeDB.rb +0 -277
@@ -1,4 +1,4 @@
1
1
  module PEROBS
2
2
  # The version number
3
- VERSION = "3.0.1"
3
+ VERSION = "4.3.0"
4
4
  end
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.0'
19
+ spec.required_ruby_version = '>=2.4'
20
20
 
21
- spec.add_development_dependency 'bundler', '~> 1.6'
22
- spec.add_development_dependency 'yard', '~>0.8.7'
23
- spec.add_development_dependency 'rake', '~> 10.0'
21
+ spec.add_development_dependency 'bundler', '~> 2.3'
22
+ spec.add_development_dependency 'yard', '~>0.9.12'
23
+ spec.add_development_dependency 'rake', '~> 12.3.3'
24
24
  end
data/test/Array_spec.rb CHANGED
@@ -33,7 +33,7 @@ require 'perobs'
33
33
 
34
34
  class PO < PEROBS::Object
35
35
 
36
- po_attr :name
36
+ attr_persist :name
37
37
 
38
38
  def initialize(store, name = nil)
39
39
  super(store)
@@ -65,7 +65,7 @@ describe PEROBS::Array do
65
65
  @store.transaction do
66
66
  @store['b'] = @store.new(PEROBS::Array)
67
67
  end
68
- @store.sync
68
+ @store.exit
69
69
  @store = nil
70
70
  GC.start
71
71
 
@@ -85,7 +85,7 @@ describe PEROBS::Array do
85
85
  expect(a[0]).to eq('A')
86
86
  expect(a[1]).to eq('B')
87
87
  expect(a[2].name).to eq('foobar')
88
- @store.sync
88
+ @store.exit
89
89
 
90
90
  @store = PEROBS::Store.new(@db_name)
91
91
  a = @store['a']
@@ -102,7 +102,7 @@ describe PEROBS::Array do
102
102
  vs = ''
103
103
  a.each { |v| vs << v }
104
104
  expect(vs).to eq('ABC')
105
- @store.sync
105
+ @store.exit
106
106
 
107
107
  @store = PEROBS::Store.new(@db_name)
108
108
  a = @store['a']
@@ -113,15 +113,15 @@ describe PEROBS::Array do
113
113
  end
114
114
 
115
115
  # Utility method to create a PEROBS::Array from a normal Array.
116
- def cpa(ary = nil)
116
+ def cpa(ary = nil, id = 'a')
117
117
  a = @store.new(PEROBS::Array)
118
118
  a.replace(ary) unless ary.nil?
119
- @store['a'] = a
119
+ @store[id] = a
120
120
  end
121
121
 
122
122
  def pcheck
123
123
  yield
124
- @store.sync
124
+ @store.exit
125
125
  @store = PEROBS::Store.new(@db_name)
126
126
  yield
127
127
  end
@@ -147,44 +147,54 @@ describe PEROBS::Array do
147
147
  it 'should support re-writing methods' do
148
148
  x = cpa([2, 5, 3, 1, 7])
149
149
  x.sort!{ |a, b| a <=> b }
150
- pcheck { expect(x).to eq([ 1, 2, 3, 5, 7 ]) }
151
- x.sort!{ |a, b| b - a }
152
- pcheck { expect(x).to eq([ 7, 5, 3, 2, 1 ]) }
150
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 5, 7 ]) }
151
+ @store['a'].sort!{ |a, b| b - a }
152
+ pcheck { expect(@store['a']).to eq([ 7, 5, 3, 2, 1 ]) }
153
153
 
154
- x.clear
155
- pcheck { expect(x).to eq([]) }
154
+ @store['a'].clear
155
+ pcheck { expect(@store['a']).to eq([]) }
156
156
  end
157
157
 
158
158
  it 'should support <<()' do
159
159
  a = cpa([ 0, 1, 2 ])
160
160
  a << 4
161
- pcheck { expect(a).to eq([ 0, 1, 2, 4 ]) }
161
+ pcheck { expect(@store['a']).to eq([ 0, 1, 2, 4 ]) }
162
162
  end
163
163
 
164
164
  it 'should support []=' do
165
165
  a = cpa([ 0, nil, 2 ])
166
166
  a[1] = 1
167
- pcheck { expect(a).to eq([ 0, 1, 2 ]) }
167
+ pcheck { expect(@store['a']).to eq([ 0, 1, 2 ]) }
168
168
  end
169
169
 
170
170
  it 'should support collect!()' do
171
171
  a = cpa([ 1, 'cat', 1..1 ])
172
- expect(a.collect! { |e| e.class }).to eq([ Fixnum, String, Range ])
173
- pcheck { expect(a).to eq([ Fixnum, String, Range ]) }
172
+ if RUBY_VERSION < '2.2'
173
+ expect(a.collect! { |e| e.class.to_s }.to_a).to eq([ 'Fixnum', 'String', 'Range' ])
174
+ pcheck { expect(@store['a'].to_a).to eq([ 'Fixnum', 'String', 'Range' ]) }
175
+ else
176
+ expect(a.collect! { |e| e.class.to_s }.to_a).to eq([ 'Integer', 'String', 'Range' ])
177
+ pcheck { expect(@store['a'].to_a).to eq([ 'Integer', 'String', 'Range' ]) }
178
+ end
174
179
 
175
180
  a = cpa([ 1, 'cat', 1..1 ])
176
181
  expect(a.collect! { 99 }).to eq([ 99, 99, 99])
177
- pcheck { expect(a).to eq([ 99, 99, 99]) }
182
+ pcheck { expect(@store['a']).to eq([ 99, 99, 99]) }
178
183
  end
179
184
 
180
185
  it 'should support map!()' do
181
186
  a = cpa([ 1, 'cat', 1..1 ])
182
- expect(a.map! { |e| e.class }).to eq([ Fixnum, String, Range ])
183
- pcheck { expect(a).to eq([ Fixnum, String, Range ]) }
187
+ if RUBY_VERSION < '2.2'
188
+ expect(a.map! { |e| e.class.to_s }.to_a).to eq([ 'Fixnum', 'String', 'Range' ])
189
+ pcheck { expect(@store['a'].to_a).to eq([ 'Fixnum', 'String', 'Range' ]) }
190
+ else
191
+ expect(a.map! { |e| e.class.to_s }.to_a).to eq([ 'Integer', 'String', 'Range' ])
192
+ pcheck { expect(@store['a'].to_a).to eq([ 'Integer', 'String', 'Range' ]) }
193
+ end
184
194
 
185
195
  a = cpa([ 1, 'cat', 1..1 ])
186
196
  expect(a.map! { 99 }).to eq([ 99, 99, 99])
187
- pcheck { expect(a).to eq ([ 99, 99, 99]) }
197
+ pcheck { expect(@store['a']).to eq ([ 99, 99, 99]) }
188
198
  end
189
199
 
190
200
  it 'should support fill()' do
@@ -194,39 +204,39 @@ describe PEROBS::Array do
194
204
  end
195
205
 
196
206
  it 'should support flatten!()' do
197
- a1 = cpa([ 1, 2, 3])
198
- a2 = cpa([ 5, 6 ])
199
- a3 = cpa([ 4, a2 ])
200
- a4 = cpa([ a1, a3 ])
201
- pcheck { expect(a4.flatten).to eq([ 1, 2, 3, 4, 5, 6 ]) }
207
+ a1 = cpa([ 1, 2, 3], 'a1')
208
+ a2 = cpa([ 5, 6 ], 'a2')
209
+ a3 = cpa([ 4, a2 ], 'a3')
210
+ a4 = cpa([ a1, a3 ], 'a4')
211
+ pcheck { expect(@store['a4'].flatten).to eq([ 1, 2, 3, 4, 5, 6 ]) }
202
212
  end
203
213
 
204
214
  it 'should support replace()' do
205
- a = cpa([ 1, 2, 3])
206
- a_id = a.__id__
207
- expect(a.replace(cpa([4, 5, 6]))).to eq([ 4, 5, 6 ])
208
- pcheck { expect(a).to eq ([ 4, 5, 6 ]) }
215
+ a1 = cpa([ 1, 2, 3], 'a1')
216
+ a_id = a1.__id__
217
+ expect(a1.replace(cpa([4, 5, 6], 'a2'))).to eq([ 4, 5, 6 ])
218
+ pcheck { expect(@store['a1']).to eq ([ 4, 5, 6 ]) }
209
219
  end
210
220
 
211
221
  it 'should support insert()' do
212
222
  a = cpa([ 0 ])
213
223
  a.insert(1)
214
- pcheck { expect(a).to eq([ 0 ]) }
215
- a.insert(1, 1)
216
- pcheck { expect(a).to eq([ 0, 1]) }
224
+ pcheck { expect(@store['a']).to eq([ 0 ]) }
225
+ @store['a'].insert(1, 1)
226
+ pcheck { expect(@store['a']).to eq([ 0, 1]) }
217
227
  end
218
228
 
219
229
  it 'should support push()' do
220
230
  a = cpa([ 1, 2, 3 ])
221
231
  a.push(4, 5)
222
- pcheck { expect(a).to eq([ 1, 2, 3, 4, 5 ]) }
223
- a.push(nil)
224
- pcheck { expect(a).to eq([ 1, 2, 3, 4, 5, nil ]) }
232
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 4, 5 ]) }
233
+ @store['a'].push(nil)
234
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 4, 5, nil ]) }
225
235
  end
226
236
 
227
237
  it 'should support inspect' do
228
- a1 = cpa([ 1 ])
229
- a2 = cpa([ 1, a1 ])
238
+ a1 = cpa([ 1 ], 'a1')
239
+ a2 = cpa([ 1, a1 ], 'a2')
230
240
  expect(a1.inspect).to eq("<PEROBS::Array:#{a1._id}>\n[\n 1\n]\n")
231
241
  expect(a2.inspect).to eq("<PEROBS::Array:#{a2._id}>\n[\n 1,\n <PEROBS::ObjectBase:#{a1._id}>\n]\n")
232
242
  end
@@ -242,9 +252,8 @@ describe PEROBS::Array do
242
252
  it 'should catch a leaked PEROBS::ObjectBase object' do
243
253
  @store['a'] = a = @store.new(PEROBS::Array)
244
254
  o = @store.new(PO)
245
- a[0] = o.get_self
246
255
  PEROBS.log.open(StringIO.new)
247
- expect { @store.sync }.to raise_error(PEROBS::FatalError)
256
+ expect { a[0] = o.get_self }.to raise_error(PEROBS::FatalError)
248
257
  PEROBS.log.open($stderr)
249
258
  end
250
259
 
data/test/BTreeDB_spec.rb CHANGED
@@ -56,7 +56,7 @@ describe PEROBS::BTreeDB do
56
56
  expect(@db.include?(0)).to be false
57
57
  h = {
58
58
  'String' => 'What god has wrought',
59
- 'Fixnum' => 42,
59
+ 'Integer' => 42,
60
60
  'Float' => 3.14,
61
61
  'True' => true,
62
62
  'False' => false,
@@ -75,7 +75,7 @@ describe PEROBS::BTreeDB do
75
75
  expect(@db.include?(0)).to be false
76
76
  h = {
77
77
  'String' => 'What god has wrought',
78
- 'Fixnum' => 42,
78
+ 'Integer' => 42,
79
79
  'Float' => 3.14,
80
80
  'True' => true,
81
81
  'False' => false,
data/test/BTree_spec.rb CHANGED
@@ -27,13 +27,16 @@ require 'fileutils'
27
27
 
28
28
  require 'spec_helper'
29
29
  require 'perobs/BTree'
30
+ require 'perobs/ProgressMeter'
30
31
 
31
32
  describe PEROBS::BTree do
32
33
 
33
34
  before(:all) do
34
35
  @db_dir = generate_db_name('BTree')
35
36
  FileUtils.mkdir_p(@db_dir)
36
- @m = PEROBS::BTree.new(@db_dir, 'btree', 11)
37
+ @m = PEROBS::BTree.new(@db_dir, 'btree', 11, PEROBS::ProgressMeter.new)
38
+ PEROBS.log.level = Logger::ERROR
39
+ PEROBS.log.open($stderr)
37
40
  end
38
41
 
39
42
  after(:all) do
@@ -48,6 +51,7 @@ describe PEROBS::BTree do
48
51
  @m.open
49
52
  expect(@m.to_s).to eql("o--- @1\n")
50
53
  #expect(@m.to_a).to eql([])
54
+ expect(@m.check).to be true
51
55
  end
52
56
 
53
57
  it 'should support adding sequential key/value pairs' do
@@ -125,4 +129,49 @@ describe PEROBS::BTree do
125
129
  end
126
130
  end
127
131
 
132
+ it 'should survive a real-world usage test' do
133
+ @m.clear
134
+ ref = {}
135
+ 0.upto(20000) do
136
+ case rand(5)
137
+ when 0
138
+ 0.upto(2) do
139
+ key = rand(100000)
140
+ value = rand(10000000)
141
+ @m.insert(key, value)
142
+ ref[key] = value
143
+ end
144
+ when 1
145
+ if ref.length > 0
146
+ key = ref.keys[rand(ref.keys.length)]
147
+ expect(@m.remove(key)).to eql(ref[key])
148
+ ref.delete(key)
149
+ end
150
+ when 2
151
+ if ref.length > 0
152
+ 0.upto(3) do
153
+ key = ref.keys[rand(ref.keys.length)]
154
+ expect(@m.get(key)).to eql(ref[key])
155
+ end
156
+ end
157
+ when 3
158
+ if ref.length > 0
159
+ key = ref.keys[rand(ref.keys.length)]
160
+ value = rand(10000000)
161
+ @m.insert(key, value)
162
+ ref[key] = value
163
+ end
164
+ when 4
165
+ if rand(50) == 0
166
+ expect(@m.check).to be true
167
+ end
168
+ when 5
169
+ if rand(50) == 0
170
+ @m.close
171
+ @m.open
172
+ end
173
+ end
174
+ end
175
+ end
176
+
128
177
  end
@@ -0,0 +1,261 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2015, 2016 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # This file contains tests for Array that are similar to the tests for the
6
+ # Array implementation in MRI. The ideas of these tests were replicated in
7
+ # this code.
8
+ #
9
+ # MIT License
10
+ #
11
+ # Permission is hereby granted, free of charge, to any person obtaining
12
+ # a copy of this software and associated documentation files (the
13
+ # "Software"), to deal in the Software without restriction, including
14
+ # without limitation the rights to use, copy, modify, merge, publish,
15
+ # distribute, sublicense, and/or sell copies of the Software, and to
16
+ # permit persons to whom the Software is furnished to do so, subject to
17
+ # the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be
20
+ # included in all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+
30
+ require 'spec_helper'
31
+
32
+ require 'perobs'
33
+ require 'perobs/BigArray'
34
+
35
+ NODE_ENTRIES = 6
36
+
37
+ describe PEROBS::BigArray do
38
+
39
+ before(:all) do
40
+ @db_name = generate_db_name(__FILE__)
41
+ @store = PEROBS::Store.new(@db_name)
42
+ end
43
+
44
+ before(:each) do
45
+ @store['array'] = @a = @store.new(PEROBS::BigArray, NODE_ENTRIES)
46
+ end
47
+
48
+ after(:each) do
49
+ @store['array'] = @a = nil
50
+ @store.gc
51
+ end
52
+
53
+ after(:all) do
54
+ @store.delete_store
55
+ end
56
+
57
+ it 'should be empty on create' do
58
+ expect(@a.empty?).to be true
59
+ expect(@a.length).to eq(0)
60
+ expect(@a.check).to be true
61
+ expect(@a[0]).to be nil
62
+ expect(@a.first).to be nil
63
+ expect(@a.last).to be nil
64
+ end
65
+
66
+ it 'should append the first element' do
67
+ @a << 0
68
+ expect(@a.empty?).to be false
69
+ expect(@a[0]).to eq(0)
70
+ expect(@a.first).to eq(0)
71
+ expect(@a.last).to eq(0)
72
+ expect(@a.length).to eq(1)
73
+ expect(@a.check).to be true
74
+ end
75
+
76
+ it 'should fill 10 nodes with appends' do
77
+ (10 * NODE_ENTRIES).times do |i|
78
+ @a << i
79
+ expect(@a.check).to be true
80
+ expect(@a.length).to eq(i + 1)
81
+ end
82
+ expect(@a.first).to eq(0)
83
+ expect(@a.last).to eq(10 * NODE_ENTRIES - 1)
84
+ end
85
+
86
+ it 'should insert at 0' do
87
+ @a.insert(0, 0)
88
+ expect(@a.empty?).to be false
89
+ end
90
+
91
+ it 'should insert at end' do
92
+ 0.upto(3 * NODE_ENTRIES) do |i|
93
+ @a.insert(i, i)
94
+ expect(@a.check).to be true
95
+ expect(@a.length).to eq(i + 1)
96
+ end
97
+ end
98
+
99
+ it 'should insert in the middle' do
100
+ 0.upto(NODE_ENTRIES - 1) do |i|
101
+ @a << 9999
102
+ end
103
+ 0.upto(3 * NODE_ENTRIES) do |i|
104
+ @a.insert(i, i)
105
+ expect(@a.check).to be true
106
+ expect(@a.length).to eq(i + 1 + NODE_ENTRIES)
107
+ end
108
+ end
109
+
110
+ it 'should convert to a Ruby Array' do
111
+ expect(@a.to_a).to eql([])
112
+ (3 * NODE_ENTRIES).times do |i|
113
+ @a << i
114
+ end
115
+ expect(@a.to_a).to eql((0..3 * NODE_ENTRIES - 1).to_a)
116
+ end
117
+
118
+ it 'should support the [] operator' do
119
+ expect(@a[0]).to be nil
120
+ expect(@a[-1]).to be nil
121
+ @a[0] = 0
122
+ expect(@a[0]).to eq(0)
123
+ 1.upto(3 * NODE_ENTRIES) do |i|
124
+ @a.insert(i, i)
125
+ end
126
+ 0.upto(3 * NODE_ENTRIES) do |i|
127
+ expect(@a[i]).to eq(i)
128
+ end
129
+ expect(@a[3 * NODE_ENTRIES + 1]).to be nil
130
+ 0.upto(3 * NODE_ENTRIES) do |i|
131
+ expect(@a[-3 * NODE_ENTRIES + i - 1]).to eq(i)
132
+ end
133
+ expect(@a[-3 * NODE_ENTRIES - 2]).to be nil
134
+ (3 * NODE_ENTRIES + 1).upto(4 * NODE_ENTRIES) do |i|
135
+ expect(@a[i]).to be nil
136
+ end
137
+ end
138
+
139
+ it 'should delete elements' do
140
+ expect(@a.delete_at(0)).to be nil
141
+ expect(@a.length).to eq(0)
142
+ expect(@a.check).to be true
143
+ expect(@a.delete_at(-1)).to be nil
144
+ expect(@a.length).to eq(0)
145
+ expect(@a.check).to be true
146
+ @a << 0
147
+ expect(@a.delete_at(0)).to eql(0)
148
+ expect(@a.length).to eq(0)
149
+ expect(@a.check).to be true
150
+
151
+ n = 5 * NODE_ENTRIES
152
+ 0.upto(n) { |i| @a.insert(i, i) }
153
+ 0.upto(n) do |i|
154
+ expect(@a.delete_at(0)).to eql(i)
155
+ expect(@a.check).to be true
156
+ end
157
+
158
+ 0.upto(n) { |i| @a.insert(i, i) }
159
+ n.downto(0) do |i|
160
+ expect(@a.delete_at(-1)).to eql(i)
161
+ expect(@a.check).to be true
162
+ end
163
+
164
+ n = 15 * NODE_ENTRIES
165
+ 0.upto(n - 1) { |i| @a.insert(i, i) }
166
+ expect(@a.delete_at(n + 2)).to be nil
167
+ expect(@a.delete_at(-(n + 2))).to be nil
168
+ expect(@a.size).to eql(n)
169
+
170
+ n.times do |i|
171
+ idx = rand(@a.size)
172
+ @a.delete_at(idx)
173
+ expect(@a.size).to be (n - 1 - i)
174
+ expect(@a.check).to be true
175
+ end
176
+ expect(@a.size).to eql(0)
177
+ end
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
+
210
+ it 'should iterate over all values' do
211
+ n = 3 * NODE_ENTRIES
212
+ 0.upto(n) { |i| @a.insert(i, i) }
213
+
214
+ i = 0
215
+ @a.each do |v|
216
+ expect(v).to eql(i)
217
+ i += 1
218
+ end
219
+ end
220
+
221
+ it 'should iterate over all values in reverse order' do
222
+ n = 3 * NODE_ENTRIES
223
+ 0.upto(n) { |i| @a.insert(i, i) }
224
+
225
+ i = 0
226
+ @a.reverse_each do |v|
227
+ expect(v).to eql(n - i)
228
+ i += 1
229
+ end
230
+ end
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
+
241
+ it 'should persist the data' do
242
+ db_name = generate_db_name(__FILE__ + "_persist")
243
+ store = PEROBS::Store.new(db_name)
244
+ store['array'] = a = store.new(PEROBS::BigArray, NODE_ENTRIES)
245
+
246
+ (3 * NODE_ENTRIES).times do |i|
247
+ a.insert(i, i)
248
+ end
249
+ expect(a.length).to eq(3 * NODE_ENTRIES)
250
+ store.exit
251
+
252
+ store = PEROBS::Store.new(db_name)
253
+ a = store['array']
254
+ (3 * NODE_ENTRIES).times do |i|
255
+ expect(a[i]).to eql(i)
256
+ end
257
+ expect(a.length).to eq(3 * NODE_ENTRIES)
258
+ store.delete_store
259
+ end
260
+
261
+ end