From 6cc664d6f6150143153892a431cd831e814e44bf Mon Sep 17 00:00:00 2001 From: Yurii Rashkovskii Date: Sat, 24 May 2008 22:02:25 +0300 Subject: [PATCH 1/2] :meta slot has been replaced with Meta metaslot (initial implementation) --- lib/strokedb/data_structures/point_query.rb | 1 + lib/strokedb/document.rb | 35 ++++++++++++--------- lib/strokedb/document/meta.rb | 34 ++++++++++---------- spec/integration/search_spec.rb | 10 +++--- spec/lib/strokedb/document/document_spec.rb | 10 +++--- spec/lib/strokedb/document/meta_spec.rb | 2 +- spec/lib/strokedb/sync/slot_diff_spec.rb | 12 +++---- spec/regression/meta_spec.rb | 4 +-- 8 files changed, 58 insertions(+), 50 deletions(-) diff --git a/lib/strokedb/data_structures/point_query.rb b/lib/strokedb/data_structures/point_query.rb index b9267528..43556026 100644 --- a/lib/strokedb/data_structures/point_query.rb +++ b/lib/strokedb/data_structures/point_query.rb @@ -17,6 +17,7 @@ class PointQuery def initialize(slots) @slots = {} slots.each do |k, v| + k = k.meta_uuid if k.is_a?(Module) # quick hack, but PointQuery will be thrown away as soon as we'll have new search system @slots[k.to_optimized_raw] = v.to_optimized_raw end end diff --git a/lib/strokedb/document.rb b/lib/strokedb/document.rb index a9d6aa9f..f32da2f6 100644 --- a/lib/strokedb/document.rb +++ b/lib/strokedb/document.rb @@ -97,7 +97,7 @@ def marshal_load(content) #:nodoc: class Metas < Array #:nodoc: def initialize(document) @document = document - _meta = document[:meta] + _meta = document[Meta] concat _meta.to_a end @@ -118,7 +118,7 @@ def delete(meta) raise ArgumentError, "Meta should be either document or meta module" end - @document[:meta] = self + @document[Meta] = self if _module @document.unextend(_module) @@ -143,7 +143,7 @@ def add_meta(meta, opts = {}) end # register meta in the document - @document[:meta] = self + @document[Meta] = self if _module @document.extend(_module) @@ -203,7 +203,7 @@ def initialize(*args, &block) # If slot was not found, it will return nil # def [](slotname) - slotname = slotname.document.uuid if (slotname.is_a?(Meta) && slotname.is_a?(Module)) || (slotname == Meta) + slotname = slotname.meta_uuid if (slotname.is_a?(Meta) && slotname.is_a?(Module)) || (slotname == Meta) @slots[slotname.to_s].value rescue nil end @@ -213,7 +213,7 @@ def [](slotname) # document[:slot_1] = "some value" # def []=(slotname, value) - slotname = slotname.document.uuid if (slotname.is_a?(Meta) && slotname.is_a?(Module)) || (slotname == Meta) + slotname = slotname.meta_uuid if (slotname.is_a?(Meta) && slotname.is_a?(Module)) || (slotname == Meta) slotname = slotname.to_s (@slots[slotname] ||= Slot.new(self, slotname)).value = value @@ -269,12 +269,12 @@ def diff(from) end def pretty_print #:nodoc: - slots = to_raw.except('meta') + slots = to_raw.except(Meta.meta_uuid) s = is_a?(ImmutableDocument) ? "#<^" : "#<" Util.catch_circular_reference(self) do - if self[:meta] && name = meta[:name] + if self[Meta] && name = meta[:name] s << "#{name} " else s << "Doc " @@ -299,7 +299,7 @@ def pretty_print #:nodoc: s rescue Util::CircularReferenceCondition - "#(#{(self[:meta] ? "#{meta}" : "Doc")} #{('@#'+uuid)[0,5]}...)" + "#(#{(self[Meta] ? "#{meta}" : "Doc")} #{('@#'+uuid)[0,5]}...)" end alias :to_s :pretty_print @@ -342,7 +342,7 @@ def to_optimized_raw #:nodoc: def self.from_raw(store, raw_slots, opts = {}, &block) #:nodoc: doc = new(store, raw_slots, true, &block) - collect_meta_modules(store, raw_slots['meta']).each do |meta_module| + collect_meta_modules(store, raw_slots[Meta.meta_uuid]).each do |meta_module| unless doc.is_a? meta_module doc.extend(meta_module) end @@ -470,7 +470,7 @@ def reverse_update_slots!(hash) # it will combine all metadocuments into one 'virtual' metadocument # def meta - unless (m = self[:meta]).kind_of? Array + unless (m = self[Meta]).kind_of? Array # simple case return m || Document.new(@store) end @@ -648,16 +648,21 @@ def do_initialize(store, slots={}, initialize_raw = false) #:nodoc: # initialize slots for a new, just created document def initialize_slots(slots) #:nodoc: @slots = {} - slots = slots.stringify_keys - + slots = slots.clone # there is a reason for meta slot is initialized separately — # we need to setup coercions before initializing actual slots - if meta = slots['meta'] + if meta = slots[Meta] meta = [meta] unless meta.is_a?(Array) meta.each {|m| metas.add_meta(m) } end - - slots.except('meta').each {|name,value| send("#{name}=", value) } + slots.delete(Meta) + slots.each do |name,value| + if name.is_a?(Module) + self[name] = value + else + send("#{name}=", value) + end + end # now, when we have all slots initialized, we can run initialization callbacks execute_callbacks :on_initialization diff --git a/lib/strokedb/document/meta.rb b/lib/strokedb/document/meta.rb index e54d17ea..3ed0f276 100644 --- a/lib/strokedb/document/meta.rb +++ b/lib/strokedb/document/meta.rb @@ -73,16 +73,15 @@ def name def document(store=nil) raise NoDefaultStoreError.new unless store ||= StrokeDB.default_store - unless meta_doc = store.find(uuid) - meta_doc = Document.create!(store, :name => Meta.name.demodulize, :uuid => uuid, :nsurl => StrokeDB.nsurl) + unless meta_doc = store.find(meta_uuid) + meta_doc = Document.create!(store, :name => Meta.name.demodulize, :uuid => meta_uuid, :nsurl => StrokeDB.nsurl) end meta_doc end - private - def uuid + def meta_uuid @uuid ||= ::StrokeDB::Util.sha1_uuid("meta:#{StrokeDB.nsurl}##{Meta.name.demodulize}") end @@ -156,7 +155,7 @@ def #{callback_name}(uid=nil, &block) def new(*args, &block) args = args.clone args << {} unless args.last.is_a?(Hash) - args.last[:meta] = @metas + args.last[Meta] = @metas doc = Document.new(*args, &block) doc end @@ -204,7 +203,7 @@ def find(*args, &block) end store = args[0] - opt = { :meta => @metas.map {|m| m.document(store)} } + opt = { Meta => @metas.map {|m| m.document(store)} } case args[1] when String @@ -255,9 +254,18 @@ def document(store=nil) def extended(obj) - setup_callbacks(obj) if obj.is_a?(Document) + setup_callbacks(obj) if obj.is_a?(Document) end + def meta_uuid + values = @args.clone.select{|a| a.is_a?(Hash) }.first + values[:nsurl] ||= name.modulize.empty? ? Module.nsurl : name.modulize.constantize.nsurl + values[:name] ||= name.demodulize + + @uuid ||= Meta.make_uuid(values[:nsurl],values[:name]) + end + + private @@ -266,16 +274,16 @@ def make_document(store=nil) @meta_initialization_procs.each {|proc| proc.call }.clear values = @args.clone.select{|a| a.is_a?(Hash) }.first - values[:meta] = Meta.document(store) + values[Meta] = Meta.document(store) values[:name] ||= name.demodulize raise ArgumentError, "meta can't be nameless" if values[:name].blank? values[:nsurl] ||= name.modulize.empty? ? Module.nsurl : name.modulize.constantize.nsurl - values[:uuid] ||= Meta.make_uuid(values[:nsurl],values[:name]) + values[:uuid] ||= meta_uuid - if meta_doc = find_meta_doc(values, store) + if meta_doc = store.find(meta_uuid) values[:version] = meta_doc.version values[:uuid] = meta_doc.uuid args = [store, values] @@ -288,12 +296,6 @@ def make_document(store=nil) meta_doc end - def find_meta_doc(values, store) - if uuid = values[:uuid] - store.find(uuid) - end - end - def changed?(meta_doc, args) !(Document.new(*args).to_raw.except('previous_version') == meta_doc.to_raw.except('previous_version')) end diff --git a/spec/integration/search_spec.rb b/spec/integration/search_spec.rb index bf67092b..cdf85025 100644 --- a/spec/integration/search_spec.rb +++ b/spec/integration/search_spec.rb @@ -26,7 +26,7 @@ # end it "should add new doc" do - doc = Document.create!(@f_store, :name => "Oleg", :state => 'Russia', :age => 21, :meta => @profile_meta) + doc = Document.create!(@f_store, :name => "Oleg", :state => 'Russia', :age => 21, Meta => @profile_meta) doc.uuid.should_not be_nil @oleg_uuid = doc.uuid results = @index.find(:name => "Oleg") @@ -35,13 +35,13 @@ end it "should find doc in a separate index instance" do - results = @index2.find(:name => "Oleg", :meta => @profile_meta) + results = @index2.find(:name => "Oleg", Meta => @profile_meta) results.should_not be_empty results[0]["name"].should == "Oleg" end it "should store & find several docs" do - doc = Document.create!(@f_store, :name => "Yurii", :state => 'Ukraine', :meta => @profile_meta) + doc = Document.create!(@f_store, :name => "Yurii", :state => 'Ukraine', Meta => @profile_meta) doc.save! @yura_uuid = doc.uuid results = @index.find(:name => "Yurii") @@ -50,13 +50,13 @@ end it "should find all profiles" do - results = @index.find(:meta => @profile_meta) + results = @index.find(Meta => @profile_meta) results.should_not be_empty results.map{|e| e.uuid}.to_set == [ @yura_uuid, @oleg_uuid ].to_set end it "should find all profiles from Ukraine" do - results = @index.find(:meta => @profile_meta, :state => 'Ukraine') + results = @index.find(Meta => @profile_meta, :state => 'Ukraine') results.should_not be_empty results.map{|e| e.uuid}.to_set == [ @yura_uuid ].to_set end diff --git a/spec/lib/strokedb/document/document_spec.rb b/spec/lib/strokedb/document/document_spec.rb index 4e133efa..7b503360 100644 --- a/spec/lib/strokedb/document/document_spec.rb +++ b/spec/lib/strokedb/document/document_spec.rb @@ -692,11 +692,11 @@ def slot1=(v) Object.send!(:remove_const, "SomeMeta") if defined? ::SomeMeta ::SomeMeta = Meta.new(@store) @meta = ::SomeMeta - @document = Document.create!(@store, :meta => @meta) + @document = Document.create!(@store, Meta => @meta) end it "but specified within array should return single meta which should be mutable" do - @document = Document.create!(@store, :meta => [@meta]) + @document = Document.create!(@store, Meta => [@meta]) @document.meta.should == @meta.document @document.meta.should be_mutable end @@ -726,7 +726,7 @@ def slot1=(v) end end - @document = Document.new(:meta => @metas) + @document = Document.new(Meta => @metas) end it "should return single merged meta" do @@ -737,7 +737,7 @@ def slot1=(v) meta[1].should == 1 meta[2].should == 2 meta.name.should == "0,1,2" - @document[:meta].should be_a_kind_of(Array) + @document[Meta].should be_a_kind_of(Array) end it "should make single merged meta immutable" do @@ -916,7 +916,7 @@ def slot1=(v) 3.times do |i| @metas << Meta.new(:name => "SomeDocument#{i}") end - @document = @metas.inject{|a,b| a+=b}.new(@store,:slot1 => "val1", :slot2 => "val2", :meta => @metas) + @document = @metas.inject{|a,b| a+=b}.new(@store,:slot1 => "val1", :slot2 => "val2", Meta => @metas) @json = @document.to_raw.to_json @decoded_json = JSON.parse(@json) end diff --git a/spec/lib/strokedb/document/meta_spec.rb b/spec/lib/strokedb/document/meta_spec.rb index 9a0c6c04..028a4e7e 100644 --- a/spec/lib/strokedb/document/meta_spec.rb +++ b/spec/lib/strokedb/document/meta_spec.rb @@ -227,7 +227,7 @@ module A it "should initialize Document with all metas" do d = (User+Buyer+Seller).new - d[:meta].should == [User.document,Buyer.document,Seller.document] + d[Meta].should == [User.document,Buyer.document,Seller.document] end it "should be able to find respective documents" do diff --git a/spec/lib/strokedb/sync/slot_diff_spec.rb b/spec/lib/strokedb/sync/slot_diff_spec.rb index f6d6087c..bf40479d 100644 --- a/spec/lib/strokedb/sync/slot_diff_spec.rb +++ b/spec/lib/strokedb/sync/slot_diff_spec.rb @@ -10,8 +10,8 @@ @meta = Document.create! :diff_strategy_slot1 => 'slot_1_diff', :name => "Slot1DiffMeta" - @from = Document.create! :slot1 => 1, :meta => @meta - @to = Document.create! :slot1 => 2, :meta => @meta + @from = Document.create! :slot1 => 1, Meta => @meta + @to = Document.create! :slot1 => 2, Meta => @meta @diff = @to.diff(@from) end @@ -31,8 +31,8 @@ Object.send!(:remove_const,'Slot1Diff') if defined?(Slot1Diff) @meta = Document.create! :diff_strategy_slot1 => 'slot_1_diff', :name => "Slot1DiffMeta" - @from = Document.create! :slot1 => 1, :meta => @meta - @to = Document.create! :slot1 => 2, :meta => @meta + @from = Document.create! :slot1 => 1, Meta => @meta + @to = Document.create! :slot1 => 2, Meta => @meta @diff = @to.diff(@from) end @@ -53,8 +53,8 @@ @meta = Document.create! :diff_strategy_slot1 => 'slot_1_diff', :name => "Slot1DiffMeta" - @from = Document.create! :slot1 => 1, :meta => @meta - @to = Document.create! :slot1 => 2, :meta => @meta + @from = Document.create! :slot1 => 1, Meta => @meta + @to = Document.create! :slot1 => 2, Meta => @meta @diff = @to.diff(@from) end diff --git a/spec/regression/meta_spec.rb b/spec/regression/meta_spec.rb index 8428d930..e3f4ba42 100644 --- a/spec/regression/meta_spec.rb +++ b/spec/regression/meta_spec.rb @@ -14,9 +14,9 @@ it "and saving document should not alter list of actual metas" do @user.metas << Buyer - metas = @user[:meta].map{|v| v.to_raw } + metas = @user[Meta].map{|v| v.to_raw } @user.save! - @user[:meta].map{|v| v.to_raw }.should == metas + @user[Meta].map{|v| v.to_raw }.should == metas end From 03795003ae925546efc24a45b3bb5047d76b6c36 Mon Sep 17 00:00:00 2001 From: Yurii Rashkovskii Date: Sat, 24 May 2008 23:01:17 +0300 Subject: [PATCH 2/2] autosync/close files in specs even for mem storage --- spec/spec_helper.rb | 68 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7606700a..8d97241c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,52 +7,50 @@ TEMP_STORAGES = TEMP_DIR + '/storages' def setup_default_store(store=nil) - if store - StrokeDB.stub!(:default_store).and_return(store) - return store - end - @path = TEMP_STORAGES - FileUtils.rm_rf @path +if store + StrokeDB.stub!(:default_store).and_return(store) + return store +end +@path = TEMP_STORAGES +FileUtils.rm_rf @path - @storage = if ENV['STORAGE'].to_s.downcase == 'file' - StrokeDB::FileStorage.new(:path => @path + '/file_storage') - else - StrokeDB::MemoryStorage.new - end +@storage = if ENV['STORAGE'].to_s.downcase == 'file' + StrokeDB::FileStorage.new(:path => @path + '/file_storage') +else + StrokeDB::MemoryStorage.new +end - $store = StrokeDB::Store.new(:storage => @storage,:index => @index, :path => @path) - StrokeDB.stub!(:default_store).and_return($store) - StrokeDB.default_store +$store = StrokeDB::Store.new(:storage => @storage,:index => @index, :path => @path) +StrokeDB.stub!(:default_store).and_return($store) +StrokeDB.default_store end def stub_meta_in_store(store=nil) - store ||= StrokeDB.default_store - meta = store.find(NIL_UUID) - store.should_receive(:find).with(NIL_UUID).any_number_of_times.and_return(meta) - store.should_receive(:include?).with(NIL_UUID).any_number_of_times.and_return(true) +store ||= StrokeDB.default_store +meta = store.find(NIL_UUID) +store.should_receive(:find).with(NIL_UUID).any_number_of_times.and_return(meta) +store.should_receive(:include?).with(NIL_UUID).any_number_of_times.and_return(true) end def setup_index(store=nil) - store ||= StrokeDB.default_store - index_storage = StrokeDB::InvertedListFileStorage.new(:path => TEMP_STORAGES + '/inverted_list_storage') - index_storage.clear! - @index = StrokeDB::InvertedListIndex.new(index_storage) - @index.document_store = store - store.index_store = @index - @index +store ||= StrokeDB.default_store +index_storage = StrokeDB::InvertedListFileStorage.new(:path => TEMP_STORAGES + '/inverted_list_storage') +index_storage.clear! +@index = StrokeDB::InvertedListIndex.new(index_storage) +@index.document_store = store +store.index_store = @index +@index end Spec::Runner.configure do |config| - config.after(:all) do +config.after(:all) do + + ObjectSpace.each_object do |obj| + obj.stop_autosync! if obj.is_a?(Store) rescue nil + end - if ENV['STORAGE'].to_s.downcase == 'file' - ObjectSpace.each_object do |obj| - obj.stop_autosync! if obj.is_a?(Store) - end - - ObjectSpace.each_object do |obj| - obj.close if obj.is_a?(::File) rescue nil - end + ObjectSpace.each_object do |obj| + obj.close if obj.is_a?(::File) rescue nil end - end +end end \ No newline at end of file