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

Unified Diff: net/http/http_cache_transaction.cc

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Initial patch Created 4 years 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
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index b8f1eb06b2f9eae0f29072e47e64ecadb800d03e..7f93f704ddcad05ff275395570b74490e059c357 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -180,6 +180,9 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
couldnt_conditionalize_request_(false),
bypass_lock_for_test_(false),
fail_conditionalization_for_test_(false),
+ shared_(false),
+ finalize_doomed_(false),
+ orphaned_(false),
io_buf_len_(0),
read_offset_(0),
effective_load_flags_(0),
@@ -189,6 +192,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
total_received_bytes_(0),
total_sent_bytes_(0),
websocket_handshake_stream_base_create_helper_(NULL),
+ have_full_request_headers_(false),
weak_factory_(this) {
TRACE_EVENT0("io", "HttpCacheTransaction::Transaction");
static_assert(HttpCache::Transaction::kNumValidationHeaders ==
@@ -201,12 +205,18 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
HttpCache::Transaction::~Transaction() {
TRACE_EVENT0("io", "HttpCacheTransaction::~Transaction");
+
+ // Assert to make sure that any owner of HttpCache::Transaction always invokes
+ // Orphan and not the destructor directly.
+ DCHECK(orphaned_);
+
// We may have to issue another IO, but we should never invoke the callback_
// after this point.
callback_.Reset();
+ weak_factory_.InvalidateWeakPtrs();
if (cache_) {
- if (entry_) {
+ if (entry_ && !finalize_doomed_) {
bool cancel_request = reading_ && response_.headers.get();
if (cancel_request) {
if (partial_) {
@@ -215,7 +225,6 @@ HttpCache::Transaction::~Transaction() {
cancel_request &= (response_.headers->response_code() == 200);
}
}
-
cache_->DoneWithEntry(entry_, this, cancel_request);
} else if (cache_pending_) {
cache_->RemovePendingTransaction(this);
@@ -262,6 +271,8 @@ bool HttpCache::Transaction::AddTruncatedFlag() {
LoadState HttpCache::Transaction::GetWriterLoadState() const {
if (network_trans_.get())
return network_trans_->GetLoadState();
+ if (shared_ && entry_)
+ return entry_->shared_writers->GetLoadState();
if (entry_ || !request_)
return LOAD_STATE_IDLE;
return LOAD_STATE_WAITING_FOR_CACHE;
@@ -371,6 +382,10 @@ bool HttpCache::Transaction::IsReadyToRestartForAuth() {
int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
+ if (next_state_ == STATE_SHARED_READ_WRITE_FAILED) {
+ return ERR_CACHE_WRITE_FAILURE;
+ }
+
DCHECK_EQ(next_state_, STATE_NONE);
DCHECK(buf);
DCHECK_GT(buf_len, 0);
@@ -395,12 +410,21 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
read_buf_ = buf;
io_buf_len_ = buf_len;
if (network_trans_) {
+ DCHECK(!shared_);
DCHECK(mode_ == WRITE || mode_ == NONE ||
(mode_ == READ_WRITE && partial_));
next_state_ = STATE_NETWORK_READ;
- } else {
+ } else if (!shared_) {
DCHECK(mode_ == READ || (mode_ == READ_WRITE && partial_));
next_state_ = STATE_CACHE_READ_DATA;
+ } else { // uses SharedWriters
+ if (read_offset_ == entry_->disk_entry->GetDataSize(kResponseContentIndex))
+ next_state_ = STATE_SHARED_NETWORK_READ;
+ else {
+ DCHECK_LT(read_offset_,
+ entry_->disk_entry->GetDataSize(kResponseContentIndex));
+ next_state_ = STATE_CACHE_READ_DATA;
+ }
}
int rv = DoLoop(OK);
@@ -424,8 +448,13 @@ void HttpCache::Transaction::StopCaching() {
// TODO(mmenke): This doesn't release the lock on the cache entry, so a
// future request for the resource will be blocked on this one.
// Fix this.
- if (cache_.get() && entry_ && (mode_ & WRITE) && network_trans_.get() &&
- !is_sparse_ && !range_requested_) {
+ if (shared_) {
+ // This might or might not stop caching based on whether other consumers
+ // exist for this resource or not. If it does, shared_ will be set to false.
+ network_trans_ = cache_->StopCachingSharedWriters(this, entry_);
+ }
+ if (!shared_ && cache_.get() && entry_ && (mode_ & WRITE) &&
+ network_trans_.get() && !is_sparse_ && !range_requested_) {
mode_ = NONE;
}
}
@@ -434,7 +463,12 @@ bool HttpCache::Transaction::GetFullRequestHeaders(
HttpRequestHeaders* headers) const {
if (network_trans_)
return network_trans_->GetFullRequestHeaders(headers);
-
+ else if (shared_) {
+ return entry_->shared_writers->GetFullRequestHeaders(headers);
+ } else if (have_full_request_headers_) {
+ *headers = full_request_headers_;
+ return true;
+ }
// TODO(juliatuttle): Read headers from cache.
return false;
}
@@ -443,6 +477,9 @@ int64_t HttpCache::Transaction::GetTotalReceivedBytes() const {
int64_t total_received_bytes = total_received_bytes_;
if (network_trans_)
total_received_bytes += network_trans_->GetTotalReceivedBytes();
+ else if (shared_) {
+ total_received_bytes += entry_->shared_writers->GetTotalReceivedBytes();
+ }
return total_received_bytes;
}
@@ -450,14 +487,23 @@ int64_t HttpCache::Transaction::GetTotalSentBytes() const {
int64_t total_sent_bytes = total_sent_bytes_;
if (network_trans_)
total_sent_bytes += network_trans_->GetTotalSentBytes();
+ else if (shared_) {
+ total_sent_bytes += entry_->shared_writers->GetTotalSentBytes();
+ }
return total_sent_bytes;
}
void HttpCache::Transaction::DoneReading() {
if (cache_.get() && entry_) {
DCHECK_NE(mode_, UPDATE);
+ bool perform_entry_cleanup = true;
+ if (shared_) {
+ cache_->DoneReadingSharedWriters(this, entry_);
+ // entry_ cleanup already performed, if any.
+ perform_entry_cleanup = false;
+ }
if (mode_ & WRITE) {
- DoneWritingToEntry(true);
+ DoneWritingToEntry(true, perform_entry_cleanup);
} else if (mode_ & READ) {
// It is necessary to check mode_ & READ because it is possible
// for mode_ to be NONE and entry_ non-NULL with a write entry
@@ -498,6 +544,8 @@ bool HttpCache::Transaction::GetLoadTimingInfo(
LoadTimingInfo* load_timing_info) const {
if (network_trans_)
return network_trans_->GetLoadTimingInfo(load_timing_info);
+ else if (shared_)
+ return entry_->shared_writers->GetLoadTimingInfo(load_timing_info);
if (old_network_trans_load_timing_) {
*load_timing_info = *old_network_trans_load_timing_;
@@ -518,6 +566,8 @@ bool HttpCache::Transaction::GetLoadTimingInfo(
bool HttpCache::Transaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
if (network_trans_)
return network_trans_->GetRemoteEndpoint(endpoint);
+ else if (shared_)
+ return entry_->shared_writers->GetRemoteEndpoint(endpoint);
if (!old_remote_endpoint_.address().empty()) {
*endpoint = old_remote_endpoint_;
@@ -531,6 +581,8 @@ void HttpCache::Transaction::PopulateNetErrorDetails(
NetErrorDetails* details) const {
if (network_trans_)
return network_trans_->PopulateNetErrorDetails(details);
+ else if (shared_)
+ return entry_->shared_writers->PopulateNetErrorDetails(details);
return;
}
@@ -538,6 +590,8 @@ void HttpCache::Transaction::SetPriority(RequestPriority priority) {
priority_ = priority;
if (network_trans_)
network_trans_->SetPriority(priority_);
+ else if (shared_)
+ return entry_->shared_writers->SetPriority(priority_);
}
void HttpCache::Transaction::SetWebSocketHandshakeStreamCreateHelper(
@@ -545,6 +599,10 @@ void HttpCache::Transaction::SetWebSocketHandshakeStreamCreateHelper(
websocket_handshake_stream_base_create_helper_ = create_helper;
if (network_trans_)
network_trans_->SetWebSocketHandshakeStreamCreateHelper(create_helper);
+ else if (shared_) {
+ return entry_->shared_writers->SetWebSocketHandshakeStreamCreateHelper(
+ create_helper);
+ }
}
void HttpCache::Transaction::SetBeforeNetworkStartCallback(
@@ -562,6 +620,8 @@ void HttpCache::Transaction::SetBeforeHeadersSentCallback(
int HttpCache::Transaction::ResumeNetworkStart() {
if (network_trans_)
return network_trans_->ResumeNetworkStart();
+ else if (shared_)
+ return entry_->shared_writers->ResumeNetworkStart();
return ERR_UNEXPECTED;
}
@@ -570,6 +630,9 @@ void HttpCache::Transaction::GetConnectionAttempts(
ConnectionAttempts new_connection_attempts;
if (network_trans_)
network_trans_->GetConnectionAttempts(&new_connection_attempts);
+ else if (shared_) {
+ entry_->shared_writers->GetConnectionAttempts(&new_connection_attempts);
+ }
out->swap(new_connection_attempts);
out->insert(out->begin(), old_connection_attempts_.begin(),
@@ -852,6 +915,16 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_NETWORK_READ_COMPLETE:
rv = DoNetworkReadComplete(rv);
break;
+ case STATE_SHARED_NETWORK_READ:
+ DCHECK_EQ(OK, rv);
+ rv = DoSharedNetworkRead();
+ break;
+ case STATE_SHARED_NETWORK_READ_COMPLETE:
+ rv = DoSharedNetworkReadComplete(rv);
+ break;
+ case STATE_SHARED_NETWORK_READ_WAIT_COMPLETE:
+ rv = DoSharedNetworkReadWaitComplete(rv);
+ break;
case STATE_CACHE_READ_DATA:
DCHECK_EQ(OK, rv);
rv = DoCacheReadData();
@@ -1508,6 +1581,27 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
return OK;
}
+ // If the transaction is shared and it is a 200 or an error response, then
+ // doom the entry and let this transaction continue without writing to the
+ // cache if shared writers contain more transactions. If not, continue
+ // writing to the cache and also transfer the network transaction to shared
+ // writers.
+ if (shared_ && new_response->headers->response_code() != 304) {
+ network_trans_ = cache_->ValidationNoMatchSharedWriters(
+ cache_key_, this, std::move(network_trans_), priority_, entry_);
+ if (!shared_) {
+ DCHECK(network_trans_);
+ if (cache_entry_status_ == CacheEntryStatus::ENTRY_UNDEFINED) {
+ UpdateCacheEntryStatus(
+ CacheEntryStatus::ENTRY_VALIDATED_DOOM_SHARED_WRITING);
+ }
+ DoneWritingToEntry(false, false);
+ return OK;
+ } else {
+ DCHECK(!network_trans_);
+ }
+ }
+
// Are we expecting a response to a conditional query?
if (mode_ == READ_WRITE || mode_ == UPDATE) {
if (new_response->headers->response_code() == 304 || handling_206_) {
@@ -1653,7 +1747,40 @@ int HttpCache::Transaction::DoCacheWriteResponse() {
int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete");
next_state_ = STATE_TRUNCATE_CACHED_DATA;
- return OnWriteResponseInfoToEntryComplete(result);
+ int res = OnWriteResponseInfoToEntryComplete(result);
+
+ if (res != OK)
+ return result;
+
+ return OK;
+}
+
+void HttpCache::Transaction::ResetShared(bool continue_network_reading,
+ bool continue_cache_reading) {
+ if (!continue_network_reading) {
+ SaveSharedNetworkTransInfo();
+ }
+ if (continue_cache_reading) {
+ mode_ = READ;
+ }
+ shared_ = false;
+}
+
+void HttpCache::Transaction::SetFinalizeDoomed() {
+ finalize_doomed_ = true;
+}
+
+void HttpCache::Transaction::SetShared() {
+ shared_ = true;
+}
+
+bool HttpCache::Transaction::shared() const {
+ return shared_;
+}
+
+bool HttpCache::Transaction::validating_shared() const {
+ return shared_ && next_state_ != STATE_NONE &&
+ next_state_ <= STATE_START_STATE_MACHINE_FINAL;
}
int HttpCache::Transaction::DoTruncateCachedData() {
@@ -1704,11 +1831,46 @@ int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) {
return OK;
}
+void HttpCache::Transaction::ProcessForSharedWriting() {
+ // Should not be already reading.
+ if (reading_)
+ return;
+
+ // If not already part of SharedWriters, then check if one should be
+ // created.
+ if (!shared_ && !IsEligibleForSharedWriting())
+ return;
+
+ if (shared_) {
+ // Non 304 case is already handled in DoSuccessfulSendRequest.
+ if (response_.headers->response_code() != 304) {
+ return;
+ }
+ UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_VALIDATED_DO_SHARED_WRITING);
+ cache_->ValidationMatchSharedWriters(this, priority_, entry_);
+ network_trans_.reset();
+ return;
+ }
+
+ // Do not create a SharedWriters if its a Redirect response.
+ if (response_.headers->response_code() != 200)
+ return;
+
+ // or if its a no-store response.
+ if (!entry_)
+ return;
+
+ DCHECK(entry_ && network_trans_);
+ cache_->CreateSharedWriters(this, std::move(network_trans_), priority_);
+}
+
int HttpCache::Transaction::DoPartialHeadersReceived() {
new_response_ = NULL;
if (entry_ && !partial_ && entry_->disk_entry->GetDataSize(kMetadataIndex))
next_state_ = STATE_CACHE_READ_METADATA;
+ ProcessForSharedWriting();
+
if (!partial_)
return OK;
@@ -1754,6 +1916,7 @@ int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
int HttpCache::Transaction::DoNetworkRead() {
TRACE_EVENT0("io", "HttpCacheTransaction::DoNetworkRead");
next_state_ = STATE_NETWORK_READ_COMPLETE;
+
return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_);
}
@@ -1773,6 +1936,57 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) {
return result;
}
+int HttpCache::Transaction::DoSharedNetworkRead() {
+ next_state_ = STATE_SHARED_NETWORK_READ_COMPLETE;
+ bool shared_read_in_progress = false;
+ int result =
+ entry_->shared_writers->Read(read_buf_.get(), io_buf_len_, io_callback_,
+ this, shared_read_in_progress);
+ if (shared_read_in_progress) {
+ next_state_ = STATE_SHARED_NETWORK_READ_WAIT_COMPLETE;
+ }
+ return result;
+}
+
+int HttpCache::Transaction::DoSharedNetworkReadComplete(int result) {
+ if (result < 0) {
+ cache_->NetworkReadFailedSharedWriters(this, entry_, result);
+
+ // Set entry as null so that the destructor does not invoke DoneWithEntry
+ // again as we have already processed the entry_ in
+ // NetworkReadFailedSharedWriters
+ entry_ = nullptr;
+ return result;
+ }
+
+ read_offset_ += result;
+ entry_->shared_writers->OnNetworkReadSuccess(this, read_buf_, result);
+
+ next_state_ = STATE_CACHE_WRITE_DATA;
+ return result;
+}
+
+int HttpCache::Transaction::DoSharedNetworkReadWaitComplete(int result) {
+ // If its a network read failure, we just return the result.
+ // If its a cache write failure, we return the result which is filled as -1
+ // by SharedWriters,
+ // If its a cache write success, read_buf_ would have been filled
+ // with the read data by SharedWriters, so just return from here.
+
+ if (result == 0) { // response is complete.
+ DoneWritingToEntry(true, false); // changes the mode_ to NONE.
+ } else if (result > 0) {
+ read_offset_ += result;
+ } else {
+ // Set entry as null so that the destructor does not invoke DoneWithEntry
+ // again as we have already processed the entry_ in
+ // NetworkReadFailedSharedWriters
+ entry_ = nullptr;
+ }
+
+ return result;
+}
+
int HttpCache::Transaction::DoCacheReadData() {
TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadData");
if (request_->method == "HEAD")
@@ -1852,7 +2066,14 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
if (result != write_len_) {
DLOG(ERROR) << "failed to write response data to cache";
- DoneWritingToEntry(false);
+ if (shared_) {
+ // Fail any shared writers.
+ network_trans_.reset(cache_->CacheWriteFailedSharedWriters(this, entry_));
+ DCHECK(network_trans_);
+ DoneWritingToEntry(false, false);
+ } else {
+ DoneWritingToEntry(false);
+ }
// We want to ignore errors writing to disk and just keep reading from
// the network.
@@ -1872,15 +2093,28 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
}
}
+ bool complete = false;
if (result == 0) {
// End of file. This may be the result of a connection problem so see if we
// have to keep the entry around to be flagged as truncated later on.
if (done_reading_ || !entry_ || partial_ ||
response_.headers->GetContentLength() <= 0) {
- DoneWritingToEntry(true);
+ complete = true;
}
}
+ bool perform_entry_cleanup = true;
+ if (shared_) {
+ if (result || (!result && complete)) {
+ cache_->CacheWriteSuccessSharedWriters(this, entry_, result);
+ // entry_ cleanup already performed, if any.
+ perform_entry_cleanup = false;
+ }
+ }
+ if (complete) {
+ DoneWritingToEntry(true, perform_entry_cleanup);
+ }
+
return result;
}
@@ -2089,8 +2323,14 @@ int HttpCache::Transaction::BeginCacheValidation() {
}
if (skip_validation) {
- UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
- return SetupEntryForRead();
+ if (shared_) {
+ UpdateCacheEntryStatus(
+ CacheEntryStatus::ENTRY_SKIP_VALIDATION_DO_SHARED_WRITING);
+ entry_->shared_writers->OnValidationMatch(this, priority_);
+ } else {
+ UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
+ return SetupEntryForRead();
+ }
} else {
// Make the network request conditional, to see if we may reuse our cached
// response. If we cannot do so, then we just resort to a normal fetch.
@@ -2241,6 +2481,49 @@ int HttpCache::Transaction::RestartNetworkRequestWithAuth(
return rv;
}
+void HttpCache::Transaction::Orphan(std::unique_ptr<HttpTransaction> trans) {
+ DCHECK_EQ(trans.get(), this);
+ orphaned_ = true;
+
+ // Reset consumer's callback.
+ callback_.Reset();
+
+ if (shared_) {
+ if (next_state_ == STATE_SHARED_NETWORK_READ_COMPLETE ||
+ next_state_ == STATE_CACHE_WRITE_DATA_COMPLETE) {
+ // Might lead to setting shared_ to false if this is the only transaction
+ // in SharedWriters.
+ cache_->DoomCurrentSharedWriter(std::move(trans), entry_);
+ } else if (next_state_ == STATE_SHARED_NETWORK_READ_WAIT_COMPLETE) {
+ entry_->shared_writers->RemoveWaitingWriter(this);
+ } else if (next_state_ != STATE_NONE &&
+ next_state_ <= STATE_ADD_TO_ENTRY_COMPLETE) {
+ cache_->RemovePendingTransaction(this);
+ // Set cache_pending_ to false so that more cleanup is not attempted in
+ // the destructor.
+ cache_pending_ = false;
+ } else if (validating_shared()) {
+ cache_->RemoveValidatingTransSharedWriters(this, entry_);
+ } else {
+ bool cancel_request = reading_ && response_.headers.get();
+ if (cancel_request) {
+ cancel_request &= (response_.headers->response_code() == 200);
+ }
+ cache_->RemoveIdleSharedWriter(this, entry_, cancel_request);
+ }
+
+ if (!shared_) {
+ // Since any cleanup needed in entry_ and shared_writers is already done,
+ // set entry_ to null.
+ entry_ = nullptr;
+ }
+ }
+
+ if (!shared_) {
+ trans.reset();
+ }
+}
+
ValidationType HttpCache::Transaction::RequiresValidation() {
// TODO(darin): need to do more work here:
// - make sure we have a matching request method
@@ -2573,8 +2856,10 @@ int HttpCache::Transaction::WriteToEntry(int index, int offset,
int rv = 0;
if (!partial_ || !data_len) {
- rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback,
- true);
+ CompletionCallback io_callback = callback;
+
+ rv = entry_->disk_entry->WriteData(index, offset, data, data_len,
+ io_callback, true);
} else {
rv = partial_->CacheWrite(entry_->disk_entry, data, data_len, callback);
}
@@ -2634,17 +2919,28 @@ int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
return OK;
}
-void HttpCache::Transaction::DoneWritingToEntry(bool success) {
+void HttpCache::Transaction::DoneWritingToEntry(bool success,
+ bool perform_entry_cleanup) {
if (!entry_)
return;
RecordHistograms();
- cache_->DoneWritingToEntry(entry_, success);
- entry_ = NULL;
+ if (perform_entry_cleanup) {
+ cache_->DoneWritingToEntry(entry_, success);
+ }
+ entry_ = nullptr;
mode_ = NONE; // switch to 'pass through' mode
}
+void HttpCache::Transaction::ContinueWithoutSharedWriting() {
+ // Should own a network transaction to continue.
+ DCHECK(network_trans_);
+ shared_ = false;
+ entry_ = nullptr;
+ mode_ = NONE;
+}
+
int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
DLOG(ERROR) << "ReadData failed: " << result;
const int result_for_histogram = std::max(0, -result);
@@ -2663,7 +2959,11 @@ int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
if (restart) {
DCHECK(!reading_);
DCHECK(!network_trans_.get());
- cache_->DoneWithEntry(entry_, this, false);
+ if (shared_) {
+ cache_->RemoveValidatingTransSharedWriters(this, entry_);
+ } else {
+ cache_->DoneWithEntry(entry_, this, false);
+ }
entry_ = NULL;
is_sparse_ = false;
partial_.reset();
@@ -2688,6 +2988,8 @@ void HttpCache::Transaction::OnAddToEntryTimeout(base::TimeTicks start_time) {
}
void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
+ // Partial requests not supported with shared writing as of now.
+ DCHECK(!shared_);
DVLOG(2) << "DoomPartialEntry";
int rv = cache_->DoomEntry(cache_key_, NULL);
DCHECK_EQ(OK, rv);
@@ -2748,7 +3050,7 @@ void HttpCache::Transaction::ResetPartialState(bool delete_object) {
}
}
-void HttpCache::Transaction::ResetNetworkTransaction() {
+void HttpCache::Transaction::SaveNetworkTransInfo() {
DCHECK(!old_network_trans_load_timing_);
DCHECK(network_trans_);
LoadTimingInfo load_timing;
@@ -2762,6 +3064,37 @@ void HttpCache::Transaction::ResetNetworkTransaction() {
old_connection_attempts_.push_back(attempt);
old_remote_endpoint_ = IPEndPoint();
network_trans_->GetRemoteEndpoint(&old_remote_endpoint_);
+}
+
+void HttpCache::Transaction::SaveSharedNetworkTransInfo() {
+ // If network_trans_ is still present, this transaction has not started using
+ // the "shared" network transaction, so do nothing.
+ if (network_trans_)
+ return;
+ DCHECK(!old_network_trans_load_timing_);
+
+ // If the transaction is being deleted while still in the waiting queue,
+ // entry_ is not yet set, do nothing.
+ if (!entry_)
+ return;
+ DCHECK(entry_->shared_writers);
+ LoadTimingInfo load_timing;
+ if (entry_->shared_writers->GetLoadTimingInfo(&load_timing))
+ old_network_trans_load_timing_.reset(new LoadTimingInfo(load_timing));
+ total_received_bytes_ += entry_->shared_writers->GetTotalReceivedBytes();
+ total_sent_bytes_ += entry_->shared_writers->GetTotalSentBytes();
+ ConnectionAttempts attempts;
+ entry_->shared_writers->GetConnectionAttempts(&attempts);
+ for (const auto& attempt : attempts)
+ old_connection_attempts_.push_back(attempt);
+ old_remote_endpoint_ = IPEndPoint();
+ entry_->shared_writers->GetRemoteEndpoint(&old_remote_endpoint_);
+ have_full_request_headers_ =
+ entry_->shared_writers->GetFullRequestHeaders(&full_request_headers_);
+}
+
+void HttpCache::Transaction::ResetNetworkTransaction() {
+ SaveNetworkTransInfo();
network_trans_.reset();
}
@@ -2929,19 +3262,35 @@ void HttpCache::Transaction::RecordHistograms() {
UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone", total_time);
+ if (cache_entry_status_ ==
+ CacheEntryStatus::ENTRY_VALIDATED_DO_SHARED_WRITING) {
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.ValidationMatchSharedWriting",
+ total_time);
+ }
+
bool did_send_request = !send_request_since_.is_null();
- DCHECK(
- (did_send_request &&
- (cache_entry_status_ == CacheEntryStatus::ENTRY_NOT_IN_CACHE ||
- cache_entry_status_ == CacheEntryStatus::ENTRY_VALIDATED ||
- cache_entry_status_ == CacheEntryStatus::ENTRY_UPDATED ||
- cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE)) ||
- (!did_send_request &&
- cache_entry_status_ == CacheEntryStatus::ENTRY_USED));
+ DCHECK((did_send_request &&
+ (cache_entry_status_ == CacheEntryStatus::ENTRY_NOT_IN_CACHE ||
+ cache_entry_status_ == CacheEntryStatus::ENTRY_VALIDATED ||
+ cache_entry_status_ == CacheEntryStatus::ENTRY_UPDATED ||
+ cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE ||
+ cache_entry_status_ ==
+ CacheEntryStatus::ENTRY_VALIDATED_DO_SHARED_WRITING ||
+ cache_entry_status_ ==
+ CacheEntryStatus::ENTRY_VALIDATED_DOOM_SHARED_WRITING)) ||
+ (!did_send_request &&
+ (cache_entry_status_ == CacheEntryStatus::ENTRY_USED ||
+ cache_entry_status_ ==
+ CacheEntryStatus::ENTRY_SKIP_VALIDATION_DO_SHARED_WRITING)));
if (!did_send_request) {
- DCHECK(cache_entry_status_ == CacheEntryStatus::ENTRY_USED);
- UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time);
+ if (cache_entry_status_ == CacheEntryStatus::ENTRY_USED) {
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time);
+ } else if (cache_entry_status_ ==
+ CacheEntryStatus::ENTRY_SKIP_VALIDATION_DO_SHARED_WRITING) {
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SkipValidationSharedWriting",
+ total_time);
+ }
return;
}
@@ -2986,13 +3335,58 @@ void HttpCache::Transaction::RecordHistograms() {
before_send_sample);
break;
}
+ case CacheEntryStatus::ENTRY_VALIDATED_DO_SHARED_WRITING: {
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.ValidationMatchSharedWriting",
+ before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.ValidationMatchSharedWriting",
+ before_send_sample);
+ break;
+ }
+ case CacheEntryStatus::ENTRY_VALIDATED_DOOM_SHARED_WRITING: {
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.ValidationDoomSharedWriting",
+ before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.ValidationDoomSharedWriting",
+ before_send_sample);
+ break;
+ }
default:
NOTREACHED();
}
}
+bool HttpCache::Transaction::IsEligibleForSharedWriting() const {
+ if (!(mode_ & WRITE))
+ return false;
+
+ DCHECK(request_);
+ if (request_->method != "GET")
+ return false;
+
+ if (partial_ || range_requested_)
+ return false;
+
+ return true;
+}
+
+void HttpCache::Transaction::SetSharedWritingFailState() {
+ // This state should only be set when the transaction is idle waiting for Read
+ // to be invoked.
+ DCHECK_EQ(next_state_, STATE_NONE);
+ next_state_ = STATE_SHARED_READ_WRITE_FAILED;
+ entry_ = nullptr;
+}
+
void HttpCache::Transaction::OnIOComplete(int result) {
+ // Setting this in a local variable because if the consumer still exists, its
+ // possible for this object to get destroyed during the consumer's callback
+ // processing.
+ bool orphaned = orphaned_;
DoLoop(result);
+ if (orphaned && finalize_doomed_) {
jkarlin 2016/12/06 21:06:28 finalized_doomed_ should cause a crash if this obj
shivanisha 2016/12/06 21:53:35 The underlying assumption here is that since orpha
jkarlin 2016/12/07 01:09:04 Makes sense, thanks.
+ cache_->FinalizeDoomedSharedWriter(entry_);
jkarlin 2016/12/06 21:06:28 Also entry_
shivanisha 2016/12/06 21:53:35 Same as above.
shivanisha 2016/12/07 00:09:02 For clarity, I will add a comment for this assumpt
+ }
}
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698