blob: fc333866cc09c13ccec281e5e2dea2a63a68744d [file] [log] [blame]
/*
* Copyright 2013 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: pulkitg@google.com (Pulkit Goyal)
#include "pagespeed/opt/http/property_store.h"
#include "base/logging.h"
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/opt/http/property_cache.h"
namespace net_instaweb {
namespace {
Histogram* fast_finish_lookup_latency_ms_ = NULL;
} // namespace
PropertyStore::PropertyStore()
: enable_get_cancellation_(false) {
}
PropertyStore::~PropertyStore() {
}
void PropertyStoreGetCallback::InitStats(Statistics* statistics) {
fast_finish_lookup_latency_ms_ =
statistics->AddHistogram("PropertyStoreLatencyAfterFastFinishCalledMs");
}
PropertyStoreGetCallback::PropertyStoreGetCallback(
AbstractMutex* mutex,
PropertyPage* page,
bool is_cancellable,
BoolCallback* done,
Timer* timer)
: mutex_(mutex),
page_(page),
is_cancellable_(is_cancellable),
done_(done),
delete_when_done_(false),
done_called_(false),
timer_(timer),
fast_finish_time_ms_(0) {
}
PropertyStoreGetCallback::~PropertyStoreGetCallback() {
}
void PropertyStoreGetCallback::FastFinishLookup() {
if (!is_cancellable_) {
// Returns early as it is in non-cancelable mode.
return;
}
// Call done callback if it is not yet called.
BoolCallback* done = NULL;
{
ScopedMutex lock(mutex());
if (done_ == NULL) {
return;
}
// NULL out page_ since we shouldn't be touching it any longer.
page_ = NULL;
done = done_;
done_ = NULL;
fast_finish_time_ms_ = timer_->NowMs();
}
// Don't run callback while holding lock.
done->Run(false);
}
void PropertyStoreGetCallback::Done(bool success) {
BoolCallback* done = NULL;
bool delete_this = false;
{
ScopedMutex lock(mutex());
DCHECK(!done_called_);
// done_ will be NULL if FastFinishLookup() is called, though Done() is not
// yet called.
if (done_ != NULL) {
page_ = NULL;
done = done_;
done_ = NULL;
} else {
DCHECK_NE(fast_finish_time_ms_, 0);
int64 latency_ms = timer_->NowMs() - fast_finish_time_ms_;
fast_finish_lookup_latency_ms_->Add(latency_ms);
}
delete_this = delete_when_done_;
done_called_ = true;
}
// Call done callback if it is not yet called.
if (done != NULL) {
done->Run(success);
}
// If DeleteWhenDone() is already called, delete this.
if (delete_this) {
delete this;
}
}
void PropertyStoreGetCallback::DeleteWhenDone() {
{
ScopedMutex lock(mutex());
if (delete_when_done_) {
LOG(DFATAL) << "PropertyStoreGetCallback::DeleteWhenDone() "
<< "is called twice.";
}
delete_when_done_ = true;
if (!done_called_) {
// Returns if Done() is not yet called.
return;
}
}
delete this;
}
bool PropertyStoreGetCallback::AddPropertyValueProtobufToPropertyPage(
const PropertyCache::Cohort* cohort,
const PropertyValueProtobuf& pcache_value,
int64 min_write_timestamp_ms) {
ScopedMutex lock(mutex());
if (page() == NULL || !page()->IsCacheValid(min_write_timestamp_ms)) {
return false;
}
page()->AddValueFromProtobuf(cohort, pcache_value);
return true;
}
} // namespace net_instaweb