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

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

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