strokedb 0.0.2.1 → 0.0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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,20 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+ describe "fasle" do
5
+ it "should be blank" do
6
+ false.should be_blank
7
+ end
8
+ end
9
+
10
+ describe "true" do
11
+ it "should not be blank" do
12
+ true.should_not be_blank
13
+ end
14
+ end
15
+
16
+ describe "Numeric" do
17
+ it "should not be blank" do
18
+ Numeric.should_not be_blank
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Kernel#extract" do
4
+
5
+ it "should correctly extract various arguments" do
6
+ extract(Regexp, String, Hash, [ ]).should == [nil, nil, nil]
7
+
8
+ extract(Regexp, String, Hash, [/a/ ]).should == [/a/, nil, nil]
9
+ extract(Regexp, String, Hash, [ "a" ]).should == [nil, "a", nil]
10
+ extract(Regexp, String, Hash, [ {1=>2}]).should == [nil, nil, {1=>2}]
11
+
12
+ extract(Regexp, String, Hash, [//, "" ]).should == [//, "", nil]
13
+ extract(Regexp, String, Hash, [//, {}]).should == [//, nil, {} ]
14
+ extract(Regexp, String, Hash, [ "", {}]).should == [nil, "", {}]
15
+
16
+ extract(Regexp, String, Hash, [//, "", {}]).should == [//, "", {} ]
17
+ end
18
+
19
+ it "should raise ArgumentError when wrong arguments are passed" do
20
+
21
+ bad_case(Regexp, String, Hash, [123])
22
+ bad_case(Regexp, String, Hash, ["", //])
23
+ bad_case(Regexp, String, Hash, [{}, ""])
24
+ bad_case(Regexp, String, Hash, [true])
25
+ bad_case(Regexp, String, Hash, [false])
26
+ bad_case(Regexp, String, Hash, [//,false])
27
+ bad_case(Regexp, String, Hash, [nil])
28
+ bad_case(Regexp, String, Hash, ["", nil])
29
+ bad_case(Regexp, String, Hash, [nil, nil])
30
+ bad_case(Regexp, String, Hash, [{}, {}])
31
+ bad_case(Regexp, String, Hash, [//, //])
32
+ bad_case(Regexp, String, Hash, [ [] ])
33
+ bad_case(Regexp, String, Hash, [Object.new])
34
+ bad_case(Regexp, String, Hash, [Object.new, Object.new])
35
+
36
+ end
37
+
38
+ def bad_case(*args)
39
+ lambda { extract(*args) }.should raise_error(ArgumentError)
40
+ end
41
+
42
+ end
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Infinity do
4
+
5
+ it "should correctly compare with integers and floats" do
6
+ Infinity.should > 1
7
+ Infinity.should > 1.0
8
+ end
9
+
10
+ it "should correctly work with ranges" do
11
+ (-Infinity..1).should include(-100)
12
+ (-Infinity..Infinity).should include(Float::MAX)
13
+ (0..Infinity).should include(Float::MAX)
14
+ end
15
+
16
+ it "should return Infinity in arithmetics" do
17
+ (Infinity + Infinity).should == Infinity
18
+ (Infinity * Infinity).should == Infinity
19
+ (Infinity ** Infinity).should == Infinity
20
+ (Infinity / 0).should == Infinity
21
+ (Infinity / 0.0).should == Infinity
22
+ end
23
+
24
+ it "should return NaN in arithmetics" do
25
+ (Infinity - Infinity).should be_nan
26
+ (Infinity / Infinity).should be_nan
27
+ (Infinity * 0).should be_nan
28
+ (Infinity * 0.0).should be_nan
29
+ end
30
+
31
+ end
32
+
33
+ describe NaN do
34
+
35
+ it "should correctly compare with numerics" do
36
+ (NaN < 1).should be_false
37
+ (NaN > 1).should be_false
38
+ (NaN == 1).should be_false
39
+ end
40
+
41
+ it "should not compare with itself" do
42
+ NaN.should_not == NaN
43
+ NaN.should be_nan
44
+ NaN.object_id.should == NaN.object_id
45
+ (NaN + 1).object_id.should_not == NaN.object_id
46
+ end
47
+
48
+ it "should produce NaN in all the operations except NaN**0 == 1" do
49
+ (NaN + 1).should be_nan
50
+ (NaN + Infinity).should be_nan
51
+ (NaN - 1).should be_nan
52
+ (NaN * 0).should be_nan
53
+ (NaN * Infinity).should be_nan
54
+ (NaN ** 0).should == 1 # <-- WTF? (Ruby 1.8.6 rel. 2007-03-13)
55
+ (NaN ** 1).should be_nan
56
+ (NaN ** Infinity).should be_nan
57
+ (NaN / 0).should be_nan
58
+ (NaN / 1).should be_nan
59
+ (NaN / Infinity).should be_nan
60
+ end
61
+
62
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Object#infinity?" do
4
+ it "should return false for the finite values" do
5
+ Object.should_not be_infinite
6
+ Object.new.should_not be_infinite
7
+ String.new.should_not be_infinite
8
+ Time.now.should_not be_infinite
9
+ :sym.should_not be_infinite
10
+ nil.should_not be_infinite
11
+ false.should_not be_infinite
12
+ true.should_not be_infinite
13
+ Float::MAX.should_not be_infinite
14
+ 2.71828.should_not be_infinite
15
+ 42.should_not be_infinite
16
+ (1..Infinity).should_not be_infinite # yep, this too.
17
+ end
18
+ it "should return true for infinite 'values'" do
19
+ Infinity.should be_infinite
20
+ (-Infinity).should be_infinite
21
+ (InfiniteString).should be_infinite
22
+ (InfiniteTime).should be_infinite
23
+ end
24
+ end
25
+
26
+ describe InfiniteString do
27
+ it "should be used in Range" do
28
+ (InfiniteString.."a").should be_a_kind_of(Range)
29
+ ("a"..InfiniteString).should be_a_kind_of(Range)
30
+ (InfiniteString..InfiniteString).should be_a_kind_of(Range)
31
+ end
32
+ end
33
+
34
+ describe InfiniteTime do
35
+ it "should be used in Range" do
36
+ (InfiniteTime..Time.now).should be_a_kind_of(Range)
37
+ (Time.now..InfiniteTime).should be_a_kind_of(Range)
38
+ (InfiniteTime..InfiniteTime).should be_a_kind_of(Range)
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "String#/" do
4
+ it "should concatenate strings with /" do
5
+ "lib"/"core_ext".should == "lib/core_ext"
6
+ "lib/core_ext"/"foo".should == "lib/core_ext/foo"
7
+ end
8
+ end
9
+
10
+ describe "String#modulize" do
11
+
12
+ it "if there is no module, leave nothing" do
13
+ "A".modulize.should == ""
14
+ "::A".modulize.should == ""
15
+ end
16
+
17
+ it "should leave single module" do
18
+ "A::B".modulize.should == "A"
19
+ end
20
+
21
+ it "should leave multiple modules" do
22
+ "A::B::C".modulize.should == "A::B"
23
+ end
24
+
25
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Symbol#/" do
4
+ it "should concatenate symbols with / as a string" do
5
+ :lib/:core_ext.should == "lib/core_ext"
6
+ :lib/:core_ext/:foo.should == "lib/core_ext/foo"
7
+ end
8
+ end
@@ -0,0 +1,144 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Empty chunked skiplist" do
4
+ before(:each) do
5
+ @cut_level = 4
6
+ @list = Skiplist.new({}, nil, @cut_level)
7
+ end
8
+
9
+ it "should make first node level first-level only" do
10
+ @list.head.level.should == 1
11
+ @list.insert("k","v", @cut_level + 1)
12
+ @list.head.level.should == 1
13
+ @list.head.forward[0].level.should == 1
14
+ end
15
+
16
+ end
17
+
18
+
19
+ describe "Chunked skiplist (variants)" do
20
+
21
+ before(:each) do
22
+ @cut_level = 16
23
+ end
24
+
25
+ it "should be valid with ascending level order" do
26
+ @list = Skiplist.new({}, nil, @cut_level)
27
+ (1..10).each do |i|
28
+ @list.insert("K#{i*10}", "V", i)
29
+ end
30
+ @list.should have(10).items
31
+ end
32
+
33
+ it "should be valid with descending level order" do
34
+ @list = Skiplist.new({}, nil, @cut_level)
35
+ (1..10).each do |i|
36
+ @list.insert("K#{i*10}", "V", 11 - i)
37
+ end
38
+ @list.should have(10).items
39
+ end
40
+
41
+ it "should be valid with fixed level order" do
42
+ @list = Skiplist.new({}, nil, @cut_level)
43
+ (1..10).each do |i|
44
+ @list.insert("K#{i*10}", "V", 15)
45
+ end
46
+ @list.should have(10).items
47
+ end
48
+
49
+ end
50
+
51
+
52
+ describe "Insertion into skiplist" do
53
+
54
+ before(:each) do
55
+ @cut_level = 4
56
+ @list = Skiplist.new({}, nil, @cut_level)
57
+ @levels_list = []
58
+ (0..9).each do |i|
59
+ @list.insert("K#{i*10}", "V", x = rand(@cut_level-1)+1)
60
+ @levels_list << x
61
+ end
62
+ end
63
+
64
+ it "should return [self, nil] if not cut" do
65
+ a, b = @list.insert("K42", "L", @cut_level-1)
66
+ a.should == @list
67
+ b.should be_nil
68
+ end
69
+
70
+ it "should cut list by middle-entered value" do
71
+ a, b = @list.insert("K42", "H", @cut_level)
72
+ a.should == @list
73
+ b.should be_a_kind_of(Skiplist)
74
+ (0..4).each do |i|
75
+ chunks_should_have_separate_values(a, b, "K#{i*10}", "V")
76
+ end
77
+ chunks_should_have_separate_values(b, a, "K42", "H")
78
+ (5..9).each do |i|
79
+ chunks_should_have_separate_values(b, a, "K#{i*10}", "V")
80
+ end
81
+ end
82
+
83
+ def chunks_should_have_separate_values(a, b, a_key, a_value)
84
+ a.find(a_key).should == a_value
85
+ b.find(a_key).should == nil
86
+ end
87
+ end
88
+
89
+ =begin
90
+ random chunk writings, bad test. Come back to it in ChunkStore
91
+ describe "Chunked skiplist process" do
92
+
93
+ before(:all) do
94
+ @cut_level = 4
95
+ list = Skiplist.new({}, nil, @cut_level)
96
+ @lists = {list => 1}
97
+ n = ((1/Skiplist::PROBABILITY)**(@cut_level+2)).round
98
+ srand 12345
99
+ n.times do |i|
100
+ a, b = @lists.keys[rand(@lists.size)].insert(rand(100_000).to_s, "V")
101
+ @lists[a] = 1
102
+ @lists[b] = 1 if b
103
+ end
104
+ @lists = @lists.keys
105
+ end
106
+
107
+ it "should produce several chunks after many insertions" do
108
+ @lists.size.should > 1
109
+ end
110
+
111
+ # TODO: move to separate description with narrow assertions
112
+ it "should keep all the nodes except the first one on a lower level in each chunk" do
113
+ counted_first_node = false
114
+ @lists.each do |list|
115
+ cut_level = list.map{|node| node.level }.max
116
+ counted_cut = false
117
+ puts list.to_s_levels
118
+ puts "------"
119
+ if cut_level < @cut_level
120
+ #puts list
121
+ #puts "------- #{cut_level}"
122
+ end
123
+ if cut_level < @cut_level && !counted_first_node
124
+ counted_first_node = true
125
+ else
126
+ #cut_level.should >= @cut_level
127
+ end
128
+
129
+ list.each do |node|
130
+ unless counted_cut && node.level == cut_level
131
+ counted_cut = true
132
+ else
133
+ if node.level >= @cut_level
134
+ #puts list
135
+ end
136
+ #node.level.should < @cut_level
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ end
143
+ =end
144
+
@@ -0,0 +1,172 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe InvertedList, " with flat string attributes" do
4
+
5
+ before(:all) do
6
+ @il = InvertedList.new
7
+ @oleg_profile = new_doc('Profile', :name => 'Oleg',
8
+ :email => 'oleganza')
9
+ @yrashk_profile = new_doc('Profile', :name => 'Yurii',
10
+ :email => 'yrashk')
11
+ @article1 = new_doc('Article', :title => 'StrokeDB kicks ass',
12
+ :author => ('@#' + @yrashk_profile[:uuid]))
13
+ @article2 = new_doc('Article', :title => 'StrokeDB strikes back',
14
+ :date => '28 Jan 2008',
15
+ :author => ('@#' + @yrashk_profile[:uuid]))
16
+ @post1 = new_doc('Post', :title => 'Hello',
17
+ :date => '28 Jan 2008',
18
+ :author => ('@#' + @yrashk_profile[:uuid]))
19
+
20
+ insert_doc(@il, @oleg_profile)
21
+ insert_doc(@il, @yrashk_profile)
22
+ insert_doc(@il, @article1)
23
+ insert_doc(@il, @article2)
24
+ insert_doc(@il, @post1)
25
+ end
26
+
27
+ it "should find objects by a single attribute" do
28
+ @il.find(:name => 'Oleg').should == [@oleg_profile[:uuid]].to_set
29
+ @il.find(:email => 'yrashk').should == [@yrashk_profile[:uuid]].to_set
30
+ @il.find(:meta => 'Article').should == [@article1[:uuid], @article2[:uuid]].to_set
31
+ @il.find(:version => @article1[:slots][:version]).should == [@article1[:uuid]].to_set
32
+ end
33
+
34
+ it "should not find object by a not matched attribute" do
35
+ @il.find(:name => 'Nobody').should == [ ].to_set
36
+ @il.find(:meta => 'NoMeta').should == [ ].to_set
37
+ @il.find(:version => 'no-version').should == [ ].to_set
38
+ end
39
+
40
+ it "should find objects by a pair of attributes" do
41
+ @il.find(:date => '28 Jan 2008', :title => 'Hello').should == [@post1[:uuid]].to_set
42
+ @il.find(:date => '28 Jan 2008', :meta => 'Article').should == [@article2[:uuid]].to_set
43
+ @il.find(:date => '28 Jan 2008', :author => ('@#' + @yrashk_profile[:uuid])).should == [@post1[:uuid], @article2[:uuid]].to_set
44
+ end
45
+
46
+ it "should not find objects by a not matched pair of attributes" do
47
+ @il.find(:date => '28 Jan 2008', :title => 'StrokeDB kicks ass').should == [ ].to_set
48
+ @il.find(:date => '28 Jan 2008', :meta => 'Profile').should == [ ].to_set
49
+ @il.find(:date => '28 Jan 2008', :author => ('@#' + @oleg_profile[:uuid])).should == [ ].to_set
50
+ end
51
+
52
+ it "should find objects by three attributes" do
53
+ @il.find(:date => '28 Jan 2008',
54
+ :author => ('@#' + @yrashk_profile[:uuid]),
55
+ :meta => 'Article'
56
+ ).should == [ @article2[:uuid] ].to_set
57
+ end
58
+
59
+ it "should not find objects by not matched three attributes" do
60
+ @il.find(:date => '28 Jan 2008',
61
+ :author => ('@#' + @oleg_profile[:uuid]),
62
+ :meta => 'Article'
63
+ ).should == [ ].to_set
64
+ @il.find(:date => '42 Jan 2008',
65
+ :author => ('@#' + @yrashk_profile[:uuid]),
66
+ :meta => 'Article'
67
+ ).should == [ ].to_set
68
+ @il.find(:date => '28 Jan 2008',
69
+ :author => ('@#' + @yrashk_profile[:uuid]),
70
+ :meta => 'Profile'
71
+ ).should == [ ].to_set
72
+ end
73
+
74
+ it "should delete doc from index" do
75
+ @il.find(:name => 'Oleg').should == [@oleg_profile[:uuid]].to_set
76
+ delete_doc(@il, @oleg_profile)
77
+ @il.find(:name => 'Oleg').should == [ ].to_set
78
+ @il.find(:email => 'yrashk').should == [@yrashk_profile[:uuid]].to_set
79
+ delete_doc(@il, @yrashk_profile)
80
+ @il.find(:email => 'yrashk').should == [ ].to_set
81
+ end
82
+
83
+ end
84
+
85
+ describe InvertedList, " with numeric attributes" do
86
+
87
+ before(:all) do
88
+ @il = InvertedList.new
89
+ @ps = []
90
+ @ps << new_doc('Point', :x => 0, :y => 0) # 0
91
+ @ps << new_doc('Point', :x => 10, :y => 50) # 1
92
+ @ps << new_doc('Point', :x => 50, :y => 50) # 2
93
+ @ps << new_doc('Point', :x => 200, :y => 10) # 3
94
+ @ps << new_doc('Point', :x => 500, :y => 10) # 4
95
+ @ps << new_doc('Point', :x => -500, :y => 10) # 5
96
+ @ps << new_doc('Point', :x => -20, :y => 10) # 6
97
+ @ps << new_doc('Point', :x => -2.1, :y => 10) # 7
98
+ @ps << new_doc('Point', :x => 20.6, :y => 10) # 8
99
+
100
+ @ps.each {|p| insert_doc(@il, p) }
101
+ end
102
+
103
+ it "should find by positive value" do
104
+ @il.find(:x => 10).should == [@ps[1][:uuid]].to_set
105
+ @il.find(:x => 50).should == [@ps[2][:uuid]].to_set
106
+ @il.find(:x => 200).should == [@ps[3][:uuid]].to_set
107
+ end
108
+
109
+ it "should find by negative value" do
110
+ @il.find(:x => -500).should == [@ps[5][:uuid]].to_set
111
+ @il.find(:x => -20).should == [@ps[6][:uuid]].to_set
112
+ end
113
+
114
+ it "should find by zero value" do
115
+ @il.find(:x => 0).should == [@ps[0][:uuid]].to_set
116
+ end
117
+
118
+ # Dangerous: 2.1 may suddenly appear as 2.0999999999996235 or like that
119
+ it "should find by float value" do
120
+ @il.find(:x => -2.1).should == [@ps[7][:uuid]].to_set
121
+ @il.find(:x => 20.6).should == [@ps[8][:uuid]].to_set
122
+ end
123
+
124
+ end
125
+ =begin
126
+ describe InvertedList, " with multivalue slots" do
127
+ before(:all) do
128
+ @il = InvertedList.new
129
+ @ab = new_doc(%w[A B])
130
+ @a = new_doc(%w[A])
131
+ @b = new_doc(%w[B])
132
+ @c = new_doc(%w[C])
133
+ insert_doc(@il, @ab)
134
+ insert_doc(@il, @a)
135
+ insert_doc(@il, @b)
136
+ insert_doc(@il, @c)
137
+ end
138
+
139
+ it "should find multivalue objects by a single value" do
140
+ @il.find(:meta => proc{|v| v.include? 'A' }).should == [@a[:uuid], @ab[:uuid]].to_set
141
+ @il.find(:meta => proc{|v| v.include? 'B' }).should == [@b[:uuid], @ab[:uuid]].to_set
142
+ end
143
+
144
+ it "should not find by scalar value" do
145
+ @il.find(:meta => 'A').should == [ ].to_set
146
+ @il.find(:meta => 'B').should == [ ].to_set
147
+ end
148
+
149
+ it "should find multivalue objects with a complex predicate" do
150
+ @il.find(:meta => proc{|v| v.include?('A') && !v.include?('B') }).should == [@a[:uuid]].to_set
151
+ @il.find(:meta => proc{|v| v.include?('A') || v.include?('B') }).should ==
152
+ [@a[:uuid], @ab[:uuid], @b[:uuid]].to_set
153
+ @il.find(:meta => proc{|v| v.include?('A') && v.include?('B') }).should == [@ab[:uuid]].to_set
154
+ end
155
+ end
156
+ =end
157
+
158
+
159
+ def new_doc(meta, slots = {})
160
+ slots[:meta] = meta
161
+ slots[:version] = 'v1' + rand(10000000).to_s
162
+ {:uuid => meta.to_s + '-' + rand(1000000).to_s, :slots => slots}
163
+ end
164
+
165
+ def insert_doc(il, doc)
166
+ il.insert(doc[:slots], doc[:uuid])
167
+ end
168
+
169
+ def delete_doc(il, doc)
170
+ il.delete(doc[:slots], doc[:uuid])
171
+ end
172
+