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,149 @@
1
+ module StrokeDB
2
+
3
+ StoreInfo = Meta.new
4
+
5
+ class Store
6
+ include Enumerable
7
+ attr_accessor :storage, :index_store, :uuid
8
+ attr_reader :timestamp
9
+
10
+ def initialize(options = {})
11
+ @options = options.stringify_keys
12
+ @storage = @options['storage']
13
+ @index_store = @options['index']
14
+ initialize_files
15
+ autosync! unless @options['noautosync']
16
+ raise "Missing chunk storage" unless @storage
17
+ end
18
+
19
+ def find(uuid, version=nil, opts = {}, &block)
20
+ @storage.find(uuid,version,opts.merge(:store => self),&block)
21
+ end
22
+
23
+ def search(*args)
24
+ return [] unless @index_store
25
+ @index_store.find(*args)
26
+ end
27
+
28
+ def include?(uuid,version=nil)
29
+ @storage.include?(uuid,version)
30
+ end
31
+ alias_method :contains?, :include?
32
+
33
+ def head_version(uuid)
34
+ @storage.head_version(uuid,{ :store => self })
35
+ end
36
+
37
+ def save!(doc)
38
+ next_timestamp!
39
+ storage.save!(doc, timestamp)
40
+ #
41
+ if @index_store
42
+ if doc.previous_version
43
+ raw_pdoc = find(doc.uuid,doc.previous_version,:no_instantiation => true)
44
+ pdoc = Document.from_raw(self,raw_pdoc.freeze,:skip_callbacks => true)
45
+ pdoc.extend(VersionedDocument)
46
+ @index_store.delete(pdoc)
47
+ end
48
+ @index_store.insert(doc)
49
+ @index_store.save!
50
+ end
51
+ end
52
+
53
+ def save_as_head!(doc)
54
+ @storage.save_as_head!(doc,timestamp)
55
+ end
56
+
57
+
58
+
59
+ def each(options = {},&block)
60
+ @storage.each(options.merge(:store => self),&block)
61
+ end
62
+
63
+ def next_timestamp!
64
+ @timestamp = timestamp.next
65
+ update_timestamp!
66
+ @timestamp
67
+ end
68
+
69
+ def uuid
70
+ return @uuid if @uuid
71
+ @uuid = Util.random_uuid
72
+ end
73
+
74
+
75
+ def document
76
+ find(uuid) || StoreInfo.create!(self, :uuid => uuid)
77
+ end
78
+
79
+ def inspect
80
+ "#<Store #{uuid}>"
81
+ end
82
+
83
+ def autosync!
84
+ @autosync_mutex ||= Mutex.new
85
+ @autosync = nil if @autosync && !@autosync.status
86
+ at_exit { stop_autosync! }
87
+ @autosync ||= Thread.new do
88
+ until @stop_autosync
89
+ @autosync_mutex.synchronize { storage.sync_chained_storages! }
90
+ sleep(1)
91
+ end
92
+ end
93
+ end
94
+
95
+ def stop_autosync!
96
+ if @autosync_mutex
97
+ @autosync_mutex.synchronize { @stop_autosync = true; storage.sync_chained_storages! }
98
+ end
99
+ end
100
+
101
+ def path
102
+ @options['path']
103
+ end
104
+
105
+
106
+ private
107
+
108
+ def initialize_files
109
+ FileUtils.mkdir_p(path)
110
+ uuid_file = File.join(path,'UUID')
111
+ timestamp_file = File.join(path,'TIMESTAMP')
112
+
113
+ if File.exists?(uuid_file)
114
+ @uuid = IO.read(uuid_file)
115
+ else
116
+ File.open(uuid_file,'w') do |f|
117
+ f.write(uuid)
118
+ end
119
+ end
120
+ if File.exists?(timestamp_file)
121
+ @timestamp = LTS.new(IO.read(timestamp_file).to_i,uuid)
122
+ else
123
+ @timestamp = LTS.zero(uuid)
124
+ update_timestamp!
125
+ end
126
+ end
127
+
128
+ def update_timestamp!
129
+ timestamp_file = File.join(path,'TIMESTAMP')
130
+ File.open(timestamp_file,'w') do |f|
131
+ f.write(timestamp.counter)
132
+ end
133
+ end
134
+
135
+ end
136
+ end
137
+
138
+ require 'stores/chainable_storage'
139
+ module StrokeDB
140
+ class Storage
141
+ include ChainableStorage
142
+
143
+ attr_accessor :authoritative_source
144
+
145
+ def initialize(opts={})
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,6 @@
1
+ require 'store'
2
+ require 'stores/chainable_storage'
3
+ require 'stores/file_storage'
4
+ require 'stores/memory_storage'
5
+ require 'stores/remote_store'
6
+ require 'stores/inverted_list_file_storage'
@@ -2,7 +2,7 @@ module StrokeDB
2
2
  module ChainableStorage
