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.
Files changed (192) hide show
  1. data/README +18 -20
  2. data/bench.html +4001 -0
  3. data/bin/strokedb +14 -0
  4. data/examples/movies.rb +105 -0
  5. data/examples/movies2.rb +97 -0
  6. data/examples/strokewiki/README +28 -0
  7. data/examples/strokewiki/view/edit.xhtml +27 -0
  8. data/examples/strokewiki/view/new.xhtml +26 -0
  9. data/examples/strokewiki/view/pages.xhtml +27 -0
  10. data/examples/strokewiki/view/show.xhtml +40 -0
  11. data/examples/strokewiki/view/versions.xhtml +25 -0
  12. data/examples/strokewiki/wiki.rb +106 -0
  13. data/examples/todo.rb +92 -0
  14. data/lib/strokedb.rb +85 -0
  15. data/lib/{config → strokedb}/config.rb +14 -9
  16. data/lib/strokedb/console.rb +87 -0
  17. data/lib/strokedb/core_ext.rb +10 -0
  18. data/lib/{util/ext → strokedb/core_ext}/blank.rb +1 -1
  19. data/lib/{util/ext → strokedb/core_ext}/enumerable.rb +0 -0
  20. data/lib/{util/ext → strokedb/core_ext}/fixnum.rb +0 -0
  21. data/lib/strokedb/core_ext/float.rb +4 -0
  22. data/lib/{util/ext → strokedb/core_ext}/hash.rb +0 -0
  23. data/lib/strokedb/core_ext/infinity.rb +33 -0
  24. data/lib/strokedb/core_ext/kernel.rb +41 -0
  25. data/lib/strokedb/core_ext/object.rb +16 -0
  26. data/lib/{util/ext → strokedb/core_ext}/string.rb +28 -1
  27. data/lib/strokedb/core_ext/symbol.rb +13 -0
  28. data/lib/strokedb/data_structures.rb +5 -0
  29. data/lib/strokedb/data_structures/chunked_skiplist.rb +123 -0
  30. data/lib/{data_structures → strokedb/data_structures}/inverted_list.rb +0 -0
  31. data/lib/{data_structures → strokedb/data_structures}/point_query.rb +0 -0
  32. data/lib/strokedb/data_structures/simple_skiplist.rb +350 -0
  33. data/lib/{data_structures → strokedb/data_structures}/skiplist.rb +1 -1
  34. data/lib/{document → strokedb}/document.rb +180 -71
  35. data/lib/{document → strokedb/document}/callback.rb +0 -0
  36. data/lib/{document → strokedb/document}/delete.rb +2 -2
  37. data/lib/strokedb/document/dsl.rb +4 -0
  38. data/lib/{document → strokedb/document/dsl}/associations.rb +0 -0
  39. data/lib/{document → strokedb/document/dsl}/coercions.rb +0 -0
  40. data/lib/strokedb/document/dsl/meta_dsl.rb +7 -0
  41. data/lib/{document → strokedb/document/dsl}/validations.rb +26 -21
  42. data/lib/{document → strokedb/document/dsl}/virtualize.rb +0 -0
  43. data/lib/{document → strokedb/document}/meta.rb +92 -29
  44. data/lib/{document → strokedb/document}/slot.rb +17 -5
  45. data/lib/{document → strokedb/document}/util.rb +0 -0
  46. data/lib/{document → strokedb/document}/versions.rb +2 -2
  47. data/lib/strokedb/index.rb +2 -0
  48. data/lib/strokedb/nsurl.rb +24 -0
  49. data/lib/strokedb/store.rb +149 -0
  50. data/lib/strokedb/stores.rb +6 -0
  51. data/lib/{stores → strokedb/stores}/chainable_storage.rb +20 -14
  52. data/lib/strokedb/stores/file_storage.rb +118 -0
  53. data/lib/{stores/inverted_list_index → strokedb/stores}/inverted_list_file_storage.rb +50 -0
  54. data/lib/strokedb/stores/memory_storage.rb +80 -0
  55. data/lib/{stores → strokedb/stores}/remote_store.rb +10 -4
  56. data/lib/strokedb/sync.rb +4 -0
  57. data/lib/{sync → strokedb/sync}/chain_sync.rb +0 -0
  58. data/lib/{sync → strokedb/sync}/diff.rb +12 -1
  59. data/lib/{sync/stroke_diff → strokedb/sync/diff}/array.rb +1 -1
  60. data/lib/{sync/stroke_diff → strokedb/sync/diff}/default.rb +0 -0
  61. data/lib/{sync/stroke_diff → strokedb/sync/diff}/hash.rb +1 -1
  62. data/lib/{sync/stroke_diff → strokedb/sync/diff}/string.rb +1 -1
  63. data/lib/{sync → strokedb/sync}/lamport_timestamp.rb +0 -0
  64. data/lib/{sync → strokedb/sync}/store_sync.rb +15 -7
  65. data/lib/strokedb/transaction.rb +78 -0
  66. data/lib/{util → strokedb}/util.rb +14 -7
  67. data/lib/strokedb/util/attach_dsl.rb +29 -0
  68. data/lib/{util → strokedb/util}/blankslate.rb +0 -0
  69. data/lib/strokedb/util/class_optimization.rb +93 -0
  70. data/lib/{util → strokedb/util}/inflect.rb +0 -0
  71. data/lib/strokedb/util/java_util.rb +13 -0
  72. data/lib/{util → strokedb/util}/lazy_array.rb +0 -0
  73. data/lib/{util → strokedb/util}/lazy_mapping_array.rb +4 -0
  74. data/lib/{util → strokedb/util}/lazy_mapping_hash.rb +0 -0
  75. data/lib/{util → strokedb/util}/serialization.rb +21 -0
  76. data/lib/strokedb/util/uuid.rb +159 -0
  77. data/lib/{util → strokedb/util}/xml.rb +0 -0
  78. data/lib/{view → strokedb}/view.rb +2 -2
  79. data/lib/strokedb/volumes.rb +5 -0
  80. data/lib/strokedb/volumes/archive_volume.rb +165 -0
  81. data/lib/strokedb/volumes/block_volume.rb +169 -0
  82. data/lib/strokedb/volumes/distributed_pointer.rb +43 -0
  83. data/lib/strokedb/volumes/fixed_length_skiplist_volume.rb +109 -0
  84. data/lib/strokedb/volumes/map_volume.rb +268 -0
  85. data/meta/MANIFEST +175 -0
  86. data/script/console +2 -70
  87. data/spec/integration/remote_store_spec.rb +70 -0
  88. data/spec/integration/search_spec.rb +76 -0
  89. data/spec/integration/spec_helper.rb +1 -0
  90. data/spec/lib/spec_helper.rb +1 -0
  91. data/spec/lib/strokedb/config_spec.rb +250 -0
  92. data/spec/lib/strokedb/core_ext/blank_spec.rb +20 -0
  93. data/spec/lib/strokedb/core_ext/extract_spec.rb +42 -0
  94. data/spec/lib/strokedb/core_ext/float_spec.rb +62 -0
  95. data/spec/lib/strokedb/core_ext/infinity_spec.rb +40 -0
  96. data/spec/lib/strokedb/core_ext/spec_helper.rb +1 -0
  97. data/spec/lib/strokedb/core_ext/string_spec.rb +25 -0
  98. data/spec/lib/strokedb/core_ext/symbol_spec.rb +8 -0
  99. data/spec/lib/strokedb/data_structures/chunked_skiplist_spec.rb +144 -0
  100. data/spec/lib/strokedb/data_structures/inverted_list_spec.rb +172 -0
  101. data/spec/lib/strokedb/data_structures/simple_skiplist_spec.rb +200 -0
  102. data/spec/lib/strokedb/data_structures/skiplist_spec.rb +253 -0
  103. data/spec/lib/strokedb/data_structures/spec_helper.rb +1 -0
  104. data/spec/lib/strokedb/document/associations_spec.rb +319 -0
  105. data/spec/lib/strokedb/document/callbacks_spec.rb +134 -0
  106. data/spec/lib/strokedb/document/coercions_spec.rb +110 -0
  107. data/spec/lib/strokedb/document/document_spec.rb +1063 -0
  108. data/spec/lib/strokedb/document/meta_meta_spec.rb +30 -0
  109. data/spec/lib/strokedb/document/meta_spec.rb +435 -0
  110. data/spec/lib/strokedb/document/metaslot_spec.rb +43 -0
  111. data/spec/lib/strokedb/document/slot_spec.rb +130 -0
  112. data/spec/lib/strokedb/document/spec_helper.rb +1 -0
  113. data/spec/lib/strokedb/document/validations_spec.rb +1081 -0
  114. data/spec/lib/strokedb/document/virtualize_spec.rb +80 -0
  115. data/spec/lib/strokedb/nsurl_spec.rb +73 -0
  116. data/spec/lib/strokedb/spec_helper.rb +1 -0
  117. data/spec/lib/strokedb/stores/chained_storages_spec.rb +116 -0
  118. data/spec/lib/strokedb/stores/spec_helper.rb +1 -0
  119. data/spec/lib/strokedb/stores/store_spec.rb +201 -0
  120. data/spec/lib/strokedb/stores/transaction_spec.rb +107 -0
  121. data/spec/lib/strokedb/sync/chain_sync_spec.rb +43 -0
  122. data/spec/lib/strokedb/sync/diff_spec.rb +111 -0
  123. data/spec/lib/strokedb/sync/lamport_timestamp_spec.rb +174 -0
  124. data/spec/lib/strokedb/sync/slot_diff_spec.rb +164 -0
  125. data/spec/lib/strokedb/sync/spec_helper.rb +1 -0
  126. data/spec/lib/strokedb/sync/store_sync_spec.rb +181 -0
  127. data/spec/lib/strokedb/sync/stroke_diff/array_spec.rb +97 -0
  128. data/spec/lib/strokedb/sync/stroke_diff/complex_spec.rb +58 -0
  129. data/spec/lib/strokedb/sync/stroke_diff/hash_spec.rb +144 -0
  130. data/spec/lib/strokedb/sync/stroke_diff/scalar_spec.rb +23 -0
  131. data/spec/lib/strokedb/sync/stroke_diff/spec_helper.rb +25 -0
  132. data/spec/lib/strokedb/sync/stroke_diff/string_spec.rb +61 -0
  133. data/spec/lib/strokedb/util/attach_dsl_spec.rb +45 -0
  134. data/spec/lib/strokedb/util/inflect_spec.rb +14 -0
  135. data/spec/lib/strokedb/util/lazy_array_spec.rb +157 -0
  136. data/spec/lib/strokedb/util/lazy_mapping_array_spec.rb +174 -0
  137. data/spec/lib/strokedb/util/lazy_mapping_hash_spec.rb +92 -0
  138. data/spec/lib/strokedb/util/spec_helper.rb +1 -0
  139. data/spec/lib/strokedb/util/uuid_spec.rb +46 -0
  140. data/spec/lib/strokedb/view_spec.rb +228 -0
  141. data/spec/lib/strokedb/volumes/archive_volume_spec.rb +105 -0
  142. data/spec/lib/strokedb/volumes/block_volume_spec.rb +100 -0
  143. data/spec/lib/strokedb/volumes/distributed_pointer_spec.rb +14 -0
  144. data/spec/lib/strokedb/volumes/fixed_length_skiplist_volume_spec.rb +177 -0
  145. data/spec/lib/strokedb/volumes/map_volume_spec.rb +172 -0
  146. data/spec/lib/strokedb/volumes/spec_helper.rb +1 -0
  147. data/spec/regression/docref_spec.rb +94 -0
  148. data/spec/regression/meta_spec.rb +23 -0
  149. data/spec/regression/spec_helper.rb +1 -0
  150. data/spec/regression/sync_spec.rb +36 -0
  151. data/spec/spec.opts +7 -0
  152. data/spec/spec_helper.rb +37 -0
  153. data/spec/temp/storages/TIMESTAMP +1 -0
  154. data/spec/temp/storages/UUID +1 -0
  155. data/spec/temp/storages/database-sync/TIMESTAMP +1 -0
  156. data/spec/temp/storages/database-sync/UUID +1 -0
  157. data/spec/temp/storages/database-sync/config +1 -0
  158. data/spec/temp/storages/database-sync/file/LAST +1 -0
  159. data/spec/temp/storages/database-sync/file/bd/f6/bdf675e5-8a7b-494e-97f2-f74a14ccd95d.av +0 -0
  160. data/spec/temp/storages/database-sync/file/uindex.wal +0 -0
  161. data/spec/temp/storages/database-sync/inverted_list_file/INVERTED_INDEX +1 -0
  162. data/spec/temp/storages/inverted_list_storage/INVERTED_INDEX +0 -0
  163. data/strokedb.gemspec +120 -0
  164. data/task/benchmark.task +9 -0
  165. data/task/ditz.task +30 -0
  166. data/task/echoe.rb +17 -0
  167. data/task/rcov.task +50 -0
  168. data/task/rdoc.task +10 -0
  169. data/task/rspec.task +0 -0
  170. data/vendor/java_inline.rb +106 -0
  171. data/vendor/rbmodexcl/mrimodexcl.rb +82 -0
  172. data/vendor/rbmodexcl/rbmodexcl.rb +5 -0
  173. data/vendor/rbmodexcl/rbxmodexcl.rb +48 -0
  174. data/vendor/rbmodexcl/spec/unextend_spec.rb +50 -0
  175. data/vendor/rbmodexcl/spec/uninclude_spec.rb +26 -0
  176. metadata +271 -79
  177. data/CONTRIBUTORS +0 -7
  178. data/CREDITS +0 -13
  179. data/bin/sdbc +0 -2
  180. data/lib/init.rb +0 -57
  181. data/lib/stores/inverted_list_index/inverted_list_index.rb +0 -49
  182. data/lib/stores/skiplist_store/chunk.rb +0 -119
  183. data/lib/stores/skiplist_store/chunk_storage.rb +0 -21
  184. data/lib/stores/skiplist_store/file_chunk_storage.rb +0 -44
  185. data/lib/stores/skiplist_store/memory_chunk_storage.rb +0 -37
  186. data/lib/stores/skiplist_store/skiplist_store.rb +0 -217
  187. data/lib/stores/store.rb +0 -5
  188. data/lib/sync/stroke_diff/stroke_diff.rb +0 -9
  189. data/lib/util/ext/object.rb +0 -8
  190. data/lib/util/java_util.rb +0 -9
  191. data/lib/util/trigger_partition.rb +0 -136
  192. 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