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

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

Issue 2774603003: Doom and create new entry when validation is not a match (Closed)
Patch Set: Rebased with parent branch Created 3 years, 6 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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 new_response_(NULL), 157 new_response_(NULL),
158 mode_(NONE), 158 mode_(NONE),
159 reading_(false), 159 reading_(false),
160 invalid_range_(false), 160 invalid_range_(false),
161 truncated_(false), 161 truncated_(false),
162 is_sparse_(false), 162 is_sparse_(false),
163 range_requested_(false), 163 range_requested_(false),
164 handling_206_(false), 164 handling_206_(false),
165 cache_pending_(false), 165 cache_pending_(false),
166 done_reading_(false), 166 done_reading_(false),
167 done_headers_create_new_entry_(false),
167 vary_mismatch_(false), 168 vary_mismatch_(false),
168 couldnt_conditionalize_request_(false), 169 couldnt_conditionalize_request_(false),
169 bypass_lock_for_test_(false), 170 bypass_lock_for_test_(false),
170 fail_conditionalization_for_test_(false), 171 fail_conditionalization_for_test_(false),
171 io_buf_len_(0), 172 io_buf_len_(0),
172 read_offset_(0), 173 read_offset_(0),
173 effective_load_flags_(0), 174 effective_load_flags_(0),
174 write_len_(0), 175 write_len_(0),
175 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), 176 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED),
176 validation_cause_(VALIDATION_CAUSE_UNDEFINED), 177 validation_cause_(VALIDATION_CAUSE_UNDEFINED),
(...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 case STATE_CREATE_ENTRY_COMPLETE: 747 case STATE_CREATE_ENTRY_COMPLETE:
747 rv = DoCreateEntryComplete(rv); 748 rv = DoCreateEntryComplete(rv);
748 break; 749 break;
749 case STATE_ADD_TO_ENTRY: 750 case STATE_ADD_TO_ENTRY:
750 DCHECK_EQ(OK, rv); 751 DCHECK_EQ(OK, rv);
751 rv = DoAddToEntry(); 752 rv = DoAddToEntry();
752 break; 753 break;
753 case STATE_ADD_TO_ENTRY_COMPLETE: 754 case STATE_ADD_TO_ENTRY_COMPLETE:
754 rv = DoAddToEntryComplete(rv); 755 rv = DoAddToEntryComplete(rv);
755 break; 756 break;
757 case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE:
758 rv = DoDoneHeadersAddToEntryComplete(rv);
759 break;
756 case STATE_CACHE_READ_RESPONSE: 760 case STATE_CACHE_READ_RESPONSE:
757 DCHECK_EQ(OK, rv); 761 DCHECK_EQ(OK, rv);
758 rv = DoCacheReadResponse(); 762 rv = DoCacheReadResponse();
759 break; 763 break;
760 case STATE_CACHE_READ_RESPONSE_COMPLETE: 764 case STATE_CACHE_READ_RESPONSE_COMPLETE:
761 rv = DoCacheReadResponseComplete(rv); 765 rv = DoCacheReadResponseComplete(rv);
762 break; 766 break;
763 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: 767 case STATE_TOGGLE_UNUSED_SINCE_PREFETCH:
764 DCHECK_EQ(OK, rv); 768 DCHECK_EQ(OK, rv);
765 rv = DoCacheToggleUnusedSincePrefetch(); 769 rv = DoCacheToggleUnusedSincePrefetch();
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
1104 case ERR_CACHE_RACE: 1108 case ERR_CACHE_RACE:
1105 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); 1109 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1106 break; 1110 break;
1107 1111
1108 default: 1112 default:
1109 // We have a race here: Maybe we failed to open the entry and decided to 1113 // We have a race here: Maybe we failed to open the entry and decided to
1110 // create one, but by the time we called create, another transaction 1114 // create one, but by the time we called create, another transaction
1111 // already created the entry. If we want to eliminate this issue, we 1115 // already created the entry. If we want to eliminate this issue, we
1112 // need an atomic OpenOrCreate() method exposed by the disk cache. 1116 // need an atomic OpenOrCreate() method exposed by the disk cache.
1113 DLOG(WARNING) << "Unable to create cache entry"; 1117 DLOG(WARNING) << "Unable to create cache entry";
1118 // Switching into passing through data directly from the network, avoiding
1119 // the cache entry.
1114 mode_ = NONE; 1120 mode_ = NONE;
1115 if (partial_) 1121 if (!done_headers_create_new_entry_) {
1116 partial_->RestoreHeaders(&custom_request_->extra_headers); 1122 if (partial_)
1117 TransitionToState(STATE_SEND_REQUEST); 1123 partial_->RestoreHeaders(&custom_request_->extra_headers);
1124 TransitionToState(STATE_SEND_REQUEST);
1125 return OK;
1126 }
1127 // The headers have already been received as a result of validation,
1128 // triggering the doom of the old entry. So no network request needs to
1129 // be sent. Note that since mode_ is set to pass-through, response will
1130 // not be written to the cache but moving to state
1131 // STATE_CACHE_WRITE_RESPONSE for consistency.
1132 done_headers_create_new_entry_ = false;
1133 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1118 } 1134 }
1119 return OK; 1135 return OK;
1120 } 1136 }
1121 1137
1122 int HttpCache::Transaction::DoAddToEntry() { 1138 int HttpCache::Transaction::DoAddToEntry() {
1123 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry"); 1139 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntry");
1124 DCHECK(new_entry_); 1140 DCHECK(new_entry_);
1125 cache_pending_ = true; 1141 cache_pending_ = true;
1126 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE);
1127 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY); 1142 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY);
1128 DCHECK(entry_lock_waiting_since_.is_null()); 1143 DCHECK(entry_lock_waiting_since_.is_null());
1144 int rv = cache_->AddTransactionToEntry(new_entry_, this);
1145 DCHECK_EQ(rv, ERR_IO_PENDING);
1146
1147 // If headers phase is already done and we are here because of validation not
1148 // matching and creating a new entry, then this transaction should be the
1149 // first transaction of that entry and thus it should not be subject
1150 // to any cache lock delays, thus returning early from here.
1151 if (done_headers_create_new_entry_) {
1152 DCHECK_EQ(mode_, WRITE);
1153 TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE);
1154 return rv;
1155 }
1156
1157 TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE);
1129 entry_lock_waiting_since_ = TimeTicks::Now(); 1158 entry_lock_waiting_since_ = TimeTicks::Now();
1130 int rv = cache_->AddTransactionToEntry(new_entry_, this); 1159
1131 if (rv == ERR_IO_PENDING) { 1160 if (bypass_lock_for_test_) {
1132 if (bypass_lock_for_test_) { 1161 base::ThreadTaskRunnerHandle::Get()->PostTask(
1133 base::ThreadTaskRunnerHandle::Get()->PostTask( 1162 FROM_HERE,
1134 FROM_HERE, 1163 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
1135 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, 1164 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_));
1136 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); 1165 } else {
1137 } else { 1166 int timeout_milliseconds = 20 * 1000;
1138 int timeout_milliseconds = 20 * 1000; 1167 if (partial_ && new_entry_->writer &&
1139 if (partial_ && new_entry_->writer && 1168 new_entry_->writer->range_requested_) {
1140 new_entry_->writer->range_requested_) { 1169 // Quickly timeout and bypass the cache if we're a range request and
1141 // Quickly timeout and bypass the cache if we're a range request and 1170 // we're blocked by the reader/writer lock. Doing so eliminates a long
1142 // we're blocked by the reader/writer lock. Doing so eliminates a long 1171 // running issue, http://crbug.com/31014, where two of the same media
1143 // running issue, http://crbug.com/31014, where two of the same media 1172 // resources could not be played back simultaneously due to one locking
1144 // resources could not be played back simultaneously due to one locking 1173 // the cache entry until the entire video was downloaded.
1145 // the cache entry until the entire video was downloaded. 1174 //
1146 // 1175 // Bypassing the cache is not ideal, as we are now ignoring the cache
1147 // Bypassing the cache is not ideal, as we are now ignoring the cache 1176 // entirely for all range requests to a resource beyond the first. This
1148 // entirely for all range requests to a resource beyond the first. This 1177 // is however a much more succinct solution than the alternatives, which
1149 // is however a much more succinct solution than the alternatives, which 1178 // would require somewhat significant changes to the http caching logic.
1150 // would require somewhat significant changes to the http caching logic. 1179 //
1151 // 1180 // Allow some timeout slack for the entry addition to complete in case
1152 // Allow some timeout slack for the entry addition to complete in case 1181 // the writer lock is imminently released; we want to avoid skipping
1153 // the writer lock is imminently released; we want to avoid skipping 1182 // the cache if at all possible. See http://crbug.com/408765
1154 // the cache if at all possible. See http://crbug.com/408765 1183 timeout_milliseconds = 25;
1155 timeout_milliseconds = 25;
1156 }
1157 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1158 FROM_HERE,
1159 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
1160 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
1161 TimeDelta::FromMilliseconds(timeout_milliseconds));
1162 } 1184 }
1185 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1186 FROM_HERE,
1187 base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
1188 weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
1189 TimeDelta::FromMilliseconds(timeout_milliseconds));
1163 } 1190 }
1191
1164 return rv; 1192 return rv;
1165 } 1193 }
1166 1194
1167 int HttpCache::Transaction::DoAddToEntryComplete(int result) { 1195 int HttpCache::Transaction::DoAddToEntryComplete(int result) {
1168 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); 1196 TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete");
1169 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, 1197 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY,
1170 result); 1198 result);
1171 const TimeDelta entry_lock_wait = 1199 const TimeDelta entry_lock_wait =
1172 TimeTicks::Now() - entry_lock_waiting_since_; 1200 TimeTicks::Now() - entry_lock_waiting_since_;
1173 UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait); 1201 UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 partial_->RestoreHeaders(&custom_request_->extra_headers); 1249 partial_->RestoreHeaders(&custom_request_->extra_headers);
1222 TransitionToState(STATE_SEND_REQUEST); 1250 TransitionToState(STATE_SEND_REQUEST);
1223 } else { 1251 } else {
1224 // We have to read the headers from the cached entry. 1252 // We have to read the headers from the cached entry.
1225 DCHECK(mode_ & READ_META); 1253 DCHECK(mode_ & READ_META);
1226 TransitionToState(STATE_CACHE_READ_RESPONSE); 1254 TransitionToState(STATE_CACHE_READ_RESPONSE);
1227 } 1255 }
1228 return OK; 1256 return OK;
1229 } 1257 }
1230 1258
1259 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
1260 // This state is reached when |this| has already completed validation leading
1261 // to a no-match with original entry which was doomed and |new_entry_| was
1262 // created. A response of no-match from a validation request also includes the
1263 // full contents of the URL, so go ahead and write the response to the newly
1264 // created entry.
1265
1266 DCHECK_EQ(result, OK);
1267 DCHECK_EQ(mode_, WRITE);
1268 DCHECK(new_entry_);
1269 DCHECK(response_.headers);
1270
1271 cache_pending_ = false;
1272 entry_ = new_entry_;
1273 done_headers_create_new_entry_ = false;
1274 bool is_match = response_.headers->response_code() == 304;
1275 DCHECK(cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match));
1276 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1277 return OK;
1278 }
1279
1231 int HttpCache::Transaction::DoCacheReadResponse() { 1280 int HttpCache::Transaction::DoCacheReadResponse() {
1232 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse"); 1281 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadResponse");
1233 DCHECK(entry_); 1282 DCHECK(entry_);
1234 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE); 1283 TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE);
1235 1284
1236 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); 1285 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
1237 read_buf_ = new IOBuffer(io_buf_len_); 1286 read_buf_ = new IOBuffer(io_buf_len_);
1238 1287
1239 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO); 1288 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO);
1240 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), 1289 return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
1706 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED); 1755 TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
1707 return OK; 1756 return OK;
1708 } 1757 }
1709 1758
1710 TransitionToState(STATE_CACHE_WRITE_RESPONSE); 1759 TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1711 return OK; 1760 return OK;
1712 } 1761 }
1713 1762
1714 int HttpCache::Transaction::DoCacheWriteResponse() { 1763 int HttpCache::Transaction::DoCacheWriteResponse() {
1715 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); 1764 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse");
1716 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
1717 1765
1718 // Invalidate any current entry with a successful response if this transaction 1766 // Invalidate any current entry with a successful response if this transaction
1719 // cannot write to this entry. This transaction then continues to read from 1767 // cannot write to this entry. This transaction then continues to read from
1720 // the network without writing to the backend. 1768 // the network without writing to the backend.
1721 bool is_match = response_.headers->response_code() == 304; 1769 bool is_match = response_.headers->response_code() == 304;
1722 if (entry_ && response_.headers && 1770 if (entry_ && response_.headers &&
1723 !cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match)) { 1771 !cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match)) {
1724 cache_->DoneWritingToEntry(entry_, false, this); 1772 done_headers_create_new_entry_ = true;
1773
1774 // This transaction should not add itself to any other existing entry but
1775 // create a new entry. Going to state STATE_INIT_ENTRY and setting mode_ to
1776 // WRITE will take care of dooming if any other entry exists.
1777 mode_ = WRITE;
1778 TransitionToState(STATE_INIT_ENTRY);
1779 cache_->DoomEntryValidationNoMatch(entry_, this);
1725 entry_ = nullptr; 1780 entry_ = nullptr;
1726 mode_ = NONE;
1727 return OK; 1781 return OK;
1728 } 1782 }
1729 1783
1784 TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
1730 return WriteResponseInfoToEntry(truncated_); 1785 return WriteResponseInfoToEntry(truncated_);
1731 } 1786 }
1732 1787
1733 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { 1788 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
1734 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete"); 1789 TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponseComplete");
1735 TransitionToState(STATE_TRUNCATE_CACHED_DATA); 1790 TransitionToState(STATE_TRUNCATE_CACHED_DATA);
1736 return OnWriteResponseInfoToEntryComplete(result); 1791 return OnWriteResponseInfoToEntryComplete(result);
1737 } 1792 }
1738 1793
1739 int HttpCache::Transaction::DoTruncateCachedData() { 1794 int HttpCache::Transaction::DoTruncateCachedData() {
(...skipping 1379 matching lines...) Expand 10 before | Expand all | Expand 10 after
3119 } 3174 }
3120 3175
3121 void HttpCache::Transaction::TransitionToState(State state) { 3176 void HttpCache::Transaction::TransitionToState(State state) {
3122 // Ensure that the state is only set once per Do* state. 3177 // Ensure that the state is only set once per Do* state.
3123 DCHECK(in_do_loop_); 3178 DCHECK(in_do_loop_);
3124 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; 3179 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state;
3125 next_state_ = state; 3180 next_state_ = state;
3126 } 3181 }
3127 3182
3128 } // namespace net 3183 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698