Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Unified Diff: net/http/http_cache_transaction.cc

Issue 387017: Http Cache: Split HttpCache::Transaction to its own set... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/http_cache_transaction.cc
===================================================================
--- net/http/http_cache_transaction.cc (revision 31582)
+++ net/http/http_cache_transaction.cc (working copy)
@@ -2,19 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/http/http_cache.h"
+#include "net/http/http_cache_transaction.h"
-#include <algorithm>
-#include <string>
-
#include "base/compiler_specific.h"
#if defined(OS_POSIX)
#include <unistd.h>
#endif
-#include "base/message_loop.h"
-#include "base/pickle.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -24,11 +19,8 @@
#include "net/base/net_errors.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/disk_cache/disk_cache.h"
-#include "net/http/http_network_layer.h"
-#include "net/http/http_network_session.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_transaction.h"
#include "net/http/http_util.h"
#include "net/http/partial_data.h"
@@ -69,15 +61,6 @@
{ "if-none-match", "etag" },
};
-// Helper struct to pair a header name with its value, for
-// headers used to validate cache entries.
-struct ValidationHeaders {
- ValidationHeaders() : initialized(false) {}
-
- std::string values[ARRAYSIZE_UNSAFE(kValidationHeaders)];
- bool initialized;
-};
-
// If the request includes one of these request headers, then avoid reusing
// our cached copy if any.
static const HeaderNameAndValue kForceFetchHeaders[] = {
@@ -113,282 +96,38 @@
//-----------------------------------------------------------------------------
-HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* e)
- : disk_entry(e),
- writer(NULL),
- will_process_pending_queue(false),
- doomed(false) {
+HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
+ : request_(NULL),
+ cache_(cache->AsWeakPtr()),
+ entry_(NULL),
+ network_trans_(NULL),
+ callback_(NULL),
+ mode_(NONE),
+ reading_(false),
+ invalid_range_(false),
+ enable_range_support_(enable_range_support),
+ truncated_(false),
+ read_offset_(0),
+ effective_load_flags_(0),
+ final_upload_progress_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ cache_read_callback_(new CancelableCompletionCallback<Transaction>(
+ this, &Transaction::OnCacheReadCompleted))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ cache_write_callback_(new CancelableCompletionCallback<Transaction>(
+ this, &Transaction::OnCacheWriteCompleted))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
+ this, &Transaction::OnCacheEntryReady))) {
+ COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
+ ARRAYSIZE_UNSAFE(kValidationHeaders),
+ Invalid_number_of_validation_headers);
}
-HttpCache::ActiveEntry::~ActiveEntry() {
- if (disk_entry)
- disk_entry->Close();
-}
-
-//-----------------------------------------------------------------------------
-
-class HttpCache::Transaction : public HttpTransaction {
- public:
- Transaction(HttpCache* cache, bool enable_range_support)
- : request_(NULL),
- cache_(cache->AsWeakPtr()),
- entry_(NULL),
- network_trans_(NULL),
- callback_(NULL),
- mode_(NONE),
- reading_(false),
- invalid_range_(false),
- enable_range_support_(enable_range_support),
- truncated_(false),
- read_offset_(0),
- effective_load_flags_(0),
- final_upload_progress_(0),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- cache_read_callback_(new CancelableCompletionCallback<Transaction>(
- this, &Transaction::OnCacheReadCompleted))),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- cache_write_callback_(new CancelableCompletionCallback<Transaction>(
- this, &Transaction::OnCacheWriteCompleted))),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
- this, &Transaction::OnCacheEntryReady))) {
- }
-
- // Clean up the transaction.
- virtual ~Transaction();
-
- // HttpTransaction methods:
- virtual int Start(const HttpRequestInfo*, CompletionCallback*, LoadLog*);
- virtual int RestartIgnoringLastError(CompletionCallback*);
- virtual int RestartWithCertificate(X509Certificate* client_cert,
- CompletionCallback* callback);
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
- CompletionCallback* callback);
- virtual bool IsReadyToRestartForAuth();
- virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback*);
- virtual const HttpResponseInfo* GetResponseInfo() const;
- virtual LoadState GetLoadState() const;
- virtual uint64 GetUploadProgress(void) const;
-
- // The transaction has the following modes, which apply to how it may access
- // its cache entry.
- //
- // o If the mode of the transaction is NONE, then it is in "pass through"
- // mode and all methods just forward to the inner network transaction.
- //
- // o If the mode of the transaction is only READ, then it may only read from
- // the cache entry.
- //
- // o If the mode of the transaction is only WRITE, then it may only write to
- // the cache entry.
- //
- // o If the mode of the transaction is READ_WRITE, then the transaction may
- // optionally modify the cache entry (e.g., possibly corresponding to
- // cache validation).
- //
- // o If the mode of the transaction is UPDATE, then the transaction may
- // update existing cache entries, but will never create a new entry or
- // respond using the entry read from the cache.
- enum Mode {
- NONE = 0,
- READ_META = 1 << 0,
- READ_DATA = 1 << 1,
- READ = READ_META | READ_DATA,
- WRITE = 1 << 2,
- READ_WRITE = READ | WRITE,
- UPDATE = READ_META | WRITE, // READ_WRITE & ~READ_DATA
- };
-
- Mode mode() const { return mode_; }
-
- const std::string& key() const { return cache_key_; }
-
- // Associates this transaction with a cache entry.
- int AddToEntry();
-
- // Called by the HttpCache when the given disk cache entry becomes accessible
- // to the transaction. Returns network error code.
- int EntryAvailable(ActiveEntry* entry);
-
- // This transaction is being deleted and we are not done writing to the cache.
- // We need to indicate that the response data was truncated. Returns true on
- // success.
- bool AddTruncatedFlag();
-
- private:
- // This is a helper function used to trigger a completion callback. It may
- // only be called if callback_ is non-null.
- void DoCallback(int rv);
-
- // This will trigger the completion callback if appropriate.
- int HandleResult(int rv);
-
- // Sets request_ and fields derived from it.
- void SetRequest(LoadLog* load_log, const HttpRequestInfo* request);
-
- // Returns true if the request should be handled exclusively by the network
- // layer (skipping the cache entirely).
- bool ShouldPassThrough();
-
- // Called to begin reading from the cache. Returns network error code.
- int BeginCacheRead();
-
- // Called to begin validating the cache entry. Returns network error code.
- int BeginCacheValidation();
-
- // Called to begin validating an entry that stores partial content. Returns
- // a network error code.
- int BeginPartialCacheValidation();
-
- // Validates the entry headers against the requested range and continues with
- // the validation of the rest of the entry. Returns a network error code.
- int ValidateEntryHeadersAndContinue(bool byte_range_requested);
-
- // Performs the cache validation for the next chunk of data stored by the
- // cache. If this chunk is not currently stored, starts the network request
- // to fetch it. Returns a network error code.
- int ContinuePartialCacheValidation();
-
- // Called to start requests which were given an "if-modified-since" or
- // "if-none-match" validation header by the caller (NOT when the request was
- // conditionalized internally in response to LOAD_VALIDATE_CACHE).
- // Returns a network error code.
- int BeginExternallyConditionalizedRequest();
-
- // Called to begin a network transaction. Returns network error code.
- int BeginNetworkRequest();
-
- // Called to restart a network transaction after an error. Returns network
- // error code.
- int RestartNetworkRequest();
-
- // Called to restart a network transaction with a client certificate.
- // Returns network error code.
- int RestartNetworkRequestWithCertificate(X509Certificate* client_cert);
-
- // Called to restart a network transaction with authentication credentials.
- // Returns network error code.
- int RestartNetworkRequestWithAuth(const std::wstring& username,
- const std::wstring& password);
-
- // Called to determine if we need to validate the cache entry before using it.
- bool RequiresValidation();
-
- // Called to make the request conditional (to ask the server if the cached
- // copy is valid). Returns true if able to make the request conditional.
- bool ConditionalizeRequest();
-
- // Makes sure that a 206 response is expected. Returns a network error code.
- bool ValidatePartialResponse(const HttpResponseHeaders* headers);
-
- // Handles a response validation error by bypassing the cache.
- void IgnoreRangeRequest();
-
- // Reads data from the network.
- int ReadFromNetwork(IOBuffer* data, int data_len);
-
- // Reads data from the cache entry.
- int ReadFromEntry(IOBuffer* data, int data_len);
-
- // Called to populate response_ from the cache entry.
- int ReadResponseInfoFromEntry();
-
- // Called to write data to the cache entry. If the write fails, then the
- // cache entry is destroyed. Future calls to this function will just do
- // nothing without side-effect. Returns a network error code.
- int WriteToEntry(int index, int offset, IOBuffer* data, int data_len,
- CompletionCallback* callback);
-
- // Called to write response_ to the cache entry. |truncated| indicates if the
- // entry should be marked as incomplete.
- void WriteResponseInfoToEntry(bool truncated);
-
- // Called to append response data to the cache entry. Returns a network error
- // code.
- int AppendResponseDataToEntry(IOBuffer* data, int data_len,
- CompletionCallback* callback);
-
- // Called to truncate response content in the entry.
- void TruncateResponseData();
-
- // Called when we are done writing to the cache entry.
- void DoneWritingToEntry(bool success);
-
- // Deletes the current partial cache entry (sparse), and optionally removes
- // the control object (partial_).
- void DoomPartialEntry(bool delete_object);
-
- // Performs the needed work after receiving data from the network.
- int DoNetworkReadCompleted(int result);
-
- // Performs the needed work after receiving data from the network, when
- // working with range requests.
- int DoPartialNetworkReadCompleted(int result);
-
- // Performs the needed work after receiving data from the cache.
- int DoCacheReadCompleted(int result);
-
- // Performs the needed work after receiving data from the cache, when
- // working with range requests.
- int DoPartialCacheReadCompleted(int result);
-
- // Performs the needed work after writing data to the cache.
- int DoCacheWriteCompleted(int result);
-
- // Called to signal completion of the network transaction's Start method:
- void OnNetworkInfoAvailable(int result);
-
- // Called to signal completion of the network transaction's Read method:
- void OnNetworkReadCompleted(int result);
-
- // Called to signal completion of the cache's ReadData method:
- void OnCacheReadCompleted(int result);
-
- // Called to signal completion of the cache's WriteData method:
- void OnCacheWriteCompleted(int result);
-
- // Called to signal completion of the cache entry's ReadyForSparseIO method:
- void OnCacheEntryReady(int result);
-
- scoped_refptr<LoadLog> load_log_;
- const HttpRequestInfo* request_;
- scoped_ptr<HttpRequestInfo> custom_request_;
- // If extra_headers specified a "if-modified-since" or "if-none-match",
- // |external_validation_| contains the value of those headers.
- ValidationHeaders external_validation_;
- base::WeakPtr<HttpCache> cache_;
- HttpCache::ActiveEntry* entry_;
- scoped_ptr<HttpTransaction> network_trans_;
- CompletionCallback* callback_; // Consumer's callback.
- HttpResponseInfo response_;
- HttpResponseInfo auth_response_;
- std::string cache_key_;
- Mode mode_;
- bool reading_; // We are already reading.
- bool invalid_range_; // We may bypass the cache for this request.
- bool enable_range_support_;
- bool truncated_; // We don't have all the response data.
- scoped_refptr<IOBuffer> read_buf_;
- int read_buf_len_;
- int read_offset_;
- int effective_load_flags_;
- scoped_ptr<PartialData> partial_; // We are dealing with range requests.
- uint64 final_upload_progress_;
- CompletionCallbackImpl<Transaction> network_info_callback_;
- CompletionCallbackImpl<Transaction> network_read_callback_;
- scoped_refptr<CancelableCompletionCallback<Transaction> >
- cache_read_callback_;
- scoped_refptr<CancelableCompletionCallback<Transaction> >
- cache_write_callback_;
- scoped_refptr<CancelableCompletionCallback<Transaction> >
- entry_ready_callback_;
-};
-
HttpCache::Transaction::~Transaction() {
if (cache_) {
if (entry_) {
@@ -1629,487 +1368,4 @@
ValidateEntryHeadersAndContinue(true);
}
-//-----------------------------------------------------------------------------
-
-HttpCache::HttpCache(HostResolver* host_resolver,
- ProxyService* proxy_service,
- SSLConfigService* ssl_config_service,
- const FilePath& cache_dir,
- int cache_size)
- : disk_cache_dir_(cache_dir),
- mode_(NORMAL),
- type_(DISK_CACHE),
- network_layer_(HttpNetworkLayer::CreateFactory(
- host_resolver, proxy_service, ssl_config_service)),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true),
- cache_size_(cache_size) {
-}
-
-HttpCache::HttpCache(HttpNetworkSession* session,
- const FilePath& cache_dir,
- int cache_size)
- : disk_cache_dir_(cache_dir),
- mode_(NORMAL),
- type_(DISK_CACHE),
- network_layer_(HttpNetworkLayer::CreateFactory(session)),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true),
- cache_size_(cache_size) {
-}
-
-HttpCache::HttpCache(HostResolver* host_resolver,
- ProxyService* proxy_service,
- SSLConfigService* ssl_config_service,
- int cache_size)
- : mode_(NORMAL),
- type_(MEMORY_CACHE),
- network_layer_(HttpNetworkLayer::CreateFactory(
- host_resolver, proxy_service, ssl_config_service)),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true),
- cache_size_(cache_size) {
-}
-
-HttpCache::HttpCache(HttpTransactionFactory* network_layer,
- disk_cache::Backend* disk_cache)
- : mode_(NORMAL),
- type_(DISK_CACHE),
- network_layer_(network_layer),
- disk_cache_(disk_cache),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true),
- cache_size_(0) {
-}
-
-HttpCache::~HttpCache() {
- // If we have any active entries remaining, then we need to deactivate them.
- // We may have some pending calls to OnProcessPendingQueue, but since those
- // won't run (due to our destruction), we can simply ignore the corresponding
- // will_process_pending_queue flag.
- while (!active_entries_.empty()) {
- ActiveEntry* entry = active_entries_.begin()->second;
- entry->will_process_pending_queue = false;
- entry->pending_queue.clear();
- entry->readers.clear();
- entry->writer = NULL;
- DeactivateEntry(entry);
- }
-
- ActiveEntriesSet::iterator it = doomed_entries_.begin();
- for (; it != doomed_entries_.end(); ++it)
- delete *it;
-}
-
-disk_cache::Backend* HttpCache::GetBackend() {
- if (disk_cache_.get())
- return disk_cache_.get();
-
- DCHECK_GE(cache_size_, 0);
- if (type_ == MEMORY_CACHE) {
- // We may end up with no folder name and no cache if the initialization
- // of the disk cache fails. We want to be sure that what we wanted to have
- // was an in-memory cache.
- disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_));
- } else if (!disk_cache_dir_.empty()) {
- disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true,
- cache_size_, type_));
- disk_cache_dir_ = FilePath(); // Reclaim memory.
- }
- return disk_cache_.get();
-}
-
-int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
- // Do lazy initialization of disk cache if needed.
- GetBackend();
- trans->reset(new HttpCache::Transaction(this, enable_range_support_));
- return OK;
-}
-
-HttpCache* HttpCache::GetCache() {
- return this;
-}
-
-HttpNetworkSession* HttpCache::GetSession() {
- net::HttpNetworkLayer* network =
- static_cast<net::HttpNetworkLayer*>(network_layer_.get());
- return network->GetSession();
-}
-
-void HttpCache::Suspend(bool suspend) {
- network_layer_->Suspend(suspend);
-}
-
-// static
-bool HttpCache::ParseResponseInfo(const char* data, int len,
- HttpResponseInfo* response_info,
- bool* response_truncated) {
- Pickle pickle(data, len);
- return response_info->InitFromPickle(pickle, response_truncated);
-}
-
-// static
-bool HttpCache::ReadResponseInfo(disk_cache::Entry* disk_entry,
- HttpResponseInfo* response_info,
- bool* response_truncated) {
- int size = disk_entry->GetDataSize(kResponseInfoIndex);
-
- scoped_refptr<IOBuffer> buffer = new IOBuffer(size);
- int rv = disk_entry->ReadData(kResponseInfoIndex, 0, buffer, size, NULL);
- if (rv != size) {
- DLOG(ERROR) << "ReadData failed: " << rv;
- return false;
- }
-
- return ParseResponseInfo(buffer->data(), size, response_info,
- response_truncated);
-}
-
-// static
-bool HttpCache::WriteResponseInfo(disk_cache::Entry* disk_entry,
- const HttpResponseInfo* response_info,
- bool skip_transient_headers,
- bool response_truncated) {
- Pickle pickle;
- response_info->Persist(
- &pickle, skip_transient_headers, response_truncated);
-
- scoped_refptr<WrappedIOBuffer> data = new WrappedIOBuffer(
- reinterpret_cast<const char*>(pickle.data()));
- int len = static_cast<int>(pickle.size());
-
- return disk_entry->WriteData(kResponseInfoIndex, 0, data, len, NULL,
- true) == len;
-}
-
-// Generate a key that can be used inside the cache.
-std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
- // Strip out the reference, username, and password sections of the URL.
- std::string url = HttpUtil::SpecForRequest(request->url);
-
- DCHECK(mode_ != DISABLE);
- if (mode_ == NORMAL) {
- // No valid URL can begin with numerals, so we should not have to worry
- // about collisions with normal URLs.
- if (request->upload_data && request->upload_data->identifier())
- url.insert(0, StringPrintf("%lld/", request->upload_data->identifier()));
- return url;
- }
-
- // In playback and record mode, we cache everything.
-
- // Lazily initialize.
- if (playback_cache_map_ == NULL)
- playback_cache_map_.reset(new PlaybackCacheMap());
-
- // Each time we request an item from the cache, we tag it with a
- // generation number. During playback, multiple fetches for the same
- // item will use the same generation number and pull the proper
- // instance of an URL from the cache.
- int generation = 0;
- DCHECK(playback_cache_map_ != NULL);
- if (playback_cache_map_->find(url) != playback_cache_map_->end())
- generation = (*playback_cache_map_)[url];
- (*playback_cache_map_)[url] = generation + 1;
-
- // The key into the cache is GENERATION # + METHOD + URL.
- std::string result = IntToString(generation);
- result.append(request->method);
- result.append(url);
- return result;
-}
-
-void HttpCache::DoomEntry(const std::string& key) {
- // Need to abandon the ActiveEntry, but any transaction attached to the entry
- // should not be impacted. Dooming an entry only means that it will no
- // longer be returned by FindActiveEntry (and it will also be destroyed once
- // all consumers are finished with the entry).
- ActiveEntriesMap::iterator it = active_entries_.find(key);
- if (it == active_entries_.end()) {
- disk_cache_->DoomEntry(key);
- } else {
- ActiveEntry* entry = it->second;
- active_entries_.erase(it);
-
- // We keep track of doomed entries so that we can ensure that they are
- // cleaned up properly when the cache is destroyed.
- doomed_entries_.insert(entry);
-
- entry->disk_entry->Doom();
- entry->doomed = true;
-
- DCHECK(entry->writer || !entry->readers.empty());
- }
-}
-
-void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
- DCHECK(entry->doomed);
- DCHECK(!entry->writer);
- DCHECK(entry->readers.empty());
- DCHECK(entry->pending_queue.empty());
-
- ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
- DCHECK(it != doomed_entries_.end());
- doomed_entries_.erase(it);
-
- delete entry;
-}
-
-HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
- ActiveEntriesMap::const_iterator it = active_entries_.find(key);
- return it != active_entries_.end() ? it->second : NULL;
-}
-
-HttpCache::ActiveEntry* HttpCache::OpenEntry(const std::string& key) {
- DCHECK(!FindActiveEntry(key));
-
- disk_cache::Entry* disk_entry;
- if (!disk_cache_->OpenEntry(key, &disk_entry))
- return NULL;
-
- return ActivateEntry(key, disk_entry);
-}
-
-HttpCache::ActiveEntry* HttpCache::CreateEntry(const std::string& key) {
- DCHECK(!FindActiveEntry(key));
-
- disk_cache::Entry* disk_entry;
- if (!disk_cache_->CreateEntry(key, &disk_entry))
- return NULL;
-
- return ActivateEntry(key, disk_entry);
-}
-
-void HttpCache::DestroyEntry(ActiveEntry* entry) {
- if (entry->doomed) {
- FinalizeDoomedEntry(entry);
- } else {
- DeactivateEntry(entry);
- }
-}
-
-HttpCache::ActiveEntry* HttpCache::ActivateEntry(
- const std::string& key,
- disk_cache::Entry* disk_entry) {
- ActiveEntry* entry = new ActiveEntry(disk_entry);
- active_entries_[key] = entry;
- return entry;
-}
-
-void HttpCache::DeactivateEntry(ActiveEntry* entry) {
- DCHECK(!entry->will_process_pending_queue);
- DCHECK(!entry->doomed);
- DCHECK(!entry->writer);
- DCHECK(entry->readers.empty());
- DCHECK(entry->pending_queue.empty());
-
- std::string key = entry->disk_entry->GetKey();
- if (key.empty())
- return SlowDeactivateEntry(entry);
-
- ActiveEntriesMap::iterator it = active_entries_.find(key);
- DCHECK(it != active_entries_.end());
- DCHECK(it->second == entry);
-
- active_entries_.erase(it);
- delete entry;
-}
-
-// We don't know this entry's key so we have to find it without it.
-void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
- for (ActiveEntriesMap::iterator it = active_entries_.begin();
- it != active_entries_.end(); ++it) {
- if (it->second == entry) {
- active_entries_.erase(it);
- delete entry;
- break;
- }
- }
-}
-
-int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
- DCHECK(entry);
-
- // We implement a basic reader/writer lock for the disk cache entry. If
- // there is already a writer, then everyone has to wait for the writer to
- // finish before they can access the cache entry. There can be multiple
- // readers.
- //
- // NOTE: If the transaction can only write, then the entry should not be in
- // use (since any existing entry should have already been doomed).
-
- if (entry->writer || entry->will_process_pending_queue) {
- entry->pending_queue.push_back(trans);
- return ERR_IO_PENDING;
- }
-
- if (trans->mode() & Transaction::WRITE) {
- // transaction needs exclusive access to the entry
- if (entry->readers.empty()) {
- entry->writer = trans;
- } else {
- entry->pending_queue.push_back(trans);
- return ERR_IO_PENDING;
- }
- } else {
- // transaction needs read access to the entry
- entry->readers.push_back(trans);
- }
-
- // We do this before calling EntryAvailable to force any further calls to
- // AddTransactionToEntry to add their transaction to the pending queue, which
- // ensures FIFO ordering.
- if (!entry->writer && !entry->pending_queue.empty())
- ProcessPendingQueue(entry);
-
- return trans->EntryAvailable(entry);
-}
-
-void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
- bool cancel) {
- // If we already posted a task to move on to the next transaction and this was
- // the writer, there is nothing to cancel.
- if (entry->will_process_pending_queue && entry->readers.empty())
- return;
-
- if (entry->writer) {
- DCHECK(trans == entry->writer);
-
- // Assume there was a failure.
- bool success = false;
- if (cancel) {
- DCHECK(entry->disk_entry);
- // This is a successful operation in the sense that we want to keep the
- // entry.
- success = trans->AddTruncatedFlag();
- }
- DoneWritingToEntry(entry, success);
- } else {
- DoneReadingFromEntry(entry, trans);
- }
-}
-
-void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
- DCHECK(entry->readers.empty());
-
- entry->writer = NULL;
-
- if (success) {
- ProcessPendingQueue(entry);
- } else {
- DCHECK(!entry->will_process_pending_queue);
-
- // We failed to create this entry.
- TransactionList pending_queue;
- pending_queue.swap(entry->pending_queue);
-
- entry->disk_entry->Doom();
- DestroyEntry(entry);
-
- // We need to do something about these pending entries, which now need to
- // be added to a new entry.
- while (!pending_queue.empty()) {
- pending_queue.front()->AddToEntry();
- pending_queue.pop_front();
- }
- }
-}
-
-void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
- DCHECK(!entry->writer);
-
- TransactionList::iterator it =
- std::find(entry->readers.begin(), entry->readers.end(), trans);
- DCHECK(it != entry->readers.end());
-
- entry->readers.erase(it);
-
- ProcessPendingQueue(entry);
-}
-
-void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
- DCHECK(entry->writer);
- DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
- DCHECK(entry->readers.empty());
-
- Transaction* trans = entry->writer;
-
- entry->writer = NULL;
- entry->readers.push_back(trans);
-
- ProcessPendingQueue(entry);
-}
-
-void HttpCache::RemovePendingTransaction(Transaction* trans) {
- ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
- bool found = false;
- if (i != active_entries_.end())
- found = RemovePendingTransactionFromEntry(i->second, trans);
-
- if (found)
- return;
-
- ActiveEntriesSet::iterator it = doomed_entries_.begin();
- for (; it != doomed_entries_.end() && !found; ++it)
- found = RemovePendingTransactionFromEntry(*it, trans);
-}
-
-bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
- Transaction* trans) {
- TransactionList& pending_queue = entry->pending_queue;
-
- TransactionList::iterator j =
- find(pending_queue.begin(), pending_queue.end(), trans);
- if (j == pending_queue.end())
- return false;
-
- pending_queue.erase(j);
- return true;
-}
-
-void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
- // Multiple readers may finish with an entry at once, so we want to batch up
- // calls to OnProcessPendingQueue. This flag also tells us that we should
- // not delete the entry before OnProcessPendingQueue runs.
- if (entry->will_process_pending_queue)
- return;
- entry->will_process_pending_queue = true;
-
- MessageLoop::current()->PostTask(FROM_HERE,
- task_factory_.NewRunnableMethod(&HttpCache::OnProcessPendingQueue,
- entry));
-}
-
-void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
- entry->will_process_pending_queue = false;
- DCHECK(!entry->writer);
-
- // If no one is interested in this entry, then we can de-activate it.
- if (entry->pending_queue.empty()) {
- if (entry->readers.empty())
- DestroyEntry(entry);
- return;
- }
-
- // Promote next transaction from the pending queue.
- Transaction* next = entry->pending_queue.front();
- if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
- return; // Have to wait.
-
- entry->pending_queue.erase(entry->pending_queue.begin());
-
- AddTransactionToEntry(entry, next);
-}
-
-void HttpCache::CloseIdleConnections() {
- net::HttpNetworkLayer* network =
- static_cast<net::HttpNetworkLayer*>(network_layer_.get());
- HttpNetworkSession* session = network->GetSession();
- if (session) {
- session->tcp_socket_pool()->CloseIdleSockets();
- }
-}
-
-//-----------------------------------------------------------------------------
-
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698