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

Side by Side Diff: net/http/http_cache_transaction.cc

Issue 2886483002: Adds a new class HttpCache::Writers for multiple cache transactions reading from the network. (Closed)
Patch Set: Feedback addressed. Created 3 years, 5 months 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_cache_transaction.h" 5 #include "net/http/http_cache_transaction.h"
6 6
7 #include "build/build_config.h" // For OS_POSIX 7 #include "build/build_config.h" // For OS_POSIX
8 8
9 #if defined(OS_POSIX) 9 #if defined(OS_POSIX)
10 #include <unistd.h> 10 #include <unistd.h>
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 new_response_(NULL), 158 new_response_(NULL),
159 mode_(NONE), 159 mode_(NONE),
160 reading_(false), 160 reading_(false),
161 invalid_range_(false), 161 invalid_range_(false),
162 truncated_(false), 162 truncated_(false),
163 is_sparse_(false), 163 is_sparse_(false),
164 range_requested_(false), 164 range_requested_(false),
165 handling_206_(false), 165 handling_206_(false),
166 cache_pending_(false), 166 cache_pending_(false),
167 done_reading_(false), 167 done_reading_(false),
168 done_headers_create_new_entry_(false),
168 vary_mismatch_(false), 169 vary_mismatch_(false),
169 couldnt_conditionalize_request_(false), 170 couldnt_conditionalize_request_(false),
170 bypass_lock_for_test_(false), 171 bypass_lock_for_test_(false),
171 bypass_lock_after_headers_for_test_(false), 172 bypass_lock_after_headers_for_test_(false),
172 fail_conditionalization_for_test_(false), 173 fail_conditionalization_for_test_(false),
173 io_buf_len_(0), 174 io_buf_len_(0),
174 read_offset_(0), 175 read_offset_(0),
175 effective_load_flags_(0), 176 effective_load_flags_(0),
176 write_len_(0), 177 write_len_(0),
177 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), 178 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED),
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 573
573 next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED; 574 next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED;
574 entry_ = nullptr; 575 entry_ = nullptr;
575 } 576 }
576 577
577 size_t HttpCache::Transaction::EstimateMemoryUsage() const { 578 size_t HttpCache::Transaction::EstimateMemoryUsage() const {
578 // TODO(xunjieli): Consider improving the coverage. crbug.com/669108. 579 // TODO(xunjieli): Consider improving the coverage. crbug.com/669108.
579 return 0; 580 return 0;
580 } 581 }
581 582
583 void HttpCache::Transaction::SetSharedWritingFailState(int result) {
584 // TODO(shivanisha): Implement when integrating with HttpCache::Writers.
585 NOTIMPLEMENTED();
586 }
587
582 //----------------------------------------------------------------------------- 588 //-----------------------------------------------------------------------------
583 589
584 // A few common patterns: (Foo* means Foo -> FooComplete) 590 // A few common patterns: (Foo* means Foo -> FooComplete)
585 // 591 //
586 // 1. Not-cached entry: 592 // 1. Not-cached entry:
587 // Start(): 593 // Start():
588 // GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* -> 594 // GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
589 // SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse -> 595 // SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
590 // CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* -> 596 // CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
591 // PartialHeadersReceived -> FinishHeaders* 597 // PartialHeadersReceived -> FinishHeaders*
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 case STATE_CREATE_ENTRY_COMPLETE: 759 case STATE_CREATE_ENTRY_COMPLETE:
754 rv = DoCreateEntryComplete(rv); 760 rv = DoCreateEntryComplete(rv);
755 break; 761 break;
756 case STATE_ADD_TO_ENTRY: 762 case STATE_ADD_TO_ENTRY:
757 DCHECK_EQ(OK, rv); 763 DCHECK_EQ(OK, rv);
758 rv = DoAddToEntry(); 764 rv = DoAddToEntry();
759 break; 765 break;
760 case STATE_ADD_TO_ENTRY_COMPLETE: 766 case STATE_ADD_TO_ENTRY_COMPLETE:
761 rv = DoAddToEntryComplete(rv); 767 rv = DoAddToEntryComplete(rv);
762 break; 768 break;
769 case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE:
770 rv = DoDoneHeadersAddToEntryComplete(rv);
771 break;
763 case STATE_CACHE_READ_RESPONSE: 772 case STATE_CACHE_READ_RESPONSE:
764 DCHECK_EQ(OK, rv); 773 DCHECK_EQ(OK, rv);
765 rv = DoCacheReadResponse(); 774 rv = DoCacheReadResponse();
766 break; 775 break;
767 case STATE_CACHE_READ_RESPONSE_COMPLETE: 776 case STATE_CACHE_READ_RESPONSE_COMPLETE:
768 rv = DoCacheReadResponseComplete(rv); 777 rv = DoCacheReadResponseComplete(rv);
769 break; 778 break;
770 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: 779 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH:
771 DCHECK_EQ(OK, rv); 780 DCHECK_EQ(OK, rv);
772 rv = DoCacheToggleUnusedSincePrefetch(); 781 rv = DoCacheToggleUnusedSincePrefetch();
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 case ERR_CACHE_RACE: 1121 case ERR_CACHE_RACE:
1113 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); 1122 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1114 break; 1123 break;
1115 1124
1116 default: 1125 default:
1117 // We have a race here: Maybe we failed to open the entry and decided to 1126 // We have a race here: Maybe we failed to open the entry and decided to
1118 // create one, but by the time we called create, another transaction 1127 // create one, but by the time we called create, another transaction
1119 // already created the entry. If we want to eliminate this issue, we 1128 // already created the entry. If we want to eliminate this issue, we
1120 // need an atomic OpenOrCreate() method exposed by the disk cache. 1129 // need an atomic OpenOrCreate() method exposed by the disk cache.
1121 DLOG(WARNING) << "Unable to create cache entry"; 1130 DLOG(WARNING) << "Unable to create cache entry";
1131
1132 // Set the mode to NONE in order to bypass the cache entry and read from
1133 // the network directly.
1122 mode_ = NONE; 1134 mode_ = NONE;
1123 if (partial_) 1135 if (!done_headers_create_new_entry_) {
1124 partial_->RestoreHeaders(&custom_request_->extra_headers); 1136 if (partial_)
1125 TransitionToState(STATE_SEND_REQUEST); 1137 partial_->RestoreHeaders(&custom_request_->extra_headers);
1138 TransitionToState(STATE_SEND_REQUEST);
1139 return OK;
1140 }
1141 // The headers have already been received as a result of validation,
1142 // triggering the doom of the old entry. So no network request needs to
1143 // be sent. Note that since mode_ is NONE, the response won't be written
1144 // to cache. Transition to STATE_CACHE_WRITE_RESPONSE as that's the state
1145 // the transaction left off on when it tried to create the new entry.
1146 done_headers_create_new_entry_ = false;
1147 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1126 } 1148 }
1127 return OK; 1149 return OK;
1128 } 1150 }
1129 1151
1130 int HttpCache::Transaction::DoAddToEntry() { 1152 int HttpCache::Transaction::DoAddToEntry() {
1131 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); 1153 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry");
1132 DCHECK(new_entry_); 1154 DCHECK(new_entry_);
1133 cache_pending_ = true; 1155 cache_pending_ = true;
1134 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE);
1135 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); 1156 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY);
1136 DCHECK(entry_lock_waiting_since_.is_null()); 1157 DCHECK(entry_lock_waiting_since_.is_null());
1158 int rv = cache_->AddTransactionToEntry(new_entry_, this);
1159 DCHECK_EQ(rv, ERR_IO_PENDING);
1160
1161 // If headers phase is already done then we are here because of validation not
1162 // matching and creating a new entry. This transaction should be the
1163 // first transaction of that new entry and thus it should not be subject
jkarlin 2017/07/12 15:05:26 should not be subject to any cache lock delays.
shivanisha 2017/07/13 18:35:50 Yes, it should always be the writer of this entry.
1164 // to any cache lock delays, thus returning early from here.
1165 if (done_headers_create_new_entry_) {
1166 DCHECK_EQ(mode_, WRITE);
1167 TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE);
1168 return rv;
1169 }
1170
1171 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE);
1172
1137 entry_lock_waiting_since_ = TimeTicks::Now(); 1173 entry_lock_waiting_since_ = TimeTicks::Now();
1138 int rv = cache_->AddTransactionToEntry(new_entry_, this); 1174 AddCacheLockTimeoutHandler(new_entry_);
1139 if (rv == ERR_IO_PENDING)
1140 AddCacheLockTimeoutHandler(new_entry_);
1141 return rv; 1175 return rv;
1142 } 1176 }
1143 1177
1144 void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) { 1178 void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) {
1145 DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || 1179 DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE ||
1146 next_state_ == STATE_FINISH_HEADERS_COMPLETE); 1180 next_state_ == STATE_FINISH_HEADERS_COMPLETE);
1147 if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) || 1181 if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) ||
1148 (bypass_lock_after_headers_for_test_ && 1182 (bypass_lock_after_headers_for_test_ &&
1149 next_state_ == STATE_FINISH_HEADERS_COMPLETE)) { 1183 next_state_ == STATE_FINISH_HEADERS_COMPLETE)) {
1150 base::ThreadTaskRunnerHandle::Get()->PostTask( 1184 base::ThreadTaskRunnerHandle::Get()->PostTask(
1151 FROM_HERE, 1185 FROM_HERE,
1152 base::Bind(&HttpCache::Transaction::OnCacheLockTimeout, 1186 base::Bind(&HttpCache::Transaction::OnCacheLockTimeout,
1153 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); 1187 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_));
1154 } else { 1188 } else {
1155 int timeout_milliseconds = 20 * 1000; 1189 int timeout_milliseconds = 20 * 1000;
1156 if (partial_ && entry->writer && entry->writer->range_requested_) { 1190 if (partial_ && entry->writer && entry->writer->range_requested_) {
1157 // Quickly timeout and bypass the cache if we're a range request and
1158 // we're blocked by the reader/writer lock. Doing so eliminates a long 1191 // we're blocked by the reader/writer lock. Doing so eliminates a long
1159 // running issue, http://crbug.com/31014, where two of the same media 1192 // running issue, http://crbug.com/31014, where two of the same media
1160 // resources could not be played back simultaneously due to one locking 1193 // resources could not be played back simultaneously due to one locking
1161 // the cache entry until the entire video was downloaded. 1194 // the cache entry until the entire video was downloaded.
1162 // 1195 //
1163 // Bypassing the cache is not ideal, as we are now ignoring the cache 1196 // Bypassing the cache is not ideal, as we are now ignoring the cache
1164 // entirely for all range requests to a resource beyond the first. This 1197 // entirely for all range requests to a resource beyond the first. This
1165 // is however a much more succinct solution than the alternatives, which 1198 // is however a much more succinct solution than the alternatives, which
1166 // would require somewhat significant changes to the http caching logic. 1199 // would require somewhat significant changes to the http caching logic.
1167 // 1200 //
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1235 partial_->RestoreHeaders(&custom_request_->extra_headers); 1268 partial_->RestoreHeaders(&custom_request_->extra_headers);
1236 TransitionToState(STATE_SEND_REQUEST); 1269 TransitionToState(STATE_SEND_REQUEST);
1237 } else { 1270 } else {
1238 // We have to read the headers from the cached entry. 1271 // We have to read the headers from the cached entry.
1239 DCHECK(mode_ & READ_META); 1272 DCHECK(mode_ & READ_META);
1240 TransitionToState(STATE_CACHE_READ_RESPONSE); 1273 TransitionToState(STATE_CACHE_READ_RESPONSE);
1241 } 1274 }
1242 return OK; 1275 return OK;
1243 } 1276 }
1244 1277
1278 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
1279 // This transaction's response headers did not match its ActiveEntry so it
1280 // created a new ActiveEntry (new_entry_) to write to (and doomed the old
1281 // one). Now that the new entry has been created, start writing the response.
1282
1283 DCHECK_EQ(result, OK);
1284 DCHECK_EQ(mode_, WRITE);
1285 DCHECK(new_entry_);
1286 DCHECK(response_.headers);
1287
1288 cache_pending_ = false;
1289 entry_ = new_entry_;
1290 done_headers_create_new_entry_ = false;
1291 DCHECK_NE(response_.headers->response_code(), 304);
1292 DCHECK(cache_->CanTransactionWriteResponseHeaders(
1293 entry_, this, partial_ != nullptr, false));
1294 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1295 return OK;
1296 }
1297
1245 int HttpCache::Transaction::DoCacheReadResponse() { 1298 int HttpCache::Transaction::DoCacheReadResponse() {
1246 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); 1299 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse");
1247 DCHECK(entry_); 1300 DCHECK(entry_);
1248 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); 1301 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE);
1249 1302
1250 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); 1303 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
1251 read_buf_ = new IOBuffer(io_buf_len_); 1304 read_buf_ = new IOBuffer(io_buf_len_);
1252 1305
1253 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); 1306 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO);
1254 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), 1307 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
1720 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); 1773 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
1721 return OK; 1774 return OK;
1722 } 1775 }
1723 1776
1724 TransitionToState(STATE_CACHE_WRITE_RESPONSE); 1777 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1725 return OK; 1778 return OK;
1726 } 1779 }
1727 1780
1728 int HttpCache::Transaction::DoCacheWriteResponse() { 1781 int HttpCache::Transaction::DoCacheWriteResponse() {
1729 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); 1782 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse");
1730 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
1731 1783
1732 // Invalidate any current entry with a successful response if this transaction 1784 // Invalidate any current entry with a successful response if this transaction
1733 // cannot write to this entry. This transaction then continues to read from 1785 // cannot write to this entry. This transaction then continues to read from
1734 // the network without writing to the backend. 1786 // the network without writing to the backend.
1735 bool is_match = response_.headers->response_code() == 304; 1787 bool is_match = response_.headers->response_code() == 304;
1736 if (entry_ && response_.headers && 1788 if (entry_ && response_.headers &&
1737 !cache_->CanTransactionWriteResponseHeaders( 1789 !cache_->CanTransactionWriteResponseHeaders(
1738 entry_, this, partial_ != nullptr, is_match)) { 1790 entry_, this, partial_ != nullptr, is_match)) {
1739 cache_->DoneWritingToEntry(entry_, false, this); 1791 done_headers_create_new_entry_ = true;
1792
1793 // The transaction needs to overwrite this response. Doom the current entry,
1794 // create a new one (by going to STATE_INIT_ENTRY), and then jump straight
1795 // to writing out the response, bypassing the headers checks. The mode_ is
1796 // set to WRITE in order to doom any other existing entries that might exist
1797 // so that this transaction can go straight to writing a response.
1798 mode_ = WRITE;
1799 TransitionToState(STATE_INIT_ENTRY);
1800 cache_->DoomEntryValidationNoMatch(entry_);
1740 entry_ = nullptr; 1801 entry_ = nullptr;
1741 mode_ = NONE;
1742 return OK; 1802 return OK;
1743 } 1803 }
1744 1804
1805 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
1745 return WriteResponseInfoToEntry(truncated_); 1806 return WriteResponseInfoToEntry(truncated_);
1746 } 1807 }
1747 1808
1748 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { 1809 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
1749 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); 1810 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete");
1750 TransitionToState(STATE_TRUNCATE_CACHED_DATA); 1811 TransitionToState(STATE_TRUNCATE_CACHED_DATA);
1751 return OnWriteResponseInfoToEntryComplete(result); 1812 return OnWriteResponseInfoToEntryComplete(result);
1752 } 1813 }
1753 1814
1754 int HttpCache::Transaction::DoTruncateCachedData() { 1815 int HttpCache::Transaction::DoTruncateCachedData() {
(...skipping 1408 matching lines...) Expand 10 before | Expand all | Expand 10 after
3163 } 3224 }
3164 3225
3165 void HttpCache::Transaction::TransitionToState(State state) { 3226 void HttpCache::Transaction::TransitionToState(State state) {
3166 // Ensure that the state is only set once per Do* state. 3227 // Ensure that the state is only set once per Do* state.
3167 DCHECK(in_do_loop_); 3228 DCHECK(in_do_loop_);
3168 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; 3229 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state;
3169 next_state_ = state; 3230 next_state_ = state;
3170 } 3231 }
3171 3232
3172 } // namespace net 3233 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698