Merge pull request #648 from bhollis/threading

Make Sitemap::Store more thread-safe.
This commit is contained in:
Thomas Reynolds 2012-10-22 22:23:04 -07:00
commit 0ab6d03845

View file

@ -1,5 +1,6 @@
# Used for merging results of metadata callbacks # Used for merging results of metadata callbacks
require "active_support/core_ext/hash/deep_merge" require "active_support/core_ext/hash/deep_merge"
require 'monitor'
module Middleman module Middleman
@ -25,6 +26,8 @@ module Middleman
@_cached_metadata = {} @_cached_metadata = {}
@resource_list_manipulators = [] @resource_list_manipulators = []
@needs_sitemap_rebuild = true @needs_sitemap_rebuild = true
@lock = Monitor.new
reset_lookup_cache! reset_lookup_cache!
# Register classes which can manipulate the main site map list # Register classes which can manipulate the main site map list
@ -48,36 +51,44 @@ module Middleman
# Rebuild the list of resources from scratch, using registed manipulators # Rebuild the list of resources from scratch, using registed manipulators
# @return [void] # @return [void]
def rebuild_resource_list!(reason=nil) def rebuild_resource_list!(reason=nil)
@needs_sitemap_rebuild = true @lock.synchronize do
@needs_sitemap_rebuild = true
end
end end
# Find a resource given its original path # Find a resource given its original path
# @param [String] request_path The original path of a resource. # @param [String] request_path The original path of a resource.
# @return [Middleman::Sitemap::Resource] # @return [Middleman::Sitemap::Resource]
def find_resource_by_path(request_path) def find_resource_by_path(request_path)
request_path = ::Middleman::Util.normalize_path(request_path) @lock.synchronize do
ensure_resource_list_updated! request_path = ::Middleman::Util.normalize_path(request_path)
@_lookup_by_path[request_path] ensure_resource_list_updated!
@_lookup_by_path[request_path]
end
end end
# Find a resource given its destination path # Find a resource given its destination path
# @param [String] request_path The destination (output) path of a resource. # @param [String] request_path The destination (output) path of a resource.
# @return [Middleman::Sitemap::Resource] # @return [Middleman::Sitemap::Resource]
def find_resource_by_destination_path(request_path) def find_resource_by_destination_path(request_path)
request_path = ::Middleman::Util.normalize_path(request_path) @lock.synchronize do
ensure_resource_list_updated! request_path = ::Middleman::Util.normalize_path(request_path)
@_lookup_by_destination_path[request_path] ensure_resource_list_updated!
@_lookup_by_destination_path[request_path]
end
end end
# Get the array of all resources # Get the array of all resources
# @param [Boolean] include_ignored Whether to include ignored resources # @param [Boolean] include_ignored Whether to include ignored resources
# @return [Array<Middleman::Sitemap::Resource>] # @return [Array<Middleman::Sitemap::Resource>]
def resources(include_ignored=false) def resources(include_ignored=false)
ensure_resource_list_updated! @lock.synchronize do
if include_ignored ensure_resource_list_updated!
@resources if include_ignored
else @resources
@resources.reject(&:ignored?) else
@resources.reject(&:ignored?)
end
end end
end end
@ -201,30 +212,34 @@ module Middleman
# rebuild_resource_list! since the last time it was run. This is # rebuild_resource_list! since the last time it was run. This is
# very expensive! # very expensive!
def ensure_resource_list_updated! def ensure_resource_list_updated!
return unless @needs_sitemap_rebuild @lock.synchronize do
@needs_sitemap_rebuild = false return unless @needs_sitemap_rebuild
@needs_sitemap_rebuild = false
@app.logger.debug "== Rebuilding resource list" @app.logger.debug "== Rebuilding resource list"
@resources = @resource_list_manipulators.inject([]) do |result, (_, inst)| @resources = @resource_list_manipulators.inject([]) do |result, (_, inst)|
newres = inst.manipulate_resource_list(result) newres = inst.manipulate_resource_list(result)
# Reset lookup cache # Reset lookup cache
reset_lookup_cache! reset_lookup_cache!
newres.each do |resource| newres.each do |resource|
@_lookup_by_path[resource.path] = resource @_lookup_by_path[resource.path] = resource
@_lookup_by_destination_path[resource.destination_path] = resource @_lookup_by_destination_path[resource.destination_path] = resource
end
newres
end end
newres
end end
end end
private private
def reset_lookup_cache! def reset_lookup_cache!
@_lookup_by_path = {} @lock.synchronize {
@_lookup_by_destination_path = {} @_lookup_by_path = {}
@_lookup_by_destination_path = {}
}
end end
end end
end end