3
3
  def add_chained_storage!(storage)
4
4
  @chained_storages ||= {}
5
- @chained_storages[storage] = []
5
+ @chained_storages[storage] = [{},[]]
6
6
  class <<self
7
7
  alias :save! :save_with_chained_storages!
8
8
  end
@@ -13,7 +13,7 @@ module StrokeDB
13
13
  @chained_storages.delete(storage)
14
14
  storage.remove_chained_storage!(self) if storage.has_chained_storage?(self)
15
15
  if @chained_storages.keys.empty?
16
- class <<self
16
+ class << self
17
17
  alias :save! :save_without_chained_storages!
18
18
  end
19
19
  end
@@ -27,28 +27,34 @@ module StrokeDB
27
27
  return unless @chained_storages.is_a?(Hash)
28
28
  @chained_storages.each_pair do |storage, savings|
29
29
  next if storage == origin
30
- savings.each {|saving| storage.save!(saving, self)}
30
+ savings.last.each {|saving| storage.save!(saving[0], saving[1], saving[2], self)}
31
31
  storage.sync_chained_storages!(self)
32
- @chained_storages[storage] = []
32
+ @chained_storages[storage] = [{},[]]
33
33
  end
34
34
  end
35
-
35
+
36
36
  def sync_chained_storage!(storage)
37
37
  return unless @chained_storages.is_a?(Hash)
38
- (@chained_storages[storage]||[]).each do |saving|
39
- storage.save!(saving, self)
38
+ ((@chained_storages[storage]||[]).last||[]).each do |saving|
39
+ storage.save!(saving[0], saving[1], saving[2], self)
40
40
  end
41
- @chained_storages[storage] = []
41
+ @chained_storages[storage] = [{},[]]
42
42
  end
43
43
 
44
- def save_without_chained_storages!(chunk, source=nil)
45
- perform_save!(chunk)
44
+ def save_without_chained_storages!(document, timestamp, options = {},source=nil)
45
+ perform_save!(document, timestamp, options)
46
46
  end
47
47
 
48
- def save_with_chained_storages!(chunk, source=nil)
49
- perform_save!(chunk)
50
- (@chained_storages||{}).each_pair do |storage, savings|
51
- savings << chunk unless storage == source || savings.include?(chunk) # TODO: here we had a bug (storage == document), spec it
48
+ def save_with_chained_storages!(document, timestamp, options = {},source=nil)
49
+ perform_save!(document, timestamp, options)
50
+ (@chained_storages||{}).each_pair do |storage, accumulator|
51
+ next if storage == source
52
+ hsh = [document,timestamp,options].hash
53
+ hashes, savings = accumulator
54
+ unless hashes.has_key?(hsh) # TODO: here we had a bug (storage == document), spec it
55
+ hashes[hsh] = true
56
+ savings << [document,timestamp,options]
57
+ end
52
58
  end
53
59
  end
54
60
 
