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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Truncation and StopCaching changes. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_cache.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.
jkarlin 2017/06/08 16:14:09 I don't understand this comment.
shivanisha 2017/06/08 18:26:01 No transaction should bypass the queue because thi
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)
jkarlin 2017/06/08 16:14:09 Can we DCHECK that this is a range request?
shivanisha 2017/06/08 18:26:01 done
827 828 return OK;
828 if (trans->mode() & Transaction::WRITE) { 829
829 // transaction needs exclusive access to the entry 830 // TODO(crbug.com/715913, crbug.com/715974, crbug.com/715920,
830 if (entry->readers.empty()) { 831 // crbug.com/715911): Convert the CHECKs in this function to DCHECKs once
831 entry->writer = trans; 832 // canary is clear of any crashes.
832 } else { 833 CHECK_EQ(entry->headers_transaction, transaction);
833 entry->pending_queue.push_back(trans); 834
834 return ERR_IO_PENDING; 835 entry->headers_transaction = nullptr;
836
837 // If transaction is responsible for writing the response body, then do not go
838 // through done_headers_queue for performance benefit. (Also, in case of
839 // writer transaction, the consumer sometimes depend on synchronous behaviour
840 // e.g. while computing raw headers size. (crbug.com/711766))
841 if (transaction->mode() & Transaction::WRITE) {
842 // Partial requests may have write mode even when there is a writer present
843 // since they may be reader for a particular range and writer for another
844 // range.
845 CHECK(is_partial || (!entry->writer && entry->done_headers_queue.empty()));
846
847 if (!entry->writer) {
848 entry->writer = transaction;
849 ProcessQueuedTransactions(entry);
850 return OK;
835 } 851 }
836 } else { 852 }
837 // transaction needs read access to the entry 853
838 entry->readers.insert(trans); 854 // If this is not the first transaction in done_headers_queue, it should be a
839 } 855 // read-mode transaction except if it is a partial request.
840 856 CHECK(is_partial || (entry->done_headers_queue.empty() ||
841 // We do this before calling EntryAvailable to force any further calls to 857 !(transaction->mode() & Transaction::WRITE)));
842 // AddTransactionToEntry to add their transaction to the pending queue, which 858
843 // ensures FIFO ordering. 859 entry->done_headers_queue.push_back(transaction);
844 if (!entry->writer && !entry->pending_queue.empty()) 860 ProcessQueuedTransactions(entry);
845 ProcessPendingQueue(entry); 861 return ERR_IO_PENDING;
846 862 }
847 return OK; 863
848 } 864 void HttpCache::DoneWithEntry(ActiveEntry* entry,
849 865 Transaction* transaction,
850 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 866 bool process_cancel,
851 bool cancel) { 867 bool is_partial) {
852 // If we already posted a task to move on to the next transaction and this was 868 // |should_restart| is true if there may be other transactions dependent on
853 // the writer, there is nothing to cancel. 869 // this transaction and they will need to be restarted.
854 if (entry->will_process_pending_queue && entry->readers.empty()) 870 bool should_restart = process_cancel && HasDependentTransactions(
855 return; 871 entry, transaction, is_partial);
856 872 if (should_restart && is_partial)
857 if (entry->writer) { 873 entry->disk_entry->CancelSparseIO();
858 DCHECK(trans == entry->writer); 874
859 875 // Transaction is waiting in the done_headers_queue.
876 auto it = std::find(entry->done_headers_queue.begin(),
877 entry->done_headers_queue.end(), transaction);
878 if (it != entry->done_headers_queue.end()) {
879 entry->done_headers_queue.erase(it);
880 if (should_restart)
881 ProcessEntryFailure(entry, transaction);
882 return;
883 }
884
885 // Transaction is removed in the headers phase.
886 if (transaction == entry->headers_transaction) {
887 // If the response is not written (should_restart is true), consider it a
888 // failure.
889 DoneWritingToEntry(entry, !should_restart, transaction);
890 return;
891 }
892
893 // Transaction is removed in the writing phase.
894 if (transaction == entry->writer) {
860 // Assume there was a failure. 895 // Assume there was a failure.
861 bool success = false; 896 bool success = false;
862 if (cancel) { 897 bool is_truncated = false;
898 if (should_restart) {
863 DCHECK(entry->disk_entry); 899 DCHECK(entry->disk_entry);
864 // 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
865 // entry. 901 // entry.
866 success = trans->AddTruncatedFlag(); 902 success = transaction->AddTruncatedFlag(&is_truncated);
867 // The previous operation may have deleted the entry. 903 // The previous operation may have deleted the entry.
868 if (!trans->entry()) 904 if (!transaction->entry())
869 return; 905 return;
870 } 906 }
871 DoneWritingToEntry(entry, success); 907 if (success && is_truncated) {
872 } else { 908 entry->writer = nullptr;
873 DoneReadingFromEntry(entry, trans); 909 // Restart already validated transactions so that they are able to read
874 } 910 // the truncated status of the entry.
875 } 911 RestartHeadersPhaseTransactions(entry, transaction);
876 912 return;
877 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 913 }
878 DCHECK(entry->readers.empty()); 914 DoneWritingToEntry(entry, success && !is_truncated, transaction);
879 915 return;
880 entry->writer = NULL; 916 }
881 917
882 if (success) { 918 // Transaction is reading from the entry.
883 ProcessPendingQueue(entry); 919 DoneReadingFromEntry(entry, transaction);
884 } else { 920 }
885 DCHECK(!entry->will_process_pending_queue); 921
886 922 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
887 // We failed to create this entry. 923 bool success,
888 TransactionList pending_queue; 924 Transaction* transaction) {
889 pending_queue.swap(entry->pending_queue); 925 DCHECK(transaction == entry->writer ||
890 926 transaction == entry->headers_transaction);
927
928 if (transaction == entry->writer)
929 entry->writer = nullptr;
930 else
931 entry->headers_transaction = nullptr;
932
933 if (!success)
934 ProcessEntryFailure(entry, transaction);
935 else
936 ProcessQueuedTransactions(entry);
937 }
938
939 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
940 Transaction* transaction) {
941 DCHECK(!entry->writer);
942 auto it = entry->readers.find(transaction);
943 DCHECK(it != entry->readers.end());
944 entry->readers.erase(it);
945
946 ProcessQueuedTransactions(entry);
947 }
948
949 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
950 TransactionList* list) {
951 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
952 // order.
953
954 for (auto* transaction : entry->done_headers_queue)
955 list->push_back(transaction);
956 entry->done_headers_queue.clear();
957
958 for (auto* pending_transaction : entry->add_to_entry_queue)
959 list->push_back(pending_transaction);
960 entry->add_to_entry_queue.clear();
961 }
962
963 void HttpCache::ProcessEntryFailure(ActiveEntry* entry,
964 Transaction* transaction) {
965 // Failure case is either writer failing to completely write the response to
966 // the cache or validating transaction received a non-304 response.
967
968 if (entry->headers_transaction && transaction != entry->headers_transaction)
969 RestartHeadersTransaction(entry, transaction);
970
971 TransactionList list;
972 RemoveAllQueuedTransactions(entry, &list);
973
974 if (entry->HasNoTransactions() && !entry->will_process_queued_transactions) {
891 entry->disk_entry->Doom(); 975 entry->disk_entry->Doom();
892 DestroyEntry(entry); 976 DestroyEntry(entry);
893 977 } else {
894 // We need to do something about these pending entries, which now need to 978 DoomActiveEntry(entry->disk_entry->GetKey());
895 // be added to a new entry. 979 }
896 while (!pending_queue.empty()) { 980 // ERR_CACHE_RACE causes the transaction to restart the whole process.
897 // ERR_CACHE_RACE causes the transaction to restart the whole process. 981 for (auto* transaction : list)
898 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 982 transaction->io_callback().Run(net::ERR_CACHE_RACE);
899 pending_queue.pop_front(); 983 }
900 } 984
901 } 985 void HttpCache::RestartHeadersPhaseTransactions(ActiveEntry* entry,
902 } 986 Transaction* transaction) {
903 987 if (entry->headers_transaction && transaction != entry->headers_transaction)
904 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 988 RestartHeadersTransaction(entry, transaction);
989
990 auto it = entry->done_headers_queue.begin();
991 while (it != entry->done_headers_queue.end()) {
992 Transaction* done_headers_transaction = *it;
993 it = entry->done_headers_queue.erase(it);
jkarlin 2017/06/08 16:14:09 DCHECK_NE(transaction, done_headers_transaction);
shivanisha 2017/06/08 18:26:01 done
994 done_headers_transaction->io_callback().Run(net::ERR_CACHE_RACE);
995 }
996 }
997
998 void HttpCache::RestartHeadersTransaction(ActiveEntry* entry,
999 Transaction* transaction) {
jkarlin 2017/06/08 16:14:09 Transaction argument is unused, but: DCHECK_NE(en
shivanisha 2017/06/08 18:26:01 done
jkarlin 2017/06/13 13:03:31 Hmm, actually, it doesn't make sense to keep an un
shivanisha 2017/06/13 14:21:17 removed.
1000 entry->headers_transaction->SetValidatingCannotProceed();
1001 entry->headers_transaction = nullptr;
1002 }
1003
1004 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
1005 // Multiple readers may finish with an entry at once, so we want to batch up
1006 // calls to OnProcessQueuedTransactions. This flag also tells us that we
1007 // should not delete the entry before OnProcessQueuedTransactions runs.
1008 if (entry->will_process_queued_transactions)
1009 return;
1010
1011 entry->will_process_queued_transactions = true;
1012
1013 // Post a task instead of invoking the io callback of another transaction here
1014 // to avoid re-entrancy.
1015 base::ThreadTaskRunnerHandle::Get()->PostTask(
1016 FROM_HERE,
1017 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
1018 }
1019
1020 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
1021 DCHECK(!entry->add_to_entry_queue.empty());
1022
1023 // Note the entry may be new or may already have a response body written to
1024 // it. In both cases, a transaction needs to wait since only one transaction
1025 // can be in the headers phase at a time.
1026 if (entry->headers_transaction) {
1027 return;
1028 }
1029 Transaction* transaction = entry->add_to_entry_queue.front();
1030 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1031 entry->headers_transaction = transaction;
1032
1033 transaction->io_callback().Run(OK);
1034 }
1035
1036 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
905 DCHECK(!entry->writer); 1037 DCHECK(!entry->writer);
906 1038 DCHECK(!entry->done_headers_queue.empty());
907 auto it = entry->readers.find(trans); 1039
908 DCHECK(it != entry->readers.end()); 1040 Transaction* transaction = entry->done_headers_queue.front();
909 1041
910 entry->readers.erase(it); 1042 // If this transaction is responsible for writing the response body.
911 1043 if (transaction->mode() & Transaction::WRITE) {
912 ProcessPendingQueue(entry); 1044 entry->writer = transaction;
913 } 1045 } else {
914 1046 // If a transaction is in front of this queue with only read mode set and
915 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1047 // there is no writer, it implies response body is already written, convert
916 DCHECK(entry->writer); 1048 // to a reader.
917 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1049 auto return_val = entry->readers.insert(transaction);
918 DCHECK(entry->readers.empty()); 1050 DCHECK_EQ(return_val.second, true);
919 1051 }
920 Transaction* trans = entry->writer; 1052
921 1053 // Post another task to give a chance to more transactions to either join
922 entry->writer = NULL; 1054 // readers or another transaction to start parallel validation.
923 entry->readers.insert(trans); 1055 ProcessQueuedTransactions(entry);
924 1056
925 ProcessPendingQueue(entry); 1057 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
1058 transaction->io_callback().Run(OK);
1059 }
1060
1061 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
1062 Transaction* transaction,
1063 bool is_match) const {
1064 if (transaction != entry->headers_transaction)
1065 return false;
1066
1067 if (!(transaction->mode() & Transaction::WRITE))
1068 return false;
1069
1070 // If its not a match then check if it is the transaction responsible for
1071 // writing the response body.
1072 if (!is_match) {
1073 return !entry->writer && entry->done_headers_queue.empty() &&
1074 entry->readers.empty();
1075 }
1076
1077 return true;
1078 }
1079
1080 bool HttpCache::HasDependentTransactions(ActiveEntry* entry,
1081 Transaction* transaction,
1082 bool is_partial) const {
1083 if (transaction->method() == "HEAD" || transaction->method() == "DELETE")
1084 return false;
1085
1086 // Check if transaction is about to start writing to the cache.
1087
1088 // Transaction's mode may have been set to NONE if StopCaching was invoked but
1089 // that should still be considered a writer failure.
jkarlin 2017/06/08 16:14:09 This below conditional is hard for me to parse. Co
shivanisha 2017/06/08 18:26:01 done
1090 if (!(transaction->mode() & Transaction::WRITE ||
1091 transaction->mode() == Transaction::NONE)) {
1092 return false;
1093 }
1094
1095 // If transaction is not in add_to_entry_queue and has a WRITE bit set or is
1096 // NONE, then there may be other transactions depending on it to completely
1097 // write the response.
1098 for (auto* pending_transaction : entry->add_to_entry_queue) {
1099 if (pending_transaction == transaction)
1100 return false;
1101 }
1102
1103 return true;
1104 }
1105
1106 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1107 return entry->writer != nullptr;
926 } 1108 }
927 1109
928 LoadState HttpCache::GetLoadStateForPendingTransaction( 1110 LoadState HttpCache::GetLoadStateForPendingTransaction(
929 const Transaction* trans) { 1111 const Transaction* trans) {
930 auto i = active_entries_.find(trans->key()); 1112 auto i = active_entries_.find(trans->key());
931 if (i == active_entries_.end()) { 1113 if (i == active_entries_.end()) {
932 // If this is really a pending transaction, and it is not part of 1114 // 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. 1115 // active_entries_, we should be creating the backend or the entry.
934 return LOAD_STATE_WAITING_FOR_CACHE; 1116 return LOAD_STATE_WAITING_FOR_CACHE;
935 } 1117 }
(...skipping 29 matching lines...) Expand all
965 1147
966 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1148 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
967 ++k) { 1149 ++k) {
968 found = RemovePendingTransactionFromEntry(k->first, trans); 1150 found = RemovePendingTransactionFromEntry(k->first, trans);
969 } 1151 }
970 1152
971 DCHECK(found) << "Pending transaction not found"; 1153 DCHECK(found) << "Pending transaction not found";
972 } 1154 }
973 1155
974 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1156 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
975 Transaction* trans) { 1157 Transaction* transaction) {
976 TransactionList& pending_queue = entry->pending_queue; 1158 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
977 1159
978 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1160 auto j =
979 if (j == pending_queue.end()) 1161 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1162 if (j == add_to_entry_queue.end())
980 return false; 1163 return false;
981 1164
982 pending_queue.erase(j); 1165 add_to_entry_queue.erase(j);
983 return true; 1166 return true;
984 } 1167 }
985 1168
986 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1169 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
987 Transaction* trans) { 1170 Transaction* trans) {
988 if (pending_op->writer->Matches(trans)) { 1171 if (pending_op->writer->Matches(trans)) {
989 pending_op->writer->ClearTransaction(); 1172 pending_op->writer->ClearTransaction();
990 pending_op->writer->ClearEntry(); 1173 pending_op->writer->ClearEntry();
991 return true; 1174 return true;
992 } 1175 }
993 WorkItemList& pending_queue = pending_op->pending_queue; 1176 WorkItemList& pending_queue = pending_op->pending_queue;
994 1177
995 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1178 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
996 if ((*it)->Matches(trans)) { 1179 if ((*it)->Matches(trans)) {
997 pending_queue.erase(it); 1180 pending_queue.erase(it);
998 return true; 1181 return true;
999 } 1182 }
1000 } 1183 }
1001 return false; 1184 return false;
1002 } 1185 }
1003 1186
1004 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1187 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1005 // Multiple readers may finish with an entry at once, so we want to batch up 1188 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 1189
1012 base::ThreadTaskRunnerHandle::Get()->PostTask( 1190 // Note that this function should only invoke one transaction's IO callback
1013 FROM_HERE, 1191 // 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 1192
1021 // If no one is interested in this entry, then we can deactivate it. 1193 // If no one is interested in this entry, then we can deactivate it.
1022 if (entry->HasNoTransactions()) { 1194 if (entry->HasNoTransactions()) {
1023 DestroyEntry(entry); 1195 DestroyEntry(entry);
1024 return; 1196 return;
1025 } 1197 }
1026 1198
1027 if (entry->pending_queue.empty()) 1199 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1028 return; 1200 return;
1029 1201
1030 // Promote next transaction from the pending queue. 1202 // To maintain FIFO order of transactions, done_headers_queue should be
1031 Transaction* next = entry->pending_queue.front(); 1203 // checked for processing before add_to_entry_queue.
1032 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1033 return; // Have to wait.
1034 1204
1035 entry->pending_queue.erase(entry->pending_queue.begin()); 1205 // If another transaction is writing the response, let validated transactions
1206 // wait till the response is complete. If the response is not yet started, the
1207 // done_headers_queue transaction should start writing it.
1208 if (!entry->writer && !entry->done_headers_queue.empty()) {
1209 ProcessDoneHeadersQueue(entry);
1210 return;
1211 }
1036 1212
1037 int rv = AddTransactionToEntry(entry, next); 1213 if (!entry->add_to_entry_queue.empty())
1038 if (rv != ERR_IO_PENDING) { 1214 ProcessAddToEntryQueue(entry);
1039 next->io_callback().Run(rv);
1040 }
1041 } 1215 }
1042 1216
1043 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1217 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1044 WorkItemOperation op = pending_op->writer->operation(); 1218 WorkItemOperation op = pending_op->writer->operation();
1045 1219
1046 // Completing the creation of the backend is simpler than the other cases. 1220 // Completing the creation of the backend is simpler than the other cases.
1047 if (op == WI_CREATE_BACKEND) 1221 if (op == WI_CREATE_BACKEND)
1048 return OnBackendCreated(result, pending_op); 1222 return OnBackendCreated(result, pending_op);
1049 1223
1050 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1224 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; 1351 building_backend_ = false;
1178 DeletePendingOp(pending_op); 1352 DeletePendingOp(pending_op);
1179 } 1353 }
1180 1354
1181 // The cache may be gone when we return from the callback. 1355 // The cache may be gone when we return from the callback.
1182 if (!item->DoCallback(result, disk_cache_.get())) 1356 if (!item->DoCallback(result, disk_cache_.get()))
1183 item->NotifyTransaction(result, NULL); 1357 item->NotifyTransaction(result, NULL);
1184 } 1358 }
1185 1359
1186 } // namespace net 1360 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698