diff options
author | rvargas@chromium.org <rvargas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-30 17:49:48 +0000 |
---|---|---|
committer | rvargas@chromium.org <rvargas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-30 17:49:48 +0000 |
commit | b851da9d3d378df04225d39ea44502742c73c20f (patch) | |
tree | 75926f3dd54b06e16f8fd97a856aed89ab3e8817 /net | |
parent | 6042bccc5aa73335796043eb35a5f2a76f3addf1 (diff) | |
download | chromium_src-b851da9d3d378df04225d39ea44502742c73c20f.zip chromium_src-b851da9d3d378df04225d39ea44502742c73c20f.tar.gz chromium_src-b851da9d3d378df04225d39ea44502742c73c20f.tar.bz2 |
Http cache: disable the infinite cache simulation and perform cleanup of local data.
BUG=147383
TEST=none
Review URL: https://chromiumcodereview.appspot.com/13000003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191528 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_cache.cc | 21 | ||||
-rw-r--r-- | net/http/http_cache.h | 7 | ||||
-rw-r--r-- | net/http/http_cache_transaction.cc | 29 | ||||
-rw-r--r-- | net/http/http_cache_transaction.h | 4 | ||||
-rw-r--r-- | net/http/infinite_cache.cc | 1189 | ||||
-rw-r--r-- | net/http/infinite_cache.h | 121 | ||||
-rw-r--r-- | net/http/infinite_cache_unittest.cc | 276 | ||||
-rw-r--r-- | net/net.gyp | 3 |
8 files changed, 16 insertions, 1634 deletions
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index ab9a0bb..a2a9dfc 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" +#include "base/file_util.h" #include "base/format_macros.h" #include "base/location.h" #include "base/memory/ref_counted.h" @@ -25,6 +26,7 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/stringprintf.h" +#include "base/threading/worker_pool.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -38,6 +40,15 @@ #include "net/http/http_response_info.h" #include "net/http/http_util.h" +namespace { + +// Adaptor to delete a file on a worker thread. +void DeletePath(base::FilePath path) { + file_util::Delete(path, false); +} + +} // namespace + namespace net { HttpCache::DefaultBackend::DefaultBackend(CacheType type, @@ -356,7 +367,7 @@ void HttpCache::WriteMetadata(const GURL& url, } HttpCache::Transaction* trans = - new HttpCache::Transaction(priority, this, NULL, NULL); + new HttpCache::Transaction(priority, this, NULL); MetadataWriter* writer = new MetadataWriter(trans); // The writer will self destruct when done. @@ -394,8 +405,7 @@ void HttpCache::OnExternalCacheHit(const GURL& url, void HttpCache::InitializeInfiniteCache(const base::FilePath& path) { if (base::FieldTrialList::FindFullName("InfiniteCache") != "Yes") return; - // To be enabled after everything is fully wired. - infinite_cache_.Init(path); + base::WorkerPool::PostTask(FROM_HERE, base::Bind(&DeletePath, path), true); } int HttpCache::CreateTransaction(RequestPriority priority, @@ -407,10 +417,7 @@ int HttpCache::CreateTransaction(RequestPriority priority, CreateBackend(NULL, net::CompletionCallback()); } - InfiniteCacheTransaction* infinite_cache_transaction = - infinite_cache_.CreateInfiniteCacheTransaction(); - trans->reset(new HttpCache::Transaction(priority, this, delegate, - infinite_cache_transaction)); + trans->reset(new HttpCache::Transaction(priority, this, delegate)); return OK; } diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 92dbee1..9e6b73c 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -33,7 +33,6 @@ #include "net/base/request_priority.h" #include "net/http/http_network_session.h" #include "net/http/http_transaction_factory.h" -#include "net/http/infinite_cache.h" class GURL; @@ -188,9 +187,6 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory, // Initializes the Infinite Cache, if selected by the field trial. void InitializeInfiniteCache(const base::FilePath& path); - // Returns a pointer to the Infinite Cache. - InfiniteCache* infinite_cache() { return &infinite_cache_; } - // HttpTransactionFactory implementation: virtual int CreateTransaction(RequestPriority priority, scoped_ptr<HttpTransaction>* trans, @@ -217,7 +213,6 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory, class Transaction; class WorkItem; friend class Transaction; - friend class InfiniteCache; struct PendingOp; // Info for an entry under construction. typedef std::list<Transaction*> TransactionList; @@ -399,8 +394,6 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory, scoped_ptr<PlaybackCacheMap> playback_cache_map_; - InfiniteCache infinite_cache_; - DISALLOW_COPY_AND_ASSIGN(HttpCache); }; diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 5ecdb47..fce6bac 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -129,8 +129,7 @@ static bool HeaderMatches(const HttpRequestHeaders& headers, HttpCache::Transaction::Transaction( RequestPriority priority, HttpCache* cache, - HttpTransactionDelegate* transaction_delegate, - InfiniteCacheTransaction* infinite_cache_transaction) + HttpTransactionDelegate* transaction_delegate) : next_state_(STATE_NONE), request_(NULL), priority_(priority), @@ -138,7 +137,6 @@ HttpCache::Transaction::Transaction( entry_(NULL), new_entry_(NULL), network_trans_(NULL), - infinite_cache_transaction_(infinite_cache_transaction), new_response_(NULL), mode_(NONE), target_state_(STATE_NONE), @@ -236,9 +234,6 @@ bool HttpCache::Transaction::AddTruncatedFlag() { if (done_reading_) return true; - if (infinite_cache_transaction_.get()) - infinite_cache_transaction_->OnTruncatedResponse(); - truncated_ = true; target_state_ = STATE_NONE; next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE; @@ -274,20 +269,6 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request, return ERR_UNEXPECTED; SetRequest(net_log, request); - if (infinite_cache_transaction_.get()) { - if ((effective_load_flags_ & LOAD_BYPASS_CACHE) || - (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) || - (effective_load_flags_ & LOAD_DISABLE_CACHE) || - (effective_load_flags_ & LOAD_VALIDATE_CACHE) || - (effective_load_flags_ & LOAD_PREFERRING_CACHE) || - partial_.get()) { - if (effective_load_flags_ & LOAD_PREFERRING_CACHE) - infinite_cache_transaction_->OnBackForwardNavigation(); - infinite_cache_transaction_.reset(); - } else { - infinite_cache_transaction_->OnRequestStart(request); - } - } // We have to wait until the backend is initialized so we start the SM. next_state_ = STATE_GET_BACKEND; @@ -862,8 +843,6 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) { int HttpCache::Transaction::DoSuccessfulSendRequest() { DCHECK(!new_response_); const HttpResponseInfo* new_response = network_trans_->GetResponseInfo(); - if (infinite_cache_transaction_.get()) - infinite_cache_transaction_->OnResponseReceived(new_response); if (new_response->headers->response_code() == 401 || new_response->headers->response_code() == 407) { @@ -947,9 +926,6 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) { if (!cache_) return ERR_UNEXPECTED; - if (infinite_cache_transaction_.get()) - infinite_cache_transaction_->OnDataRead(read_buf_->data(), result); - // If there is an error or we aren't saving the data, we are done; just wait // until the destructor runs to see if we can keep the data. if (mode_ == NONE || result < 0) @@ -1508,9 +1484,6 @@ int HttpCache::Transaction::DoCacheReadData() { DCHECK(entry_); next_state_ = STATE_CACHE_READ_DATA_COMPLETE; - if (infinite_cache_transaction_.get()) - infinite_cache_transaction_->OnServedFromCache(&response_); - if (net_log_.IsLoggingAllEvents()) net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA); ReportCacheActionStart(); diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index e5365c4..a5ddfcd 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h @@ -60,8 +60,7 @@ class HttpCache::Transaction : public HttpTransaction { Transaction(RequestPriority priority, HttpCache* cache, - HttpTransactionDelegate* transaction_delegate, - InfiniteCacheTransaction* infinite_cache_transaction); + HttpTransactionDelegate* transaction_delegate); virtual ~Transaction(); Mode mode() const { return mode_; } @@ -399,7 +398,6 @@ class HttpCache::Transaction : public HttpTransaction { HttpCache::ActiveEntry* entry_; HttpCache::ActiveEntry* new_entry_; scoped_ptr<HttpTransaction> network_trans_; - scoped_ptr<InfiniteCacheTransaction> infinite_cache_transaction_; CompletionCallback callback_; // Consumer's callback. HttpResponseInfo response_; HttpResponseInfo auth_response_; diff --git a/net/http/infinite_cache.cc b/net/http/infinite_cache.cc deleted file mode 100644 index f8a710b..0000000 --- a/net/http/infinite_cache.cc +++ /dev/null @@ -1,1189 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/infinite_cache.h" - -#include <algorithm> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/hash.h" -#include "base/hash_tables.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/metrics/histogram.h" -#include "base/pickle.h" -#include "base/platform_file.h" -#include "base/rand_util.h" -#include "base/sha1.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/time.h" -#include "net/base/net_errors.h" -#include "net/http/http_cache_transaction.h" -#include "net/http/http_request_info.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_response_info.h" -#include "net/http/http_util.h" -#include "third_party/zlib/zlib.h" - -using base::PlatformFile; -using base::Time; -using base::TimeDelta; - -namespace { - -// Flags to use with a particular resource. -enum Flags { - NO_CACHE = 1 << 0, - NO_STORE = 1 << 1, - EXPIRED = 1 << 2, - TRUNCATED = 1 << 3, - RESUMABLE = 1 << 4, - REVALIDATEABLE = 1 << 5, - DOOM_METHOD = 1 << 6, - CACHED = 1 << 7, - GA_JS_HTTP = 1 << 8, - GA_JS_HTTPS = 1 << 9, -}; - -const char kGaJsHttpUrl[] = "http://www.google-analytics.com/ga.js"; -const char kGaJsHttpsUrl[] = "https://ssl.google-analytics.com/ga.js"; - -const int kKeySizeBytes = 20; -COMPILE_ASSERT(base::kSHA1Length == static_cast<unsigned>(kKeySizeBytes), - invalid_key_length); -struct Key { - char value[kKeySizeBytes]; -}; - -// The actual data that we store for every resource. -struct Details { - int32 expiration; - int32 last_access; - uint16 flags; - uint8 use_count; - uint8 update_count; - uint32 vary_hash; - int32 headers_size; - int32 response_size; - uint32 headers_hash; - uint32 response_hash; -}; -const size_t kRecordSize = sizeof(Key) + sizeof(Details); - -// Some constants related to the database file. -uint32 kMagicSignature = 0x1f00cace; -uint32 kCurrentVersion = 0x10002; - -// Basic limits for the experiment. -int kMaxNumEntries = 500 * 1000; -int kMaxTrackingSize = 40 * 1024 * 1024; - -// Settings that control how we generate histograms. -int kTimerMinutes = 5; -int kReportSizeStep = 100 * 1024 * 1024; - -// Buffer to read and write the file. -const size_t kBufferSize = 1024 * 1024; -const size_t kMaxRecordsToRead = kBufferSize / kRecordSize; -COMPILE_ASSERT(kRecordSize * kMaxRecordsToRead < kBufferSize, wrong_buffer); - -// Functor for operator <. -struct Key_less { - bool operator()(const Key& left, const Key& right) const { - // left < right. - return (memcmp(left.value, right.value, kKeySizeBytes) < 0); - } -}; - -// Functor for operator ==. -struct Key_eq { - bool operator()(const Key& left, const Key& right) const { - return (memcmp(left.value, right.value, kKeySizeBytes) == 0); - } -}; - -// Simple adaptor for the sha1 interface. -void CryptoHash(std::string source, Key* destination) { - base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(source.data()), - source.size(), - reinterpret_cast<unsigned char*>(destination->value)); -} - -// Simple adaptor for base::ReadPlatformFile. -bool ReadPlatformFile(PlatformFile file, size_t offset, - void* buffer, size_t buffer_len) { - DCHECK_LE(offset, static_cast<size_t>(kuint32max)); - int bytes = base::ReadPlatformFile(file, static_cast<int64>(offset), - reinterpret_cast<char*>(buffer), - static_cast<int>(buffer_len)); - return (bytes == static_cast<int>(buffer_len)); -} - -// Simple adaptor for base::WritePlatformFile. -bool WritePlatformFile(PlatformFile file, size_t offset, - const void* buffer, size_t buffer_len) { - DCHECK_LE(offset, static_cast<size_t>(kuint32max)); - int bytes = base::WritePlatformFile(file, static_cast<int64>(offset), - reinterpret_cast<const char*>(buffer), - static_cast<int>(buffer_len)); - return (bytes == static_cast<int>(buffer_len)); -} - -// 1 second resolution, +- 68 years from the baseline. -int32 TimeToInt(Time time) { - int64 seconds = (time - Time::UnixEpoch()).InSeconds(); - if (seconds > kint32max) - seconds = kint32max; - if (seconds < kint32min) - seconds = kint32min; - return static_cast<int32>(seconds); -} - -Time IntToTime(int32 time) { - return Time::UnixEpoch() + TimeDelta::FromSeconds(time); -} - -int32 GetExpiration(const net::HttpResponseInfo* response) { - TimeDelta freshness = - response->headers->GetFreshnessLifetime(response->response_time); - - // Avoid overflow when adding to current time. - if (freshness.InDays() > 365 * 10) - freshness = TimeDelta::FromDays(365 * 10); - return TimeToInt(response->response_time + freshness); -} - -uint32 GetCacheability(const net::HttpResponseInfo* response) { - uint32 cacheability = 0; - const net::HttpResponseHeaders* headers = response->headers; - if (headers->HasHeaderValue("cache-control", "no-cache") || - headers->HasHeaderValue("pragma", "no-cache") || - headers->HasHeaderValue("vary", "*")) { - cacheability |= NO_CACHE; - } - - if (headers->HasHeaderValue("cache-control", "no-store")) - cacheability |= NO_STORE; - - TimeDelta max_age; - if (headers->GetMaxAgeValue(&max_age) && max_age.InSeconds() <= 0) - cacheability |= NO_CACHE; - - return cacheability; -} - -uint32 GetRevalidationFlags(const net::HttpResponseInfo* response) { - uint32 revalidation = 0; - std::string etag; - response->headers->EnumerateHeader(NULL, "etag", &etag); - - std::string last_modified; - response->headers->EnumerateHeader(NULL, "last-modified", &last_modified); - - if (!etag.empty() || !last_modified.empty()) - revalidation = REVALIDATEABLE; - - if (response->headers->HasStrongValidators()) - revalidation = RESUMABLE; - - return revalidation; -} - - -uint32 GetVaryHash(const net::HttpResponseInfo* response) { - if (!response->vary_data.is_valid()) - return 0; - - uint32 hash = adler32(0, Z_NULL, 0); - Pickle pickle; - response->vary_data.Persist(&pickle); - return adler32(hash, reinterpret_cast<const Bytef*>(pickle.data()), - pickle.size()); -} - -// Adaptor for PostTaskAndReply. -void OnComplete(const net::CompletionCallback& callback, int* result) { - callback.Run(*result); -} - -#define CACHE_COUNT_HISTOGRAM(name, count) \ - UMA_HISTOGRAM_CUSTOM_COUNTS(name, count, 0, kuint8max, 25) - -} // namespace - -namespace BASE_HASH_NAMESPACE { -#if defined(COMPILER_MSVC) -inline size_t hash_value(const Key& key) { - return base::Hash(key.value, kKeySizeBytes); -} -#elif defined(COMPILER_GCC) -template <> -struct hash<Key> { - size_t operator()(const Key& key) const { - return base::Hash(key.value, kKeySizeBytes); - } -}; -#endif - -} // BASE_HASH_NAMESPACE - -namespace net { - -struct InfiniteCacheTransaction::ResourceData { - ResourceData() { - memset(this, 0, sizeof(*this)); - } - - Key key; - Details details; -}; - -InfiniteCacheTransaction::InfiniteCacheTransaction(InfiniteCache* cache) - : cache_(cache->AsWeakPtr()) { -} - -InfiniteCacheTransaction::~InfiniteCacheTransaction() { - Finish(); -} - -void InfiniteCacheTransaction::OnRequestStart(const HttpRequestInfo* request) { - if (!cache_) - return; - - std::string method = request->method; - resource_data_.reset(new ResourceData); - if (method == "POST" || method == "DELETE" || method == "PUT") { - resource_data_->details.flags |= DOOM_METHOD; - } else if (method != "GET") { - cache_.reset(); - return; - } - const std::string cache_key = cache_->GenerateKey(request); - if (cache_key == kGaJsHttpUrl) { - resource_data_->details.flags |= GA_JS_HTTP; - } else if (cache_key == kGaJsHttpsUrl) { - resource_data_->details.flags |= GA_JS_HTTPS; - } - - CryptoHash(cache_key, &resource_data_->key); -} - -void InfiniteCacheTransaction::OnBackForwardNavigation() { - if (!cache_) - return; - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.BackForwardNavigation", true); -} - -void InfiniteCacheTransaction::OnResponseReceived( - const HttpResponseInfo* response) { - if (!cache_) - return; - - Details& details = resource_data_->details; - - // Store the old flag values that we want to preserve. - const uint32 kPreserveFlagsBitMask = (GA_JS_HTTP | GA_JS_HTTPS | DOOM_METHOD); - uint32 old_flag_values = details.flags & kPreserveFlagsBitMask; - - details.expiration = GetExpiration(response); - details.last_access = TimeToInt(response->request_time); - details.flags = GetCacheability(response); - details.vary_hash = GetVaryHash(response); - details.response_hash = adler32(0, Z_NULL, 0); // Init the hash. - - if (!details.flags && - TimeToInt(response->response_time) == details.expiration) { - details.flags = EXPIRED; - } - - // Restore the old flag values we wanted to preserve. - details.flags |= old_flag_values; - - details.flags |= GetRevalidationFlags(response); - - Pickle pickle; - response->Persist(&pickle, true, false); // Skip transient headers. - details.headers_size = pickle.size(); - details.headers_hash = adler32(0, Z_NULL, 0); - details.headers_hash = adler32(details.headers_hash, - reinterpret_cast<const Bytef*>(pickle.data()), - pickle.size()); -} - -void InfiniteCacheTransaction::OnDataRead(const char* data, int data_len) { - if (!cache_) - return; - - if (!data_len) - return Finish(); - - if (data_len < 0) - return OnTruncatedResponse(); - - resource_data_->details.response_size += data_len; - - resource_data_->details.response_hash = - adler32(resource_data_->details.response_hash, - reinterpret_cast<const Bytef*>(data), data_len); -} - -void InfiniteCacheTransaction::OnTruncatedResponse() { - if (!cache_) - return; - - resource_data_->details.flags |= TRUNCATED; -} - -void InfiniteCacheTransaction::OnServedFromCache( - const HttpResponseInfo* response) { - if (!cache_) - return; - - resource_data_->details.flags |= CACHED; - if (!resource_data_->details.last_access) { - OnResponseReceived(response); - // For cached responses, the request time is the last revalidation time. - resource_data_->details.last_access = TimeToInt(Time::Now()); - } -} - -void InfiniteCacheTransaction::Finish() { - if (!cache_ || !resource_data_.get()) - return; - - if (!resource_data_->details.headers_size) - return; - - cache_->ProcessResource(resource_data_.Pass()); - cache_.reset(); -} - -// ---------------------------------------------------------------------------- - -// This is the object that performs the bulk of the work. -// InfiniteCacheTransaction posts the transaction data to the InfiniteCache, and -// the InfiniteCache basically just forward requests to the Worker for actual -// processing. -// The Worker lives on a worker thread (basically a dedicated worker pool with -// only one thread), and flushes data to disk once every five minutes, when it -// is notified by the InfiniteCache. -// In general, there are no callbacks on completion of tasks, and the Worker can -// be as behind as it has to when processing requests. -class InfiniteCache::Worker : public base::RefCountedThreadSafe<Worker> { - public: - Worker() : init_(false), flushed_(false) {} - - // Construction and destruction helpers. - void Init(const base::FilePath& path); - void Cleanup(); - - // Deletes all tracked data. - void DeleteData(int* result); - - // Deletes requests between |initial_time| and |end_time|. - void DeleteDataBetween(base::Time initial_time, - base::Time end_time, - int* result); - - // Performs the actual processing of a new transaction. Takes ownership of - // the transaction |data|. - void Process(scoped_ptr<InfiniteCacheTransaction::ResourceData> data); - - // Test helpers. - void Query(int* result); - void Flush(int* result); - - // Timer notification. - void OnTimer(); - - private: - friend class base::RefCountedThreadSafe<Worker>; -#if defined(COMPILER_MSVC) - typedef BASE_HASH_NAMESPACE::hash_map< - Key, Details, BASE_HASH_NAMESPACE::hash_compare<Key, Key_less> > KeyMap; -#elif defined(COMPILER_GCC) - typedef BASE_HASH_NAMESPACE::hash_map< - Key, Details, BASE_HASH_NAMESPACE::hash<Key>, Key_eq> KeyMap; -#endif - - // Header for the data file. The file starts with the header, followed by - // all the records, and a data hash at the end (just of the records, not the - // header). Note that the header has a dedicated hash. - struct Header { - uint32 magic; - uint32 version; - int32 num_entries; - int32 generation; - uint64 creation_time; - uint64 update_time; - int64 total_size; - int64 size_last_report; - int32 use_minutes; - int32 num_hits; - int32 num_bad_hits; - int32 num_requests; - int32 disabled; - uint32 header_hash; - }; - - ~Worker() {} - - // Methods to load and store data on disk. - void LoadData(); - void StoreData(); - void InitializeData(); - bool ReadData(PlatformFile file); - bool WriteData(PlatformFile file); - bool ReadAndVerifyHeader(PlatformFile file); - - // Book-keeping methods. - void Add(const Details& details); - void Remove(const Details& details); - void UpdateSize(int old_size, int new_size); - - // Bulk of report generation methods. - void RecordHit(const Details& old, Details* details); - void RecordUpdate(const Details& old, Details* details); - void RecordComparison(bool infinite_used_or_validated, - bool http_used_or_validated) const; - void GenerateHistograms(); - - // Cache logic methods. - bool CanReuse(const Details& old, const Details& current); - bool DataChanged(const Details& old, const Details& current); - bool HeadersChanged(const Details& old, const Details& current); - - KeyMap map_; - bool init_; - bool flushed_; - scoped_ptr<Header> header_; - base::FilePath path_; - - DISALLOW_COPY_AND_ASSIGN(Worker); -}; - -void InfiniteCache::Worker::Init(const base::FilePath& path) { - path_ = path; - LoadData(); - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.NewSession", true); -} - -void InfiniteCache::Worker::Cleanup() { - if (init_) - StoreData(); - - map_.clear(); -} - -void InfiniteCache::Worker::DeleteData(int* result) { - if (!init_) - return; - - map_.clear(); - InitializeData(); - file_util::Delete(path_, false); - *result = OK; - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.DeleteAll", true); -} - -void InfiniteCache::Worker::DeleteDataBetween(base::Time initial_time, - base::Time end_time, - int* result) { - if (!init_) - return; - - for (KeyMap::iterator i = map_.begin(); i != map_.end();) { - Time last_access = IntToTime(i->second.last_access); - if (last_access >= initial_time && last_access <= end_time) { - KeyMap::iterator next = i; - ++next; - Remove(i->second); - map_.erase(i); - i = next; - continue; - } - ++i; - } - - file_util::Delete(path_, false); - StoreData(); - *result = OK; - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.DeleteRange", true); -} - -void InfiniteCache::Worker::Process( - scoped_ptr<InfiniteCacheTransaction::ResourceData> data) { - if (!init_) - return; - - if (data->details.response_size > kMaxTrackingSize) - return; - - if (header_->num_entries == kMaxNumEntries || header_->disabled) - return; - - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.TotalRequests", true); - if (data->details.flags & NO_STORE) - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.NoStore", true); - - if (data->details.flags & (GA_JS_HTTP | GA_JS_HTTPS)) { - bool https = data->details.flags & GA_JS_HTTPS ? true : false; - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.GaJs_Https", https); - } - - // True if the first range of the http request was validated or used - // unconditionally, false if it was not found in the cache, was updated, - // or was found but was unconditionalizable. - bool http_used_or_validated = (data->details.flags & CACHED) == CACHED; - - header_->num_requests++; - KeyMap::iterator i = map_.find(data->key); - if (i != map_.end()) { - if (data->details.flags & DOOM_METHOD) { - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.DoomMethodHit", true); - Remove(i->second); - map_.erase(i); - return; - } - data->details.use_count = i->second.use_count; - data->details.update_count = i->second.update_count; - bool reused = CanReuse(i->second, data->details); - bool data_changed = DataChanged(i->second, data->details); - bool headers_changed = HeadersChanged(i->second, data->details); - - RecordComparison(reused, http_used_or_validated); - - if (reused && data_changed) - header_->num_bad_hits++; - - if (reused) - RecordHit(i->second, &data->details); - - if (headers_changed) - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.HeadersChange", true); - - if (data_changed) - RecordUpdate(i->second, &data->details); - - if (data->details.flags & NO_STORE) { - Remove(i->second); - map_.erase(i); - return; - } - - map_[data->key] = data->details; - return; - } else { - RecordComparison(false, http_used_or_validated); - } - - if (data->details.flags & NO_STORE) - return; - - if (data->details.flags & DOOM_METHOD) { - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.DoomMethodHit", false); - return; - } - - map_[data->key] = data->details; - Add(data->details); -} - -void InfiniteCache::Worker::LoadData() { - if (path_.empty()) - return InitializeData(); - - PlatformFile file = base::CreatePlatformFile( - path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL, NULL); - if (file == base::kInvalidPlatformFileValue) - return InitializeData(); - if (!ReadData(file)) - InitializeData(); - base::ClosePlatformFile(file); - if (header_->disabled) { - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.Full", true); - InitializeData(); - } -} - -void InfiniteCache::Worker::StoreData() { - if (!init_ || flushed_ || path_.empty()) - return; - - header_->update_time = Time::Now().ToInternalValue(); - header_->generation++; - header_->header_hash = base::Hash( - reinterpret_cast<char*>(header_.get()), offsetof(Header, header_hash)); - - base::FilePath temp_file = path_.ReplaceExtension(FILE_PATH_LITERAL("tmp")); - PlatformFile file = base::CreatePlatformFile( - temp_file, base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE, - NULL, NULL); - if (file == base::kInvalidPlatformFileValue) - return; - bool success = WriteData(file); - base::ClosePlatformFile(file); - if (success) { - if (!file_util::ReplaceFile(temp_file, path_)) - file_util::Delete(temp_file, false); - } else { - LOG(ERROR) << "Failed to write experiment data"; - } -} - -void InfiniteCache::Worker::InitializeData() { - header_.reset(new Header); - memset(header_.get(), 0, sizeof(Header)); - header_->magic = kMagicSignature; - header_->version = kCurrentVersion; - header_->creation_time = Time::Now().ToInternalValue(); - map_.clear(); - - UMA_HISTOGRAM_BOOLEAN("InfiniteCache.Initialize", true); - init_ = true; -} - -bool InfiniteCache::Worker::ReadData(PlatformFile file) { - if (!ReadAndVerifyHeader(file)) - return false; - - scoped_array<char> buffer(new char[kBufferSize]); - size_t offset = sizeof(Header); - uint32 hash = adler32(0, Z_NULL, 0); - - for (int remaining_records = header_->num_entries; remaining_records;) { - int num_records = std::min(remaining_records, - static_cast<int>(kMaxRecordsToRead)); - size_t num_bytes = num_records * kRecordSize; - remaining_records -= num_records; - if (!remaining_records) - num_bytes += sizeof(uint32); // Trailing hash. - DCHECK_LE(num_bytes, kBufferSize); - - if (!ReadPlatformFile(file, offset, buffer.get(), num_bytes)) - return false; - - hash = adler32(hash, reinterpret_cast<const Bytef*>(buffer.get()), - num_records * kRecordSize); - if (!remaining_records && - hash != *reinterpret_cast<uint32*>(buffer.get() + - num_records * kRecordSize)) { - return false; - } - - for (int i = 0; i < num_records; i++) { - char* record = buffer.get() + i * kRecordSize; - Key key = *reinterpret_cast<Key*>(record); - Details details = *reinterpret_cast<Details*>(record + sizeof(key)); - map_[key] = details; - } - offset += num_bytes; - } - if (header_->num_entries != static_cast<int>(map_.size())) { - NOTREACHED(); - return false; - } - - init_ = true; - return true; -} - -bool InfiniteCache::Worker::WriteData(PlatformFile file) { - if (!base::TruncatePlatformFile(file, 0)) - return false; - - if (!WritePlatformFile(file, 0, header_.get(), sizeof(Header))) - return false; - - scoped_array<char> buffer(new char[kBufferSize]); - size_t offset = sizeof(Header); - uint32 hash = adler32(0, Z_NULL, 0); - int unused_entries = 0; - static bool first_time = true; - - DCHECK_EQ(header_->num_entries, static_cast<int32>(map_.size())); - KeyMap::iterator iterator = map_.begin(); - for (int remaining_records = header_->num_entries; remaining_records;) { - int num_records = std::min(remaining_records, - static_cast<int>(kMaxRecordsToRead)); - size_t num_bytes = num_records * kRecordSize; - remaining_records -= num_records; - - for (int i = 0; i < num_records; i++) { - if (iterator == map_.end()) { - NOTREACHED(); - return false; - } - int use_count = iterator->second.use_count; - if (!use_count) - unused_entries++; - - if (first_time) { - int response_size = iterator->second.response_size; - if (response_size < 16 * 1024) - CACHE_COUNT_HISTOGRAM("InfiniteCache.Reuse-16k", use_count); - else if (response_size < 128 * 1024) - CACHE_COUNT_HISTOGRAM("InfiniteCache.Reuse-128k", use_count); - else if (response_size < 2048 * 1024) - CACHE_COUNT_HISTOGRAM("InfiniteCache.Reuse-2M", use_count); - else - CACHE_COUNT_HISTOGRAM("InfiniteCache.Reuse-40M", use_count); - } - - char* record = buffer.get() + i * kRecordSize; - *reinterpret_cast<Key*>(record) = iterator->first; - *reinterpret_cast<Details*>(record + sizeof(Key)) = iterator->second; - ++iterator; - } - - hash = adler32(hash, reinterpret_cast<const Bytef*>(buffer.get()), - num_bytes); - - if (!remaining_records) { - num_bytes += sizeof(uint32); // Trailing hash. - *reinterpret_cast<uint32*>(buffer.get() + - num_records * kRecordSize) = hash; - } - - DCHECK_LE(num_bytes, kBufferSize); - if (!WritePlatformFile(file, offset, buffer.get(), num_bytes)) - return false; - - offset += num_bytes; - } - base::FlushPlatformFile(file); // Ignore return value. - first_time = false; - - if (header_->num_entries) - unused_entries = unused_entries * 100 / header_->num_entries; - - UMA_HISTOGRAM_PERCENTAGE("InfiniteCache.UnusedEntries", unused_entries); - UMA_HISTOGRAM_COUNTS("InfiniteCache.StoredEntries", header_->num_entries); - if (base::RandInt(0, 99) < unused_entries) { - UMA_HISTOGRAM_COUNTS("InfiniteCache.UnusedEntriesByStoredEntries", - header_->num_entries); - } - return true; -} - -bool InfiniteCache::Worker::ReadAndVerifyHeader(PlatformFile file) { - base::PlatformFileInfo info; - if (!base::GetPlatformFileInfo(file, &info)) - return false; - - if (info.size < static_cast<int>(sizeof(Header))) - return false; - - header_.reset(new Header); - if (!ReadPlatformFile(file, 0, header_.get(), sizeof(Header))) - return false; - - if (header_->magic != kMagicSignature) - return false; - - if (header_->version != kCurrentVersion) - return false; - - if (header_->num_entries > kMaxNumEntries) - return false; - - size_t expected_size = kRecordSize * header_->num_entries + - sizeof(Header) + sizeof(uint32); // Trailing hash. - - if (info.size < static_cast<int>(expected_size)) - return false; - - uint32 hash = base::Hash(reinterpret_cast<char*>(header_.get()), - offsetof(Header, header_hash)); - if (hash != header_->header_hash) - return false; - - return true; -} - -void InfiniteCache::Worker::Query(int* result) { - *result = static_cast<int>(map_.size()); -} - -void InfiniteCache::Worker::Flush(int* result) { - flushed_ = false; - StoreData(); - flushed_ = true; - *result = OK; -} - -void InfiniteCache::Worker::OnTimer() { - header_->use_minutes += kTimerMinutes; - GenerateHistograms(); - StoreData(); -} - -void InfiniteCache::Worker::Add(const Details& details) { - UpdateSize(0, details.headers_size); - UpdateSize(0, details.response_size); - header_->num_entries = static_cast<int>(map_.size()); - if (header_->num_entries == kMaxNumEntries) { - int use_hours = header_->use_minutes / 60; - int age_hours = (Time::Now() - - Time::FromInternalValue(header_->creation_time)).InHours(); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.MaxUseTime", use_hours); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.MaxAge", age_hours); - - int entry_size = static_cast<int>(header_->total_size / kMaxNumEntries); - UMA_HISTOGRAM_COUNTS("InfiniteCache.FinalAvgEntrySize", entry_size); - header_->disabled = 1; - header_->num_entries = 0; - map_.clear(); - } -} - -void InfiniteCache::Worker::Remove(const Details& details) { - UpdateSize(details.headers_size, 0); - UpdateSize(details.response_size, 0); - header_->num_entries--; -} - -void InfiniteCache::Worker::UpdateSize(int old_size, int new_size) { - header_->total_size += new_size - old_size; - DCHECK_GE(header_->total_size, 0); -} - -void InfiniteCache::Worker::RecordHit(const Details& old, Details* details) { - header_->num_hits++; - int access_delta = (IntToTime(details->last_access) - - IntToTime(old.last_access)).InMinutes(); - if (old.use_count) { - UMA_HISTOGRAM_COUNTS("InfiniteCache.ReuseAge2", access_delta); - if (details->flags & GA_JS_HTTP) { - UMA_HISTOGRAM_COUNTS("InfiniteCache.GaJsHttpReuseAge2", access_delta); - } else if (details->flags & GA_JS_HTTPS) { - UMA_HISTOGRAM_COUNTS("InfiniteCache.GaJsHttpsReuseAge2", access_delta); - } - } else { - UMA_HISTOGRAM_COUNTS("InfiniteCache.FirstReuseAge2", access_delta); - if (details->flags & GA_JS_HTTP) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpFirstReuseAge2", access_delta); - } else if (details->flags & GA_JS_HTTPS) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpsFirstReuseAge2", access_delta); - } - } - - details->use_count = old.use_count; - if (details->use_count < kuint8max) - details->use_count++; - CACHE_COUNT_HISTOGRAM("InfiniteCache.UseCount", details->use_count); - if (details->flags & GA_JS_HTTP) { - CACHE_COUNT_HISTOGRAM("InfiniteCache.GaJsHttpUseCount", details->use_count); - } else if (details->flags & GA_JS_HTTPS) { - CACHE_COUNT_HISTOGRAM("InfiniteCache.GaJsHttpsUseCount", - details->use_count); - } -} - -void InfiniteCache::Worker::RecordUpdate(const Details& old, Details* details) { - int access_delta = (IntToTime(details->last_access) - - IntToTime(old.last_access)).InMinutes(); - if (old.update_count) { - UMA_HISTOGRAM_COUNTS("InfiniteCache.UpdateAge2", access_delta); - if (details->flags & GA_JS_HTTP) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpUpdateAge2", access_delta); - } else if (details->flags & GA_JS_HTTPS) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpsUpdateAge2", access_delta); - } - } else { - UMA_HISTOGRAM_COUNTS("InfiniteCache.FirstUpdateAge2", access_delta); - if (details->flags & GA_JS_HTTP) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpFirstUpdateAge2", access_delta); - } else if (details->flags & GA_JS_HTTPS) { - UMA_HISTOGRAM_COUNTS( - "InfiniteCache.GaJsHttpsFirstUpdateAge2", access_delta); - } - } - - details->update_count = old.update_count; - if (details->update_count < kuint8max) - details->update_count++; - - CACHE_COUNT_HISTOGRAM("InfiniteCache.UpdateCount", details->update_count); - if (details->flags & GA_JS_HTTP) { - CACHE_COUNT_HISTOGRAM("InfiniteCache.GaJsHttpUpdateCount", - details->update_count); - } else if (details->flags & GA_JS_HTTPS) { - CACHE_COUNT_HISTOGRAM("InfiniteCache.GaJsHttpsUpdateCount", - details->update_count); - } - details->use_count = 0; -} - -void InfiniteCache::Worker::RecordComparison( - bool infinite_used_or_validated, - bool http_used_or_validated) const { - enum Comparison { - INFINITE_NOT_STRONG_HIT_HTTP_NOT_STRONG_HIT, - INFINITE_NOT_STRONG_HIT_HTTP_STRONG_HIT, - INFINITE_STRONG_HIT_HTTP_NOT_STRONG_HIT, - INFINITE_STRONG_HIT_HTTP_STRONG_HIT, - COMPARISON_ENUM_MAX, - }; - - Comparison comparison; - if (infinite_used_or_validated) { - if (http_used_or_validated) - comparison = INFINITE_STRONG_HIT_HTTP_STRONG_HIT; - else - comparison = INFINITE_STRONG_HIT_HTTP_NOT_STRONG_HIT; - } else { - if (http_used_or_validated) - comparison = INFINITE_NOT_STRONG_HIT_HTTP_STRONG_HIT; - else - comparison = INFINITE_NOT_STRONG_HIT_HTTP_NOT_STRONG_HIT; - } - - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.Comparison", - comparison, COMPARISON_ENUM_MAX); - const int size_bucket = - static_cast<int>(header_->total_size / kReportSizeStep); - const int kComparisonBuckets = 50; - UMA_HISTOGRAM_ENUMERATION( - "InfiniteCache.ComparisonBySize", - comparison * kComparisonBuckets + std::min(size_bucket, - kComparisonBuckets-1), - kComparisonBuckets * COMPARISON_ENUM_MAX); -} - -void InfiniteCache::Worker::GenerateHistograms() { - bool new_size_step = (header_->total_size / kReportSizeStep != - header_->size_last_report / kReportSizeStep); - header_->size_last_report = header_->total_size; - if (!new_size_step && (header_->use_minutes % 60 != 0)) - return; - - if (header_->disabled) - return; - - int hit_ratio = header_->num_hits * 100; - if (header_->num_requests) - hit_ratio /= header_->num_requests; - else - hit_ratio = 0; - - // We'll be generating pairs of histograms that can be used to get the hit - // ratio for any bucket of the paired histogram. - bool report_second_stat = base::RandInt(0, 99) < hit_ratio; - - if (header_->use_minutes % 60 == 0) { - int use_hours = header_->use_minutes / 60; - int age_hours = (Time::Now() - - Time::FromInternalValue(header_->creation_time)).InHours(); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.UseTime", use_hours); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.Age", age_hours); - if (report_second_stat) { - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.HitRatioByUseTime", use_hours); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.HitRatioByAge", age_hours); - } - } - - if (new_size_step) { - int size_bucket = static_cast<int>(header_->total_size / kReportSizeStep); - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.Size", std::min(size_bucket, 50), - 51); - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.SizeCoarse", size_bucket / 5, 51); - UMA_HISTOGRAM_COUNTS("InfiniteCache.Entries", header_->num_entries); - UMA_HISTOGRAM_COUNTS_10000("InfiniteCache.BadHits", header_->num_bad_hits); - if (report_second_stat) { - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.HitRatioBySize", - std::min(size_bucket, 50), 51); - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.HitRatioBySizeCoarse", - size_bucket / 5, 51); - UMA_HISTOGRAM_COUNTS("InfiniteCache.HitRatioByEntries", - header_->num_entries); - } - header_->num_hits = 0; - header_->num_bad_hits = 0; - header_->num_requests = 0; - } -} - -bool InfiniteCache::Worker::CanReuse(const Details& old, - const Details& current) { - enum ReuseStatus { - REUSE_OK = 0, - REUSE_NO_CACHE, - REUSE_ALWAYS_EXPIRED, - REUSE_EXPIRED, - REUSE_TRUNCATED, - REUSE_VARY, - REUSE_DUMMY_VALUE, - // Not an individual value; it's added to another reason. - REUSE_REVALIDATEABLE = 7 - }; - int reason = REUSE_OK; - - if (old.expiration < current.last_access) - reason = REUSE_EXPIRED; - - if (old.flags & EXPIRED) - reason = REUSE_ALWAYS_EXPIRED; - - if (old.flags & NO_CACHE) - reason = REUSE_NO_CACHE; - - if (old.flags & TRUNCATED) - reason = REUSE_TRUNCATED; - - if (old.vary_hash != current.vary_hash) - reason = REUSE_VARY; - - bool have_to_drop = (old.flags & TRUNCATED) && !(old.flags & RESUMABLE); - if (reason && (old.flags & (REVALIDATEABLE | RESUMABLE)) && !have_to_drop) - reason += REUSE_REVALIDATEABLE; - - UMA_HISTOGRAM_ENUMERATION("InfiniteCache.ReuseFailure2", reason, 15); - if (current.flags & GA_JS_HTTP) { - UMA_HISTOGRAM_ENUMERATION( - "InfiniteCache.GaJsHttpReuseFailure2", reason, 15); - } else if (current.flags & GA_JS_HTTPS) { - UMA_HISTOGRAM_ENUMERATION( - "InfiniteCache.GaJsHttpsReuseFailure2", reason, 15); - } - return !reason; -} - -bool InfiniteCache::Worker::DataChanged(const Details& old, - const Details& current) { - if (current.flags & CACHED) - return false; - - bool changed = false; - if (old.response_size != current.response_size) { - changed = true; - UpdateSize(old.response_size, current.response_size); - } - - if (old.response_hash != current.response_hash) - changed = true; - - return changed; -} - -bool InfiniteCache::Worker::HeadersChanged(const Details& old, - const Details& current) { - bool changed = false; - if (old.headers_size != current.headers_size) { - changed = true; - UpdateSize(old.headers_size, current.headers_size); - } - - if (old.headers_hash != current.headers_hash) - changed = true; - - return changed; -} - -// ---------------------------------------------------------------------------- - -InfiniteCache::InfiniteCache() { -} - -InfiniteCache::~InfiniteCache() { - if (!worker_) - return; - - task_runner_->PostTask(FROM_HERE, - base::Bind(&InfiniteCache::Worker::Cleanup, worker_)); - worker_ = NULL; -} - -void InfiniteCache::Init(const base::FilePath& path) { - worker_pool_ = new base::SequencedWorkerPool(1, "Infinite cache thread"); - task_runner_ = worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool_->GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); - - worker_ = new Worker(); - task_runner_->PostTask(FROM_HERE, - base::Bind(&InfiniteCache::Worker::Init, worker_, - path)); - - timer_.Start(FROM_HERE, TimeDelta::FromMinutes(kTimerMinutes), this, - &InfiniteCache::OnTimer); -} - -InfiniteCacheTransaction* InfiniteCache::CreateInfiniteCacheTransaction() { - if (!worker_) - return NULL; - return new InfiniteCacheTransaction(this); -} - -int InfiniteCache::DeleteData(const CompletionCallback& callback) { - if (!worker_) - return OK; - int* result = new int; - task_runner_->PostTaskAndReply( - FROM_HERE, base::Bind(&InfiniteCache::Worker::DeleteData, worker_, - result), - base::Bind(&OnComplete, callback, base::Owned(result))); - return ERR_IO_PENDING; -} - -int InfiniteCache::DeleteDataBetween(base::Time initial_time, - base::Time end_time, - const CompletionCallback& callback) { - if (!worker_) - return OK; - int* result = new int; - task_runner_->PostTaskAndReply( - FROM_HERE, base::Bind(&InfiniteCache::Worker::DeleteDataBetween, worker_, - initial_time, end_time, result), - base::Bind(&OnComplete, callback, base::Owned(result))); - return ERR_IO_PENDING; -} - -std::string InfiniteCache::GenerateKey(const HttpRequestInfo* request) { - // Don't add any upload data identifier. - return HttpUtil::SpecForRequest(request->url); -} - -void InfiniteCache::ProcessResource( - scoped_ptr<InfiniteCacheTransaction::ResourceData> data) { - if (!worker_) - return; - task_runner_->PostTask(FROM_HERE, - base::Bind(&InfiniteCache::Worker::Process, worker_, - base::Passed(&data))); -} - -void InfiniteCache::OnTimer() { - task_runner_->PostTask(FROM_HERE, - base::Bind(&InfiniteCache::Worker::OnTimer, worker_)); -} - -int InfiniteCache::QueryItemsForTest(const CompletionCallback& callback) { - DCHECK(worker_); - int* result = new int; - task_runner_->PostTaskAndReply( - FROM_HERE, base::Bind(&InfiniteCache::Worker::Query, worker_, result), - base::Bind(&OnComplete, callback, base::Owned(result))); - return net::ERR_IO_PENDING; -} - -int InfiniteCache::FlushDataForTest(const CompletionCallback& callback) { - DCHECK(worker_); - int* result = new int; - task_runner_->PostTaskAndReply( - FROM_HERE, base::Bind(&InfiniteCache::Worker::Flush, worker_, result), - base::Bind(&OnComplete, callback, base::Owned(result))); - return net::ERR_IO_PENDING; -} - -} // namespace net diff --git a/net/http/infinite_cache.h b/net/http/infinite_cache.h deleted file mode 100644 index a93d4c1..0000000 --- a/net/http/infinite_cache.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is the interface of a simulated infinite cache. The purpose of this -// code is to evaluate the performance of an HTTP cache that is not constrained -// to evict resources. - -#ifndef NET_HTTP_INFINITE_CACHE_H_ -#define NET_HTTP_INFINITE_CACHE_H_ - -#include <string> - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/timer.h" -#include "net/base/completion_callback.h" -#include "net/base/net_export.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -class SequencedWorkerPool; -} - -namespace net { - -class HttpCache; -class HttpResponseInfo; -class InfiniteCache; -struct HttpRequestInfo; - -// An InfiniteCacheTransaction is paired with an HttpCache::Transaction to track -// every request that goes through the HttpCache. This object is notified when -// relevant steps are reached while processing the request. -class NET_EXPORT_PRIVATE InfiniteCacheTransaction { - public: - explicit InfiniteCacheTransaction(InfiniteCache* cache); - ~InfiniteCacheTransaction(); - - // Called when a new HttpTransaction is started. - void OnRequestStart(const HttpRequestInfo* request); - - // Called when the transaction corresponds to a back navigation. - void OnBackForwardNavigation(); - - // Called when the response headers are available. - void OnResponseReceived(const HttpResponseInfo* response); - - // Called when the response data is received from the network. - void OnDataRead(const char* data, int data_len); - - // Called when the resource is marked as truncated by the HttpCache. - void OnTruncatedResponse(); - - // Called when the resource is served from the cache, so OnDataRead will not - // be called for this request. - void OnServedFromCache(const HttpResponseInfo* response); - - private: - friend class InfiniteCache; - struct ResourceData; - void Finish(); - - base::WeakPtr<InfiniteCache> cache_; - scoped_ptr<ResourceData> resource_data_; - DISALLOW_COPY_AND_ASSIGN(InfiniteCacheTransaction); -}; - -// An InfiniteCache is paired with an HttpCache instance to simulate an infinite -// backend storage. -class NET_EXPORT_PRIVATE InfiniteCache - : public base::SupportsWeakPtr<InfiniteCache> { - public: - InfiniteCache(); - ~InfiniteCache(); - - // Initializes this object to start tracking requests. |path| is the location - // of the file to use to store data; it can be empty, in which case the data - // will not be persisted to disk. - void Init(const base::FilePath& path); - - InfiniteCacheTransaction* CreateInfiniteCacheTransaction(); - - // Removes all data for this experiment. Returns a net error code. - int DeleteData(const CompletionCallback& callback); - - // Removes requests between |initial_time| and |end_time|. - int DeleteDataBetween(base::Time initial_time, - base::Time end_time, - const CompletionCallback& callback); - - // Returns the number of elements currently tracked. - int QueryItemsForTest(const CompletionCallback& callback); - - // Flush the data to disk, preventing flushing when the destructor runs. Any - // data added to the cache after calling this method will not be written to - // disk, unless this method is called again to do so. - int FlushDataForTest(const CompletionCallback& callback); - - private: - class Worker; - friend class base::RepeatingTimer<InfiniteCache>; - friend class InfiniteCacheTransaction; - - std::string GenerateKey(const HttpRequestInfo* request); - void ProcessResource(scoped_ptr<InfiniteCacheTransaction::ResourceData> data); - void OnTimer(); - - scoped_refptr<Worker> worker_; - scoped_refptr<base::SequencedWorkerPool> worker_pool_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; - base::RepeatingTimer<InfiniteCache> timer_; - - DISALLOW_COPY_AND_ASSIGN(InfiniteCache); -}; - -} // namespace net - -#endif // NET_HTTP_INFINITE_CACHE_H_ diff --git a/net/http/infinite_cache_unittest.cc b/net/http/infinite_cache_unittest.cc deleted file mode 100644 index 24d2ccc..0000000 --- a/net/http/infinite_cache_unittest.cc +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/infinite_cache.h" - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/stringprintf.h" -#include "base/threading/platform_thread.h" -#include "base/time.h" -#include "net/base/net_errors.h" -#include "net/base/test_completion_callback.h" -#include "net/http/http_transaction_unittest.h" -#include "net/http/http_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::Time; -using base::TimeDelta; -using net::InfiniteCache; -using net::InfiniteCacheTransaction; - -namespace { - -void StartRequest(const MockTransaction& http_transaction, - InfiniteCacheTransaction* transaction) { - std::string standard_headers(http_transaction.status); - standard_headers.push_back('\n'); - standard_headers.append(http_transaction.response_headers); - std::string raw_headers = - net::HttpUtil::AssembleRawHeaders(standard_headers.c_str(), - standard_headers.size()); - - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(raw_headers)); - net::HttpResponseInfo response; - response.headers = headers; - response.request_time = http_transaction.request_time.is_null() ? - Time::Now() : http_transaction.request_time; - response.response_time = http_transaction.response_time.is_null() ? - Time::Now() : http_transaction.response_time; - - MockHttpRequest request(http_transaction); - transaction->OnRequestStart(&request); - transaction->OnResponseReceived(&response); -} - -void ProcessRequest(const MockTransaction& http_transaction, - InfiniteCache* cache) { - scoped_ptr<InfiniteCacheTransaction> transaction - (cache->CreateInfiniteCacheTransaction()); - - StartRequest(http_transaction, transaction.get()); - transaction->OnDataRead(http_transaction.data, strlen(http_transaction.data)); -} - -void ProcessRequestWithTime(const MockTransaction& http_transaction, - InfiniteCache* cache, - Time time) { - scoped_ptr<InfiniteCacheTransaction> transaction - (cache->CreateInfiniteCacheTransaction()); - - MockTransaction timed_transaction = http_transaction; - timed_transaction.request_time = time; - timed_transaction.response_time = time; - StartRequest(timed_transaction, transaction.get()); - transaction->OnDataRead(http_transaction.data, strlen(http_transaction.data)); -} - -} // namespace - -TEST(InfiniteCache, Basics) { - InfiniteCache cache; - cache.Init(base::FilePath()); - - scoped_ptr<InfiniteCacheTransaction> transaction - (cache.CreateInfiniteCacheTransaction()); - - // Don't even Start() this transaction. - transaction.reset(cache.CreateInfiniteCacheTransaction()); - - net::TestCompletionCallback cb; - EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - MockHttpRequest request(kTypicalGET_Transaction); - transaction->OnRequestStart(&request); - - // Don't have a response yet. - transaction.reset(cache.CreateInfiniteCacheTransaction()); - EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - net::HttpResponseInfo response; - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(kTypicalGET_Transaction.response_headers)); - response.headers = headers; - - transaction->OnRequestStart(&request); - transaction->OnResponseReceived(&response); - transaction.reset(cache.CreateInfiniteCacheTransaction()); - EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - // Hit the same URL again. - transaction->OnRequestStart(&request); - transaction->OnResponseReceived(&response); - transaction.reset(cache.CreateInfiniteCacheTransaction()); - EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - // Now a different URL. - MockHttpRequest request2(kSimpleGET_Transaction); - transaction->OnRequestStart(&request2); - transaction->OnResponseReceived(&response); - transaction.reset(); - EXPECT_EQ(2, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); -} - -TEST(InfiniteCache, Save_Restore) { - base::ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - base::FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); - - scoped_ptr<InfiniteCache> cache(new InfiniteCache); - cache->Init(path); - net::TestCompletionCallback cb; - - ProcessRequest(kTypicalGET_Transaction, cache.get()); - ProcessRequest(kSimpleGET_Transaction, cache.get()); - ProcessRequest(kETagGET_Transaction, cache.get()); - ProcessRequest(kSimplePOST_Transaction, cache.get()); - - EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); - - cache.reset(new InfiniteCache); - cache->Init(path); - EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - - ProcessRequest(kTypicalGET_Transaction, cache.get()); - EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); -} - -TEST(InfiniteCache, DoomMethod) { - InfiniteCache cache; - cache.Init(base::FilePath()); - - ProcessRequest(kTypicalGET_Transaction, &cache); - ProcessRequest(kSimpleGET_Transaction, &cache); - ProcessRequest(kETagGET_Transaction, &cache); - net::TestCompletionCallback cb; - EXPECT_EQ(3, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - MockTransaction request(kTypicalGET_Transaction); - request.method = "PUT"; - ProcessRequest(request, &cache); - EXPECT_EQ(2, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - request.method = "POST"; - request.url = kSimpleGET_Transaction.url; - ProcessRequest(request, &cache); - EXPECT_EQ(1, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); - - request.method = "DELETE"; - request.url = kETagGET_Transaction.url; - ProcessRequest(request, &cache); - EXPECT_EQ(0, cb.GetResult(cache.QueryItemsForTest(cb.callback()))); -} - -TEST(InfiniteCache, Delete) { - base::ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - base::FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); - - scoped_ptr<InfiniteCache> cache(new InfiniteCache); - cache->Init(path); - net::TestCompletionCallback cb; - - ProcessRequest(kTypicalGET_Transaction, cache.get()); - ProcessRequest(kSimpleGET_Transaction, cache.get()); - EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); - EXPECT_TRUE(file_util::PathExists(path)); - - cache.reset(new InfiniteCache); - cache->Init(path); - EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, cb.GetResult(cache->DeleteData(cb.callback()))); - EXPECT_EQ(0, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_FALSE(file_util::PathExists(path)); - - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); -} - -TEST(InfiniteCache, DeleteBetween) { -#if !defined(OS_ANDROID) - base::ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - base::FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); - - scoped_ptr<InfiniteCache> cache(new InfiniteCache); - cache->Init(path); - net::TestCompletionCallback cb; - - Time::Exploded baseline = {}; - baseline.year = 2012; - baseline.month = 1; - baseline.day_of_month = 1; - Time base_time = Time::FromUTCExploded(baseline); - - ProcessRequestWithTime(kTypicalGET_Transaction, cache.get(), base_time); - - Time start = base_time + TimeDelta::FromSeconds(2); - ProcessRequestWithTime(kSimpleGET_Transaction, cache.get(), start); - Time end = start + TimeDelta::FromSeconds(2); - - ProcessRequestWithTime(kETagGET_Transaction, cache.get(), - end + TimeDelta::FromSeconds(2)); - - EXPECT_EQ(3, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, - cb.GetResult(cache->DeleteDataBetween(start, end, - cb.callback()))); - EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - - // Make sure the data is deleted from disk. - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); - cache.reset(new InfiniteCache); - cache->Init(path); - - EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - ProcessRequestWithTime(kETagGET_Transaction, cache.get(), - end + TimeDelta::FromMinutes(5)); - EXPECT_EQ(2, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - - EXPECT_EQ(net::OK, - cb.GetResult(cache->DeleteDataBetween(start, Time::Now(), - cb.callback()))); - EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - - // Make sure the data is deleted from disk. - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); - cache.reset(new InfiniteCache); - cache->Init(path); - - EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - ProcessRequest(kTypicalGET_Transaction, cache.get()); - EXPECT_EQ(1, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); -#endif // OS_ANDROID -} - -#if 0 -// This test is too slow for the bots. -TEST(InfiniteCache, FillUp) { - base::ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - base::FilePath path = dir.path().Append(FILE_PATH_LITERAL("infinite")); - - scoped_ptr<InfiniteCache> cache(new InfiniteCache); - cache->Init(path); - net::TestCompletionCallback cb; - - const int kNumEntries = 25000; - for (int i = 0; i < kNumEntries; i++) { - std::string url = StringPrintf("http://foo.com/%d/foo.html", i); - MockTransaction transaction = kTypicalGET_Transaction; - transaction.url = url.c_str(); - ProcessRequest(transaction, cache.get()); - } - - EXPECT_EQ(kNumEntries, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); - EXPECT_EQ(net::OK, cb.GetResult(cache->FlushDataForTest(cb.callback()))); - - cache.reset(new InfiniteCache); - cache->Init(path); - EXPECT_EQ(kNumEntries, cb.GetResult(cache->QueryItemsForTest(cb.callback()))); -} -#endif diff --git a/net/net.gyp b/net/net.gyp index 715d7ef..46d8225 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -577,8 +577,6 @@ 'http/http_vary_data.cc', 'http/http_vary_data.h', 'http/http_version.h', - 'http/infinite_cache.cc', - 'http/infinite_cache.h', 'http/md4.cc', 'http/md4.h', 'http/partial_data.cc', @@ -1511,7 +1509,6 @@ 'http/http_transaction_unittest.h', 'http/http_util_unittest.cc', 'http/http_vary_data_unittest.cc', - 'http/infinite_cache_unittest.cc', 'http/mock_allow_url_security_manager.cc', 'http/mock_allow_url_security_manager.h', 'http/mock_gssapi_library_posix.cc', |