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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Convert DCHECK -> CHECK for important invariants. Created 3 years, 7 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
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.h" 5 #include "net/http/http_cache.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 true, 89 true,
90 thread_, 90 thread_,
91 net_log, 91 net_log,
92 backend, 92 backend,
93 callback); 93 callback);
94 } 94 }
95 95
96 //----------------------------------------------------------------------------- 96 //-----------------------------------------------------------------------------
97 97
98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry) 98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
99 : disk_entry(entry), 99 : disk_entry(entry) {}
100 writer(NULL),
101 will_process_pending_queue(false),
102 doomed(false) {
103 }
104 100
105 HttpCache::ActiveEntry::~ActiveEntry() { 101 HttpCache::ActiveEntry::~ActiveEntry() {
106 if (disk_entry) { 102 if (disk_entry) {
107 disk_entry->Close(); 103 disk_entry->Close();
108 disk_entry = NULL; 104 disk_entry = nullptr;
109 } 105 }
110 } 106 }
111 107
112 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const { 108 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
113 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers| 109 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
114 // and |pending_queue| because the Transactions are owned by their respective 110 // and |add_to_entry_queue| because the Transactions are owned by their
115 // URLRequestHttpJobs. 111 // respective URLRequestHttpJobs.
116 return 0; 112 return 0;
117 } 113 }
118 114
119 bool HttpCache::ActiveEntry::HasNoTransactions() { 115 bool HttpCache::ActiveEntry::HasNoTransactions() {
120 return !writer && readers.empty() && pending_queue.empty(); 116 return !writer && readers.empty() && add_to_entry_queue.empty() &&
117 done_headers_queue.empty() && !headers_transaction;
118 }
119
120 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
121 return !writer && readers.empty() && !headers_transaction;
121 } 122 }
122 123
123 //----------------------------------------------------------------------------- 124 //-----------------------------------------------------------------------------
124 125
125 // This structure keeps track of work items that are attempting to create or 126 // This structure keeps track of work items that are attempting to create or
126 // open cache entries or the backend itself. 127 // open cache entries or the backend itself.
127 struct HttpCache::PendingOp { 128 struct HttpCache::PendingOp {
128 PendingOp() : disk_entry(NULL) {} 129 PendingOp() : disk_entry(NULL) {}
129 ~PendingOp() {} 130 ~PendingOp() {}
130 131
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 disk_cache::Backend** backend_; 213 disk_cache::Backend** backend_;
213 }; 214 };
214 215
215 //----------------------------------------------------------------------------- 216 //-----------------------------------------------------------------------------
216 217
217 // This class encapsulates a transaction whose only purpose is to write metadata 218 // This class encapsulates a transaction whose only purpose is to write metadata
218 // to a given entry. 219 // to a given entry.
219 class HttpCache::MetadataWriter { 220 class HttpCache::MetadataWriter {
220 public: 221 public:
221 explicit MetadataWriter(HttpCache::Transaction* trans) 222 explicit MetadataWriter(HttpCache::Transaction* trans)
222 : transaction_(trans), 223 : verified_(false), buf_len_(0), transaction_(trans) {}
223 verified_(false),
224 buf_len_(0) {
225 }
226 224
227 ~MetadataWriter() {} 225 ~MetadataWriter() {}
228 226
229 // Implements the bulk of HttpCache::WriteMetadata. 227 // Implements the bulk of HttpCache::WriteMetadata.
230 void Write(const GURL& url, 228 void Write(const GURL& url,
231 base::Time expected_response_time, 229 base::Time expected_response_time,
232 IOBuffer* buf, 230 IOBuffer* buf,
233 int buf_len); 231 int buf_len);
234 232
235 private: 233 private:
236 void VerifyResponse(int result); 234 void VerifyResponse(int result);
237 void SelfDestroy(); 235 void SelfDestroy();
238 void OnIOComplete(int result); 236 void OnIOComplete(int result);
239 237
240 std::unique_ptr<HttpCache::Transaction> transaction_;
241 bool verified_; 238 bool verified_;
242 scoped_refptr<IOBuffer> buf_; 239 scoped_refptr<IOBuffer> buf_;
243 int buf_len_; 240 int buf_len_;
244 base::Time expected_response_time_; 241 base::Time expected_response_time_;
245 HttpRequestInfo request_info_; 242 HttpRequestInfo request_info_;
243
244 // |transaction_| to come after |request_info_| so that |request_info_| is not
245 // destroyed earlier.
246 std::unique_ptr<HttpCache::Transaction> transaction_;
246 DISALLOW_COPY_AND_ASSIGN(MetadataWriter); 247 DISALLOW_COPY_AND_ASSIGN(MetadataWriter);
247 }; 248 };
248 249
249 void HttpCache::MetadataWriter::Write(const GURL& url, 250 void HttpCache::MetadataWriter::Write(const GURL& url,
250 base::Time expected_response_time, 251 base::Time expected_response_time,
251 IOBuffer* buf, 252 IOBuffer* buf,
252 int buf_len) { 253 int buf_len) {
253 DCHECK_GT(buf_len, 0); 254 DCHECK_GT(buf_len, 0);
254 DCHECK(buf); 255 DCHECK(buf);
255 DCHECK(buf->data()); 256 DCHECK(buf->data());
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 session->SetServerPushDelegate( 336 session->SetServerPushDelegate(
336 base::MakeUnique<HttpCacheLookupManager>(this)); 337 base::MakeUnique<HttpCacheLookupManager>(this));
337 } 338 }
338 339
339 HttpCache::~HttpCache() { 340 HttpCache::~HttpCache() {
340 // Transactions should see an invalid cache after this point; otherwise they 341 // Transactions should see an invalid cache after this point; otherwise they
341 // could see an inconsistent object (half destroyed). 342 // could see an inconsistent object (half destroyed).
342 weak_factory_.InvalidateWeakPtrs(); 343 weak_factory_.InvalidateWeakPtrs();
343 344
344 // If we have any active entries remaining, then we need to deactivate them. 345 // If we have any active entries remaining, then we need to deactivate them.
345 // We may have some pending calls to OnProcessPendingQueue, but since those 346 // We may have some pending tasks to process queued transactions ,but since
346 // won't run (due to our destruction), we can simply ignore the corresponding 347 // those won't run (due to our destruction), we can simply ignore the
347 // will_process_pending_queue flag. 348 // corresponding flags.
348 while (!active_entries_.empty()) { 349 while (!active_entries_.empty()) {
349 ActiveEntry* entry = active_entries_.begin()->second.get(); 350 ActiveEntry* entry = active_entries_.begin()->second.get();
350 entry->will_process_pending_queue = false; 351 entry->will_process_queued_transactions = false;
351 entry->pending_queue.clear(); 352 entry->add_to_entry_queue.clear();
352 entry->readers.clear(); 353 entry->readers.clear();
353 entry->writer = NULL; 354 entry->done_headers_queue.clear();
355 entry->headers_transaction = nullptr;
356 entry->writer = nullptr;
354 DeactivateEntry(entry); 357 DeactivateEntry(entry);
355 } 358 }
356 359
357 doomed_entries_.clear(); 360 doomed_entries_.clear();
358 361
359 // Before deleting pending_ops_, we have to make sure that the disk cache is 362 // Before deleting pending_ops_, we have to make sure that the disk cache is
360 // done with said operations, or it will attempt to use deleted data. 363 // done with said operations, or it will attempt to use deleted data.
361 disk_cache_.reset(); 364 disk_cache_.reset();
362 365
363 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 366 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // We keep track of doomed entries so that we can ensure that they are 607 // We keep track of doomed entries so that we can ensure that they are
605 // cleaned up properly when the cache is destroyed. 608 // cleaned up properly when the cache is destroyed.
606 ActiveEntry* entry_ptr = entry.get(); 609 ActiveEntry* entry_ptr = entry.get();
607 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 610 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
608 doomed_entries_[entry_ptr] = std::move(entry); 611 doomed_entries_[entry_ptr] = std::move(entry);
609 612
610 entry_ptr->disk_entry->Doom(); 613 entry_ptr->disk_entry->Doom();
611 entry_ptr->doomed = true; 614 entry_ptr->doomed = true;
612 615
613 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 616 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
614 entry_ptr->will_process_pending_queue); 617 entry_ptr->headers_transaction ||
618 entry_ptr->will_process_queued_transactions);
615 return OK; 619 return OK;
616 } 620 }
617 621
618 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 622 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
619 std::unique_ptr<WorkItem> item = 623 std::unique_ptr<WorkItem> item =
620 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 624 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
621 PendingOp* pending_op = GetPendingOp(key); 625 PendingOp* pending_op = GetPendingOp(key);
622 if (pending_op->writer) { 626 if (pending_op->writer) {
623 pending_op->pending_queue.push_back(std::move(item)); 627 pending_op->pending_queue.push_back(std::move(item));
624 return ERR_IO_PENDING; 628 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 DCHECK(entry->doomed); 664 DCHECK(entry->doomed);
661 DCHECK(entry->HasNoTransactions()); 665 DCHECK(entry->HasNoTransactions());
662 666
663 auto it = doomed_entries_.find(entry); 667 auto it = doomed_entries_.find(entry);
664 DCHECK(it != doomed_entries_.end()); 668 DCHECK(it != doomed_entries_.end());
665 doomed_entries_.erase(it); 669 doomed_entries_.erase(it);
666 } 670 }
667 671
668 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 672 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
669 auto it = active_entries_.find(key); 673 auto it = active_entries_.find(key);
670 return it != active_entries_.end() ? it->second.get() : NULL; 674 return it != active_entries_.end() ? it->second.get() : nullptr;
671 } 675 }
672 676
673 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 677 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
674 disk_cache::Entry* disk_entry) { 678 disk_cache::Entry* disk_entry) {
675 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 679 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
676 ActiveEntry* entry = new ActiveEntry(disk_entry); 680 ActiveEntry* entry = new ActiveEntry(disk_entry);
677 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 681 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
678 return entry; 682 return entry;
679 } 683 }
680 684
681 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 685 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
682 DCHECK(!entry->will_process_pending_queue); 686 DCHECK(!entry->will_process_queued_transactions);
683 DCHECK(!entry->doomed); 687 DCHECK(!entry->doomed);
684 DCHECK(entry->disk_entry); 688 DCHECK(entry->disk_entry);
685 DCHECK(entry->HasNoTransactions()); 689 DCHECK(entry->HasNoTransactions());
686 690
687 std::string key = entry->disk_entry->GetKey(); 691 std::string key = entry->disk_entry->GetKey();
688 if (key.empty()) 692 if (key.empty())
689 return SlowDeactivateEntry(entry); 693 return SlowDeactivateEntry(entry);
690 694
691 auto it = active_entries_.find(key); 695 auto it = active_entries_.find(key);
692 DCHECK(it != active_entries_.end()); 696 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 } 806 }
803 807
804 void HttpCache::DestroyEntry(ActiveEntry* entry) { 808 void HttpCache::DestroyEntry(ActiveEntry* entry) {
805 if (entry->doomed) { 809 if (entry->doomed) {
806 FinalizeDoomedEntry(entry); 810 FinalizeDoomedEntry(entry);
807 } else { 811 } else {
808 DeactivateEntry(entry); 812 DeactivateEntry(entry);
809 } 813 }
810 } 814 }
811 815
812 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 816 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
817 Transaction* transaction) {
813 DCHECK(entry); 818 DCHECK(entry);
814 DCHECK(entry->disk_entry); 819 DCHECK(entry->disk_entry);
815 820 // Always add a new transaction to the queue to maintain FIFO order.
816 // We implement a basic reader/writer lock for the disk cache entry. If 821 entry->add_to_entry_queue.push_back(transaction);
817 // there is already a writer, then everyone has to wait for the writer to 822 ProcessQueuedTransactions(entry);
818 // finish before they can access the cache entry. There can be multiple 823 return ERR_IO_PENDING;
819 // readers. 824 }
820 // 825
821 // NOTE: If the transaction can only write, then the entry should not be in 826 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
822 // use (since any existing entry should have already been doomed). 827 Transaction* transaction,
823 828 bool is_partial) {
824 if (entry->writer || entry->will_process_pending_queue) { 829 // If |transaction| is the current writer, do nothing. This can happen for
825 entry->pending_queue.push_back(trans); 830 // range requests since they can go back to headers phase after starting to
826 return ERR_IO_PENDING; 831 // write.
827 } 832 if (entry->writer == transaction)
828 833 return OK;
829 if (trans->mode() & Transaction::WRITE) { 834
830 // transaction needs exclusive access to the entry 835 CHECK_EQ(entry->headers_transaction, transaction);
831 if (entry->readers.empty()) { 836
832 entry->writer = trans; 837 entry->headers_transaction = nullptr;
833 } else { 838
834 entry->pending_queue.push_back(trans); 839 // If transaction is responsible for writing the response body, then do not go
835 return ERR_IO_PENDING; 840 // through done_headers_queue for performance benefit. (Also, in case of
841 // writer transaction, the consumer sometimes depend on synchronous behaviour
842 // e.g. while computing raw headers size. (crbug.com/711766))
843 if (transaction->mode() & Transaction::WRITE) {
844 // Partial requests may have write mode even when there is a writer present
845 // since they may be reader for a particular range and writer for another
846 // range.
847 CHECK(is_partial || (!entry->writer && entry->done_headers_queue.empty()));
Randy Smith (Not in Mondays) 2017/05/09 23:20:32 This is a (check-level) behavior change. Crashes
shivanisha 2017/05/10 14:46:03 Ah right. I forgot to mention that in the patch de
Randy Smith (Not in Mondays) 2017/05/10 21:34:26 Gotcha; that makes sense.
shivanisha 2017/05/11 19:58:24 a) is true because speculatively most of canary cr
Randy Smith (Not in Mondays) 2017/05/11 21:47:09 I'm perfectly happy with you having CHECKs in to h
jkarlin 2017/05/16 17:25:52 The style guide makes the usage of CHECKS clear:
848
849 if (!entry->writer) {
850 entry->writer = transaction;
851 ProcessQueuedTransactions(entry);
852 return OK;
836 } 853 }
837 } else { 854 }
838 // transaction needs read access to the entry 855
839 entry->readers.insert(trans); 856 // If this is not the first transaction in done_headers_queue, it should be a
840 } 857 // read-mode transaction except if it is a partial request.
841 858 CHECK(is_partial || (entry->done_headers_queue.empty() ||
842 // We do this before calling EntryAvailable to force any further calls to 859 !(transaction->mode() & Transaction::WRITE)));
843 // AddTransactionToEntry to add their transaction to the pending queue, which 860
844 // ensures FIFO ordering. 861 entry->done_headers_queue.push_back(transaction);
845 if (!entry->writer && !entry->pending_queue.empty()) 862 ProcessQueuedTransactions(entry);
846 ProcessPendingQueue(entry); 863 return ERR_IO_PENDING;
847 864 }
848 return OK; 865
849 } 866 void HttpCache::DoneWithEntry(ActiveEntry* entry,
850 867 Transaction* transaction,
851 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 868 bool process_cancel,
852 bool cancel) { 869 bool is_partial) {
853 // If we already posted a task to move on to the next transaction and this was 870 bool cancel = false;
854 // the writer, there is nothing to cancel. 871 if (process_cancel) {
855 if (entry->will_process_pending_queue && entry->readers.empty()) 872 cancel = IsTransactionExclusivelyWriting(entry, transaction, is_partial);
856 return; 873 if (cancel && is_partial)
857 874 entry->disk_entry->CancelSparseIO();
858 if (entry->writer) { 875 }
859 DCHECK(trans == entry->writer); 876
860 877 // Transaction is waiting in the done_headers_queue.
878 auto it = std::find(entry->done_headers_queue.begin(),
879 entry->done_headers_queue.end(), transaction);
880 if (it != entry->done_headers_queue.end()) {
881 entry->done_headers_queue.erase(it);
882 if (cancel)
883 ProcessEntryFailure(entry);
884 return;
885 }
886
887 // Transaction is removed in the headers phase.
888 if (transaction == entry->headers_transaction) {
889 // If the response is not written (cancel is true), consider it a failure.
890 DoneWritingToEntry(entry, !cancel, transaction);
891 return;
892 }
893
894 // Transaction is removed in the writing phase.
895 if (transaction == entry->writer) {
861 // Assume there was a failure. 896 // Assume there was a failure.
862 bool success = false; 897 bool success = false;
863 if (cancel) { 898 if (cancel) {
864 DCHECK(entry->disk_entry); 899 DCHECK(entry->disk_entry);
865 // This is a successful operation in the sense that we want to keep the 900 // This is a successful operation in the sense that we want to keep the
866 // entry. 901 // entry.
867 success = trans->AddTruncatedFlag(); 902 success = transaction->AddTruncatedFlag();
868 // The previous operation may have deleted the entry. 903 // The previous operation may have deleted the entry.
869 if (!trans->entry()) 904 if (!transaction->entry())
870 return; 905 return;
871 } 906 }
872 DoneWritingToEntry(entry, success); 907 DoneWritingToEntry(entry, success, transaction);
908 return;
909 }
910
911 // Transaction is reading from the entry.
912 DoneReadingFromEntry(entry, transaction);
913 }
914
915 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
916 bool success,
917 Transaction* transaction) {
918 DCHECK(transaction == entry->writer ||
919 transaction == entry->headers_transaction);
920
921 if (transaction == entry->writer)
922 entry->writer = nullptr;
923 else
924 entry->headers_transaction = nullptr;
925
926 // If writer fails, restart the headers_transaction by setting its state.
927 // Since the headers_transactions is awaiting an asynchronous operation
928 // completion, when it's IO callback is invoked, it will be restarted.
929 if (!success && entry->headers_transaction) {
930 entry->headers_transaction->SetValidatingCannotProceed();
931 entry->headers_transaction = nullptr;
932 DCHECK(entry->HasNoActiveTransactions());
933 }
934 if (!success)
935 ProcessEntryFailure(entry);
936 else
937 ProcessQueuedTransactions(entry);
938 }
939
940 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
941 Transaction* transaction) {
942 DCHECK(!entry->writer);
943 auto it = entry->readers.find(transaction);
944 DCHECK(it != entry->readers.end());
945 entry->readers.erase(it);
946
947 ProcessQueuedTransactions(entry);
948 }
949
950 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
951 TransactionList* list) {
952 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
953 // order.
954 for (auto* transaction : entry->done_headers_queue)
955 list->push_back(transaction);
956 entry->done_headers_queue.clear();
957
958 for (auto* transaction : entry->add_to_entry_queue)
959 list->push_back(transaction);
960 entry->add_to_entry_queue.clear();
961 }
962
963 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
964 // Failure case is either writer failing to completely write the response to
965 // the cache or validating transaction received a non-304 response.
966 TransactionList list;
967 if (entry->HasNoActiveTransactions() &&
968 !entry->will_process_queued_transactions) {
969 entry->disk_entry->Doom();
970 RemoveAllQueuedTransactions(entry, &list);
971 DestroyEntry(entry);
873 } else { 972 } else {
874 DoneReadingFromEntry(entry, trans); 973 DoomActiveEntry(entry->disk_entry->GetKey());
875 } 974 RemoveAllQueuedTransactions(entry, &list);
876 } 975 }
877 976 // ERR_CACHE_RACE causes the transaction to restart the whole process.
878 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 977 for (auto* transaction : list)
879 DCHECK(entry->readers.empty()); 978 transaction->io_callback().Run(net::ERR_CACHE_RACE);
880 979 }
881 entry->writer = NULL; 980
882 981 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
883 if (success) { 982 // Multiple readers may finish with an entry at once, so we want to batch up
884 ProcessPendingQueue(entry); 983 // calls to OnProcessQueuedTransactions. This flag also tells us that we
984 // should not delete the entry before OnProcessQueuedTransactions runs.
985 if (entry->will_process_queued_transactions)
986 return;
987
988 entry->will_process_queued_transactions = true;
989
990 // Post a task instead of invoking the io callback of another transaction here
991 // to avoid re-entrancy.
992 base::ThreadTaskRunnerHandle::Get()->PostTask(
993 FROM_HERE,
994 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
995 }
996
997 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
998 DCHECK(!entry->add_to_entry_queue.empty());
999
1000 // Note the entry may be new or may already have a response body written to
1001 // it. In both cases, a transaction needs to wait since only one transaction
1002 // can be in the headers phase at a time.
1003 if (entry->headers_transaction) {
1004 return;
1005 }
1006 Transaction* transaction = entry->add_to_entry_queue.front();
1007 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1008 entry->headers_transaction = transaction;
1009
1010 transaction->io_callback().Run(OK);
1011 }
1012
1013 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1014 DCHECK(!entry->writer);
1015 DCHECK(!entry->done_headers_queue.empty());
1016
1017 Transaction* transaction = entry->done_headers_queue.front();
1018
1019 // If this transaction is responsible for writing the response body.
1020 if (transaction->mode() & Transaction::WRITE) {
1021 entry->writer = transaction;
885 } else { 1022 } else {
886 DCHECK(!entry->will_process_pending_queue); 1023 // If a transaction is in front of this queue with only read mode set and
887 1024 // there is no writer, it implies response body is already written, convert
888 // We failed to create this entry. 1025 // to a reader.
889 TransactionList pending_queue; 1026 auto return_val = entry->readers.insert(transaction);
890 pending_queue.swap(entry->pending_queue); 1027 DCHECK_EQ(return_val.second, true);
891 1028 }
892 entry->disk_entry->Doom(); 1029
893 DestroyEntry(entry); 1030 // Post another task to give a chance to more transactions to either join
894 1031 // readers or another transaction to start parallel validation.
895 // We need to do something about these pending entries, which now need to 1032 ProcessQueuedTransactions(entry);
896 // be added to a new entry. 1033
897 while (!pending_queue.empty()) { 1034 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
898 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1035 transaction->io_callback().Run(OK);
899 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1036 }
900 pending_queue.pop_front(); 1037
901 } 1038 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
902 } 1039 Transaction* transaction,
903 } 1040 bool is_match) const {
904 1041 if (transaction != entry->headers_transaction)
905 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1042 return false;
906 DCHECK(!entry->writer); 1043
907 1044 if (!(transaction->mode() & Transaction::WRITE))
908 auto it = entry->readers.find(trans); 1045 return false;
909 DCHECK(it != entry->readers.end()); 1046
910 1047 // If its not a match then check if it is the transaction responsible for
911 entry->readers.erase(it); 1048 // writing the response body.
912 1049 if (!is_match) {
913 ProcessPendingQueue(entry); 1050 return !entry->writer && entry->done_headers_queue.empty() &&
914 } 1051 entry->readers.empty();
915 1052 }
916 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1053
917 DCHECK(entry->writer); 1054 return true;
918 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1055 }
919 DCHECK(entry->readers.empty()); 1056
920 1057 bool HttpCache::IsTransactionExclusivelyWriting(ActiveEntry* entry,
921 Transaction* trans = entry->writer; 1058 Transaction* transaction,
922 1059 bool is_partial) const {
923 entry->writer = NULL; 1060 if (transaction == entry->writer)
924 entry->readers.insert(trans); 1061 return true;
925 1062
926 ProcessPendingQueue(entry); 1063 if (transaction->method() == "HEAD" || transaction->method() == "DELETE")
1064 return false;
1065
1066 // Check if transaction is about to start writing to the cache.
1067
1068 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1069 if (!(transaction->mode() & Transaction::WRITE ||
1070 transaction->mode() == Transaction::NONE)) {
1071 return false;
1072 }
1073
1074 if (!is_partial) {
1075 // If a transaction is completing headers or done with headers phase with
1076 // write mode then it should be the future writer. Just checking the front
1077 // of done_headers_queue since the rest should anyways be READ mode
1078 // transactions as they would be a result of validation match (for non-range
1079 // requests).
1080 return transaction == entry->headers_transaction ||
1081 transaction == entry->done_headers_queue.front();
1082 }
1083
1084 // Range requests specific cases.
1085
1086 // For range requests, it is possible to have WRITE mode set even if another
1087 // transaction is the writer.
1088 if (entry->writer)
1089 return false;
1090
1091 if (transaction == entry->headers_transaction ||
1092 transaction == entry->done_headers_queue.front()) {
1093 return true;
1094 }
1095
1096 // If transaction is not in front of done_headers_queue, see if its the first
1097 // writer transaction in the queue.
1098 for (auto* done_headers : entry->done_headers_queue) {
1099 if (transaction == done_headers)
1100 return true;
1101 if (done_headers->mode() & Transaction::WRITE)
1102 return false;
1103 }
1104
1105 return false;
1106 }
1107
1108 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1109 return entry->writer != nullptr;
927 } 1110 }
928 1111
929 LoadState HttpCache::GetLoadStateForPendingTransaction( 1112 LoadState HttpCache::GetLoadStateForPendingTransaction(
930 const Transaction* trans) { 1113 const Transaction* trans) {
931 auto i = active_entries_.find(trans->key()); 1114 auto i = active_entries_.find(trans->key());
932 if (i == active_entries_.end()) { 1115 if (i == active_entries_.end()) {
933 // If this is really a pending transaction, and it is not part of 1116 // If this is really a pending transaction, and it is not part of
934 // active_entries_, we should be creating the backend or the entry. 1117 // active_entries_, we should be creating the backend or the entry.
935 return LOAD_STATE_WAITING_FOR_CACHE; 1118 return LOAD_STATE_WAITING_FOR_CACHE;
936 } 1119 }
(...skipping 29 matching lines...) Expand all
966 1149
967 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1150 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
968 ++k) { 1151 ++k) {
969 found = RemovePendingTransactionFromEntry(k->first, trans); 1152 found = RemovePendingTransactionFromEntry(k->first, trans);
970 } 1153 }
971 1154
972 DCHECK(found) << "Pending transaction not found"; 1155 DCHECK(found) << "Pending transaction not found";
973 } 1156 }
974 1157
975 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1158 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
976 Transaction* trans) { 1159 Transaction* transaction) {
977 TransactionList& pending_queue = entry->pending_queue; 1160 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
978 1161
979 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1162 auto j =
980 if (j == pending_queue.end()) 1163 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1164 if (j == add_to_entry_queue.end())
981 return false; 1165 return false;
982 1166
983 pending_queue.erase(j); 1167 add_to_entry_queue.erase(j);
984 return true; 1168 return true;
985 } 1169 }
986 1170
987 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1171 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
988 Transaction* trans) { 1172 Transaction* trans) {
989 if (pending_op->writer->Matches(trans)) { 1173 if (pending_op->writer->Matches(trans)) {
990 pending_op->writer->ClearTransaction(); 1174 pending_op->writer->ClearTransaction();
991 pending_op->writer->ClearEntry(); 1175 pending_op->writer->ClearEntry();
992 return true; 1176 return true;
993 } 1177 }
994 WorkItemList& pending_queue = pending_op->pending_queue; 1178 WorkItemList& pending_queue = pending_op->pending_queue;
995 1179
996 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1180 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
997 if ((*it)->Matches(trans)) { 1181 if ((*it)->Matches(trans)) {
998 pending_queue.erase(it); 1182 pending_queue.erase(it);
999 return true; 1183 return true;
1000 } 1184 }
1001 } 1185 }
1002 return false; 1186 return false;
1003 } 1187 }
1004 1188
1005 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1189 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1006 // Multiple readers may finish with an entry at once, so we want to batch up 1190 entry->will_process_queued_transactions = false;
1007 // calls to OnProcessPendingQueue. This flag also tells us that we should
1008 // not delete the entry before OnProcessPendingQueue runs.
1009 if (entry->will_process_pending_queue)
1010 return;
1011 entry->will_process_pending_queue = true;
1012 1191
1013 base::ThreadTaskRunnerHandle::Get()->PostTask( 1192 // Note that this function should only invoke one transaction's IO callback
1014 FROM_HERE, 1193 // since its possible for IO callbacks' consumers to destroy the cache/entry.
1015 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1016 }
1017
1018 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1019 entry->will_process_pending_queue = false;
1020 DCHECK(!entry->writer);
1021 1194
1022 // If no one is interested in this entry, then we can deactivate it. 1195 // If no one is interested in this entry, then we can deactivate it.
1023 if (entry->HasNoTransactions()) { 1196 if (entry->HasNoTransactions()) {
1024 DestroyEntry(entry); 1197 DestroyEntry(entry);
1025 return; 1198 return;
1026 } 1199 }
1027 1200
1028 if (entry->pending_queue.empty()) 1201 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1029 return; 1202 return;
1030 1203
1031 // Promote next transaction from the pending queue. 1204 // To maintain FIFO order of transactions, done_headers_queue should be
1032 Transaction* next = entry->pending_queue.front(); 1205 // checked for processing before add_to_entry_queue.
1033 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1034 return; // Have to wait.
1035 1206
1036 entry->pending_queue.erase(entry->pending_queue.begin()); 1207 // If another transaction is writing the response, let validated transactions
1208 // wait till the response is complete. If the response is not yet started, the
1209 // done_headers_queue transaction should start writing it.
1210 if (!entry->writer && !entry->done_headers_queue.empty()) {
1211 ProcessDoneHeadersQueue(entry);
1212 return;
1213 }
1037 1214
1038 int rv = AddTransactionToEntry(entry, next); 1215 if (!entry->add_to_entry_queue.empty())
1039 if (rv != ERR_IO_PENDING) { 1216 ProcessAddToEntryQueue(entry);
1040 next->io_callback().Run(rv);
1041 }
1042 } 1217 }
1043 1218
1044 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1219 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1045 WorkItemOperation op = pending_op->writer->operation(); 1220 WorkItemOperation op = pending_op->writer->operation();
1046 1221
1047 // Completing the creation of the backend is simpler than the other cases. 1222 // Completing the creation of the backend is simpler than the other cases.
1048 if (op == WI_CREATE_BACKEND) 1223 if (op == WI_CREATE_BACKEND)
1049 return OnBackendCreated(result, pending_op); 1224 return OnBackendCreated(result, pending_op);
1050 1225
1051 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1226 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1178 building_backend_ = false; 1353 building_backend_ = false;
1179 DeletePendingOp(pending_op); 1354 DeletePendingOp(pending_op);
1180 } 1355 }
1181 1356
1182 // The cache may be gone when we return from the callback. 1357 // The cache may be gone when we return from the callback.
1183 if (!item->DoCallback(result, disk_cache_.get())) 1358 if (!item->DoCallback(result, disk_cache_.get()))
1184 item->NotifyTransaction(result, NULL); 1359 item->NotifyTransaction(result, NULL);
1185 } 1360 }
1186 1361
1187 } // namespace net 1362 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698