Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |