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,100 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe BlockVolume, "initialization" do
|
|
4
|
+
|
|
5
|
+
before(:all) do
|
|
6
|
+
FileUtils.rm_rf TEMP_STORAGES + '/block_volume_spec'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
before(:each) do
|
|
10
|
+
@path = TEMP_STORAGES + '/block_volume_spec'
|
|
11
|
+
@size = 2
|
|
12
|
+
@count = 2
|
|
13
|
+
@options = {:block_size => @size,
|
|
14
|
+
:blocks_count => @count,
|
|
15
|
+
:path => @path}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should go well with raw uuid" do
|
|
19
|
+
raw_uuid = Util.random_uuid_raw
|
|
20
|
+
BlockVolume.new(@options.merge(:uuid => raw_uuid)).uuid.should == raw_uuid.to_formatted_uuid
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should go well with formatted uuid" do
|
|
24
|
+
uuid = Util.random_uuid
|
|
25
|
+
BlockVolume.new(@options.merge(:uuid => uuid)).uuid.should == uuid
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should generate new UUID if none given" do
|
|
29
|
+
BlockVolume.new(@options).uuid.should match(/#{UUID_RE}/)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe BlockVolume do
|
|
36
|
+
|
|
37
|
+
before(:all) do
|
|
38
|
+
FileUtils.rm_rf TEMP_STORAGES + '/block_volume_spec'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
before(:each) do
|
|
42
|
+
@path = TEMP_STORAGES + '/block_volume_spec'
|
|
43
|
+
@raw_uuid = Util.random_uuid_raw
|
|
44
|
+
@size = 2
|
|
45
|
+
@count = 2
|
|
46
|
+
@options = {:uuid => @raw_uuid,
|
|
47
|
+
:block_size => @size,
|
|
48
|
+
:blocks_count => @count,
|
|
49
|
+
:path => @path}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should be created with given size" do
|
|
53
|
+
dv = BlockVolume.new(@options)
|
|
54
|
+
fname = dv.file_path
|
|
55
|
+
File.should be_exist(fname)
|
|
56
|
+
File.size(fname).should == 8 + 2*@size
|
|
57
|
+
File.open(fname){|f| f.read }[8..-1].should == "\x00"*(@size*2)
|
|
58
|
+
dv.delete!
|
|
59
|
+
File.should_not be_exist(fname)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should write some data and read it" do
|
|
63
|
+
dv = BlockVolume.new(@options)
|
|
64
|
+
dv.insert(0, "x")
|
|
65
|
+
dv.read(0).should == "x\x00"
|
|
66
|
+
dv.insert(1, "y")
|
|
67
|
+
dv.read(1).should == "y\x00"
|
|
68
|
+
dv.close!
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should overwrite some data and read it" do
|
|
72
|
+
dv = BlockVolume.new(@options)
|
|
73
|
+
dv.insert(0, "x")
|
|
74
|
+
dv.read(0).should == "x\x00"
|
|
75
|
+
dv.insert(0, "y")
|
|
76
|
+
dv.read(0).should == "y\x00"
|
|
77
|
+
dv.close!
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should extend volume" do
|
|
81
|
+
dv = BlockVolume.new(@options)
|
|
82
|
+
dv.insert(0, "x")
|
|
83
|
+
dv.read(0).should == "x\x00"
|
|
84
|
+
dv.insert(1, "y")
|
|
85
|
+
dv.read(1).should == "y\x00"
|
|
86
|
+
dv.insert(2, "z")
|
|
87
|
+
dv.read(2).should == "z\x00"
|
|
88
|
+
dv.read(3).should == "\x00\x00"
|
|
89
|
+
dv.close!
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should raise exception if file is closed" do
|
|
93
|
+
dv = BlockVolume.new(@options)
|
|
94
|
+
dv.close!
|
|
95
|
+
|
|
96
|
+
lambda { dv.read(0) }.should raise_error(BlockVolume::VolumeClosedException)
|
|
97
|
+
lambda { dv.insert(0, "d") }.should raise_error(BlockVolume::VolumeClosedException)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "DistributedPointer" do
|
|
4
|
+
it "should be packed correctly" do
|
|
5
|
+
dp = DistributedPointer.new("\xff"*16, 1)
|
|
6
|
+
dp.pack.should == "\xff"*16 + "\x01\x00\x00\x00"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should be unpacked correctly" do
|
|
10
|
+
dp = DistributedPointer.unpack("\xff"*16 + "\x05\x00\x00\x00")
|
|
11
|
+
dp.volume_uuid.should == "\xff"*16
|
|
12
|
+
dp.offset.should == 5
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
# SimpleSkiplist.with_optimizations(OPTIMIZATIONS) do |lang|
|
|
4
|
+
lang = "Ruby" # FIXME: it is a (temporary?) workaround to let this spec work fine together with simple_skiplist_spec
|
|
5
|
+
|
|
6
|
+
describe "Empty FixedLengthSkiplistVolume [#{lang}]" do
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
@maxlevel = 8
|
|
10
|
+
@probability = 0.5
|
|
11
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
12
|
+
FileUtils.rm_rf @path
|
|
13
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should be empty" do
|
|
17
|
+
@list.should be_empty
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should find nil in a empty skiplist" do
|
|
21
|
+
@list.find("x"*10).should == nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
describe "Inserting in a skiplist [#{lang}]" do
|
|
28
|
+
|
|
29
|
+
before(:each) do
|
|
30
|
+
@maxlevel = 8
|
|
31
|
+
@probability = 0.5
|
|
32
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
33
|
+
FileUtils.rm_rf @path
|
|
34
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should insert non-empty key" do
|
|
38
|
+
@list.insert("x"*10, "4"*10, 1).should == @list
|
|
39
|
+
@list.find("x"*10).should == "4"*10
|
|
40
|
+
@list.find("y"*10).should be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should correctly insert keys in an ascending level order" do
|
|
44
|
+
1.upto(@maxlevel) do |i|
|
|
45
|
+
k = "x#{i}".ljust(10,'0')
|
|
46
|
+
@list.insert(k, k, i).should == @list
|
|
47
|
+
@list.find(k).should == k
|
|
48
|
+
@list.find("-"*10).should == nil
|
|
49
|
+
end
|
|
50
|
+
# repeat
|
|
51
|
+
1.upto(@maxlevel) do |i|
|
|
52
|
+
k = "x#{i}".ljust(10,'0')
|
|
53
|
+
@list.find(k).should == k
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should correctly insert keys in a descending level order" do
|
|
58
|
+
@maxlevel.downto(1) do |i|
|
|
59
|
+
k = "x#{@maxlevel-i}".ljust(10,'0')
|
|
60
|
+
@list.insert(k, k, i).should == @list
|
|
61
|
+
@list.find(k).should == k
|
|
62
|
+
@list.find("-"*10).should == nil
|
|
63
|
+
end
|
|
64
|
+
# repeat
|
|
65
|
+
@maxlevel.downto(1) do |i|
|
|
66
|
+
k = "x#{@maxlevel-i}".ljust(10,'0')
|
|
67
|
+
@list.find(k).should == k
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
describe "Big skiplist [#{lang}]" do
|
|
74
|
+
before(:each) do
|
|
75
|
+
@maxlevel = 8
|
|
76
|
+
@probability = 0.5
|
|
77
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
78
|
+
FileUtils.rm_rf @path
|
|
79
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 20, :value_length => 20)
|
|
80
|
+
1000.times do
|
|
81
|
+
v = k = rand(2**64).to_s.rjust(20,'0')
|
|
82
|
+
@list.insert(k, v)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
it "should support to_a with sorted key-value pairs" do
|
|
88
|
+
ary = @list.to_a
|
|
89
|
+
ary.should == ary.sort{|a,b| a[0] <=> b[0] }
|
|
90
|
+
ary.size.should == 1000
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
describe "FixedLengthSkiplistVolume#first_key [#{lang}]" do
|
|
96
|
+
before(:each) do
|
|
97
|
+
@maxlevel = 8
|
|
98
|
+
@probability = 0.5
|
|
99
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
100
|
+
FileUtils.rm_rf @path
|
|
101
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
102
|
+
end
|
|
103
|
+
it "should return nil for empty skiplist" do
|
|
104
|
+
@list.first_key.should == nil
|
|
105
|
+
end
|
|
106
|
+
it "should return key for non-empty skiplist" do
|
|
107
|
+
@list.insert("b"*10, "1"*10)
|
|
108
|
+
@list.first_key.should == "b"*10
|
|
109
|
+
@list.insert("c"*10, "2"*10)
|
|
110
|
+
@list.first_key.should == "b"*10
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
describe "FixedLengthSkiplistVolume#find_nearest [#{lang}]" do
|
|
116
|
+
before(:each) do
|
|
117
|
+
@maxlevel = 8
|
|
118
|
+
@probability = 0.5
|
|
119
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
120
|
+
FileUtils.rm_rf @path
|
|
121
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
122
|
+
end
|
|
123
|
+
it "should find zero value in empty skiplist" do
|
|
124
|
+
@list.find_nearest("a").should == "\x00"*10
|
|
125
|
+
@list.find_nearest("").should == "\x00"*10
|
|
126
|
+
@list.find_nearest(nil).should == "\x00"*10
|
|
127
|
+
end
|
|
128
|
+
it "should find exact value if it is present" do
|
|
129
|
+
@list.insert("b"*10, "B"*10)
|
|
130
|
+
@list.insert("f"*10, "F"*10)
|
|
131
|
+
@list.find_nearest("b"*10).should == "B"*10
|
|
132
|
+
@list.find_nearest("f"*10).should == "F"*10
|
|
133
|
+
end
|
|
134
|
+
it "should find nearest value or nil" do
|
|
135
|
+
@list.insert("b"*10, "B"*10)
|
|
136
|
+
@list.insert("f"*10, "F"*10)
|
|
137
|
+
@list.find_nearest("a"*10).should == "\x00"*10
|
|
138
|
+
@list.find_nearest("c"*10).should == "B"*10
|
|
139
|
+
@list.find_nearest("g"*10).should == "F"*10
|
|
140
|
+
end
|
|
141
|
+
# it "should always find empty-string key if nothing found" do
|
|
142
|
+
# @list.insert("", "Empty")
|
|
143
|
+
# @list.insert("b", "B")
|
|
144
|
+
# @list.insert("f", "F")
|
|
145
|
+
# @list.find_nearest("a").should == "Empty"
|
|
146
|
+
# @list.find_nearest("c").should == "B"
|
|
147
|
+
# @list.find_nearest("g").should == "F"
|
|
148
|
+
# end
|
|
149
|
+
end
|
|
150
|
+
describe "Saved FixedLengthSkiplistVolume" do
|
|
151
|
+
before(:each) do
|
|
152
|
+
@maxlevel = 8
|
|
153
|
+
@probability = 0.5
|
|
154
|
+
@path = TEMP_STORAGES + '/fixed_length_sl_volume'
|
|
155
|
+
FileUtils.rm_rf @path
|
|
156
|
+
@list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "with actual data inside should be loaded properly" do
|
|
160
|
+
@list.insert("A"*10,"B"*10)
|
|
161
|
+
@list.close!
|
|
162
|
+
@new_list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
163
|
+
@new_list.find("A"*10).should == "B"*10
|
|
164
|
+
end
|
|
165
|
+
it "with no actual data inside should be loaded properly" do
|
|
166
|
+
@list.close!
|
|
167
|
+
@new_list = FixedLengthSkiplistVolume.new(:path => @path, :maxlevel => @maxlevel, :probability => @probability, :key_length => 10, :value_length => 10)
|
|
168
|
+
@new_list.find("A"*10).should == nil
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
# end
|
|
173
|
+
|
|
174
|
+
def raw_list(list)
|
|
175
|
+
list.marshal_dump[:raw_list]
|
|
176
|
+
end
|
|
177
|
+
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
[MapVolume].each do |klass|
|
|
4
|
+
describe "#{klass}", :shared => true do
|
|
5
|
+
|
|
6
|
+
it "should have record size" do
|
|
7
|
+
@map_volume.record_size.should == 256
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should insert record of proper size" do
|
|
11
|
+
@map_volume.insert!("A"*256)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should insert record of proper size and return non-negative position" do
|
|
15
|
+
@map_volume.insert!("A"*256).should >= 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should be able to read inserted record" do
|
|
19
|
+
@map_volume.read(@map_volume.insert!("A"*256)).should == "A"*256
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should return different positions for each insertion" do
|
|
23
|
+
positions = (1..50).map { @map_volume.insert!("A"*256) }
|
|
24
|
+
positions.uniq.should == positions
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should not insert record of improper size" do
|
|
28
|
+
lambda { @map_volume.insert!(" "*255) }.should raise_error(InvalidRecordSizeError)
|
|
29
|
+
lambda { @map_volume.insert!(" "*257) }.should raise_error(InvalidRecordSizeError)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
it "should insert new record into previously deleted position" do
|
|
34
|
+
@map_volume.insert!(" "*256)
|
|
35
|
+
position = @map_volume.insert!(" "*256)
|
|
36
|
+
@map_volume.delete!(position)
|
|
37
|
+
@map_volume.insert!(" "*256).should == position
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should raise an exception if trying to read previously deleted record" do
|
|
41
|
+
@map_volume.insert!(" "*256)
|
|
42
|
+
position = @map_volume.insert!(" "*256)
|
|
43
|
+
@map_volume.delete!(position)
|
|
44
|
+
lambda { @map_volume.read(position) }.should raise_error(InvalidRecordPositionError)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
it "should be able to write record at specified position" do
|
|
49
|
+
position = @map_volume.insert!("A"*256)
|
|
50
|
+
@map_volume.write!(position,"B"*256).should == position
|
|
51
|
+
@map_volume.read(position).should == "B"*256
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should be able to write record at specified position if there is no record yet" do
|
|
55
|
+
@map_volume.write!(0,"O"*256).should == 0
|
|
56
|
+
@map_volume.available?(0).should == false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should be able to insert records of size that is greater than record size elastically" do
|
|
60
|
+
position = @map_volume.elastic_insert!("E"*300)
|
|
61
|
+
@map_volume.elastic_read(position).should == "E"*300
|
|
62
|
+
(300%8).times {|n| @map_volume.available?(position+n).should == false }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should be able to insert records of size that is less than record size - 4 when using elastic way" do
|
|
66
|
+
position = @map_volume.elastic_insert!("E"*252)
|
|
67
|
+
@map_volume.elastic_read(position).should == "E"*252
|
|
68
|
+
@map_volume.available?(position).should == false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should be able to insert records of size that is greater than record size elastically when bitmap can't fit it" do
|
|
72
|
+
(@map_volume.map_size).times { @map_volume.insert!('N'*256)}
|
|
73
|
+
position = @map_volume.elastic_insert!("E"*1024)
|
|
74
|
+
@map_volume.elastic_read(position).should == "E"*1024
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "New #{klass}" do
|
|
82
|
+
|
|
83
|
+
before(:each) do
|
|
84
|
+
@path = TEMP_STORAGES + "/map.volume.#{klass}"
|
|
85
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
86
|
+
@map_volume = klass.new(:path => @path, :record_size => 256)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
after(:each) do
|
|
90
|
+
@map_volume.close!
|
|
91
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should be empty" do
|
|
95
|
+
@map_volume.should be_empty
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should have bitmap allocated for 65536 records" do
|
|
99
|
+
(@map_volume.map_size * 8).should == 65536
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it_should_behave_like "#{klass}"
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "New #{klass} with bitmap extension pace of 16384" do
|
|
107
|
+
|
|
108
|
+
before(:each) do
|
|
109
|
+
@path = TEMP_STORAGES + "/map.volume.#{klass}"
|
|
110
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
111
|
+
@map_volume = klass.new(:path => @path, :record_size => 256, :bitmap_extension_pace => 16384)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
after(:each) do
|
|
115
|
+
@map_volume.close!
|
|
116
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should have bitmap allocated for 131072 records" do
|
|
120
|
+
(@map_volume.map_size * 8).should == 131072
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it_should_behave_like "#{klass}"
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
describe "Existing MapVolume" do
|
|
129
|
+
|
|
130
|
+
before(:each) do
|
|
131
|
+
@path = TEMP_STORAGES + "/map.volume.#{klass.name.to_s.demodulize}"
|
|
132
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
133
|
+
@map_volume = klass.new(:path => @path, :record_size => 256, :capacity => 100)
|
|
134
|
+
position = @map_volume.insert!(' '*256)
|
|
135
|
+
@map_volume.close!
|
|
136
|
+
@map_volume = klass.new(:path => @path)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
after(:each) do
|
|
140
|
+
@map_volume.close!
|
|
141
|
+
FileUtils.rm_rf(@path) if File.exists?(@path)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should not be empty" do
|
|
145
|
+
@map_volume.should_not be_empty
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it_should_behave_like "#{klass}"
|
|
149
|
+
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe "Opening invalid file with #{klass} (i.e. file with invalid signature)" do
|
|
153
|
+
|
|
154
|
+
before(:each) do
|
|
155
|
+
@path = TEMP_STORAGES + "/map.volume.#{klass.name.to_s.demodulize}"
|
|
156
|
+
FileUtils.rm_rf(@path + ".invalid") if File.exists?(@path + ".invalid")
|
|
157
|
+
FileUtils.mkdir_p(@path + ".invalid")
|
|
158
|
+
File.open(@path + ".invalid/bitmap","w+") do |f|
|
|
159
|
+
f.write "Invalid file"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
after(:each) do
|
|
164
|
+
FileUtils.rm_rf(@path + ".invalid") if File.exists?(@path + ".invalid")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "should fail with InvalidMapVolumeError exception" do
|
|
168
|
+
lambda { klass.new(:path => @path + ".invalid") }.should raise_error(InvalidMapVolumeError)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
end
|