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 mode_(NONE), | 158 mode_(NONE), |
| 159 original_mode_(NONE), | 159 original_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 fail_conditionalization_for_test_(false), | 172 fail_conditionalization_for_test_(false), |
| 172 io_buf_len_(0), | 173 io_buf_len_(0), |
| 173 read_offset_(0), | 174 read_offset_(0), |
| 174 effective_load_flags_(0), | 175 effective_load_flags_(0), |
| 175 write_len_(0), | 176 write_len_(0), |
| 176 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), | 177 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), |
| 177 validation_cause_(VALIDATION_CAUSE_UNDEFINED), | 178 validation_cause_(VALIDATION_CAUSE_UNDEFINED), |
| (...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 747 case STATE_CREATE_ENTRY_COMPLETE: | 748 case STATE_CREATE_ENTRY_COMPLETE: |
| 748 rv = DoCreateEntryComplete(rv); | 749 rv = DoCreateEntryComplete(rv); |
| 749 break; | 750 break; |
| 750 case STATE_ADD_TO_ENTRY: | 751 case STATE_ADD_TO_ENTRY: |
| 751 DCHECK_EQ(OK, rv); | 752 DCHECK_EQ(OK, rv); |
| 752 rv = DoAddToEntry(); | 753 rv = DoAddToEntry(); |
| 753 break; | 754 break; |
| 754 case STATE_ADD_TO_ENTRY_COMPLETE: | 755 case STATE_ADD_TO_ENTRY_COMPLETE: |
| 755 rv = DoAddToEntryComplete(rv); | 756 rv = DoAddToEntryComplete(rv); |
| 756 break; | 757 break; |
| 758 case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE: | |
| 759 rv = DoDoneHeadersAddToEntryComplete(rv); | |
| 760 break; | |
| 757 case STATE_CACHE_READ_RESPONSE: | 761 case STATE_CACHE_READ_RESPONSE: |
| 758 DCHECK_EQ(OK, rv); | 762 DCHECK_EQ(OK, rv); |
| 759 rv = DoCacheReadResponse(); | 763 rv = DoCacheReadResponse(); |
| 760 break; | 764 break; |
| 761 case STATE_CACHE_READ_RESPONSE_COMPLETE: | 765 case STATE_CACHE_READ_RESPONSE_COMPLETE: |
| 762 rv = DoCacheReadResponseComplete(rv); | 766 rv = DoCacheReadResponseComplete(rv); |
| 763 break; | 767 break; |
| 764 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: | 768 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: |
| 765 DCHECK_EQ(OK, rv); | 769 DCHECK_EQ(OK, rv); |
| 766 rv = DoCacheToggleUnusedSincePrefetch(); | 770 rv = DoCacheToggleUnusedSincePrefetch(); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1105 case ERR_CACHE_RACE: | 1109 case ERR_CACHE_RACE: |
| 1106 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); | 1110 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
| 1107 break; | 1111 break; |
| 1108 | 1112 |
| 1109 default: | 1113 default: |
| 1110 // We have a race here: Maybe we failed to open the entry and decided to | 1114 // We have a race here: Maybe we failed to open the entry and decided to |
| 1111 // create one, but by the time we called create, another transaction | 1115 // create one, but by the time we called create, another transaction |
| 1112 // already created the entry. If we want to eliminate this issue, we | 1116 // already created the entry. If we want to eliminate this issue, we |
| 1113 // need an atomic OpenOrCreate() method exposed by the disk cache. | 1117 // need an atomic OpenOrCreate() method exposed by the disk cache. |
| 1114 DLOG(WARNING) << "Unable to create cache entry"; | 1118 DLOG(WARNING) << "Unable to create cache entry"; |
| 1119 // Change the mode to not write anything to the cache. | |
|
Randy Smith (Not in Mondays)
2017/04/11 19:41:07
This comment doesn't really add anything to the co
shivanisha
2017/04/24 17:23:46
Done
| |
| 1115 mode_ = NONE; | 1120 mode_ = NONE; |
| 1121 if (done_headers_create_new_entry_) { | |
|
Randy Smith (Not in Mondays)
2017/04/11 19:41:07
Maybe a comment here something like "The headers t
shivanisha
2017/04/24 17:23:46
Comment added and restructured the code.
| |
| 1122 done_headers_create_new_entry_ = false; | |
| 1123 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | |
| 1124 return OK; | |
| 1125 } | |
| 1126 | |
| 1116 if (partial_) | 1127 if (partial_) |
| 1117 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1128 partial_->RestoreHeaders(&custom_request_->extra_headers); |
| 1118 TransitionToState(STATE_SEND_REQUEST); | 1129 TransitionToState(STATE_SEND_REQUEST); |
| 1119 } | 1130 } |
| 1120 return OK; | 1131 return OK; |
| 1121 } | 1132 } |
| 1122 | 1133 |
| 1123 int HttpCache::Transaction::DoAddToEntry() { | 1134 int HttpCache::Transaction::DoAddToEntry() { |
| 1124 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); | 1135 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); |
| 1125 DCHECK(new_entry_); | 1136 DCHECK(new_entry_); |
| 1126 cache_pending_ = true; | 1137 cache_pending_ = true; |
| 1127 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); | |
| 1128 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); | 1138 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); |
| 1129 DCHECK(entry_lock_waiting_since_.is_null()); | 1139 DCHECK(entry_lock_waiting_since_.is_null()); |
| 1140 int rv = cache_->AddTransactionToEntry(new_entry_, this); | |
| 1141 DCHECK_EQ(rv, ERR_IO_PENDING); | |
| 1142 | |
| 1143 if (done_headers_create_new_entry_) { | |
| 1144 TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE); | |
| 1145 return rv; | |
| 1146 } | |
| 1147 | |
| 1148 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); | |
|
Randy Smith (Not in Mondays)
2017/04/11 19:41:07
The naming makes it clear that these are parallel
shivanisha
2017/04/24 17:23:46
Added a comment in the new Do* function.
| |
| 1149 | |
| 1130 entry_lock_waiting_since_ = TimeTicks::Now(); | 1150 entry_lock_waiting_since_ = TimeTicks::Now(); |
| 1131 int rv = cache_->AddTransactionToEntry(new_entry_, this); | 1151 if (bypass_lock_for_test_) { |
| 1132 if (rv == ERR_IO_PENDING) { | 1152 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 1133 if (bypass_lock_for_test_) { | 1153 FROM_HERE, |
| 1134 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1154 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, |
| 1135 FROM_HERE, | 1155 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); |
| 1136 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | 1156 } else { |
| 1137 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); | 1157 int timeout_milliseconds = 20 * 1000; |
| 1138 } else { | 1158 if (partial_ && new_entry_->writer && |
| 1139 int timeout_milliseconds = 20 * 1000; | 1159 new_entry_->writer->range_requested_) { |
| 1140 if (partial_ && new_entry_->writer && | 1160 // Quickly timeout and bypass the cache if we're a range request and |
| 1141 new_entry_->writer->range_requested_) { | 1161 // we're blocked by the reader/writer lock. Doing so eliminates a long |
| 1142 // Quickly timeout and bypass the cache if we're a range request and | 1162 // running issue, http://crbug.com/31014, where two of the same media |
| 1143 // we're blocked by the reader/writer lock. Doing so eliminates a long | 1163 // resources could not be played back simultaneously due to one locking |
| 1144 // running issue, http://crbug.com/31014, where two of the same media | 1164 // the cache entry until the entire video was downloaded. |
| 1145 // resources could not be played back simultaneously due to one locking | 1165 // |
| 1146 // the cache entry until the entire video was downloaded. | 1166 // Bypassing the cache is not ideal, as we are now ignoring the cache |
| 1147 // | 1167 // entirely for all range requests to a resource beyond the first. This |
| 1148 // Bypassing the cache is not ideal, as we are now ignoring the cache | 1168 // is however a much more succinct solution than the alternatives, which |
| 1149 // entirely for all range requests to a resource beyond the first. This | 1169 // would require somewhat significant changes to the http caching logic. |
| 1150 // is however a much more succinct solution than the alternatives, which | 1170 // |
| 1151 // would require somewhat significant changes to the http caching logic. | 1171 // Allow some timeout slack for the entry addition to complete in case |
| 1152 // | 1172 // the writer lock is imminently released; we want to avoid skipping |
| 1153 // Allow some timeout slack for the entry addition to complete in case | 1173 // the cache if at all possible. See http://crbug.com/408765 |
| 1154 // the writer lock is imminently released; we want to avoid skipping | 1174 timeout_milliseconds = 25; |
| 1155 // the cache if at all possible. See http://crbug.com/408765 | |
| 1156 timeout_milliseconds = 25; | |
| 1157 } | |
| 1158 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 1159 FROM_HERE, | |
| 1160 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | |
| 1161 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), | |
| 1162 TimeDelta::FromMilliseconds(timeout_milliseconds)); | |
| 1163 } | 1175 } |
| 1176 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 1177 FROM_HERE, | |
| 1178 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, | |
| 1179 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), | |
| 1180 TimeDelta::FromMilliseconds(timeout_milliseconds)); | |
|
Randy Smith (Not in Mondays)
2017/04/11 19:41:07
Why is this pulled out of the conditional? It loo
shivanisha
2017/04/24 17:23:46
It is not out of the else conditional. This post t
| |
| 1164 } | 1181 } |
| 1165 return rv; | 1182 return rv; |
| 1166 } | 1183 } |
| 1167 | 1184 |
| 1168 int HttpCache::Transaction::DoAddToEntryComplete(int result) { | 1185 int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
| 1169 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); | 1186 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); |
| 1170 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, | 1187 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, |
| 1171 result); | 1188 result); |
| 1172 const TimeDelta entry_lock_wait = | 1189 const TimeDelta entry_lock_wait = |
| 1173 TimeTicks::Now() - entry_lock_waiting_since_; | 1190 TimeTicks::Now() - entry_lock_waiting_since_; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1218 partial_->RestoreHeaders(&custom_request_->extra_headers); | 1235 partial_->RestoreHeaders(&custom_request_->extra_headers); |
| 1219 TransitionToState(STATE_SEND_REQUEST); | 1236 TransitionToState(STATE_SEND_REQUEST); |
| 1220 } else { | 1237 } else { |
| 1221 // We have to read the headers from the cached entry. | 1238 // We have to read the headers from the cached entry. |
| 1222 DCHECK(mode_ & READ_META); | 1239 DCHECK(mode_ & READ_META); |
| 1223 TransitionToState(STATE_CACHE_READ_RESPONSE); | 1240 TransitionToState(STATE_CACHE_READ_RESPONSE); |
| 1224 } | 1241 } |
| 1225 return OK; | 1242 return OK; |
| 1226 } | 1243 } |
| 1227 | 1244 |
| 1245 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) { | |
|
Randy Smith (Not in Mondays)
2017/04/11 19:41:07
Comment somewhere as to the context/motivation for
shivanisha
2017/04/24 17:23:46
done.
| |
| 1246 DCHECK_EQ(result, OK); | |
| 1247 DCHECK(mode_ & WRITE); | |
| 1248 DCHECK(new_entry_); | |
| 1249 DCHECK(response_.headers); | |
| 1250 | |
| 1251 cache_pending_ = false; | |
| 1252 entry_ = new_entry_; | |
| 1253 done_headers_create_new_entry_ = false; | |
| 1254 DCHECK(cache_->CanTransactionWriteResponseHeaders( | |
| 1255 entry_, this, response_.headers->response_code())); | |
| 1256 TransitionToState(STATE_CACHE_WRITE_RESPONSE); | |
| 1257 return OK; | |
| 1258 } | |
| 1259 | |
| 1228 int HttpCache::Transaction::DoCacheReadResponse() { | 1260 int HttpCache::Transaction::DoCacheReadResponse() { |
| 1229 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); | 1261 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); |
| 1230 DCHECK(entry_); | 1262 DCHECK(entry_); |
| 1231 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); | 1263 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); |
| 1232 | 1264 |
| 1233 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); | 1265 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); |
| 1234 read_buf_ = new IOBuffer(io_buf_len_); | 1266 read_buf_ = new IOBuffer(io_buf_len_); |
| 1235 | 1267 |
| 1236 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); | 1268 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); |
| 1237 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), | 1269 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1706 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); | 1738 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); |
| 1707 | 1739 |
| 1708 // Invalidate any current entry with a successful response if this transaction | 1740 // Invalidate any current entry with a successful response if this transaction |
| 1709 // cannot write to this entry. This transaction then continues to read from | 1741 // cannot write to this entry. This transaction then continues to read from |
| 1710 // the network without writing to the backend. | 1742 // the network without writing to the backend. |
| 1711 if (entry_ && response_.headers && | 1743 if (entry_ && response_.headers && |
| 1712 !cache_->CanTransactionWriteResponseHeaders( | 1744 !cache_->CanTransactionWriteResponseHeaders( |
| 1713 entry_, this, response_.headers->response_code())) { | 1745 entry_, this, response_.headers->response_code())) { |
| 1714 cache_->DoneWritingToEntry(entry_, false, this); | 1746 cache_->DoneWritingToEntry(entry_, false, this); |
| 1715 entry_ = nullptr; | 1747 entry_ = nullptr; |
| 1716 mode_ = NONE; | 1748 next_state_ = STATE_CREATE_ENTRY; |
| 1749 done_headers_create_new_entry_ = true; | |
| 1717 return OK; | 1750 return OK; |
| 1718 } | 1751 } |
| 1719 | 1752 |
| 1720 return WriteResponseInfoToEntry(truncated_); | 1753 return WriteResponseInfoToEntry(truncated_); |
| 1721 } | 1754 } |
| 1722 | 1755 |
| 1723 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { | 1756 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { |
| 1724 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); | 1757 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); |
| 1725 TransitionToState(STATE_TRUNCATE_CACHED_DATA); | 1758 TransitionToState(STATE_TRUNCATE_CACHED_DATA); |
| 1726 return OnWriteResponseInfoToEntryComplete(result); | 1759 return OnWriteResponseInfoToEntryComplete(result); |
| (...skipping 1377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3104 } | 3137 } |
| 3105 | 3138 |
| 3106 void HttpCache::Transaction::TransitionToState(State state) { | 3139 void HttpCache::Transaction::TransitionToState(State state) { |
| 3107 // Ensure that the state is only set once per Do* state. | 3140 // Ensure that the state is only set once per Do* state. |
| 3108 DCHECK(in_do_loop_); | 3141 DCHECK(in_do_loop_); |
| 3109 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3142 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
| 3110 next_state_ = state; | 3143 next_state_ = state; |
| 3111 } | 3144 } |
| 3112 | 3145 |
| 3113 } // namespace net | 3146 } // namespace net |
| OLD | NEW |