blob: cbbe24a99c592455a59817558dd55f00578e45dd [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: sligocki@google.com (Shawn Ligocki)
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
#include "base/logging.h"
#include "net/instaweb/config/rewrite_options_manager.h"
#include "net/instaweb/http/public/http_cache.h"
#include "net/instaweb/http/public/http_dump_url_async_writer.h"
#include "net/instaweb/http/public/http_dump_url_fetcher.h"
#include "net/instaweb/http/public/request_context.h"
#include "net/instaweb/http/public/url_async_fetcher.h"
#include "net/instaweb/rewriter/public/beacon_critical_images_finder.h"
#include "net/instaweb/rewriter/public/beacon_critical_line_info_finder.h"
#include "net/instaweb/rewriter/public/compatible_central_controller.h"
#include "net/instaweb/rewriter/public/critical_css_finder.h"
#include "net/instaweb/rewriter/public/critical_images_finder.h"
#include "net/instaweb/rewriter/public/critical_line_info_finder.h"
#include "net/instaweb/rewriter/public/critical_selector_finder.h"
#include "net/instaweb/rewriter/public/experiment_matcher.h"
#include "net/instaweb/rewriter/public/mobilize_cached_finder.h"
#include "net/instaweb/rewriter/public/process_context.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_stats.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "net/instaweb/rewriter/public/static_asset_manager.h"
#include "net/instaweb/rewriter/public/url_namer.h"
#include "net/instaweb/rewriter/public/usage_data_reporter.h"
#include "net/instaweb/util/public/property_store.h"
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/checking_thread_system.h"
#include "pagespeed/kernel/base/file_system.h"
#include "pagespeed/kernel/base/function.h"
#include "pagespeed/kernel/base/hasher.h"
#include "pagespeed/kernel/base/hostname_util.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/named_lock_manager.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/sha1_signature.h"
#include "pagespeed/kernel/base/stl_util.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/cache/cache_batcher.h"
#include "pagespeed/kernel/http/http_options.h"
#include "pagespeed/kernel/http/user_agent_matcher.h"
#include "pagespeed/kernel/http/user_agent_normalizer.h"
#include "pagespeed/kernel/thread/queued_worker_pool.h"
#include "pagespeed/kernel/thread/scheduler.h"
#include "pagespeed/kernel/util/file_system_lock_manager.h"
#include "pagespeed/kernel/util/nonce_generator.h"
#include "pagespeed/opt/http/property_cache.h"
namespace net_instaweb {
RewriteDriverFactory::RewriteDriverFactory(
const ProcessContext& process_context, ThreadSystem* thread_system)
: url_async_fetcher_(NULL),
distributed_async_fetcher_(NULL),
js_tokenizer_patterns_(process_context.js_tokenizer_patterns()),
force_caching_(false),
slurp_read_only_(false),
slurp_print_urls_(false),
#ifdef NDEBUG
// For release binaries, use the thread-system directly.
thread_system_(thread_system),
#else
// When compiling for debug, interpose a layer that CHECKs for clean mutex
// semantics.
thread_system_(new CheckingThreadSystem(thread_system)),
#endif
server_context_mutex_(thread_system_->NewMutex()),
statistics_(&null_statistics_),
worker_pools_(kNumWorkerPools, NULL),
hostname_(GetHostname()) {
// Pre-initializes the default options. IMPORTANT: subclasses overridding
// NewRewriteOptions() should re-call this method from their constructor
// so that the correct rewrite_options_ object gets reset.
InitializeDefaultOptions();
}
void RewriteDriverFactory::InitializeDefaultOptions() {
default_options_.reset(NewRewriteOptions());
InitializeDefaultOptions(default_options_.get());
// Note that we do not need to compute a signature on the default options.
// We will never be serving requests with these options: they are just used
// as a source for merging.
}
void RewriteDriverFactory::InitializeDefaultOptions(RewriteOptions* options) {
// We default to using the "core filters". Note that this is not
// the only place the default is applied --- for directories with .htaccess
// files it is given in create_dir_config in mod_instaweb.cc
options->SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
options->DisallowTroublesomeResources();
}
void RewriteDriverFactory::reset_default_options(RewriteOptions* new_defaults) {
default_options_.reset(new_defaults);
}
RewriteDriverFactory::~RewriteDriverFactory() {
ShutDown();
{
ScopedMutex lock(server_context_mutex_.get());
STLDeleteElements(&server_contexts_);
}
for (int c = 0; c < kNumWorkerPools; ++c) {
delete worker_pools_[c];
worker_pools_[c] = NULL;
}
// Avoid double-destructing the url fetchers if they were not overridden
// programmatically
if ((url_async_fetcher_ != NULL) &&
(url_async_fetcher_ != base_url_async_fetcher_.get())) {
delete url_async_fetcher_;
}
url_async_fetcher_ = NULL;
if ((distributed_async_fetcher_ != NULL) &&
(distributed_async_fetcher_ != base_distributed_async_fetcher_.get())) {
delete distributed_async_fetcher_;
}
distributed_async_fetcher_ = NULL;
for (int i = 0, n = deferred_cleanups_.size(); i < n; ++i) {
deferred_cleanups_[i]->CallRun();
}
// Delete the lock-manager before we delete the scheduler.
lock_manager_.reset(NULL);
}
void RewriteDriverFactory::set_html_parse_message_handler(
MessageHandler* message_handler) {
html_parse_message_handler_.reset(message_handler);
}
void RewriteDriverFactory::set_message_handler(
MessageHandler* message_handler) {
message_handler_.reset(message_handler);
}
bool RewriteDriverFactory::FetchersComputed() const {
return (url_async_fetcher_ != NULL);
}
void RewriteDriverFactory::set_slurp_directory(const StringPiece& dir) {
CHECK(!FetchersComputed())
<< "Cannot call set_slurp_directory "
<< " after ComputeUrl*Fetcher has been called";
dir.CopyToString(&slurp_directory_);
}
void RewriteDriverFactory::set_slurp_read_only(bool read_only) {
CHECK(!FetchersComputed())
<< "Cannot call set_slurp_read_only "
<< " after ComputeUrl*Fetcher has been called";
slurp_read_only_ = read_only;
}
void RewriteDriverFactory::set_slurp_print_urls(bool print_urls) {
CHECK(!FetchersComputed())
<< "Cannot call set_slurp_print_urls "
<< " after ComputeUrl*Fetcher has been called";
slurp_print_urls_ = print_urls;
}
void RewriteDriverFactory::set_file_system(FileSystem* file_system) {
file_system_.reset(file_system);
}
void RewriteDriverFactory::set_base_url_async_fetcher(
UrlAsyncFetcher* url_async_fetcher) {
CHECK(!FetchersComputed())
<< "Cannot call set_base_url_async_fetcher "
<< " after ComputeUrlAsyncFetcher has been called";
base_url_async_fetcher_.reset(url_async_fetcher);
}
void RewriteDriverFactory::set_base_distributed_async_fetcher(
UrlAsyncFetcher* distributed_fetcher) {
CHECK(distributed_async_fetcher_ == NULL)
<< "Cannot call set_base_distributed_async_fetcher "
<< "after ComputeDistributedFetcher has been called";
base_distributed_async_fetcher_.reset(distributed_fetcher);
}
void RewriteDriverFactory::set_hasher(Hasher* hasher) {
hasher_.reset(hasher);
}
void RewriteDriverFactory::set_signature(SHA1Signature* signature) {
signature_.reset(signature);
}
void RewriteDriverFactory::set_timer(Timer* timer) {
timer_.reset(timer);
}
void RewriteDriverFactory::set_nonce_generator(NonceGenerator* gen) {
nonce_generator_.reset(gen);
}
void RewriteDriverFactory::set_url_namer(UrlNamer* url_namer) {
url_namer_.reset(url_namer);
}
void RewriteDriverFactory::set_usage_data_reporter(
UsageDataReporter* reporter) {
usage_data_reporter_.reset(reporter);
}
MessageHandler* RewriteDriverFactory::html_parse_message_handler() {
if (html_parse_message_handler_ == NULL) {
html_parse_message_handler_.reset(DefaultHtmlParseMessageHandler());
}
return html_parse_message_handler_.get();
}
MessageHandler* RewriteDriverFactory::message_handler() {
if (message_handler_ == NULL) {
message_handler_.reset(DefaultMessageHandler());
}
return message_handler_.get();
}
FileSystem* RewriteDriverFactory::file_system() {
if (file_system_ == NULL) {
file_system_.reset(DefaultFileSystem());
}
return file_system_.get();
}
NonceGenerator* RewriteDriverFactory::nonce_generator() {
if (nonce_generator_ == NULL) {
nonce_generator_.reset(DefaultNonceGenerator());
}
return nonce_generator_.get();
}
NonceGenerator* RewriteDriverFactory::DefaultNonceGenerator() {
// By default return NULL (no nonce generator).
return NULL;
}
Timer* RewriteDriverFactory::DefaultTimer() {
return thread_system()->NewTimer();
}
Timer* RewriteDriverFactory::timer() {
if (timer_ == NULL) {
timer_.reset(DefaultTimer());
}
return timer_.get();
}
UrlNamer* RewriteDriverFactory::url_namer() {
if (url_namer_ == NULL) {
url_namer_.reset(DefaultUrlNamer());
}
return url_namer_.get();
}
UserAgentMatcher* RewriteDriverFactory::user_agent_matcher() {
if (user_agent_matcher_ == NULL) {
user_agent_matcher_.reset(DefaultUserAgentMatcher());
}
return user_agent_matcher_.get();
}
StaticAssetManager* RewriteDriverFactory::static_asset_manager() {
if (static_asset_manager_ == NULL) {
static_asset_manager_.reset(DefaultStaticAssetManager());
InitStaticAssetManager(static_asset_manager_.get());
}
return static_asset_manager_.get();
}
RewriteOptionsManager* RewriteDriverFactory::NewRewriteOptionsManager() {
return new RewriteOptionsManager;
}
Scheduler* RewriteDriverFactory::scheduler() {
if (scheduler_ == NULL) {
scheduler_.reset(CreateScheduler());
}
return scheduler_.get();
}
Hasher* RewriteDriverFactory::hasher() {
if (hasher_ == NULL) {
hasher_.reset(NewHasher());
}
return hasher_.get();
}
SHA1Signature* RewriteDriverFactory::signature() {
if (signature_ == NULL) {
signature_.reset(DefaultSignature());
}
return signature_.get();
}
UsageDataReporter* RewriteDriverFactory::usage_data_reporter() {
if (usage_data_reporter_ == NULL) {
usage_data_reporter_.reset(DefaultUsageDataReporter());
}
return usage_data_reporter_.get();
}
const std::vector<const UserAgentNormalizer*>&
RewriteDriverFactory::user_agent_normalizers() {
if (user_agent_normalizers_.empty()) {
// Note: it's possible that we may want separate lists of normalizers for
// different applications in the future. For now, though, we centralize
// one list, because:
// a) It's simpler b) Regexp compilation isn't free.
AndroidUserAgentNormalizer* an = new AndroidUserAgentNormalizer();
IEUserAgentNormalizer* ien = new IEUserAgentNormalizer();
TakeOwnership(an);
TakeOwnership(ien);
user_agent_normalizers_.push_back(an);
user_agent_normalizers_.push_back(ien);
AddPlatformSpecificUserAgentNormalizers(&user_agent_normalizers_);
}
return user_agent_normalizers_;
}
NamedLockManager* RewriteDriverFactory::DefaultLockManager() {
return new FileSystemLockManager(file_system(), LockFilePrefix(),
scheduler(), message_handler());
}
UrlNamer* RewriteDriverFactory::DefaultUrlNamer() {
return new UrlNamer();
}
UserAgentMatcher* RewriteDriverFactory::DefaultUserAgentMatcher() {
return new UserAgentMatcher();
}
StaticAssetManager* RewriteDriverFactory::DefaultStaticAssetManager() {
return new StaticAssetManager(url_namer()->proxy_domain(),
thread_system(),
hasher(),
message_handler());
}
CriticalCssFinder* RewriteDriverFactory::DefaultCriticalCssFinder() {
return NULL;
}
CriticalImagesFinder* RewriteDriverFactory::DefaultCriticalImagesFinder(
ServerContext* server_context) {
// TODO(pulkitg): Don't create BeaconCriticalImagesFinder if beacon cohort is
// not added.
return new BeaconCriticalImagesFinder(
server_context->beacon_cohort(), nonce_generator(), statistics());
}
CriticalSelectorFinder* RewriteDriverFactory::DefaultCriticalSelectorFinder(
ServerContext* server_context) {
if (server_context->beacon_cohort() != NULL) {
return new BeaconCriticalSelectorFinder(server_context->beacon_cohort(),
nonce_generator(), statistics());
}
return NULL;
}
MobilizeCachedFinder* RewriteDriverFactory::DefaultMobilizeCachedFinder(
ServerContext* server_context) {
return NULL;
}
SHA1Signature* RewriteDriverFactory::DefaultSignature() {
return new SHA1Signature();
}
FlushEarlyInfoFinder* RewriteDriverFactory::DefaultFlushEarlyInfoFinder() {
return NULL;
}
CacheHtmlInfoFinder* RewriteDriverFactory::DefaultCacheHtmlInfoFinder(
PropertyCache* cache, ServerContext* server_context) {
return NULL;
}
CriticalLineInfoFinder* RewriteDriverFactory::DefaultCriticalLineInfoFinder(
ServerContext* server_context) {
return new BeaconCriticalLineInfoFinder(server_context->beacon_cohort(),
nonce_generator());
}
UsageDataReporter* RewriteDriverFactory::DefaultUsageDataReporter() {
return new UsageDataReporter;
}
QueuedWorkerPool* RewriteDriverFactory::CreateWorkerPool(
WorkerPoolCategory pool, StringPiece name) {
return new QueuedWorkerPool(1, name, thread_system());
}
int RewriteDriverFactory::LowPriorityLoadSheddingThreshold() const {
return QueuedWorkerPool::kNoLoadShedding;
}
Scheduler* RewriteDriverFactory::CreateScheduler() {
return new Scheduler(thread_system(), timer());
}
NamedLockManager* RewriteDriverFactory::lock_manager() {
if (lock_manager_ == NULL) {
lock_manager_.reset(DefaultLockManager());
}
return lock_manager_.get();
}
QueuedWorkerPool* RewriteDriverFactory::WorkerPool(WorkerPoolCategory pool) {
if (worker_pools_[pool] == NULL) {
StringPiece name;
switch (pool) {
case kHtmlWorkers:
name = "html";
break;
case kRewriteWorkers:
name = "rewrite";
break;
case kLowPriorityRewriteWorkers:
name = "slow_rewrite";
break;
default:
LOG(DFATAL) << "Unhandled enum value " << pool;
name = "unknown_worker";
break;
}
worker_pools_[pool] = CreateWorkerPool(pool, name);
worker_pools_[pool]->set_queue_size_stat(
rewrite_stats()->thread_queue_depth(pool));
if (pool == kLowPriorityRewriteWorkers) {
worker_pools_[pool]->SetLoadSheddingThreshold(
LowPriorityLoadSheddingThreshold());
}
}
return worker_pools_[pool];
}
bool RewriteDriverFactory::set_filename_prefix(StringPiece p) {
p.CopyToString(&filename_prefix_);
if (file_system()->IsDir(filename_prefix_.c_str(),
message_handler()).is_true()) {
return true;
}
if (!file_system()->RecursivelyMakeDir(filename_prefix_, message_handler())) {
message_handler()->FatalError(
filename_prefix_.c_str(), 0,
"Directory does not exist and cannot be created");
return false;
}
AddCreatedDirectory(filename_prefix_);
return true;
}
StringPiece RewriteDriverFactory::filename_prefix() {
return filename_prefix_;
}
ServerContext* RewriteDriverFactory::CreateServerContext() {
ServerContext* server_context = NewServerContext();
InitServerContext(server_context);
return server_context;
}
void RewriteDriverFactory::InitServerContext(ServerContext* server_context) {
ScopedMutex lock(server_context_mutex_.get());
// Init CentralController. This is not strictly related to the ServerContext,
// but needs to happen before the ServerContext starts up.
set_central_controller_interface(CreateCentralController());
server_context->ComputeSignature(server_context->global_options());
server_context->set_scheduler(scheduler());
server_context->set_timer(timer());
if (server_context->statistics() == NULL) {
server_context->set_statistics(statistics());
}
if (server_context->rewrite_stats() == NULL) {
server_context->set_rewrite_stats(rewrite_stats());
}
SetupCaches(server_context);
if (server_context->lock_manager() == NULL) {
server_context->set_lock_manager(lock_manager());
}
if (!server_context->has_default_system_fetcher()) {
server_context->set_default_system_fetcher(ComputeUrlAsyncFetcher());
}
if (!server_context->has_default_distributed_fetcher()) {
UrlAsyncFetcher* fetcher = ComputeDistributedFetcher();
if (fetcher != NULL) {
server_context->set_default_distributed_fetcher(fetcher);
}
}
server_context->set_url_namer(url_namer());
server_context->SetRewriteOptionsManager(NewRewriteOptionsManager());
server_context->set_user_agent_matcher(user_agent_matcher());
server_context->set_file_system(file_system());
server_context->set_filename_prefix(filename_prefix_);
server_context->set_hasher(hasher());
server_context->set_signature(signature());
server_context->set_message_handler(message_handler());
server_context->set_static_asset_manager(static_asset_manager());
PropertyCache* pcache = server_context->page_property_cache();
server_context->set_critical_css_finder(DefaultCriticalCssFinder());
server_context->set_critical_images_finder(
DefaultCriticalImagesFinder(server_context));
server_context->set_critical_selector_finder(
DefaultCriticalSelectorFinder(server_context));
server_context->set_flush_early_info_finder(DefaultFlushEarlyInfoFinder());
server_context->set_cache_html_info_finder(
DefaultCacheHtmlInfoFinder(pcache, server_context));
server_context->set_critical_line_info_finder(
DefaultCriticalLineInfoFinder(server_context));
server_context->set_mobilize_cached_finder(
DefaultMobilizeCachedFinder(server_context));
server_context->set_hostname(hostname_);
server_context->PostInitHook();
InitDecodingDriver(server_context);
server_contexts_.insert(server_context);
// Make sure that all lazy state gets initialized, even if we don't copy it to
// ServerContext
user_agent_normalizers();
// Fetch the remote options so that they will be cached.
HttpOptions fetch_options;
fetch_options.implicit_cache_ttl_ms =
server_context->global_options()->implicit_cache_ttl_ms();
fetch_options.respect_vary = false;
// Minimum TTL for cachable resources, -1 for no minimum.
fetch_options.min_cache_ttl_ms = -1;
RequestContextPtr request_ctx(new RequestContext(
fetch_options, server_context->thread_system()->NewMutex(),
server_context->timer()));
scoped_ptr<RewriteOptions> remote_options(
server_context->global_options()->Clone());
server_context->GetRemoteOptions(remote_options.get(),
true /* startup fetch */);
}
CentralControllerInterface* RewriteDriverFactory::CreateCentralController() {
return new CompatibleCentralController(
default_options()->image_max_rewrites_at_once(), statistics());
}
void RewriteDriverFactory::RebuildDecodingDriverForTests(
ServerContext* server_context) {
decoding_driver_.reset(NULL);
InitDecodingDriver(server_context);
}
void RewriteDriverFactory::InitDecodingDriver(ServerContext* server_context) {
if (decoding_driver_.get() == NULL) {
decoding_server_context_.reset(NewDecodingServerContext());
// decoding_driver_ takes ownership.
RewriteOptions* options = default_options_->Clone();
options->ComputeSignature();
decoding_driver_.reset(
decoding_server_context_->NewUnmanagedRewriteDriver(
NULL, options, RequestContextPtr(NULL)));
decoding_driver_->set_externally_managed(true);
// Apply platform configuration mutation for consistency's sake.
ApplyPlatformSpecificConfiguration(decoding_driver_.get());
// Inserts platform-specific rewriters into the resource_filter_map_, so
// that the decoding process can recognize those rewriter ids.
AddPlatformSpecificDecodingPasses(decoding_driver_.get());
// This call is for backwards compatibility. When adding new platform
// specific rewriters to implementations of RewriteDriverFactory, please
// do not rely on this call to include them in the decoding process.
// Instead, add them to your implementation of
// AddPlatformSpecificDecodingPasses.
AddPlatformSpecificRewritePasses(decoding_driver_.get());
decoding_server_context_->set_decoding_driver(decoding_driver_.get());
}
server_context->set_decoding_driver(decoding_driver_.get());
}
void RewriteDriverFactory::InitStubDecodingServerContext(ServerContext* sc) {
sc->set_timer(timer());
sc->set_url_namer(url_namer());
sc->set_hasher(hasher());
sc->set_message_handler(message_handler());
NullStatistics* null_stats = new NullStatistics();
TakeOwnership(null_stats);
InitStats(null_stats);
sc->set_statistics(null_stats);
sc->set_hasher(hasher());
sc->set_signature(signature());
sc->PostInitHook();
}
void RewriteDriverFactory::AddPlatformSpecificDecodingPasses(
RewriteDriver* driver) {
}
void RewriteDriverFactory::AddPlatformSpecificRewritePasses(
RewriteDriver* driver) {
}
void RewriteDriverFactory::ApplyPlatformSpecificConfiguration(
RewriteDriver* driver) {
}
void RewriteDriverFactory::AddPlatformSpecificUserAgentNormalizers(
std::vector<const UserAgentNormalizer*>* out) {
}
UrlAsyncFetcher* RewriteDriverFactory::ComputeUrlAsyncFetcher() {
if (url_async_fetcher_ == NULL) {
// Run any hooks like setting up slurp directory.
FetcherSetupHooks();
if (slurp_directory_.empty()) {
if (base_url_async_fetcher_.get() == NULL) {
url_async_fetcher_ = DefaultAsyncUrlFetcher();
} else {
url_async_fetcher_ = base_url_async_fetcher_.get();
}
} else {
SetupSlurpDirectories();
}
}
return url_async_fetcher_;
}
UrlAsyncFetcher* RewriteDriverFactory::ComputeDistributedFetcher() {
if (distributed_async_fetcher_ == NULL) {
if (base_distributed_async_fetcher_.get() == NULL) {
distributed_async_fetcher_ = DefaultDistributedUrlFetcher();
} else {
distributed_async_fetcher_ = base_distributed_async_fetcher_.get();
}
}
return distributed_async_fetcher_;
}
void RewriteDriverFactory::SetupSlurpDirectories() {
CHECK(!FetchersComputed());
if (slurp_read_only_) {
CHECK(!FetchersComputed());
HttpDumpUrlFetcher* dump_fetcher = new HttpDumpUrlFetcher(
slurp_directory_, file_system(), timer());
dump_fetcher->set_print_urls(slurp_print_urls_);
url_async_fetcher_ = dump_fetcher;
} else {
// Check to see if the factory already had set_base_url_async_fetcher
// called on it. If so, then we'll want to use that fetcher
// as the mechanism for the dump-writer to retrieve missing
// content from the internet so it can be saved in the slurp
// directory.
url_async_fetcher_ = base_url_async_fetcher_.get();
if (url_async_fetcher_ == NULL) {
url_async_fetcher_ = DefaultAsyncUrlFetcher();
}
HttpDumpUrlAsyncWriter* dump_writer = new HttpDumpUrlAsyncWriter(
slurp_directory_, url_async_fetcher_, file_system(), timer());
dump_writer->set_print_urls(slurp_print_urls_);
url_async_fetcher_ = dump_writer;
}
}
void RewriteDriverFactory::FetcherSetupHooks() {
}
StringPiece RewriteDriverFactory::LockFilePrefix() {
return filename_prefix_;
}
void RewriteDriverFactory::StopCacheActivity() {
ScopedMutex lock(server_context_mutex_.get());
// Make sure we tell HTTP cache not to write out fetch failures, as
// fetcher shutdown may create artificial ones, and we don't want to
// remember those.
//
// Note that we also cannot access our own http_cache_ since it may be
// NULL in case like Apache where server contexts get their own.
for (ServerContextSet::iterator p = server_contexts_.begin();
p != server_contexts_.end(); ++p) {
HTTPCache* cache = (*p)->http_cache();
if (cache != NULL) {
cache->SetIgnoreFailurePuts();
}
}
// Similarly stop metadata cache writes.
for (ServerContextSet::iterator p = server_contexts_.begin();
p != server_contexts_.end(); ++p) {
ServerContext* server_context = *p;
server_context->set_shutting_down();
}
}
bool RewriteDriverFactory::TerminateServerContext(ServerContext* sc) {
ScopedMutex lock(server_context_mutex_.get());
server_contexts_.erase(sc);
return server_contexts_.empty();
}
void RewriteDriverFactory::ShutDown() {
StopCacheActivity(); // Maybe already stopped, but no harm stopping it twice.
// We first shutdown the low-priority rewrite threads, as they're meant to
// be robust against cancellation, and it will make the jobs wrap up
// much quicker.
if (worker_pools_[kLowPriorityRewriteWorkers] != NULL) {
worker_pools_[kLowPriorityRewriteWorkers]->ShutDown();
}
// Now get active RewriteDrivers for each manager to wrap up.
for (ServerContextSet::iterator p = server_contexts_.begin();
p != server_contexts_.end(); ++p) {
ServerContext* server_context = *p;
server_context->ShutDownDrivers();
}
// Shut down the remaining worker threads, to quiesce the system while
// leaving the QueuedWorkerPool & QueuedWorkerPool::Sequence objects
// live. The QueuedWorkerPools will be deleted when the ServerContext
// is destructed.
for (int i = 0, n = worker_pools_.size(); i < n; ++i) {
QueuedWorkerPool* worker_pool = worker_pools_[i];
if (worker_pool != NULL) {
worker_pool->ShutDown();
}
}
// Make sure we destroy the decoding driver here, before any of the
// server contexts get destroyed, since it's tied to one. Also clear
// all of the references to it.
for (ServerContextSet::iterator p = server_contexts_.begin();
p != server_contexts_.end(); ++p) {
ServerContext* server_context = *p;
server_context->set_decoding_driver(NULL);
}
decoding_driver_.reset(NULL);
}
void RewriteDriverFactory::AddCreatedDirectory(const GoogleString& dir) {
created_directories_.insert(dir);
}
void RewriteDriverFactory::InitStats(Statistics* statistics) {
HTTPCache::InitStats(statistics);
RewriteDriver::InitStats(statistics);
RewriteStats::InitStats(statistics);
CacheBatcher::InitStats(statistics);
CompatibleCentralController::InitStats(statistics);
CriticalImagesFinder::InitStats(statistics);
CriticalCssFinder::InitStats(statistics);
CriticalSelectorFinder::InitStats(statistics);
MobilizeCachedFinder::InitStats(statistics);
PropertyStoreGetCallback::InitStats(statistics);
}
void RewriteDriverFactory::Initialize() {
RewriteDriver::Initialize();
}
void RewriteDriverFactory::Terminate() {
RewriteDriver::Terminate();
}
void RewriteDriverFactory::SetStatistics(Statistics* statistics) {
statistics_ = statistics;
rewrite_stats_.reset(NULL);
}
RewriteStats* RewriteDriverFactory::rewrite_stats() {
if (rewrite_stats_.get() == NULL) {
rewrite_stats_.reset(new RewriteStats(statistics_, thread_system_.get(),
timer()));
}
return rewrite_stats_.get();
}
void RewriteDriverFactory::set_central_controller_interface(
CentralControllerInterface* interface) {
central_controller_interface_.reset(
new CentralControllerInterfaceAdapter(interface));
}
RewriteOptions* RewriteDriverFactory::NewRewriteOptions() {
return new RewriteOptions(thread_system());
}
RewriteOptions* RewriteDriverFactory::NewRewriteOptionsForQuery() {
return NewRewriteOptions();
}
ExperimentMatcher* RewriteDriverFactory::NewExperimentMatcher() {
return new ExperimentMatcher;
}
void RewriteDriverFactory::ScheduleExpensiveOperation(
ExpensiveOperationCallback* callback) {
central_controller_interface()->ScheduleExpensiveOperation(callback);
}
} // namespace net_instaweb