Making design doc thread safe for checking status of design doc

This commit is contained in:
Sam Lown 2010-04-06 17:51:17 +00:00
parent 77cb8160c7
commit 5fd1c3903b
7 changed files with 43 additions and 57 deletions

View file

@ -336,7 +336,7 @@ module CouchRest
end
def clear_extended_doc_fresh_cache
::CouchRest::ExtendedDocument.subclasses.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) }
::CouchRest::ExtendedDocument.subclasses.each{|klass| klass.req_design_doc_refresh if klass.respond_to?(:req_design_doc_refresh)}
end
def uri_for_attachment(doc, name)

View file

@ -107,16 +107,12 @@ module CouchRest
@klass.design_doc
end
def design_doc_fresh
@klass.design_doc_fresh
end
def refresh_design_doc
@klass.refresh_design_doc_on(@database)
@klass.refresh_design_doc(@database)
end
def save_design_doc
@klass.save_design_doc_on(@database)
@klass.save_design_doc(@database)
end
end
end

View file

@ -9,23 +9,23 @@ module CouchRest
end
module ClassMethods
attr_accessor :design_doc, :design_doc_slug_cache, :design_doc_fresh
def design_doc
@design_doc ||= Design.new(default_design_doc)
end
# Use when something has been changed, like a view, so that on the next request
# the design docs will be updated.
def req_design_doc_refresh
@design_doc_fresh = { }
end
def design_doc_id
"_design/#{design_doc_slug}"
end
def design_doc_slug
return design_doc_slug_cache if (design_doc_slug_cache && design_doc_fresh)
funcs = []
design_doc['views'].each do |name, view|
funcs << "#{name}/#{view['map']}#{view['reduce']}"
end
self.design_doc_slug_cache = self.to_s
self.to_s
end
def default_design_doc
@ -43,45 +43,44 @@ module CouchRest
}
end
def refresh_design_doc
reset_design_doc
save_design_doc
end
def refresh_design_doc_on(db)
reset_design_doc
save_design_doc_on(db)
end
# Save the design doc onto the default database, and update the
# design_doc attribute
def save_design_doc
reset_design_doc unless design_doc_fresh
self.design_doc = update_design_doc(design_doc)
def refresh_design_doc(db = database)
unless design_doc_fresh(db)
reset_design_doc(db)
save_design_doc(db)
end
end
# Save the design doc onto a target database in a thread-safe way,
# not modifying the model's design_doc
def save_design_doc_on(db)
def save_design_doc(db = database)
update_design_doc(Design.new(design_doc), db)
end
private
protected
def reset_design_doc
current = self.database.get(design_doc_id) rescue nil
def design_doc_fresh(db, fresh = nil)
@design_doc_fresh ||= {}
if fresh.nil?
@design_doc_fresh[db.uri] || false
else
@design_doc_fresh[db.uri] = fresh
end
end
def reset_design_doc(db)
current = db.get(design_doc_id) rescue nil
design_doc['_id'] = design_doc_id
if current.nil?
design_doc.delete('_rev')
else
design_doc['_rev'] = current['_rev']
end
self.design_doc_fresh = true
design_doc_fresh(db, true)
end
# Writes out a design_doc to a given database, returning the
# updated design doc
def update_design_doc(design_doc, db = database)
def update_design_doc(design_doc, db)
saved = db.get(design_doc['_id']) rescue nil
if saved
design_doc['views'].each do |name, view|

View file

@ -83,8 +83,8 @@ module CouchRest
opts[:guards].push "(doc['couchrest-type'] == '#{self.to_s}')"
end
keys.push opts
self.design_doc.view_by(*keys)
self.design_doc_fresh = false
design_doc.view_by(*keys)
req_design_doc_refresh
end
# returns stored defaults if the there is a view named this in the design doc
@ -96,9 +96,7 @@ module CouchRest
# Dispatches to any named view.
def view(name, query={}, &block)
db = query.delete(:database) || database
unless design_doc_fresh
refresh_design_doc_on(db)
end
refresh_design_doc(db)
query[:raw] = true if query[:reduce]
raw = query.delete(:raw)
fetch_view_with_docs(db, name, query, raw, &block)
@ -119,13 +117,6 @@ module CouchRest
end
end
# Deletes the current design doc for the current class.
# Running it to early could mean that live code has to regenerate
# potentially large indexes.
def cleanup_design_docs!(db = database)
save_design_doc_on(db)
end
private
def fetch_view_with_docs(db, name, opts, raw=false, &block)
@ -156,7 +147,7 @@ module CouchRest
# the design doc may not have been saved yet on this database
rescue HttpAbstraction::ResourceNotFound => e
if retryable
save_design_doc_on(db)
save_design_doc(db)
retryable = false
retry
else

View file

@ -327,7 +327,7 @@ describe "ExtendedDocument" do
describe "finding all instances of a model" do
before(:all) do
WithTemplateAndUniqueID.design_doc_fresh = false
WithTemplateAndUniqueID.req_design_doc_refresh
WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
WithTemplateAndUniqueID.database.bulk_delete
WithTemplateAndUniqueID.new('important-field' => '1').save
@ -349,7 +349,7 @@ describe "ExtendedDocument" do
describe "counting all instances of a model" do
before(:each) do
@db = reset_test_db!
WithTemplateAndUniqueID.design_doc_fresh = false
WithTemplateAndUniqueID.req_design_doc_refresh
end
it ".count should return 0 if there are no docuemtns" do
@ -368,7 +368,7 @@ describe "ExtendedDocument" do
describe "finding the first instance of a model" do
before(:each) do
@db = reset_test_db!
WithTemplateAndUniqueID.design_doc_fresh = false
WithTemplateAndUniqueID.req_design_doc_refresh
WithTemplateAndUniqueID.new('important-field' => '1').save
WithTemplateAndUniqueID.new('important-field' => '2').save
WithTemplateAndUniqueID.new('important-field' => '3').save

View file

@ -76,9 +76,9 @@ describe "Subclassing an ExtendedDocument" do
it "should have its own design_doc_fresh" do
Animal.refresh_design_doc
Dog.design_doc_fresh.should_not == true
Dog.send(:design_doc_fresh, Dog.database).should_not == true
Dog.refresh_design_doc
Dog.design_doc_fresh.should == true
Dog.send(:design_doc_fresh, Dog.database).should == true
end
it "should not add views to the parent's design_doc" do

View file

@ -126,7 +126,7 @@ describe "ExtendedDocument views" do
lambda{Unattached.all}.should raise_error
end
it "should query all" do
Unattached.cleanup_design_docs!(@db)
# Unattached.cleanup_design_docs!(@db)
rs = Unattached.all :database => @db
rs.length.should == 4
end
@ -187,7 +187,7 @@ describe "ExtendedDocument views" do
Unattached.view_by :questions
Unattached.by_questions(:database => @db)
original_revision = Unattached.model_design_doc(@db)['_rev']
Unattached.cleanup_design_docs!(@db)
Unattached.save_design_doc(@db)
Unattached.model_design_doc(@db)['_rev'].should_not == original_revision
end
end