strokedb 0.0.2.1 → 0.0.2.2
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.
- data/README +18 -20
- data/bench.html +4001 -0
- data/bin/strokedb +14 -0
- data/examples/movies.rb +105 -0
- data/examples/movies2.rb +97 -0
- data/examples/strokewiki/README +28 -0
- data/examples/strokewiki/view/edit.xhtml +27 -0
- data/examples/strokewiki/view/new.xhtml +26 -0
- data/examples/strokewiki/view/pages.xhtml +27 -0
- data/examples/strokewiki/view/show.xhtml +40 -0
- data/examples/strokewiki/view/versions.xhtml +25 -0
- data/examples/strokewiki/wiki.rb +106 -0
- data/examples/todo.rb +92 -0
- data/lib/strokedb.rb +85 -0
- data/lib/{config → strokedb}/config.rb +14 -9
- data/lib/strokedb/console.rb +87 -0
- data/lib/strokedb/core_ext.rb +10 -0
- data/lib/{util/ext → strokedb/core_ext}/blank.rb +1 -1
- data/lib/{util/ext → strokedb/core_ext}/enumerable.rb +0 -0
- data/lib/{util/ext → strokedb/core_ext}/fixnum.rb +0 -0
- data/lib/strokedb/core_ext/float.rb +4 -0
- data/lib/{util/ext → strokedb/core_ext}/hash.rb +0 -0
- data/lib/strokedb/core_ext/infinity.rb +33 -0
- data/lib/strokedb/core_ext/kernel.rb +41 -0
- data/lib/strokedb/core_ext/object.rb +16 -0
- data/lib/{util/ext → strokedb/core_ext}/string.rb +28 -1
- data/lib/strokedb/core_ext/symbol.rb +13 -0
- data/lib/strokedb/data_structures.rb +5 -0
- data/lib/strokedb/data_structures/chunked_skiplist.rb +123 -0
- data/lib/{data_structures → strokedb/data_structures}/inverted_list.rb +0 -0
- data/lib/{data_structures → strokedb/data_structures}/point_query.rb +0 -0
- data/lib/strokedb/data_structures/simple_skiplist.rb +350 -0
- data/lib/{data_structures → strokedb/data_structures}/skiplist.rb +1 -1
- data/lib/{document → strokedb}/document.rb +180 -71
- data/lib/{document → strokedb/document}/callback.rb +0 -0
- data/lib/{document → strokedb/document}/delete.rb +2 -2
- data/lib/strokedb/document/dsl.rb +4 -0
- data/lib/{document → strokedb/document/dsl}/associations.rb +0 -0
- data/lib/{document → strokedb/document/dsl}/coercions.rb +0 -0
- data/lib/strokedb/document/dsl/meta_dsl.rb +7 -0
- data/lib/{document → strokedb/document/dsl}/validations.rb +26 -21
- data/lib/{document → strokedb/document/dsl}/virtualize.rb +0 -0
- data/lib/{document → strokedb/document}/meta.rb +92 -29
- data/lib/{document → strokedb/document}/slot.rb +17 -5
- data/lib/{document → strokedb/document}/util.rb +0 -0
- data/lib/{document → strokedb/document}/versions.rb +2 -2
- data/lib/strokedb/index.rb +2 -0
- data/lib/strokedb/nsurl.rb +24 -0
- data/lib/strokedb/store.rb +149 -0
- data/lib/strokedb/stores.rb +6 -0
- data/lib/{stores → strokedb/stores}/chainable_storage.rb +20 -14
- data/lib/strokedb/stores/file_storage.rb +118 -0
- data/lib/{stores/inverted_list_index → strokedb/stores}/inverted_list_file_storage.rb +50 -0
- data/lib/strokedb/stores/memory_storage.rb +80 -0
- data/lib/{stores → strokedb/stores}/remote_store.rb +10 -4
- data/lib/strokedb/sync.rb +4 -0
- data/lib/{sync → strokedb/sync}/chain_sync.rb +0 -0
- data/lib/{sync → strokedb/sync}/diff.rb +12 -1
- data/lib/{sync/stroke_diff → strokedb/sync/diff}/array.rb +1 -1
- data/lib/{sync/stroke_diff → strokedb/sync/diff}/default.rb +0 -0
- data/lib/{sync/stroke_diff → strokedb/sync/diff}/hash.rb +1 -1
- data/lib/{sync/stroke_diff → strokedb/sync/diff}/string.rb +1 -1
- data/lib/{sync → strokedb/sync}/lamport_timestamp.rb +0 -0
- data/lib/{sync → strokedb/sync}/store_sync.rb +15 -7
- data/lib/strokedb/transaction.rb +78 -0
- data/lib/{util → strokedb}/util.rb +14 -7
- data/lib/strokedb/util/attach_dsl.rb +29 -0
- data/lib/{util → strokedb/util}/blankslate.rb +0 -0
- data/lib/strokedb/util/class_optimization.rb +93 -0
- data/lib/{util → strokedb/util}/inflect.rb +0 -0
- data/lib/strokedb/util/java_util.rb +13 -0
- data/lib/{util → strokedb/util}/lazy_array.rb +0 -0
- data/lib/{util → strokedb/util}/lazy_mapping_array.rb +4 -0
- data/lib/{util → strokedb/util}/lazy_mapping_hash.rb +0 -0
- data/lib/{util → strokedb/util}/serialization.rb +21 -0
- data/lib/strokedb/util/uuid.rb +159 -0
- data/lib/{util → strokedb/util}/xml.rb +0 -0
- data/lib/{view → strokedb}/view.rb +2 -2
- data/lib/strokedb/volumes.rb +5 -0
- data/lib/strokedb/volumes/archive_volume.rb +165 -0
- data/lib/strokedb/volumes/block_volume.rb +169 -0
- data/lib/strokedb/volumes/distributed_pointer.rb +43 -0
- data/lib/strokedb/volumes/fixed_length_skiplist_volume.rb +109 -0
- data/lib/strokedb/volumes/map_volume.rb +268 -0
- data/meta/MANIFEST +175 -0
- data/script/console +2 -70
- data/spec/integration/remote_store_spec.rb +70 -0
- data/spec/integration/search_spec.rb +76 -0
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/lib/spec_helper.rb +1 -0
- data/spec/lib/strokedb/config_spec.rb +250 -0
- data/spec/lib/strokedb/core_ext/blank_spec.rb +20 -0
- data/spec/lib/strokedb/core_ext/extract_spec.rb +42 -0
- data/spec/lib/strokedb/core_ext/float_spec.rb +62 -0
- data/spec/lib/strokedb/core_ext/infinity_spec.rb +40 -0
- data/spec/lib/strokedb/core_ext/spec_helper.rb +1 -0
- data/spec/lib/strokedb/core_ext/string_spec.rb +25 -0
- data/spec/lib/strokedb/core_ext/symbol_spec.rb +8 -0
- data/spec/lib/strokedb/data_structures/chunked_skiplist_spec.rb +144 -0
- data/spec/lib/strokedb/data_structures/inverted_list_spec.rb +172 -0
- data/spec/lib/strokedb/data_structures/simple_skiplist_spec.rb +200 -0
- data/spec/lib/strokedb/data_structures/skiplist_spec.rb +253 -0
- data/spec/lib/strokedb/data_structures/spec_helper.rb +1 -0
- data/spec/lib/strokedb/document/associations_spec.rb +319 -0
- data/spec/lib/strokedb/document/callbacks_spec.rb +134 -0
- data/spec/lib/strokedb/document/coercions_spec.rb +110 -0
- data/spec/lib/strokedb/document/document_spec.rb +1063 -0
- data/spec/lib/strokedb/document/meta_meta_spec.rb +30 -0
- data/spec/lib/strokedb/document/meta_spec.rb +435 -0
- data/spec/lib/strokedb/document/metaslot_spec.rb +43 -0
- data/spec/lib/strokedb/document/slot_spec.rb +130 -0
- data/spec/lib/strokedb/document/spec_helper.rb +1 -0
- data/spec/lib/strokedb/document/validations_spec.rb +1081 -0
- data/spec/lib/strokedb/document/virtualize_spec.rb +80 -0
- data/spec/lib/strokedb/nsurl_spec.rb +73 -0
- data/spec/lib/strokedb/spec_helper.rb +1 -0
- data/spec/lib/strokedb/stores/chained_storages_spec.rb +116 -0
- data/spec/lib/strokedb/stores/spec_helper.rb +1 -0
- data/spec/lib/strokedb/stores/store_spec.rb +201 -0
- data/spec/lib/strokedb/stores/transaction_spec.rb +107 -0
- data/spec/lib/strokedb/sync/chain_sync_spec.rb +43 -0
- data/spec/lib/strokedb/sync/diff_spec.rb +111 -0
- data/spec/lib/strokedb/sync/lamport_timestamp_spec.rb +174 -0
- data/spec/lib/strokedb/sync/slot_diff_spec.rb +164 -0
- data/spec/lib/strokedb/sync/spec_helper.rb +1 -0
- data/spec/lib/strokedb/sync/store_sync_spec.rb +181 -0
- data/spec/lib/strokedb/sync/stroke_diff/array_spec.rb +97 -0
- data/spec/lib/strokedb/sync/stroke_diff/complex_spec.rb +58 -0
- data/spec/lib/strokedb/sync/stroke_diff/hash_spec.rb +144 -0
- data/spec/lib/strokedb/sync/stroke_diff/scalar_spec.rb +23 -0
- data/spec/lib/strokedb/sync/stroke_diff/spec_helper.rb +25 -0
- data/spec/lib/strokedb/sync/stroke_diff/string_spec.rb +61 -0
- data/spec/lib/strokedb/util/attach_dsl_spec.rb +45 -0
- data/spec/lib/strokedb/util/inflect_spec.rb +14 -0
- data/spec/lib/strokedb/util/lazy_array_spec.rb +157 -0
- data/spec/lib/strokedb/util/lazy_mapping_array_spec.rb +174 -0
- data/spec/lib/strokedb/util/lazy_mapping_hash_spec.rb +92 -0
- data/spec/lib/strokedb/util/spec_helper.rb +1 -0
- data/spec/lib/strokedb/util/uuid_spec.rb +46 -0
- data/spec/lib/strokedb/view_spec.rb +228 -0
- data/spec/lib/strokedb/volumes/archive_volume_spec.rb +105 -0
- data/spec/lib/strokedb/volumes/block_volume_spec.rb +100 -0
- data/spec/lib/strokedb/volumes/distributed_pointer_spec.rb +14 -0
- data/spec/lib/strokedb/volumes/fixed_length_skiplist_volume_spec.rb +177 -0
- data/spec/lib/strokedb/volumes/map_volume_spec.rb +172 -0
- data/spec/lib/strokedb/volumes/spec_helper.rb +1 -0
- data/spec/regression/docref_spec.rb +94 -0
- data/spec/regression/meta_spec.rb +23 -0
- data/spec/regression/spec_helper.rb +1 -0
- data/spec/regression/sync_spec.rb +36 -0
- data/spec/spec.opts +7 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/temp/storages/TIMESTAMP +1 -0
- data/spec/temp/storages/UUID +1 -0
- data/spec/temp/storages/database-sync/TIMESTAMP +1 -0
- data/spec/temp/storages/database-sync/UUID +1 -0
- data/spec/temp/storages/database-sync/config +1 -0
- data/spec/temp/storages/database-sync/file/LAST +1 -0
- data/spec/temp/storages/database-sync/file/bd/f6/bdf675e5-8a7b-494e-97f2-f74a14ccd95d.av +0 -0
- data/spec/temp/storages/database-sync/file/uindex.wal +0 -0
- data/spec/temp/storages/database-sync/inverted_list_file/INVERTED_INDEX +1 -0
- data/spec/temp/storages/inverted_list_storage/INVERTED_INDEX +0 -0
- data/strokedb.gemspec +120 -0
- data/task/benchmark.task +9 -0
- data/task/ditz.task +30 -0
- data/task/echoe.rb +17 -0
- data/task/rcov.task +50 -0
- data/task/rdoc.task +10 -0
- data/task/rspec.task +0 -0
- data/vendor/java_inline.rb +106 -0
- data/vendor/rbmodexcl/mrimodexcl.rb +82 -0
- data/vendor/rbmodexcl/rbmodexcl.rb +5 -0
- data/vendor/rbmodexcl/rbxmodexcl.rb +48 -0
- data/vendor/rbmodexcl/spec/unextend_spec.rb +50 -0
- data/vendor/rbmodexcl/spec/uninclude_spec.rb +26 -0
- metadata +271 -79
- data/CONTRIBUTORS +0 -7
- data/CREDITS +0 -13
- data/bin/sdbc +0 -2
- data/lib/init.rb +0 -57
- data/lib/stores/inverted_list_index/inverted_list_index.rb +0 -49
- data/lib/stores/skiplist_store/chunk.rb +0 -119
- data/lib/stores/skiplist_store/chunk_storage.rb +0 -21
- data/lib/stores/skiplist_store/file_chunk_storage.rb +0 -44
- data/lib/stores/skiplist_store/memory_chunk_storage.rb +0 -37
- data/lib/stores/skiplist_store/skiplist_store.rb +0 -217
- data/lib/stores/store.rb +0 -5
- data/lib/sync/stroke_diff/stroke_diff.rb +0 -9
- data/lib/util/ext/object.rb +0 -8
- data/lib/util/java_util.rb +0 -9
- data/lib/util/trigger_partition.rb +0 -136
- data/strokedb.rb +0 -75
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe "Skiplist serialization", :shared => true do
|
|
5
|
+
it "should correctly load what it dumped" do
|
|
6
|
+
dump1 = @list.marshal_dump
|
|
7
|
+
newlist = @list.class.allocate
|
|
8
|
+
dump2 = newlist.marshal_load(dump1).marshal_dump
|
|
9
|
+
dump1.should == dump2
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should correctly load to_a results" do
|
|
13
|
+
arr1 = @list.to_a
|
|
14
|
+
newlist = @list.class.from_a(arr1)
|
|
15
|
+
arr2 = newlist.to_a
|
|
16
|
+
arr1.should == arr2
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
SimpleSkiplist.with_optimizations(OPTIMIZATIONS) do |lang|
|
|
21
|
+
|
|
22
|
+
describe "Empty SimpleSkiplist [#{lang}]" do
|
|
23
|
+
|
|
24
|
+
before(:each) do
|
|
25
|
+
@maxlevel = 8
|
|
26
|
+
@probability = 0.5
|
|
27
|
+
@list = SimpleSkiplist.new(nil, :maxlevel => @maxlevel, :probability => @probability)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should be empty" do
|
|
31
|
+
@list.should be_empty
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should be serialized with marshal_dump" do
|
|
35
|
+
@list.marshal_dump.should == {
|
|
36
|
+
:options => {
|
|
37
|
+
:probability => @probability,
|
|
38
|
+
:maxlevel => @maxlevel
|
|
39
|
+
},
|
|
40
|
+
:raw_list => [
|
|
41
|
+
[[nil]*@maxlevel, nil, nil]
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should find nil in a empty skiplist" do
|
|
47
|
+
@list.find("xx").should == nil
|
|
48
|
+
@list.find("").should == nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it_should_behave_like "Skiplist serialization"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
describe "Inserting in a skiplist [#{lang}]" do
|
|
56
|
+
|
|
57
|
+
before(:each) do
|
|
58
|
+
@maxlevel = 8
|
|
59
|
+
@probability = 0.5
|
|
60
|
+
@list = SimpleSkiplist.new(nil, :maxlevel => @maxlevel, :probability => @probability)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should insert empty key in place of default head" do
|
|
64
|
+
@list.insert("", 42, 1).should == @list
|
|
65
|
+
@list.find("").should == 42
|
|
66
|
+
@list.find("-").should == nil
|
|
67
|
+
@list.to_a.should == [["", 42]]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should insert non-empty key" do
|
|
71
|
+
@list.insert("x", 42, 1).should == @list
|
|
72
|
+
@list.find("").should == nil
|
|
73
|
+
@list.find("x").should == 42
|
|
74
|
+
@list.find("-").should == nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should correctly insert keys in an ascending level order" do
|
|
78
|
+
1.upto(@maxlevel) do |i|
|
|
79
|
+
k = "x#{i}"
|
|
80
|
+
@list.insert(k, k, i).should == @list
|
|
81
|
+
@list.find("").should == nil
|
|
82
|
+
@list.find(k).should == k
|
|
83
|
+
@list.find("-").should == nil
|
|
84
|
+
end
|
|
85
|
+
# repeat
|
|
86
|
+
1.upto(@maxlevel) do |i|
|
|
87
|
+
k = "x#{i}"
|
|
88
|
+
@list.find(k).should == k
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should correctly insert keys in a descending level order" do
|
|
93
|
+
@maxlevel.downto(1) do |i|
|
|
94
|
+
k = "x#{@maxlevel-i}"
|
|
95
|
+
@list.insert(k, k, i).should == @list
|
|
96
|
+
@list.find("").should == nil
|
|
97
|
+
@list.find(k).should == k
|
|
98
|
+
@list.find("-").should == nil
|
|
99
|
+
end
|
|
100
|
+
# repeat
|
|
101
|
+
@maxlevel.downto(1) do |i|
|
|
102
|
+
k = "x#{@maxlevel-i}"
|
|
103
|
+
@list.find(k).should == k
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
describe "Big skiplist [#{lang}]" do
|
|
110
|
+
before(:each) do
|
|
111
|
+
@maxlevel = 8
|
|
112
|
+
@probability = 0.5
|
|
113
|
+
@list = SimpleSkiplist.new(nil, :maxlevel => @maxlevel, :probability => @probability)
|
|
114
|
+
1000.times do
|
|
115
|
+
k = rand(2**64).to_s
|
|
116
|
+
v = k
|
|
117
|
+
@list.insert(k, v)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it_should_behave_like "Skiplist serialization"
|
|
122
|
+
|
|
123
|
+
it "should support to_a with sorted key-value pairs" do
|
|
124
|
+
ary = @list.to_a
|
|
125
|
+
ary.should == ary.sort{|a,b| a[0] <=> b[0] }
|
|
126
|
+
ary.size.should == 1000
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "should have iterate pairs with #each" do
|
|
130
|
+
c = []
|
|
131
|
+
@list.each do |key, value|
|
|
132
|
+
c << [key, value]
|
|
133
|
+
end
|
|
134
|
+
c.should have_at_least(10).items
|
|
135
|
+
c[0..10].each do |a|
|
|
136
|
+
a[0].should == a[1] # key == value
|
|
137
|
+
end
|
|
138
|
+
c.should == c.sort{|a, b| a[0] <=> b[0] } # sorted order
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
describe "SimpleSkiplist#first_key [#{lang}]" do
|
|
145
|
+
before(:each) do
|
|
146
|
+
@maxlevel = 8
|
|
147
|
+
@probability = 0.5
|
|
148
|
+
@list = SimpleSkiplist.new(nil, :maxlevel => @maxlevel, :probability => @probability)
|
|
149
|
+
end
|
|
150
|
+
it "should return nil for empty skiplist" do
|
|
151
|
+
@list.first_key.should == nil
|
|
152
|
+
end
|
|
153
|
+
it "should return key for non-empty skiplist" do
|
|
154
|
+
@list.insert("b", "data1")
|
|
155
|
+
@list.first_key.should == "b"
|
|
156
|
+
@list.insert("c", "data2")
|
|
157
|
+
@list.first_key.should == "b"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
describe "SimpleSkiplist#find_nearest [#{lang}]" do
|
|
163
|
+
before(:each) do
|
|
164
|
+
@maxlevel = 8
|
|
165
|
+
@probability = 0.5
|
|
166
|
+
@list = SimpleSkiplist.new(nil, :maxlevel => @maxlevel, :probability => @probability)
|
|
167
|
+
end
|
|
168
|
+
it "should find nil in empty skiplist" do
|
|
169
|
+
@list.find_nearest("a").should == nil
|
|
170
|
+
@list.find_nearest("").should == nil
|
|
171
|
+
@list.find_nearest(nil).should == nil
|
|
172
|
+
end
|
|
173
|
+
it "should find exact value if it is present" do
|
|
174
|
+
@list.insert("b", "B")
|
|
175
|
+
@list.insert("f", "F")
|
|
176
|
+
@list.find_nearest("b").should == "B"
|
|
177
|
+
@list.find_nearest("f").should == "F"
|
|
178
|
+
end
|
|
179
|
+
it "should find nearest value or nil" do
|
|
180
|
+
@list.insert("b", "B")
|
|
181
|
+
@list.insert("f", "F")
|
|
182
|
+
@list.find_nearest("a").should == nil
|
|
183
|
+
@list.find_nearest("c").should == "B"
|
|
184
|
+
@list.find_nearest("g").should == "F"
|
|
185
|
+
end
|
|
186
|
+
it "should always find empty-string key if nothing found" do
|
|
187
|
+
@list.insert("", "Empty")
|
|
188
|
+
@list.insert("b", "B")
|
|
189
|
+
@list.insert("f", "F")
|
|
190
|
+
@list.find_nearest("a").should == "Empty"
|
|
191
|
+
@list.find_nearest("c").should == "B"
|
|
192
|
+
@list.find_nearest("g").should == "F"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def raw_list(list)
|
|
198
|
+
list.marshal_dump[:raw_list]
|
|
199
|
+
end
|
|
200
|
+
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Non-empty skiplist" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@list = Skiplist.new("a" => "1",
|
|
7
|
+
"aa" => "2",
|
|
8
|
+
"aaa" => "3",
|
|
9
|
+
"p" => "4",
|
|
10
|
+
"123.1" => "v1",
|
|
11
|
+
"123.2" => "v2",
|
|
12
|
+
"123" => "v0")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should not be empty" do
|
|
16
|
+
@list.should_not be_empty
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should have size" do
|
|
20
|
+
@list.should have(7).items
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should find" do
|
|
24
|
+
@list.find("a").should == "1"
|
|
25
|
+
@list.find("aaa").should == "3"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should find entries with prefix" do
|
|
29
|
+
@list.find_all_with_prefix("123").to_set.should == ["v1","v2","v0"].to_set
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should find default value if search with prefix returns nothing" do
|
|
33
|
+
@list.find_all_with_prefix("nothinglike123").should == []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should return default value if nothing found" do
|
|
37
|
+
@list.find("404").should be_nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should give local default value if nothing found" do
|
|
41
|
+
@list.find("404", :default_value).should == :default_value
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should insert data" do
|
|
45
|
+
@list.insert("b", "3.5")
|
|
46
|
+
@list.find("b").should == "3.5"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should replace data" do
|
|
50
|
+
@list.insert("aaa", "3.5")
|
|
51
|
+
@list.find("aaa").should == "3.5"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should delete node by key" do
|
|
55
|
+
@list.delete("aaa").should == "3"
|
|
56
|
+
@list.find("aaa").should be_nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should not delete non-existent key" do
|
|
60
|
+
@list.find("404").should be_nil
|
|
61
|
+
@list.delete("404").should be_nil
|
|
62
|
+
@list.find("404").should be_nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should find the nearest key" do
|
|
66
|
+
@list.find_nearest("0").should == "v0"
|
|
67
|
+
@list.find_nearest("a").should == "1"
|
|
68
|
+
@list.find_nearest("aa").should == "2"
|
|
69
|
+
@list.find_nearest("aa0").should == "2"
|
|
70
|
+
@list.find_nearest("aaa").should == "3"
|
|
71
|
+
@list.find_nearest("ab").should == "3"
|
|
72
|
+
@list.find_nearest("d").should == "3"
|
|
73
|
+
@list.find_nearest("xxx").should == "4"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
describe "Skiplist with duplicate keys" do
|
|
80
|
+
|
|
81
|
+
before(:all) do
|
|
82
|
+
@list = Skiplist.new({}, nil, nil, false)
|
|
83
|
+
@list.insert("a", "v1")
|
|
84
|
+
@list.insert("a", "v2")
|
|
85
|
+
@list.insert("a", "v3")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should find first value" do
|
|
89
|
+
@list.find("a").should == 'v1'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should find node iterator" do
|
|
93
|
+
@list.find_node("a").value.should == 'v1'
|
|
94
|
+
@list.find_node("a").next.value.should == 'v2'
|
|
95
|
+
@list.find_node("a").next.next.value.should == 'v3'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe "Skiplist (cut)" do
|
|
101
|
+
|
|
102
|
+
before(:each) do
|
|
103
|
+
@chunk = Skiplist.new({}, nil, 4)
|
|
104
|
+
@chunk.insert('500', 'V', 2)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "should find single value" do
|
|
108
|
+
@chunk.find('500').should == 'V'
|
|
109
|
+
@chunk.size.should == 1
|
|
110
|
+
end
|
|
111
|
+
[['low level',1],['cut level',1],['high level',6]].each do |t, l|
|
|
112
|
+
it "should insert #{t} item into the start" do
|
|
113
|
+
a, b = @chunk.insert('200', 'W', l)
|
|
114
|
+
a.find('200').should == 'W'
|
|
115
|
+
a.find('500').should == 'V'
|
|
116
|
+
a.should == @chunk
|
|
117
|
+
b.should be_nil
|
|
118
|
+
@chunk.size.should == 2
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "should cut when high level item inserted in the middle" do
|
|
123
|
+
a, b = @chunk.insert('600', 'W', 6)
|
|
124
|
+
a.find('500').should == 'V'
|
|
125
|
+
a.find('600').should be_nil
|
|
126
|
+
a.should == @chunk
|
|
127
|
+
a.size.should == 1
|
|
128
|
+
b.should be_kind_of(Skiplist)
|
|
129
|
+
b.find('500').should be_nil
|
|
130
|
+
b.find('600').should == 'W'
|
|
131
|
+
b.size.should == 1
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "should cut when high level item inserted in the middle, but several hi-level items in the start" do
|
|
135
|
+
a, b = @chunk.insert('300', 'X', 6)
|
|
136
|
+
a, b = @chunk.insert('200', 'Y', 5)
|
|
137
|
+
a, b = @chunk.insert('600', 'W', 6)
|
|
138
|
+
a.find('500').should == 'V'
|
|
139
|
+
a.find('300').should == 'X'
|
|
140
|
+
a.find('200').should == 'Y'
|
|
141
|
+
a.find('600').should be_nil
|
|
142
|
+
a.should == @chunk
|
|
143
|
+
a.size.should == 3
|
|
144
|
+
b.should be_kind_of(Skiplist)
|
|
145
|
+
b.find('500').should be_nil
|
|
146
|
+
b.find('300').should be_nil
|
|
147
|
+
b.find('200').should be_nil
|
|
148
|
+
b.find('600').should == 'W'
|
|
149
|
+
b.size.should == 1
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe "Empty big skiplist" do
|
|
156
|
+
|
|
157
|
+
before(:each) do
|
|
158
|
+
@list = Skiplist.new
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "should be empty" do
|
|
162
|
+
@list.should be_empty
|
|
163
|
+
@list.should have(0).items
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "should be empty with #each iteratpr" do
|
|
167
|
+
a = b = "each{ } did not yield"
|
|
168
|
+
@list.each{|n| a = "each{ } did yield!" }
|
|
169
|
+
a.should == b
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should not find anything" do
|
|
173
|
+
@list.find("a").should be_nil
|
|
174
|
+
@list.find("").should be_nil
|
|
175
|
+
@list.find("aaa").should be_nil
|
|
176
|
+
@list.find(123).should be_nil
|
|
177
|
+
@list.find(-1).should be_nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "should not delete anything" do
|
|
181
|
+
@list.delete("a").should be_nil
|
|
182
|
+
@list.delete("a").should be_nil
|
|
183
|
+
@list.delete("").should be_nil
|
|
184
|
+
@list.delete("aaa").should be_nil
|
|
185
|
+
@list.delete(123).should be_nil
|
|
186
|
+
@list.delete(-1).should be_nil
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
describe "Non-empty big skiplist" do
|
|
193
|
+
|
|
194
|
+
before(:each) do
|
|
195
|
+
a = []
|
|
196
|
+
100.times { |i|
|
|
197
|
+
a << "#{i}"
|
|
198
|
+
a << "#{rand(100)}"
|
|
199
|
+
}
|
|
200
|
+
@list = Skiplist.new(Hash[*a])
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "should contain all the items" do
|
|
204
|
+
#puts @list.to_s_levels
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
describe "Skiplist search" do
|
|
211
|
+
before(:each) do
|
|
212
|
+
@times = 100
|
|
213
|
+
@start = 128
|
|
214
|
+
@ratio = 2
|
|
215
|
+
@lists = [@start, @start*@ratio, @start*@ratio*@ratio].map do |len|
|
|
216
|
+
list = Skiplist.new
|
|
217
|
+
len.times do |i|
|
|
218
|
+
list.insert(i, rand)
|
|
219
|
+
end
|
|
220
|
+
list
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it "should be O(log(n))" do
|
|
225
|
+
t1 = time(@times, @lists[0])
|
|
226
|
+
t2 = time(@times, @lists[1])
|
|
227
|
+
t3 = time(@times, @lists[2])
|
|
228
|
+
|
|
229
|
+
r1 = Math.log(t2/t1)
|
|
230
|
+
r2 = Math.log(t3/t2)
|
|
231
|
+
|
|
232
|
+
#p [t1, t2, t3]
|
|
233
|
+
#p [r1, r2]
|
|
234
|
+
|
|
235
|
+
# r1.should == r2
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def time(n, list)
|
|
239
|
+
GC.start
|
|
240
|
+
t = Time.now
|
|
241
|
+
s = list.size
|
|
242
|
+
n.times { list.find(rand(s)) }
|
|
243
|
+
Time.now - t
|
|
244
|
+
ensure
|
|
245
|
+
GC.start
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|