perobs 3.0.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,152 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2017, 2019 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # This file contains tests for Hash that are similar to the tests for the
6
+ # Hash 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/BigHash'
34
+
35
+ class PEROBS::BigHash
36
+
37
+ # Redefine the hash method to make collisions very likely. This will help to
38
+ # test the collision handling with small amounts of data.
39
+ #def hash_key(key)
40
+ # key.hash & 0xF
41
+ #end
42
+
43
+ end
44
+
45
+ ENTRIES = 200
46
+
47
+ describe PEROBS::Hash do
48
+
49
+ before(:all) do
50
+ @db_name = generate_db_name(__FILE__)
51
+ end
52
+
53
+ before(:each) do
54
+ @store = PEROBS::Store.new(@db_name)
55
+ @h = @store.new(PEROBS::BigHash)
56
+ @store['hash'] = @h
57
+ end
58
+
59
+ after(:each) do
60
+ @store.delete_store
61
+ end
62
+
63
+ it 'should support storing and retrieving an object' do
64
+ expect(@h.check).to be true
65
+ expect(@h.length).to eql(0)
66
+ expect(@h.empty?).to be true
67
+ expect(@h.keys).to eql([])
68
+ @h['foo'] = 'bar'
69
+ expect(@h.check).to be true
70
+ expect(@h['foo']).to eql('bar')
71
+ expect(@h.length).to eql(1)
72
+ expect(@h.keys).to eql([ 'foo' ])
73
+ end
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
+
82
+ it 'should return nil for unknown objects' do
83
+ expect(@h['bar']).to be_nil
84
+ end
85
+
86
+ it 'should be able to store values with hash collisions' do
87
+ ENTRIES.times do |i|
88
+ @h["key#{i}"] = i
89
+ end
90
+ expect(@h.check).to be true
91
+ expect(@h.length).to eql(ENTRIES)
92
+
93
+ ENTRIES.times do |i|
94
+ expect(@h["key#{i}"]).to eql(i)
95
+ end
96
+ end
97
+
98
+ it 'should replace existing entries' do
99
+ ENTRIES.times do |i|
100
+ @h["key#{i}"] = 2 * i
101
+ end
102
+ expect(@h.check).to be true
103
+ expect(@h.length).to eql(ENTRIES)
104
+
105
+ ENTRIES.times do |i|
106
+ expect(@h["key#{i}"]).to eql(2 * i)
107
+ end
108
+ expect(@h.length).to eql(ENTRIES)
109
+ end
110
+
111
+ it 'should fail to delete a non-existing entry' do
112
+ expect(@h.delete('foo')).to be_nil
113
+ expect(@h.check).to be true
114
+ end
115
+
116
+ it 'should delete existing entries' do
117
+ (1..ENTRIES).to_a.shuffle.each do |i|
118
+ @h["key#{i}"] = 2 * i
119
+ end
120
+ expect(@h.check).to be true
121
+ expect(@h.length).to eql(ENTRIES)
122
+ (1..ENTRIES).to_a.shuffle.each do |i|
123
+ expect(@h.delete("key#{i}")).to eql(2 * i)
124
+ end
125
+ end
126
+
127
+ it 'should persist all objects' do
128
+ db_name = generate_db_name(__FILE__ + "_persist")
129
+ store = PEROBS::Store.new(db_name)
130
+ h = store['hash'] = store.new(PEROBS::BigHash)
131
+ n = ENTRIES
132
+ n.times do |i|
133
+ h["key#{i}"] = 2 * i
134
+ end
135
+ expect(h.check).to be true
136
+ expect(h.length).to eql(n)
137
+ expect(store.check).to eql(0)
138
+ store.exit
139
+
140
+ store = PEROBS::Store.new(db_name)
141
+ expect(store.check).to eql(0)
142
+ h = store['hash']
143
+ n.times do |i|
144
+ expect(h["key#{i}"]).to eql(2 * i)
145
+ end
146
+ expect(h.check).to be true
147
+ expect(h.length).to eql(n)
148
+ store.delete_store
149
+ end
150
+
151
+ end
152
+
@@ -0,0 +1,153 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # MIT License
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ require 'fileutils'
27
+
28
+ require 'spec_helper'
29
+ require 'perobs/Store'
30
+ require 'perobs/BigTree'
31
+
32
+ describe PEROBS::BigTreeNode do
33
+
34
+ before(:all) do
35
+ @db_name = generate_db_name(__FILE__)
36
+ @store = PEROBS::Store.new(@db_name)
37
+ @store['bigtree'] = @t = @store.new(PEROBS::BigTree, 4)
38
+ end
39
+
40
+ before(:each) do
41
+ @t.clear
42
+ end
43
+
44
+ after(:all) do
45
+ @store.delete_store
46
+ end
47
+
48
+ it 'should insert a key/value pair' do
49
+ n = @t.root
50
+ n.insert(0, 0)
51
+ expect(@t.check).to be true
52
+ s = @t.statistics
53
+ expect(s.leaf_nodes).to eql(1)
54
+ expect(s.branch_nodes).to eql(0)
55
+ expect(s.min_depth).to eql(1)
56
+ expect(s.max_depth).to eql(1)
57
+ node_chain = @t.node_chain(0)
58
+ expect(node_chain.size).to eql(1)
59
+ expect(node_chain.first).to eql(n)
60
+ end
61
+
62
+ it 'should split a leaf node that becomes full' do
63
+ 4.times { |n| @t.insert(n, n) }
64
+ expect(@t.check).to be true
65
+ s = @t.statistics
66
+ expect(s.leaf_nodes).to eql(1)
67
+ @t.insert(4, 4)
68
+ s = @t.statistics
69
+ expect(s.leaf_nodes).to eql(2)
70
+ expect(s.branch_nodes).to eql(1)
71
+ expect(s.min_depth).to eql(2)
72
+ expect(s.max_depth).to eql(2)
73
+ end
74
+
75
+ it 'should split a branch node that becomes full' do
76
+ 11.times { |n| @t.insert(n, n) }
77
+ s = @t.statistics
78
+ expect(s.leaf_nodes).to eql(5)
79
+ expect(s.branch_nodes).to eql(1)
80
+ expect(s.min_depth).to eql(2)
81
+ expect(s.max_depth).to eql(2)
82
+ @t.insert(11, 11)
83
+ expect(@t.check).to be true
84
+ s = @t.statistics
85
+ expect(s.leaf_nodes).to eql(5)
86
+ expect(s.branch_nodes).to eql(3)
87
+ expect(s.min_depth).to eql(3)
88
+ expect(s.max_depth).to eql(3)
89
+ end
90
+
91
+ it 'should merge leaf node with next sibling' do
92
+ 5.times { |n| @t.insert(n, n) }
93
+ expect(@t.check).to be true
94
+ s = @t.statistics
95
+ expect(s.leaf_nodes).to eql(2)
96
+
97
+ @t.remove(0)
98
+ expect(@t.check).to be true
99
+ s = @t.statistics
100
+ expect(s.leaf_nodes).to eql(1)
101
+ expect(s.min_depth).to eql(1)
102
+ expect(s.max_depth).to eql(1)
103
+ end
104
+
105
+ it 'should merge leaf node with previous siblin' do
106
+ 5.times { |n| @t.insert(n, n) }
107
+ expect(@t.check).to be true
108
+ s = @t.statistics
109
+ expect(s.leaf_nodes).to eql(2)
110
+
111
+ @t.remove(2)
112
+ @t.remove(3)
113
+ expect(@t.check).to be true
114
+ s = @t.statistics
115
+ expect(s.leaf_nodes).to eql(1)
116
+ end
117
+
118
+ it 'should merge branch node with next sibling' do
119
+ 12.times { |n| @t.insert(n, n) }
120
+ expect(@t.check).to be true
121
+ s = @t.statistics
122
+ expect(s.leaf_nodes).to eql(5)
123
+ expect(s.branch_nodes).to eql(3)
124
+
125
+ @t.remove(2)
126
+ @t.remove(3)
127
+ @t.remove(4)
128
+ @t.remove(5)
129
+ expect(@t.check).to be true
130
+ s = @t.statistics
131
+ expect(s.leaf_nodes).to eql(3)
132
+ expect(s.branch_nodes).to eql(1)
133
+ end
134
+
135
+ it 'should merge branch node with previous sibling' do
136
+ 12.times { |n| @t.insert(n, n) }
137
+ expect(@t.check).to be true
138
+ s = @t.statistics
139
+ expect(s.leaf_nodes).to eql(5)
140
+ expect(s.branch_nodes).to eql(3)
141
+
142
+ @t.remove(4)
143
+ @t.remove(5)
144
+ @t.remove(2)
145
+ @t.remove(3)
146
+ expect(@t.check).to be true
147
+ s = @t.statistics
148
+ expect(s.leaf_nodes).to eql(3)
149
+ expect(s.branch_nodes).to eql(1)
150
+ end
151
+
152
+ end
153
+
@@ -0,0 +1,259 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # MIT License
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ require 'fileutils'
27
+
28
+ require 'spec_helper'
29
+ require 'perobs/Store'
30
+ require 'perobs/BigTree'
31
+
32
+ describe PEROBS::BigTree do
33
+
34
+ ORDER = 7
35
+
36
+ before(:all) do
37
+ @db_name = generate_db_name(__FILE__)
38
+ @store = PEROBS::Store.new(@db_name)
39
+ @t = @store.new(PEROBS::BigTree, ORDER)
40
+ end
41
+
42
+ after(:all) do
43
+ @store.delete_store
44
+ end
45
+
46
+ it 'should be empty' do
47
+ expect(@t.empty?).to be true
48
+ expect(@t.length).to eql(0)
49
+ s = @t.statistics
50
+ expect(s.leaf_nodes).to eql(1)
51
+ expect(s.branch_nodes).to eql(0)
52
+ expect(s.min_depth).to eql(1)
53
+ expect(s.max_depth).to eql(1)
54
+ end
55
+
56
+ it 'should deal with requests for unknown keys' do
57
+ expect(@t.has_key?(42)).to be false
58
+ expect(@t.get(42)).to be_nil
59
+ end
60
+
61
+ it 'should support adding sequential key/value pairs' do
62
+ 0.upto(ORDER ** 3) do |i|
63
+ @t.insert(i, 3 * i)
64
+ expect(@t.check).to be true
65
+ expect(@t.length).to eql(i + 1)
66
+ expect(@t.has_key?(i)).to be true
67
+ expect(@t.get(i)).to eql(3 * i)
68
+ end
69
+ end
70
+
71
+ it 'should iterate over the stored key and value pairs' do
72
+ i = 0
73
+ @t.each do |k, v|
74
+ expect(k).to eql(i)
75
+ expect(v).to eql(3 * i)
76
+ i += 1
77
+ end
78
+ expect(i).to eql(ORDER ** 3 + 1)
79
+ end
80
+
81
+ it 'should iterate in reverse order over the stored key and value pairs' do
82
+ i = ORDER ** 3
83
+ @t.reverse_each do |k, v|
84
+ expect(k).to eql(i)
85
+ expect(v).to eql(3 * i)
86
+ i -= 1
87
+ end
88
+ expect(i).to eql(-1)
89
+ end
90
+
91
+ it 'should yield the key/value pairs on check' do
92
+ i = 0
93
+ @t.check do |k, v|
94
+ expect(k).to eql(k)
95
+ expect(v).to eql(3 * k)
96
+ i += 1
97
+ end
98
+ expect(i).to eql(ORDER ** 3 + 1)
99
+ end
100
+
101
+ it 'should support overwriting existing entries' do
102
+ 0.upto(ORDER ** 3) do |i|
103
+ @t.insert(i, 7 * i)
104
+ expect(@t.check).to be true
105
+ expect(@t.length).to eql(ORDER ** 3 + 1)
106
+ expect(@t.has_key?(i)).to be true
107
+ expect(@t.get(i)).to eql(7 * i)
108
+ end
109
+ end
110
+
111
+ it 'should support clearing the tree' do
112
+ @t.clear
113
+ expect(@t.check).to be true
114
+ expect(@t.empty?).to be true
115
+ expect(@t.length).to eql(0)
116
+ i = 0
117
+ @t.each { |k, v| i += 1 }
118
+ expect(i).to eql(0)
119
+ end
120
+
121
+ it 'should support adding random key/value pairs' do
122
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
123
+ @t.insert(i, i * 100)
124
+ end
125
+ expect(@t.check).to be true
126
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
127
+ expect(@t.get(i)).to eql(i * 100)
128
+ end
129
+ end
130
+
131
+ it 'should support removing keys in random order' do
132
+ @t.clear
133
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
134
+ @t.insert(i, i * 100)
135
+ end
136
+ expect(@t.length).to eql(ORDER ** 3)
137
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
138
+ expect(@t.remove(i)).to eql(i * 100)
139
+ expect(@t.check).to be true
140
+ end
141
+ expect(@t.length).to eql(0)
142
+ end
143
+
144
+ it 'should support removing keys in increasing order' do
145
+ @t.clear
146
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
147
+ @t.insert(i, i * 100)
148
+ end
149
+ expect(@t.length).to eql(ORDER ** 3)
150
+ (1..ORDER ** 3).to_a.each do |i|
151
+ expect(@t.remove(i)).to eql(i * 100)
152
+ expect(@t.check).to be true
153
+ end
154
+ expect(@t.length).to eql(0)
155
+ end
156
+
157
+ it 'should support removing keys in reverse order' do
158
+ @t.clear
159
+ (1..ORDER ** 3).to_a.shuffle.each do |i|
160
+ @t.insert(i, i * 100)
161
+ end
162
+ expect(@t.length).to eql(ORDER ** 3)
163
+ (1..ORDER ** 3).to_a.reverse_each do |i|
164
+ expect(@t.remove(i)).to eql(i * 100)
165
+ expect(@t.check).to be true
166
+ end
167
+ expect(@t.length).to eql(0)
168
+ end
169
+
170
+ it 'should persist the data' do
171
+ db_name = generate_db_name(__FILE__ + '_persist')
172
+ store = PEROBS::Store.new(db_name)
173
+ store['bigtree'] = t = store.new(PEROBS::BigTree, 4)
174
+ 10.times do |i|
175
+ t.insert(i, i)
176
+ end
177
+ 10.times do |i|
178
+ expect(t.get(i)).to eql(i)
179
+ end
180
+ store.exit
181
+
182
+ store = PEROBS::Store.new(db_name)
183
+ t = store['bigtree']
184
+ 10.times do |i|
185
+ expect(t.get(i)).to eql(i)
186
+ end
187
+ store.delete_store
188
+ end
189
+
190
+ it 'should delete all entries matching a condition' do
191
+ @t.clear
192
+ (1..50).to_a.shuffle.each do |i|
193
+ @t.insert(i, i)
194
+ end
195
+ @t.delete_if { |k, v| v % 7 == 0 }
196
+ expect(@t.check).to be true
197
+ @t.each do |k, v|
198
+ expect(v % 7).to be > 0, "failed for #{v}"
199
+ end
200
+ expect(@t.length).to eql(43)
201
+ @t.delete_if { |k, v| v % 2 == 0 }
202
+ expect(@t.check).to be true
203
+ @t.each do |k, v|
204
+ expect(v % 2).to be > 0
205
+ end
206
+ expect(@t.length).to eql(21)
207
+ @t.delete_if { |k, v| true }
208
+ expect(@t.check).to be true
209
+ expect(@t.empty?).to be true
210
+ end
211
+
212
+ it 'should survive a real-world usage test' do
213
+ @t.clear
214
+ ref = {}
215
+ 0.upto(1000) do
216
+ case rand(5)
217
+ when 0
218
+ 0.upto(2) do
219
+ key = rand(100000)
220
+ value = key * 10
221
+ @t.insert(key, value)
222
+ ref[key] = value
223
+ end
224
+ when 1
225
+ if ref.length > 0
226
+ key = ref.keys[rand(ref.keys.length)]
227
+ expect(@t.remove(key)).to eql(ref[key])
228
+ ref.delete(key)
229
+ end
230
+ when 2
231
+ if ref.length > 0
232
+ 0.upto(3) do
233
+ key = ref.keys[rand(ref.keys.length)]
234
+ expect(@t.get(key)).to eql(ref[key])
235
+ end
236
+ end
237
+ when 3
238
+ if ref.length > 0
239
+ key = ref.keys[rand(ref.keys.length)]
240
+ value = ref[key] + 1
241
+ @t.insert(key, value)
242
+ ref[key] = value
243
+ end
244
+ when 4
245
+ if rand(50) == 0
246
+ expect(@t.check).to be true
247
+ end
248
+ end
249
+ end
250
+
251
+ i = 0
252
+ @t.each do |k, v|
253
+ expect(ref[k]).to eql(v)
254
+ i += 1
255
+ end
256
+ expect(i).to eql(ref.length)
257
+ end
258
+
259
+ end