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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: IsTransactionExclusivelyWriting simplified and renamed to HasDependentTransactions 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;
117 }
118
119 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
120 return !writer && readers.empty() && !headers_transaction;
120 } 121 }
121 122
122 //----------------------------------------------------------------------------- 123 //-----------------------------------------------------------------------------
123 124
124 // This structure keeps track of work items that are attempting to create or 125 // This structure keeps track of work items that are attempting to create or
125 // open cache entries or the backend itself. 126 // open cache entries or the backend itself.
126 struct HttpCache::PendingOp { 127 struct HttpCache::PendingOp {
127 PendingOp() : disk_entry(NULL) {} 128 PendingOp() : disk_entry(NULL) {}
128 ~PendingOp() {} 129 ~PendingOp() {}
129 130
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 disk_cache::Backend** backend_; 212 disk_cache::Backend** backend_;
212 }; 213 };
213 214
214 //----------------------------------------------------------------------------- 215 //-----------------------------------------------------------------------------
215 216
216 // This class encapsulates a transaction whose only purpose is to write metadata 217 // This class encapsulates a transaction whose only purpose is to write metadata
217 // to a given entry. 218 // to a given entry.
218 class HttpCache::MetadataWriter { 219 class HttpCache::MetadataWriter {
219 public: 220 public:
220 explicit MetadataWriter(HttpCache::Transaction* trans) 221 explicit MetadataWriter(HttpCache::Transaction* trans)
221 : transaction_(trans), 222 : verified_(false), buf_len_(0), transaction_(trans) {}
222 verified_(false),
223 buf_len_(0) {
224 }
225 223
226 ~MetadataWriter() {} 224 ~MetadataWriter() {}
227 225
228 // Implements the bulk of HttpCache::WriteMetadata. 226 // Implements the bulk of HttpCache::WriteMetadata.
229 void Write(const GURL& url, 227 void Write(const GURL& url,
230 base::Time expected_response_time, 228 base::Time expected_response_time,
231 IOBuffer* buf, 229 IOBuffer* buf,
232 int buf_len); 230 int buf_len);
233 231
234 private: 232 private:
235 void VerifyResponse(int result); 233 void VerifyResponse(int result);
236 void SelfDestroy(); 234 void SelfDestroy();
237 void OnIOComplete(int result); 235 void OnIOComplete(int result);
238 236
239 std::unique_ptr<HttpCache::Transaction> transaction_;
240 bool verified_; 237 bool verified_;
241 scoped_refptr<IOBuffer> buf_; 238 scoped_refptr<IOBuffer> buf_;
242 int buf_len_; 239 int buf_len_;
243 base::Time expected_response_time_; 240 base::Time expected_response_time_;
244 HttpRequestInfo request_info_; 241 HttpRequestInfo request_info_;
242
243 // |transaction_| to come after |request_info_| so that |request_info_| is not
244 // destroyed earlier.
245 std::unique_ptr<HttpCache::Transaction> transaction_;
245 DISALLOW_COPY_AND_ASSIGN(MetadataWriter); 246 DISALLOW_COPY_AND_ASSIGN(MetadataWriter);
246 }; 247 };
247 248
248 void HttpCache::MetadataWriter::Write(const GURL& url, 249 void HttpCache::MetadataWriter::Write(const GURL& url,
249 base::Time expected_response_time, 250 base::Time expected_response_time,
250 IOBuffer* buf, 251 IOBuffer* buf,
251 int buf_len) { 252 int buf_len) {
252 DCHECK_GT(buf_len, 0); 253 DCHECK_GT(buf_len, 0);
253 DCHECK(buf); 254 DCHECK(buf);
254 DCHECK(buf->data()); 255 DCHECK(buf->data());
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 session->SetServerPushDelegate( 335 session->SetServerPushDelegate(
335 base::MakeUnique<HttpCacheLookupManager>(this)); 336 base::MakeUnique<HttpCacheLookupManager>(this));
336 } 337 }
337 338
338 HttpCache::~HttpCache() { 339 HttpCache::~HttpCache() {
339 // Transactions should see an invalid cache after this point; otherwise they 340 // Transactions should see an invalid cache after this point; otherwise they
340 // could see an inconsistent object (half destroyed). 341 // could see an inconsistent object (half destroyed).
341 weak_factory_.InvalidateWeakPtrs(); 342 weak_factory_.InvalidateWeakPtrs();
342 343
343 // If we have any active entries remaining, then we need to deactivate them. 344 // 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 345 // 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 346 // those won't run (due to our destruction), we can simply ignore the
346 // will_process_pending_queue flag. 347 // corresponding flags.
347 while (!active_entries_.empty()) { 348 while (!active_entries_.empty()) {
348 ActiveEntry* entry = active_entries_.begin()->second.get(); 349 ActiveEntry* entry = active_entries_.begin()->second.get();
349 entry->will_process_pending_queue = false; 350 entry->will_process_queued_transactions = false;
350 entry->pending_queue.clear(); 351 entry->add_to_entry_queue.clear();
351 entry->readers.clear(); 352 entry->readers.clear();
352 entry->writer = NULL; 353 entry->done_headers_queue.clear();
354 entry->headers_transaction = nullptr;
355 entry->writer = nullptr;
353 DeactivateEntry(entry); 356 DeactivateEntry(entry);
354 } 357 }
355 358
356 doomed_entries_.clear(); 359 doomed_entries_.clear();
357 360
358 // Before deleting pending_ops_, we have to make sure that the disk cache is 361 // 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. 362 // done with said operations, or it will attempt to use deleted data.
360 disk_cache_.reset(); 363 disk_cache_.reset();
361 364
362 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 365 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 606 // We keep track of doomed entries so that we can ensure that they are
604 // cleaned up properly when the cache is destroyed. 607 // cleaned up properly when the cache is destroyed.
605 ActiveEntry* entry_ptr = entry.get(); 608 ActiveEntry* entry_ptr = entry.get();
606 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 609 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
607 doomed_entries_[entry_ptr] = std::move(entry); 610 doomed_entries_[entry_ptr] = std::move(entry);
608 611
609 entry_ptr->disk_entry->Doom(); 612 entry_ptr->disk_entry->Doom();
610 entry_ptr->doomed = true; 613 entry_ptr->doomed = true;
611 614
612 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 615 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
613 entry_ptr->will_process_pending_queue); 616 entry_ptr->headers_transaction ||
617 entry_ptr->will_process_queued_transactions);
614 return OK; 618 return OK;
615 } 619 }
616 620
617 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 621 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
618 std::unique_ptr<WorkItem> item = 622 std::unique_ptr<WorkItem> item =
619 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 623 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
620 PendingOp* pending_op = GetPendingOp(key); 624 PendingOp* pending_op = GetPendingOp(key);
621 if (pending_op->writer) { 625 if (pending_op->writer) {
622 pending_op->pending_queue.push_back(std::move(item)); 626 pending_op->pending_queue.push_back(std::move(item));
623 return ERR_IO_PENDING; 627 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 DCHECK(entry->doomed); 663 DCHECK(entry->doomed);
660 DCHECK(entry->HasNoTransactions()); 664 DCHECK(entry->HasNoTransactions());
661 665
662 auto it = doomed_entries_.find(entry); 666 auto it = doomed_entries_.find(entry);
663 DCHECK(it != doomed_entries_.end()); 667 DCHECK(it != doomed_entries_.end());
664 doomed_entries_.erase(it); 668 doomed_entries_.erase(it);
665 } 669 }
666 670
667 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 671 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
668 auto it = active_entries_.find(key); 672 auto it = active_entries_.find(key);
669 return it != active_entries_.end() ? it->second.get() : NULL; 673 return it != active_entries_.end() ? it->second.get() : nullptr;
670 } 674 }
671 675
672 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 676 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
673 disk_cache::Entry* disk_entry) { 677 disk_cache::Entry* disk_entry) {
674 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 678 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
675 ActiveEntry* entry = new ActiveEntry(disk_entry); 679 ActiveEntry* entry = new ActiveEntry(disk_entry);
676 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 680 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
677 return entry; 681 return entry;
678 } 682 }
679 683
680 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 684 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
681 DCHECK(!entry->will_process_pending_queue); 685 DCHECK(!entry->will_process_queued_transactions);
682 DCHECK(!entry->doomed); 686 DCHECK(!entry->doomed);
683 DCHECK(entry->disk_entry); 687 DCHECK(entry->disk_entry);
684 DCHECK(entry->HasNoTransactions()); 688 DCHECK(entry->HasNoTransactions());
685 689
686 std::string key = entry->disk_entry->GetKey(); 690 std::string key = entry->disk_entry->GetKey();
687 if (key.empty()) 691 if (key.empty())
688 return SlowDeactivateEntry(entry); 692 return SlowDeactivateEntry(entry);
689 693
690 auto it = active_entries_.find(key); 694 auto it = active_entries_.find(key);
691 DCHECK(it != active_entries_.end()); 695 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
801 } 805 }
802 806
803 void HttpCache::DestroyEntry(ActiveEntry* entry) { 807 void HttpCache::DestroyEntry(ActiveEntry* entry) {
804 if (entry->doomed) { 808 if (entry->doomed) {
805 FinalizeDoomedEntry(entry); 809 FinalizeDoomedEntry(entry);
806 } else { 810 } else {
807 DeactivateEntry(entry); 811 DeactivateEntry(entry);
808 } 812 }
809 } 813 }
810 814
811 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 815 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
816 Transaction* transaction) {
812 DCHECK(entry); 817 DCHECK(entry);
813 DCHECK(entry->disk_entry); 818 DCHECK(entry->disk_entry);
814 819 // 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 820 entry->add_to_entry_queue.push_back(transaction);
816 // there is already a writer, then everyone has to wait for the writer to 821 ProcessQueuedTransactions(entry);
817 // finish before they can access the cache entry. There can be multiple 822 return ERR_IO_PENDING;
818 // readers. 823 }
819 // 824
820 // NOTE: If the transaction can only write, then the entry should not be in 825 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
821 // use (since any existing entry should have already been doomed). 826 Transaction* transaction,
822 827 bool is_partial) {
823 if (entry->writer || entry->will_process_pending_queue) { 828 // If |transaction| is the current writer, do nothing. This can happen for
824 entry->pending_queue.push_back(trans); 829 // range requests since they can go back to headers phase after starting to
825 return ERR_IO_PENDING; 830 // write.
826 } 831 if (entry->writer == transaction)
827 832 return OK;
828 if (trans->mode() & Transaction::WRITE) { 833
829 // transaction needs exclusive access to the entry 834 // TODO(crbug.com/715913, crbug.com/715974, crbug.com/715920,
830 if (entry->readers.empty()) { 835 // crbug.com/715911): Convert the CHECKs in this function to DCHECKs once
831 entry->writer = trans; 836 // canary is clear of any crashes.
832 } else { 837 CHECK_EQ(entry->headers_transaction, transaction);
833 entry->pending_queue.push_back(trans); 838
834 return ERR_IO_PENDING; 839 entry->headers_transaction = nullptr;
840
841 // If transaction is responsible for writing the response body, then do not go
842 // through done_headers_queue for performance benefit. (Also, in case of
843 // writer transaction, the consumer sometimes depend on synchronous behaviour
844 // e.g. while computing raw headers size. (crbug.com/711766))
845 if (transaction->mode() & Transaction::WRITE) {
846 // Partial requests may have write mode even when there is a writer present
847 // since they may be reader for a particular range and writer for another
848 // range.
849 CHECK(is_partial || (!entry->writer && entry->done_headers_queue.empty()));
850
851 if (!entry->writer) {
852 entry->writer = transaction;
853 ProcessQueuedTransactions(entry);
854 return OK;
835 } 855 }
836 } else { 856 }
837 // transaction needs read access to the entry 857
838 entry->readers.insert(trans); 858 // If this is not the first transaction in done_headers_queue, it should be a
839 } 859 // read-mode transaction except if it is a partial request.
840 860 CHECK(is_partial || (entry->done_headers_queue.empty() ||
841 // We do this before calling EntryAvailable to force any further calls to 861 !(transaction->mode() & Transaction::WRITE)));
842 // AddTransactionToEntry to add their transaction to the pending queue, which 862
843 // ensures FIFO ordering. 863 entry->done_headers_queue.push_back(transaction);
844 if (!entry->writer && !entry->pending_queue.empty()) 864 ProcessQueuedTransactions(entry);
845 ProcessPendingQueue(entry); 865 return ERR_IO_PENDING;
846 866 }
847 return OK; 867
848 } 868 void HttpCache::DoneWithEntry(ActiveEntry* entry,
849 869 Transaction* transaction,
850 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 870 bool process_cancel,
851 bool cancel) { 871 bool is_partial) {
852 // If we already posted a task to move on to the next transaction and this was 872 // |should_restart| is true if there may be other transactions dependent on
853 // the writer, there is nothing to cancel. 873 // this transaction and they will need to be restarted.
854 if (entry->will_process_pending_queue && entry->readers.empty()) 874 bool should_restart = process_cancel && HasDependentTransactions(
855 return; 875 entry, transaction, is_partial);
856 876 if (should_restart && is_partial)
857 if (entry->writer) { 877 entry->disk_entry->CancelSparseIO();
858 DCHECK(trans == entry->writer); 878
859 879 // Transaction is waiting in the done_headers_queue.
880 auto it = std::find(entry->done_headers_queue.begin(),
881 entry->done_headers_queue.end(), transaction);
882 if (it != entry->done_headers_queue.end()) {
883 entry->done_headers_queue.erase(it);
884 if (should_restart)
885 ProcessEntryFailure(entry);
886 return;
887 }
888
889 // Transaction is removed in the headers phase.
890 if (transaction == entry->headers_transaction) {
891 // If the response is not written (cancel is true), consider it a failure.
jkarlin 2017/06/01 18:49:21 s/cancel/should_restart/
shivanisha 2017/06/05 06:41:22 done
892 DoneWritingToEntry(entry, !should_restart, transaction);
893 return;
894 }
895
896 // Transaction is removed in the writing phase.
897 if (transaction == entry->writer) {
860 // Assume there was a failure. 898 // Assume there was a failure.
861 bool success = false; 899 bool success = false;
862 if (cancel) { 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();
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 DoneWritingToEntry(entry, success, transaction);
jkarlin 2017/06/01 18:49:21 Why do we pass success here? Doesn't this mean tha
shivanisha 2017/06/05 06:41:22 You are right, done_headers_queue transactions did
910 return;
911 }
912
913 // Transaction is reading from the entry.
914 DoneReadingFromEntry(entry, transaction);
915 }
916
917 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
918 bool success,
919 Transaction* transaction) {
920 DCHECK(transaction == entry->writer ||
921 transaction == entry->headers_transaction);
922
923 if (transaction == entry->writer)
924 entry->writer = nullptr;
925 else
926 entry->headers_transaction = nullptr;
927
928 // If writer fails, restart the headers_transaction by setting its state.
929 // Since the headers_transactions is awaiting an asynchronous operation
930 // completion, when it's IO callback is invoked, it will be restarted.
931 if (!success && entry->headers_transaction) {
932 entry->headers_transaction->SetValidatingCannotProceed();
933 entry->headers_transaction = nullptr;
934 DCHECK(entry->HasNoActiveTransactions());
935 }
936 if (!success)
937 ProcessEntryFailure(entry);
938 else
939 ProcessQueuedTransactions(entry);
940 }
941
942 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
943 Transaction* transaction) {
944 DCHECK(!entry->writer);
945 auto it = entry->readers.find(transaction);
946 DCHECK(it != entry->readers.end());
947 entry->readers.erase(it);
948
949 ProcessQueuedTransactions(entry);
950 }
951
952 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
953 TransactionList* list) {
954 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
955 // order.
956 for (auto* transaction : entry->done_headers_queue)
957 list->push_back(transaction);
958 entry->done_headers_queue.clear();
959
960 for (auto* transaction : entry->add_to_entry_queue)
961 list->push_back(transaction);
962 entry->add_to_entry_queue.clear();
963 }
964
965 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
966 // Failure case is either writer failing to completely write the response to
967 // the cache or validating transaction received a non-304 response.
968 TransactionList list;
969 if (entry->HasNoActiveTransactions() &&
970 !entry->will_process_queued_transactions) {
971 entry->disk_entry->Doom();
972 RemoveAllQueuedTransactions(entry, &list);
973 DestroyEntry(entry);
872 } else { 974 } else {
873 DoneReadingFromEntry(entry, trans); 975 DoomActiveEntry(entry->disk_entry->GetKey());
874 } 976 RemoveAllQueuedTransactions(entry, &list);
875 } 977 }
876 978 // ERR_CACHE_RACE causes the transaction to restart the whole process.
877 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 979 for (auto* transaction : list)
878 DCHECK(entry->readers.empty()); 980 transaction->io_callback().Run(net::ERR_CACHE_RACE);
879 981 }
880 entry->writer = NULL; 982
881 983 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
882 if (success) { 984 // Multiple readers may finish with an entry at once, so we want to batch up
883 ProcessPendingQueue(entry); 985 // calls to OnProcessQueuedTransactions. This flag also tells us that we
986 // should not delete the entry before OnProcessQueuedTransactions runs.
987 if (entry->will_process_queued_transactions)
988 return;
989
990 entry->will_process_queued_transactions = true;
991
992 // Post a task instead of invoking the io callback of another transaction here
993 // to avoid re-entrancy.
994 base::ThreadTaskRunnerHandle::Get()->PostTask(
995 FROM_HERE,
996 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
997 }
998
999 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
1000 DCHECK(!entry->add_to_entry_queue.empty());
1001
1002 // Note the entry may be new or may already have a response body written to
1003 // it. In both cases, a transaction needs to wait since only one transaction
1004 // can be in the headers phase at a time.
1005 if (entry->headers_transaction) {
1006 return;
1007 }
1008 Transaction* transaction = entry->add_to_entry_queue.front();
1009 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1010 entry->headers_transaction = transaction;
1011
1012 transaction->io_callback().Run(OK);
1013 }
1014
1015 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1016 DCHECK(!entry->writer);
1017 DCHECK(!entry->done_headers_queue.empty());
1018
1019 Transaction* transaction = entry->done_headers_queue.front();
1020
1021 // If this transaction is responsible for writing the response body.
1022 if (transaction->mode() & Transaction::WRITE) {
1023 entry->writer = transaction;
884 } else { 1024 } else {
885 DCHECK(!entry->will_process_pending_queue); 1025 // If a transaction is in front of this queue with only read mode set and
886 1026 // there is no writer, it implies response body is already written, convert
887 // We failed to create this entry. 1027 // to a reader.
888 TransactionList pending_queue; 1028 auto return_val = entry->readers.insert(transaction);
889 pending_queue.swap(entry->pending_queue); 1029 DCHECK_EQ(return_val.second, true);
890 1030 }
891 entry->disk_entry->Doom(); 1031
892 DestroyEntry(entry); 1032 // Post another task to give a chance to more transactions to either join
893 1033 // readers or another transaction to start parallel validation.
894 // We need to do something about these pending entries, which now need to 1034 ProcessQueuedTransactions(entry);
895 // be added to a new entry. 1035
896 while (!pending_queue.empty()) { 1036 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
897 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1037 transaction->io_callback().Run(OK);
898 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1038 }
899 pending_queue.pop_front(); 1039
900 } 1040 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
901 } 1041 Transaction* transaction,
902 } 1042 bool is_match) const {
903 1043 if (transaction != entry->headers_transaction)
904 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1044 return false;
905 DCHECK(!entry->writer); 1045
906 1046 if (!(transaction->mode() & Transaction::WRITE))
907 auto it = entry->readers.find(trans); 1047 return false;
908 DCHECK(it != entry->readers.end()); 1048
909 1049 // If its not a match then check if it is the transaction responsible for
910 entry->readers.erase(it); 1050 // writing the response body.
911 1051 if (!is_match) {
912 ProcessPendingQueue(entry); 1052 return !entry->writer && entry->done_headers_queue.empty() &&
913 } 1053 entry->readers.empty();
914 1054 }
915 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1055
916 DCHECK(entry->writer); 1056 return true;
917 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1057 }
918 DCHECK(entry->readers.empty()); 1058
919 1059 bool HttpCache::HasDependentTransactions(ActiveEntry* entry,
920 Transaction* trans = entry->writer; 1060 Transaction* transaction,
921 1061 bool is_partial) const {
922 entry->writer = NULL; 1062 if (transaction->method() == "HEAD" || transaction->method() == "DELETE")
923 entry->readers.insert(trans); 1063 return false;
924 1064
925 ProcessPendingQueue(entry); 1065 // Check if transaction is about to start writing to the cache.
1066
1067 // Transaction's mode may have been set to NONE if StopCaching was invoked but
1068 // that should still be considered a writer failure.
jkarlin 2017/06/01 18:49:21 Huh. What happens if the writer has StopCaching()
shivanisha 2017/06/05 06:41:22 Current behavior: When the transaction successfull
1069 if (!(transaction->mode() & Transaction::WRITE ||
1070 transaction->mode() == Transaction::NONE)) {
1071 return false;
1072 }
1073
1074 // If transaction is not in add_to_entry_queue and has a WRITE bit set, then
jkarlin 2017/06/01 18:49:21 WRITE bit set or is NONE, then there may be other.
shivanisha 2017/06/05 06:41:22 done
1075 // there may be other transactions depending on it to completely write the
1076 // response.
1077 for (auto* pending_transaction : entry->add_to_entry_queue) {
1078 if (pending_transaction == transaction)
1079 return false;
1080 }
1081
1082 return true;
1083 }
1084
1085 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1086 return entry->writer != nullptr;
926 } 1087 }
927 1088
928 LoadState HttpCache::GetLoadStateForPendingTransaction( 1089 LoadState HttpCache::GetLoadStateForPendingTransaction(
929 const Transaction* trans) { 1090 const Transaction* trans) {
930 auto i = active_entries_.find(trans->key()); 1091 auto i = active_entries_.find(trans->key());
931 if (i == active_entries_.end()) { 1092 if (i == active_entries_.end()) {
932 // If this is really a pending transaction, and it is not part of 1093 // 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. 1094 // active_entries_, we should be creating the backend or the entry.
934 return LOAD_STATE_WAITING_FOR_CACHE; 1095 return LOAD_STATE_WAITING_FOR_CACHE;
935 } 1096 }
(...skipping 29 matching lines...) Expand all
965 1126
966 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1127 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
967 ++k) { 1128 ++k) {
968 found = RemovePendingTransactionFromEntry(k->first, trans); 1129 found = RemovePendingTransactionFromEntry(k->first, trans);
969 } 1130 }
970 1131
971 DCHECK(found) << "Pending transaction not found"; 1132 DCHECK(found) << "Pending transaction not found";
972 } 1133 }
973 1134
974 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1135 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
975 Transaction* trans) { 1136 Transaction* transaction) {
976 TransactionList& pending_queue = entry->pending_queue; 1137 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
977 1138
978 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1139 auto j =
979 if (j == pending_queue.end()) 1140 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1141 if (j == add_to_entry_queue.end())
980 return false; 1142 return false;
981 1143
982 pending_queue.erase(j); 1144 add_to_entry_queue.erase(j);
983 return true; 1145 return true;
984 } 1146 }
985 1147
986 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1148 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
987 Transaction* trans) { 1149 Transaction* trans) {
988 if (pending_op->writer->Matches(trans)) { 1150 if (pending_op->writer->Matches(trans)) {
989 pending_op->writer->ClearTransaction(); 1151 pending_op->writer->ClearTransaction();
990 pending_op->writer->ClearEntry(); 1152 pending_op->writer->ClearEntry();
991 return true; 1153 return true;
992 } 1154 }
993 WorkItemList& pending_queue = pending_op->pending_queue; 1155 WorkItemList& pending_queue = pending_op->pending_queue;
994 1156
995 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1157 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
996 if ((*it)->Matches(trans)) { 1158 if ((*it)->Matches(trans)) {
997 pending_queue.erase(it); 1159 pending_queue.erase(it);
998 return true; 1160 return true;
999 } 1161 }
1000 } 1162 }
1001 return false; 1163 return false;
1002 } 1164 }
1003 1165
1004 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1166 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1005 // Multiple readers may finish with an entry at once, so we want to batch up 1167 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 1168
1012 base::ThreadTaskRunnerHandle::Get()->PostTask( 1169 // Note that this function should only invoke one transaction's IO callback
1013 FROM_HERE, 1170 // 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 1171
1021 // If no one is interested in this entry, then we can deactivate it. 1172 // If no one is interested in this entry, then we can deactivate it.
1022 if (entry->HasNoTransactions()) { 1173 if (entry->HasNoTransactions()) {
1023 DestroyEntry(entry); 1174 DestroyEntry(entry);
1024 return; 1175 return;
1025 } 1176 }
1026 1177
1027 if (entry->pending_queue.empty()) 1178 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1028 return; 1179 return;
1029 1180
1030 // Promote next transaction from the pending queue. 1181 // To maintain FIFO order of transactions, done_headers_queue should be
1031 Transaction* next = entry->pending_queue.front(); 1182 // checked for processing before add_to_entry_queue.
1032 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1033 return; // Have to wait.
1034 1183
1035 entry->pending_queue.erase(entry->pending_queue.begin()); 1184 // If another transaction is writing the response, let validated transactions
1185 // wait till the response is complete. If the response is not yet started, the
1186 // done_headers_queue transaction should start writing it.
1187 if (!entry->writer && !entry->done_headers_queue.empty()) {
1188 ProcessDoneHeadersQueue(entry);
1189 return;
1190 }
1036 1191
1037 int rv = AddTransactionToEntry(entry, next); 1192 if (!entry->add_to_entry_queue.empty())
1038 if (rv != ERR_IO_PENDING) { 1193 ProcessAddToEntryQueue(entry);
1039 next->io_callback().Run(rv);
1040 }
1041 } 1194 }
1042 1195
1043 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1196 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1044 WorkItemOperation op = pending_op->writer->operation(); 1197 WorkItemOperation op = pending_op->writer->operation();
1045 1198
1046 // Completing the creation of the backend is simpler than the other cases. 1199 // Completing the creation of the backend is simpler than the other cases.
1047 if (op == WI_CREATE_BACKEND) 1200 if (op == WI_CREATE_BACKEND)
1048 return OnBackendCreated(result, pending_op); 1201 return OnBackendCreated(result, pending_op);
1049 1202
1050 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1203 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; 1330 building_backend_ = false;
1178 DeletePendingOp(pending_op); 1331 DeletePendingOp(pending_op);
1179 } 1332 }
1180 1333
1181 // The cache may be gone when we return from the callback. 1334 // The cache may be gone when we return from the callback.
1182 if (!item->DoCallback(result, disk_cache_.get())) 1335 if (!item->DoCallback(result, disk_cache_.get()))
1183 item->NotifyTransaction(result, NULL); 1336 item->NotifyTransaction(result, NULL);
1184 } 1337 }
1185 1338
1186 } // namespace net 1339 } // 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