@@ -0,0 +1,118 @@
1
+ module StrokeDB
2
+ class FileStorage < Storage
3
+
4
+ def initialize(options = {})
5
+ @options = options.stringify_keys
6
+ initialize_files
7
+ end
8
+
9
+ def save_as_head!(document, timestamp)
10
+ write(document.uuid, document, timestamp)
11
+ end
12
+
13
+ def find(uuid, version=nil, opts = {}, &block)
14
+ uuid_version = uuid + (version ? ".#{version}" : "")
15
+ key = uuid.to_raw_uuid + (version ? version.to_raw_uuid : RAW_FULL_UUID)
16
+ if (ptr = @uindex.find(key)) && (ptr != "\x00" * 20) # no way ptr will be zero
17
+ raw_doc = StrokeDB::deserialize(read_at_ptr(ptr))[0]
18
+ unless opts[:no_instantiation]
19
+ doc = Document.from_raw(opts[:store], raw_doc.freeze, &block) # FIXME: there should be a better source for store (probably)
20
+ doc.extend(VersionedDocument) if version
21
+ doc
22
+ else
23
+ raw_doc
24
+ end
25
+ end
26
+ end
27
+
28
+ def include?(uuid,version=nil)
29
+ !!find(uuid,version,:no_instantiation => true)
30
+ end
31
+ # using #include? to match with Array, but #contains sounds much nicer
32
+ alias_method :contains?, :include?
33
+
34
+ def head_version(uuid, opts = {})
35
+ if doc = find(uuid,nil,opts.merge({ :no_instantiation => true }))
36
+ doc['version']
37
+ end
38
+ end
39
+
40
+ def each(options = {})
41
+ after = options[:after_timestamp]
42
+ include_versions = options[:include_versions]
43
+ @container.each do |key, value|
44
+ next if after && (value[1] <= after)
45
+ if uuid_match = key.match(/^#{UUID_RE}$/) || (include_versions && uuid_match = key.match(/#{UUID_RE}./) )
46
+ yield Document.from_raw(options[:store],value[0])
47
+ end
48
+ end
49
+ end
50
+
51
+ def perform_save!(document, timestamp, options = {})
52
+ position = @archive.insert(StrokeDB::serialize([document,timestamp.counter]))
53
+ ptr = DistributedPointer.pack(@archive.raw_uuid,position)
54
+ uuid = document.raw_uuid
55
+ @uindex.insert(uuid + RAW_FULL_UUID, ptr) if options[:head] || !document.is_a?(VersionedDocument)
56
+ @uindex.insert(uuid + document.version.to_raw_uuid, ptr) unless options[:head]
57
+ rescue ArchiveVolume::VolumeCapacityExceeded
58
+ create_new_archive!
59
+ end
60
+
61
+ def create_new_archive!
62
+ @archive = ArchiveVolume.new(:path => @options['path'])
63
+ File.open(File.join(@options['path'],'LAST'),'w') do |f|
64
+ f.write(@archive.uuid)
65
+ end
66
+ end
67
+
68
+ def last_archive_uuid
69
+ last_filename = File.join(@options['path'],'LAST')
70
+ if File.exists?(last_filename)
71
+ IO.read(last_filename)
72
+ else
73
+ uuid = Util.random_uuid
74
+ File.open(last_filename,'w') do |f|
75
+ f.write(uuid)
76
+ end
77
+ uuid
78
+ end
79
+ end
80
+
81
+ def read_at_ptr(ptr)
82
+ dptr = DistributedPointer.unpack(ptr)
83
+ volume_uuid = dptr.volume_uuid
84
+ if volume_uuid == @archive.uuid.to_raw_uuid
85
+ @archive.read(dptr.offset)
86
+ else
87
+ archive = ArchiveVolume.new(:path => @options['path'], :uuid => volume_uuid)
88
+ result = archive.read(dptr.offset)
89
+ archive.close!
90
+ result
91
+ end
92
+ end
93
+
94
+ def path
95
+ @options['path']
96
+ end
97
+
98
+ def clear!
99
+ FileUtils.rm_rf(@options['path'])
100
+ initialize_files
101
+ end
102
+
103
+ def close!
104
+ @archive.close!
105
+ @uindex.close!
106
+ end
107
+
108
+
109
+ private
110
+
111
+ def initialize_files
112
+ FileUtils.mkdir_p(@options['path'])
113
+ @archive = ArchiveVolume.new(:path => @options['path'], :uuid => last_archive_uuid)
114
+ @uindex = FixedLengthSkiplistVolume.new(:path => File.join(@options['path'],'uindex'), :key_length => 32 , :value_length => 20)
115
+ end
116
+
117
+ end
118
+ end
@@ -53,4 +53,54 @@ module StrokeDB
53
53
  "#{@path}/INVERTED_INDEX"
54
54
  end
55
55
  end
56
+
57
+
58
+
59
+ class InvertedListIndex
60
+ attr_accessor :storage, :document_store
61
+ def initialize(storage)
62
+ @storage = storage
63
+ @list = nil
64
+ end
65
+
66
+ def find_uuids(*args)
67
+ list.find(*args)
68
+ end
69
+
70
+ def find(*args)
71
+ find_uuids(*args).map do |uuid|
72
+ @document_store.find(uuid)
73
+ end
74
+ end
75
+
76
+ def insert(doc)
77
+ slots = indexable_slots_for_doc(doc)
78
+ q = PointQuery.new(slots)
79
+ list.insert(q.slots, doc.uuid)
80
+ end
81
+
82
+ def delete(doc)
83
+ slots = indexable_slots_for_doc(doc)
84
+ q = PointQuery.new(slots)
85
+ list.delete(q.slots, doc.uuid)
86
+ end
87
+
88
+ def save!
89
+ @storage.save!(list)
90
+ end
91
+
92
+ private
93
+
94
+ def indexable_slots_for_doc(doc)
95
+ raw_slots = doc.to_raw
96
+ nkeys = doc.meta['non_indexable_slots']
97
+ nkeys.each{|nk| raw_slots.delete(nk) } if nkeys
98
+ raw_slots
99
+ end
100
+
101
+ def list
102
+ @list ||= @storage.find_list
103
+ end
104
+
105
+ end
56
106
  end
@@ -0,0 +1,80 @@
1
+ module StrokeDB
2
+ class MemoryStorage < Storage
3
+
4
+ def initialize(options = {})
5
+ @options = options.stringify_keys
6
+ clear!
7
+ end
8
+
9
+ def save_as_head!(document, timestamp)
10
+ save!(document,timestamp, :head => true)
11
+ end
12
+
13
+ def find(uuid, version=nil, opts = {},&block)
14
+ uuid_version = uuid + (version ? ".#{version}" : "")
15
+ unless raw_doc = read(uuid_version)
16
+ authoritative_source.find(uuid,version,opts,&block) if authoritative_source
17
+ else
18
+ unless opts[:no_instantiation]
19
+ doc = Document.from_raw(opts[:store], raw_doc.freeze, &block) # FIXME: there should be a better source for store (probably)
20
+ doc.extend(VersionedDocument) if version
21
+ doc
22
+ else
23
+ raw_doc
24
+ end
25
+ end
26
+ end
27
+
28
+ def include?(uuid,version=nil)
29
+ uuid_version = uuid + (version ? ".#{version}" : "")
30
+ !@container.find(uuid_version).nil?
31
+ end
32
+ alias_method :contains?, :include?
33
+
34
+ def head_version(uuid, opts = {})
35
+ if doc = find(uuid,nil, opts)
36
+ doc.version
37
+ end
38
+ end
39
+
40
+ def each(options = {})
41
+ after = options[:after_timestamp]
42
+ include_versions = options[:include_versions]
43
+ @container.each do |key, value|
44
+ next if after && (value[1] <= after)
45
+ if uuid_match = key.match(/^#{UUID_RE}$/) || (include_versions && uuid_match = key.match(/#{UUID_RE}./) )
46
+ yield Document.from_raw(options[:store],value[0])
47
+ end
48
+ end
49
+ end
50
+
51
+ def perform_save!(document, timestamp, options = {})
52
+ uuid = document.uuid
53
+ version = document.version
54
+ raw_document = document.to_raw
55
+ uuid_version = uuid + (version ? ".#{version}" : "")
56
+ write(uuid, raw_document, timestamp) if options[:head] || !document.is_a?(VersionedDocument)
57
+ write(uuid_version, raw_document, timestamp) unless options[:head]
58
+ end
59
+
60
+ def clear!
61
+ @container = SimpleSkiplist.new
62
+ end
63
+
64
+ def close!
65
+ end
66
+
67
+ private
68
+
69
+ def read(key)
70
+ if record = @container.find(key)
71
+ record.first
72
+ end
73
+ end
74
+
75
+ def write(key, document, timestamp)
76
+ @container.insert(key, [document, timestamp.counter])
77
+ end
78
+
79
+ end
80
+ end