summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-05 01:37:18 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-05 01:37:18 +0000
commitb68f1b25831e7c17027814805a0a43cebfee72e4 (patch)
tree34d9152e6b1c22ee4382a7ff5f71d81c8aa294ec /net
parentac51ee9169f4e65c3fe76754821fc0864520a612 (diff)
downloadchromium_src-b68f1b25831e7c17027814805a0a43cebfee72e4.zip
chromium_src-b68f1b25831e7c17027814805a0a43cebfee72e4.tar.gz
chromium_src-b68f1b25831e7c17027814805a0a43cebfee72e4.tar.bz2
Http cache: Second pass to move the HttpCache::Transaction
to a state machine. BUG=26729 TEST=current unit tests. Review URL: http://codereview.chromium.org/464028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33904 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_cache_transaction.cc293
-rw-r--r--net/http/http_cache_transaction.h24
2 files changed, 211 insertions, 106 deletions
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 3607273..2838f9d 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -101,6 +101,7 @@ HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
request_(NULL),
cache_(cache->AsWeakPtr()),
entry_(NULL),
+ new_entry_(NULL),
network_trans_(NULL),
callback_(NULL),
mode_(NONE),
@@ -156,6 +157,9 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
// Ensure that we only have one asynchronous call at a time.
DCHECK(!callback_);
+ DCHECK(!reading_);
+ DCHECK(!network_trans_.get());
+ DCHECK(!entry_);
if (!cache_)
return ERR_UNEXPECTED;
@@ -167,7 +171,7 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
if (!ShouldPassThrough()) {
cache_key_ = cache_->GenerateCacheKey(request);
- // requested cache access mode
+ // Requested cache access mode.
if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
mode_ = READ;
} else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
@@ -188,7 +192,7 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
}
}
- // if must use cache, then we must fail. this can happen for back/forward
+ // If must use cache, then we must fail. This can happen for back/forward
// navigations to a page generated via a form post.
if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
return ERR_CACHE_MISS;
@@ -201,7 +205,7 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request,
rv = AddToEntry();
}
- // setting this here allows us to check for the existance of a callback_ to
+ // Setting this here allows us to check for the existance of a callback_ to
// determine if we are still inside Start.
if (rv == ERR_IO_PENDING)
callback_ = callback;
@@ -213,7 +217,7 @@ int HttpCache::Transaction::RestartIgnoringLastError(
CompletionCallback* callback) {
DCHECK(callback);
- // ensure that we only have one asynchronous call at a time.
+ // Ensure that we only have one asynchronous call at a time.
DCHECK(!callback_);
if (!cache_)
@@ -232,7 +236,7 @@ int HttpCache::Transaction::RestartWithCertificate(
CompletionCallback* callback) {
DCHECK(callback);
- // ensure that we only have one asynchronous call at a time.
+ // Ensure that we only have one asynchronous call at a time.
DCHECK(!callback_);
if (!cache_)
@@ -350,60 +354,128 @@ uint64 HttpCache::Transaction::GetUploadProgress() const {
}
int HttpCache::Transaction::AddToEntry() {
- ActiveEntry* entry = NULL;
+ next_state_ = STATE_INIT_ENTRY;
+ return DoLoop(OK);
+}
+
+int HttpCache::Transaction::DoInitEntry() {
+ DCHECK(!new_entry_);
if (!cache_)
return ERR_UNEXPECTED;
if (mode_ == WRITE) {
- cache_->DoomEntry(cache_key_);
- } else {
- entry = cache_->FindActiveEntry(cache_key_);
- if (!entry) {
- LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
- entry = cache_->OpenEntry(cache_key_);
- LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
- if (!entry) {
- if (mode_ == READ_WRITE) {
- mode_ = WRITE;
- } else if (mode_ == UPDATE) {
- // There is no cache entry to update; proceed without caching.
- mode_ = NONE;
- return BeginNetworkRequest();
- } else {
- if (cache_->mode() == PLAYBACK)
- DLOG(INFO) << "Playback Cache Miss: " << request_->url;
+ next_state_ = STATE_DOOM_ENTRY;
+ return OK;
+ }
- // entry does not exist, and not permitted to create a new entry, so
- // we must fail.
- return HandleResult(ERR_CACHE_MISS);
- }
- }
- }
+ new_entry_ = cache_->FindActiveEntry(cache_key_);
+ if (!new_entry_) {
+ next_state_ = STATE_OPEN_ENTRY;
+ return OK;
}
if (mode_ == WRITE) {
- DCHECK(!entry);
- LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
- entry = cache_->CreateEntry(cache_key_);
- LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
- if (!entry) {
- DLOG(WARNING) << "unable to create cache entry";
- mode_ = NONE;
- if (partial_.get())
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- return BeginNetworkRequest();
- }
+ next_state_ = STATE_CREATE_ENTRY;
+ return OK;
+ }
+
+ next_state_ = STATE_ADD_TO_ENTRY;
+ return OK;
+}
+
+int HttpCache::Transaction::DoDoomEntry() {
+ next_state_ = STATE_DOOM_ENTRY_COMPLETE;
+ cache_->DoomEntry(cache_key_);
+ return OK;
+}
+
+int HttpCache::Transaction::DoDoomEntryComplete() {
+ next_state_ = STATE_CREATE_ENTRY;
+ return OK;
+}
+
+int HttpCache::Transaction::DoOpenEntry() {
+ DCHECK(!new_entry_);
+ next_state_ = STATE_OPEN_ENTRY_COMPLETE;
+ LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
+ new_entry_ = cache_->OpenEntry(cache_key_);
+ return OK;
+}
+
+int HttpCache::Transaction::DoOpenEntryComplete() {
+ LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
+ if (new_entry_) {
+ next_state_ = STATE_ADD_TO_ENTRY;
+ return OK;
+ }
+
+ if (mode_ == READ_WRITE) {
+ mode_ = WRITE;
+ next_state_ = STATE_CREATE_ENTRY;
+ return OK;
+ }
+ if (mode_ == UPDATE) {
+ // There is no cache entry to update; proceed without caching.
+ mode_ = NONE;
+ next_state_ = STATE_SEND_REQUEST;
+ return OK;
}
+ if (cache_->mode() == PLAYBACK)
+ DLOG(INFO) << "Playback Cache Miss: " << request_->url;
+ // The entry does not exist, and we are not permitted to create a new entry,
+ // so we must fail.
+ return ERR_CACHE_MISS;
+}
+int HttpCache::Transaction::DoCreateEntry() {
+ DCHECK(!new_entry_);
+ next_state_ = STATE_CREATE_ENTRY_COMPLETE;
+ LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
+ new_entry_ = cache_->CreateEntry(cache_key_);
+ return OK;
+}
+
+int HttpCache::Transaction::DoCreateEntryComplete() {
+ LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
+ next_state_ = STATE_ADD_TO_ENTRY;
+ if (!new_entry_) {
+ // We have a race here: Maybe we failed to open the entry and decided to
+ // create one, but by the time we called create, another transaction already
+ // created the entry. If we want to eliminate this issue, we need an atomic
+ // OpenOrCreate() method exposed by the disk cache.
+ DLOG(WARNING) << "Unable to create cache entry";
+ mode_ = NONE;
+ if (partial_.get())
+ partial_->RestoreHeaders(&custom_request_->extra_headers);
+ next_state_ = STATE_SEND_REQUEST;
+ }
+ return OK;
+}
+
+int HttpCache::Transaction::DoAddToEntry() {
+ DCHECK(new_entry_);
LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
- return cache_->AddTransactionToEntry(entry, this);
+ int rv = cache_->AddTransactionToEntry(new_entry_, this);
+ new_entry_ = NULL;
+ return rv;
}
int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) {
LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
+ entry_ = entry;
+
+ next_state_ = STATE_ENTRY_AVAILABLE;
+ if (new_entry_) {
+ // We are inside AddTransactionToEntry() so avoid reentering DoLoop().
+ DCHECK_EQ(new_entry_, entry);
+ return OK;
+ }
+ return DoLoop(OK);
+}
+int HttpCache::Transaction::DoEntryAvailable() {
// We now have access to the cache entry.
//
// o if we are the writer for the transaction, then we can start the network
@@ -421,8 +493,8 @@ int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) {
// the cache entry, and check if the request headers define a validation
// request.
//
+ DCHECK(!new_entry_);
int rv;
- entry_ = entry;
switch (mode_) {
case READ:
rv = BeginCacheRead();
@@ -430,7 +502,8 @@ int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) {
case WRITE:
if (partial_.get())
partial_->RestoreHeaders(&custom_request_->extra_headers);
- rv = BeginNetworkRequest();
+ next_state_ = STATE_SEND_REQUEST;
+ rv = OK;
break;
case READ_WRITE:
rv = BeginPartialCacheValidation();
@@ -500,6 +573,46 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_NETWORK_READ_COMPLETE:
rv = DoNetworkReadComplete(rv);
break;
+ case STATE_INIT_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoInitEntry();
+ break;
+ case STATE_OPEN_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoOpenEntry();
+ break;
+ case STATE_OPEN_ENTRY_COMPLETE:
+ DCHECK_EQ(OK, rv);
+ rv = DoOpenEntryComplete();
+ break;
+ case STATE_CREATE_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoCreateEntry();
+ break;
+ case STATE_CREATE_ENTRY_COMPLETE:
+ DCHECK_EQ(OK, rv);
+ rv = DoCreateEntryComplete();
+ break;
+ case STATE_DOOM_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoDoomEntry();
+ break;
+ case STATE_DOOM_ENTRY_COMPLETE:
+ DCHECK_EQ(OK, rv);
+ rv = DoDoomEntryComplete();
+ break;
+ case STATE_ADD_TO_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoAddToEntry();
+ break;
+ case STATE_ENTRY_AVAILABLE:
+ DCHECK_EQ(OK, rv);
+ rv = DoEntryAvailable();
+ break;
+ case STATE_PARTIAL_CACHE_VALIDATION:
+ DCHECK_EQ(OK, rv);
+ rv = DoPartialCacheValidation();
+ break;
case STATE_CACHE_QUERY_DATA:
DCHECK_EQ(OK, rv);
rv = DoCacheQueryData();
@@ -681,19 +794,19 @@ int HttpCache::Transaction::BeginCacheRead() {
// Read response headers.
int rv = ReadResponseInfoFromEntry();
if (rv != OK)
- return HandleResult(rv);
+ return rv;
// We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
if (response_.headers->response_code() == 206 || partial_.get()) {
NOTREACHED();
- return HandleResult(ERR_CACHE_MISS);
+ return ERR_CACHE_MISS;
}
// We don't have the whole resource.
if (truncated_)
- return HandleResult(ERR_CACHE_MISS);
+ return ERR_CACHE_MISS;
- return HandleResult(rv);
+ return rv;
}
int HttpCache::Transaction::BeginCacheValidation() {
@@ -710,9 +823,9 @@ int HttpCache::Transaction::BeginCacheValidation() {
// either READ or WRITE mode once we hear back from the server.
if (!ConditionalizeRequest())
mode_ = WRITE;
- return BeginNetworkRequest();
+ next_state_ = STATE_SEND_REQUEST;
}
- return HandleResult(OK);
+ return OK;
}
int HttpCache::Transaction::BeginPartialCacheValidation() {
@@ -721,7 +834,7 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
int rv = ReadResponseInfoFromEntry();
if (rv != OK) {
DCHECK(rv != ERR_IO_PENDING);
- return HandleResult(rv);
+ return rv;
}
if (response_.headers->response_code() != 206 && !partial_.get() &&
@@ -734,7 +847,7 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
bool byte_range_requested = partial_.get() != NULL;
if (byte_range_requested) {
next_state_ = STATE_CACHE_QUERY_DATA;
- return DoLoop(OK);
+ return OK;
}
// The request is not for a range, but we have stored just ranges.
partial_.reset(new PartialData());
@@ -776,7 +889,8 @@ int HttpCache::Transaction::ValidateEntryHeadersAndContinue(
DoomPartialEntry(!byte_range_requested);
mode_ = WRITE;
truncated_ = false;
- return AddToEntry();
+ next_state_ = STATE_INIT_ENTRY;
+ return OK;
}
if (!partial_->IsRequestedRangeOK()) {
@@ -784,31 +898,36 @@ int HttpCache::Transaction::ValidateEntryHeadersAndContinue(
invalid_range_ = true;
}
- return ContinuePartialCacheValidation();
+ next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
+ return OK;
}
-int HttpCache::Transaction::ContinuePartialCacheValidation() {
- DCHECK(mode_ == READ_WRITE);
+int HttpCache::Transaction::DoPartialCacheValidation() {
+ if (mode_ == NONE)
+ return OK;
+
int rv = partial_->PrepareCacheValidation(entry_->disk_entry,
&custom_request_->extra_headers);
if (!rv) {
- // Don't invoke the callback before telling the cache we're done.
+ // This is the end of the request.
+ if (mode_ & WRITE) {
+ DoneWritingToEntry(true);
+ } else {
+ cache_->DoneReadingFromEntry(entry_, this);
+ entry_ = NULL;
+ }
return rv;
}
if (rv < 0) {
DCHECK(rv != ERR_IO_PENDING);
- return HandleResult(rv);
+ return rv;
}
if (reading_ && partial_->IsCurrentRangeCached()) {
- rv = ReadFromEntry(read_buf_, read_buf_len_);
-
- // We are supposed to hanlde errors here.
- if (rv < 0 && rv != ERR_IO_PENDING)
- HandleResult(rv);
- return rv;
+ next_state_ = STATE_CACHE_READ_DATA;
+ return OK;
}
return BeginCacheValidation();
@@ -822,7 +941,7 @@ int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
int rv = ReadResponseInfoFromEntry();
if (rv != OK) {
DCHECK(rv != ERR_IO_PENDING);
- return HandleResult(rv);
+ return rv;
}
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); i++) {
@@ -843,7 +962,8 @@ int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
}
}
- return BeginNetworkRequest();
+ next_state_ = STATE_SEND_REQUEST;
+ return OK;
}
int HttpCache::Transaction::BeginNetworkRequest() {
@@ -1261,16 +1381,10 @@ int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
partial_->OnNetworkReadCompleted(result);
- if (result == 0) { // End of file.
- if (mode_ == READ_WRITE) {
- // We need to move on to the next range.
- network_trans_.reset();
- result = ContinuePartialCacheValidation();
- if (result != OK)
- // Any error was already handled.
- return result;
- }
- DoneWritingToEntry(true);
+ if (result == 0) {
+ // We need to move on to the next range.
+ network_trans_.reset();
+ next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
}
return result;
}
@@ -1296,18 +1410,9 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
partial_->OnCacheReadCompleted(result);
- if (result == 0) { // End of file.
- if (partial_.get() && mode_ == READ_WRITE) {
- // We need to move on to the next range.
- result = ContinuePartialCacheValidation();
- if (result != OK || !entry_) {
- // Any error was already handled.
- return result;
- }
- cache_->ConvertWriterToReader(entry_);
- }
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
+ if (result == 0 && mode_ == READ_WRITE) {
+ // We need to move on to the next range.
+ next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
}
return result;
}
@@ -1420,19 +1525,11 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
}
if (reading_ && partial_.get()) {
if (network_trans_.get()) {
- next_state_ = STATE_NETWORK_READ_COMPLETE;
- result = ReadFromNetwork(read_buf_, read_buf_len_);
- } else {
- next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
- result = ReadFromEntry(read_buf_, read_buf_len_);
- }
- if (result >= 0 || result == ERR_IO_PENDING) {
- // Keep looping.
- return result;
+ next_state_ = STATE_NETWORK_READ;
} else {
- // Don't keep looping when we return.
- next_state_ = STATE_NONE;
+ next_state_ = STATE_CACHE_READ_DATA;
}
+ result = OK;
} else if (mode_ != NONE && partial_.get()) {
// We are about to return the headers for a byte-range request to the
// user, so let's fix them.
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 0b7e517..b396010 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -96,11 +96,11 @@ class HttpCache::Transaction : public HttpTransaction {
enum State {
STATE_NONE,
- STATE_START_REQUEST,
STATE_SEND_REQUEST,
STATE_SEND_REQUEST_COMPLETE,
STATE_NETWORK_READ,
STATE_NETWORK_READ_COMPLETE,
+ STATE_INIT_ENTRY,
STATE_OPEN_ENTRY,
STATE_OPEN_ENTRY_COMPLETE,
STATE_CREATE_ENTRY,
@@ -108,8 +108,8 @@ class HttpCache::Transaction : public HttpTransaction {
STATE_DOOM_ENTRY,
STATE_DOOM_ENTRY_COMPLETE,
STATE_ADD_TO_ENTRY,
- STATE_ADD_TO_ENTRY_COMPLETE,
STATE_ENTRY_AVAILABLE,
+ STATE_PARTIAL_CACHE_VALIDATION,
STATE_CACHE_READ_RESPONSE,
STATE_CACHE_READ_RESPONSE_COMPLETE,
STATE_CACHE_WRITE_RESPONSE,
@@ -132,11 +132,23 @@ class HttpCache::Transaction : public HttpTransaction {
// Runs the state transition loop.
int DoLoop(int result);
- // Each of these methods corresponds to a State value.
+ // Each of these methods corresponds to a State value. If there is an
+ // argument, the value corresponds to the return of the previous state or
+ // corresponding callback.
int DoSendRequest();
int DoSendRequestComplete(int result);
int DoNetworkRead();
int DoNetworkReadComplete(int result);
+ int DoInitEntry();
+ int DoOpenEntry();
+ int DoOpenEntryComplete();
+ int DoCreateEntry();
+ int DoCreateEntryComplete();
+ int DoDoomEntry();
+ int DoDoomEntryComplete();
+ int DoAddToEntry();
+ int DoEntryAvailable();
+ int DoPartialCacheValidation();
int DoCacheReadData();
int DoCacheReadDataComplete(int result);
int DoCacheQueryData();
@@ -165,11 +177,6 @@ class HttpCache::Transaction : public HttpTransaction {
// 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).
@@ -265,6 +272,7 @@ class HttpCache::Transaction : public HttpTransaction {
ValidationHeaders external_validation_;
base::WeakPtr<HttpCache> cache_;
HttpCache::ActiveEntry* entry_;
+ HttpCache::ActiveEntry* new_entry_;
scoped_ptr<HttpTransaction> network_trans_;
CompletionCallback* callback_; // Consumer's callback.
HttpResponseInfo response_;