blob: 4210f9e460762fab575f7cb8eff13f396c867cc5 [file] [log] [blame]
/*
* Copyright 2012 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: jmarantz@google.com (Joshua Marantz)
#include "pagespeed/kernel/cache/cache_stats.h"
#include "pagespeed/kernel/base/shared_string.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/cache/cache_interface.h"
#include "pagespeed/kernel/cache/delegating_cache_callback.h"
namespace {
const char kGetCountHistogram[] = "_get_count";
const char kHitLatencyHistogram[] = "_hit_latency_us";
const char kInsertLatencyHistogram[] = "_insert_latency_us";
const char kInsertSizeHistogram[] = "_insert_size_bytes";
const char kLookupSizeHistogram[] = "_lookup_size_bytes";
const char kDeletes[] = "_deletes";
const char kHits[] = "_hits";
const char kInserts[] = "_inserts";
const char kMisses[] = "_misses";
// TODO(jmarantz): tie this to CacheBatcher::kDefaultMaxQueueSize,
// but for now I want to get discrete counts in each bucket.
const int kGetCountHistogramMaxValue = 500;
const int kSizeHistogramMaxValue = 5*1000*1000;
const int kLatencyHistogramMaxValueUs = 1*1000*1000;
} // namespace
namespace net_instaweb {
CacheStats::CacheStats(StringPiece prefix,
CacheInterface* cache,
Timer* timer,
Statistics* statistics)
: cache_(cache),
timer_(timer),
get_count_histogram_(statistics->GetHistogram(
StrCat(prefix, kGetCountHistogram))),
hit_latency_us_histogram_(statistics->GetHistogram(
StrCat(prefix, kHitLatencyHistogram))),
insert_latency_us_histogram_(statistics->GetHistogram(
StrCat(prefix, kInsertLatencyHistogram))),
insert_size_bytes_histogram_(statistics->GetHistogram(
StrCat(prefix, kInsertSizeHistogram))),
lookup_size_bytes_histogram_(statistics->GetHistogram(
StrCat(prefix, kLookupSizeHistogram))),
deletes_(statistics->GetVariable(StrCat(prefix, kDeletes))),
hits_(statistics->GetVariable(StrCat(prefix, kHits))),
inserts_(statistics->GetVariable(StrCat(prefix, kInserts))),
misses_(statistics->GetVariable(StrCat(prefix, kMisses))),
prefix_(prefix.data(), prefix.size()) {
get_count_histogram_->SetMaxValue(kGetCountHistogramMaxValue);
insert_size_bytes_histogram_->SetMaxValue(kSizeHistogramMaxValue);
lookup_size_bytes_histogram_->SetMaxValue(kSizeHistogramMaxValue);
hit_latency_us_histogram_->SetMaxValue(kLatencyHistogramMaxValueUs);
insert_latency_us_histogram_->SetMaxValue(kLatencyHistogramMaxValueUs);
}
CacheStats::~CacheStats() {
}
GoogleString CacheStats::FormatName(StringPiece prefix, StringPiece cache) {
return StrCat("Stats(prefix=", prefix, ",cache=", cache, ")");
}
void CacheStats::InitStats(StringPiece prefix, Statistics* statistics) {
Histogram* get_count_histogram =
statistics->AddHistogram(StrCat(prefix, kGetCountHistogram));
get_count_histogram->SetMaxValue(kGetCountHistogramMaxValue);
statistics->AddHistogram(StrCat(prefix, kHitLatencyHistogram));
statistics->AddHistogram(StrCat(prefix, kInsertLatencyHistogram));
Histogram* insert_size_bytes_histogram =
statistics->AddHistogram(StrCat(prefix, kInsertSizeHistogram));
insert_size_bytes_histogram->SetMaxValue(kSizeHistogramMaxValue);
Histogram* lookup_size_bytes_histogram =
statistics->AddHistogram(StrCat(prefix, kLookupSizeHistogram));
lookup_size_bytes_histogram->SetMaxValue(kSizeHistogramMaxValue);
statistics->AddVariable(StrCat(prefix, kDeletes));
statistics->AddVariable(StrCat(prefix, kHits));
statistics->AddVariable(StrCat(prefix, kInserts));
statistics->AddVariable(StrCat(prefix, kMisses));
}
class CacheStats::StatsCallback : public DelegatingCacheCallback {
public:
StatsCallback(CacheStats* stats,
Timer* timer,
CacheInterface::Callback* callback)
: DelegatingCacheCallback(callback),
stats_(stats),
timer_(timer) {
start_time_us_ = timer->NowUs();
}
virtual ~StatsCallback() {
}
virtual void Done(CacheInterface::KeyState state) {
if (state == CacheInterface::kAvailable) {
int64 end_time_us = timer_->NowUs();
stats_->hits_->Add(1);
stats_->lookup_size_bytes_histogram_->Add(value()->size());
stats_->hit_latency_us_histogram_->Add(end_time_us - start_time_us_);
} else {
stats_->misses_->Add(1);
}
DelegatingCacheCallback::Done(state);
}
private:
CacheStats* stats_;
Timer* timer_;
int64 start_time_us_;
DISALLOW_COPY_AND_ASSIGN(StatsCallback);
};
void CacheStats::Get(const GoogleString& key, Callback* callback) {
if (shutdown_.value()) {
ValidateAndReportResult(key, CacheInterface::kNotFound, callback);
} else {
StatsCallback* cb = new StatsCallback(this, timer_, callback);
cache_->Get(key, cb);
get_count_histogram_->Add(1);
}
}
void CacheStats::MultiGet(MultiGetRequest* request) {
if (shutdown_.value()) {
ReportMultiGetNotFound(request);
} else {
get_count_histogram_->Add(request->size());
for (int i = 0, n = request->size(); i < n; ++i) {
KeyCallback* key_callback = &(*request)[i];
key_callback->callback = new StatsCallback(this, timer_,
key_callback->callback);
}
cache_->MultiGet(request);
}
}
void CacheStats::Put(const GoogleString& key, SharedString* value) {
if (!shutdown_.value()) {
int64 start_time_us = timer_->NowUs();
inserts_->Add(1);
insert_size_bytes_histogram_->Add(value->size());
cache_->Put(key, value);
insert_latency_us_histogram_->Add(timer_->NowUs() - start_time_us);
}
}
void CacheStats::Delete(const GoogleString& key) {
if (!shutdown_.value()) {
deletes_->Add(1);
cache_->Delete(key);
}
}
} // namespace net_instaweb