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

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

Issue 2847653002: Revert of HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_cache.h" 5 #include "net/http/http_cache.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 true, 89 true,
90 thread_, 90 thread_,
91 net_log, 91 net_log,
92 backend, 92 backend,
93 callback); 93 callback);
94 } 94 }
95 95
96 //----------------------------------------------------------------------------- 96 //-----------------------------------------------------------------------------
97 97
98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry) 98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
99 : disk_entry(entry) {} 99 : disk_entry(entry),
100 writer(NULL),
101 will_process_pending_queue(false),
102 doomed(false) {
103 }
100 104
101 HttpCache::ActiveEntry::~ActiveEntry() { 105 HttpCache::ActiveEntry::~ActiveEntry() {
102 if (disk_entry) { 106 if (disk_entry) {
103 disk_entry->Close(); 107 disk_entry->Close();
104 disk_entry = nullptr; 108 disk_entry = NULL;
105 } 109 }
106 } 110 }
107 111
108 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const { 112 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
109 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers| 113 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
110 // and |add_to_entry_queue| because the Transactions are owned by their 114 // and |pending_queue| because the Transactions are owned by their respective
111 // respective URLRequestHttpJobs. 115 // URLRequestHttpJobs.
112 return 0; 116 return 0;
113 } 117 }
114 118
115 bool HttpCache::ActiveEntry::HasNoTransactions() { 119 bool HttpCache::ActiveEntry::HasNoTransactions() {
116 return !writer && readers.empty() && add_to_entry_queue.empty() && 120 return !writer && readers.empty() && pending_queue.empty();
117 done_headers_queue.empty() && !headers_transaction;
118 }
119
120 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
121 return !writer && readers.empty() && !headers_transaction;
122 } 121 }
123 122
124 //----------------------------------------------------------------------------- 123 //-----------------------------------------------------------------------------
125 124
126 // 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
127 // open cache entries or the backend itself. 126 // open cache entries or the backend itself.
128 struct HttpCache::PendingOp { 127 struct HttpCache::PendingOp {
129 PendingOp() : disk_entry(NULL) {} 128 PendingOp() : disk_entry(NULL) {}
130 ~PendingOp() {} 129 ~PendingOp() {}
131 130
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 session->SetServerPushDelegate( 335 session->SetServerPushDelegate(
337 base::MakeUnique<HttpCacheLookupManager>(this)); 336 base::MakeUnique<HttpCacheLookupManager>(this));
338 } 337 }
339 338
340 HttpCache::~HttpCache() { 339 HttpCache::~HttpCache() {
341 // Transactions should see an invalid cache after this point; otherwise they 340 // Transactions should see an invalid cache after this point; otherwise they
342 // could see an inconsistent object (half destroyed). 341 // could see an inconsistent object (half destroyed).
343 weak_factory_.InvalidateWeakPtrs(); 342 weak_factory_.InvalidateWeakPtrs();
344 343
345 // 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.
346 // We may have some pending tasks to process queued transactions ,but since 345 // We may have some pending calls to OnProcessPendingQueue, but since those
347 // those won't run (due to our destruction), we can simply ignore the 346 // won't run (due to our destruction), we can simply ignore the corresponding
348 // corresponding flags. 347 // will_process_pending_queue flag.
349 while (!active_entries_.empty()) { 348 while (!active_entries_.empty()) {
350 ActiveEntry* entry = active_entries_.begin()->second.get(); 349 ActiveEntry* entry = active_entries_.begin()->second.get();
351 entry->will_process_queued_transactions = false; 350 entry->will_process_pending_queue = false;
352 entry->add_to_entry_queue.clear(); 351 entry->pending_queue.clear();
353 entry->readers.clear(); 352 entry->readers.clear();
354 entry->done_headers_queue.clear(); 353 entry->writer = NULL;
355 entry->headers_transaction = nullptr;
356 entry->writer = nullptr;
357 DeactivateEntry(entry); 354 DeactivateEntry(entry);
358 } 355 }
359 356
360 doomed_entries_.clear(); 357 doomed_entries_.clear();
361 358
362 // Before deleting pending_ops_, we have to make sure that the disk cache is 359 // Before deleting pending_ops_, we have to make sure that the disk cache is
363 // done with said operations, or it will attempt to use deleted data. 360 // done with said operations, or it will attempt to use deleted data.
364 disk_cache_.reset(); 361 disk_cache_.reset();
365 362
366 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 363 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 // We keep track of doomed entries so that we can ensure that they are 604 // We keep track of doomed entries so that we can ensure that they are
608 // cleaned up properly when the cache is destroyed. 605 // cleaned up properly when the cache is destroyed.
609 ActiveEntry* entry_ptr = entry.get(); 606 ActiveEntry* entry_ptr = entry.get();
610 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 607 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
611 doomed_entries_[entry_ptr] = std::move(entry); 608 doomed_entries_[entry_ptr] = std::move(entry);
612 609
613 entry_ptr->disk_entry->Doom(); 610 entry_ptr->disk_entry->Doom();
614 entry_ptr->doomed = true; 611 entry_ptr->doomed = true;
615 612
616 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 613 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
617 entry_ptr->headers_transaction || 614 entry_ptr->will_process_pending_queue);
618 entry_ptr->will_process_queued_transactions);
619 return OK; 615 return OK;
620 } 616 }
621 617
622 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 618 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
623 std::unique_ptr<WorkItem> item = 619 std::unique_ptr<WorkItem> item =
624 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 620 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
625 PendingOp* pending_op = GetPendingOp(key); 621 PendingOp* pending_op = GetPendingOp(key);
626 if (pending_op->writer) { 622 if (pending_op->writer) {
627 pending_op->pending_queue.push_back(std::move(item)); 623 pending_op->pending_queue.push_back(std::move(item));
628 return ERR_IO_PENDING; 624 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 DCHECK(entry->doomed); 660 DCHECK(entry->doomed);
665 DCHECK(entry->HasNoTransactions()); 661 DCHECK(entry->HasNoTransactions());
666 662
667 auto it = doomed_entries_.find(entry); 663 auto it = doomed_entries_.find(entry);
668 DCHECK(it != doomed_entries_.end()); 664 DCHECK(it != doomed_entries_.end());
669 doomed_entries_.erase(it); 665 doomed_entries_.erase(it);
670 } 666 }
671 667
672 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 668 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
673 auto it = active_entries_.find(key); 669 auto it = active_entries_.find(key);
674 return it != active_entries_.end() ? it->second.get() : nullptr; 670 return it != active_entries_.end() ? it->second.get() : NULL;
675 } 671 }
676 672
677 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 673 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
678 disk_cache::Entry* disk_entry) { 674 disk_cache::Entry* disk_entry) {
679 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 675 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
680 ActiveEntry* entry = new ActiveEntry(disk_entry); 676 ActiveEntry* entry = new ActiveEntry(disk_entry);
681 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 677 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
682 return entry; 678 return entry;
683 } 679 }
684 680
685 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 681 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
686 DCHECK(!entry->will_process_queued_transactions); 682 DCHECK(!entry->will_process_pending_queue);
687 DCHECK(!entry->doomed); 683 DCHECK(!entry->doomed);
688 DCHECK(entry->disk_entry); 684 DCHECK(entry->disk_entry);
689 DCHECK(entry->HasNoTransactions()); 685 DCHECK(entry->HasNoTransactions());
690 686
691 std::string key = entry->disk_entry->GetKey(); 687 std::string key = entry->disk_entry->GetKey();
692 if (key.empty()) 688 if (key.empty())
693 return SlowDeactivateEntry(entry); 689 return SlowDeactivateEntry(entry);
694 690
695 auto it = active_entries_.find(key); 691 auto it = active_entries_.find(key);
696 DCHECK(it != active_entries_.end()); 692 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 } 802 }
807 803
808 void HttpCache::DestroyEntry(ActiveEntry* entry) { 804 void HttpCache::DestroyEntry(ActiveEntry* entry) {
809 if (entry->doomed) { 805 if (entry->doomed) {
810 FinalizeDoomedEntry(entry); 806 FinalizeDoomedEntry(entry);
811 } else { 807 } else {
812 DeactivateEntry(entry); 808 DeactivateEntry(entry);
813 } 809 }
814 } 810 }
815 811
816 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, 812 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
817 Transaction* transaction) {
818 DCHECK(entry); 813 DCHECK(entry);
819 DCHECK(entry->disk_entry); 814 DCHECK(entry->disk_entry);
820 // Always add a new transaction to the queue to maintain FIFO order. 815
821 entry->add_to_entry_queue.push_back(transaction); 816 // We implement a basic reader/writer lock for the disk cache entry. If
822 ProcessQueuedTransactions(entry); 817 // there is already a writer, then everyone has to wait for the writer to
823 return ERR_IO_PENDING; 818 // finish before they can access the cache entry. There can be multiple
819 // readers.
820 //
821 // NOTE: If the transaction can only write, then the entry should not be in
822 // use (since any existing entry should have already been doomed).
823
824 if (entry->writer || entry->will_process_pending_queue) {
825 entry->pending_queue.push_back(trans);
826 return ERR_IO_PENDING;
827 }
828
829 if (trans->mode() & Transaction::WRITE) {
830 // transaction needs exclusive access to the entry
831 if (entry->readers.empty()) {
832 entry->writer = trans;
833 } else {
834 entry->pending_queue.push_back(trans);
835 return ERR_IO_PENDING;
836 }
837 } else {
838 // transaction needs read access to the entry
839 entry->readers.insert(trans);
840 }
841
842 // We do this before calling EntryAvailable to force any further calls to
843 // AddTransactionToEntry to add their transaction to the pending queue, which
844 // ensures FIFO ordering.
845 if (!entry->writer && !entry->pending_queue.empty())
846 ProcessPendingQueue(entry);
847
848 return OK;
824 } 849 }
825 850
826 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry, 851 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
827 Transaction* transaction) { 852 bool cancel) {
828 // If |transaction| is the current writer, do nothing. This can happen for 853 // If we already posted a task to move on to the next transaction and this was
829 // range requests since they can go back to headers phase after starting to 854 // the writer, there is nothing to cancel.
830 // write. 855 if (entry->will_process_pending_queue && entry->readers.empty())
831 if (entry->writer == transaction) 856 return;
832 return OK;
833 857
834 DCHECK_EQ(entry->headers_transaction, transaction); 858 if (entry->writer) {
859 DCHECK(trans == entry->writer);
835 860
836 entry->headers_transaction = nullptr;
837
838 // If transaction is responsible for writing the response body, then do not go
839 // through done_headers_queue for performance benefit. (Also, in case of
840 // writer transaction, the consumer sometimes depend on synchronous behaviour
841 // e.g. while computing raw headers size. (crbug.com/711766))
842 if (transaction->mode() & Transaction::WRITE) {
843 DCHECK(entry->done_headers_queue.empty());
844 DCHECK(!entry->writer);
845 entry->writer = transaction;
846 ProcessQueuedTransactions(entry);
847 return OK;
848 }
849
850 // If this is not the first transaction in done_headers_queue, it should be a
851 // read-mode transaction.
852 DCHECK(entry->done_headers_queue.empty() ||
853 !(transaction->mode() & Transaction::WRITE));
854
855 entry->done_headers_queue.push_back(transaction);
856 ProcessQueuedTransactions(entry);
857 return ERR_IO_PENDING;
858 }
859
860 void HttpCache::DoneWithEntry(ActiveEntry* entry,
861 Transaction* transaction,
862 bool cancel) {
863 // Transaction is waiting in the done_headers_queue.
864 auto it = std::find(entry->done_headers_queue.begin(),
865 entry->done_headers_queue.end(), transaction);
866 if (it != entry->done_headers_queue.end()) {
867 entry->done_headers_queue.erase(it);
868 if (cancel)
869 ProcessEntryFailure(entry);
870 return;
871 }
872
873 // Transaction is removed in the headers phase.
874 if (transaction == entry->headers_transaction) {
875 // If the response is not written (cancel is true), consider it a failure.
876 DoneWritingToEntry(entry, !cancel, transaction);
877 return;
878 }
879
880 // Transaction is removed in the writing phase.
881 if (transaction == entry->writer) {
882 // Assume there was a failure. 861 // Assume there was a failure.
883 bool success = false; 862 bool success = false;
884 if (cancel) { 863 if (cancel) {
885 DCHECK(entry->disk_entry); 864 DCHECK(entry->disk_entry);
886 // This is a successful operation in the sense that we want to keep the 865 // This is a successful operation in the sense that we want to keep the
887 // entry. 866 // entry.
888 success = transaction->AddTruncatedFlag(); 867 success = trans->AddTruncatedFlag();
889 // The previous operation may have deleted the entry. 868 // The previous operation may have deleted the entry.
890 if (!transaction->entry()) 869 if (!trans->entry())
891 return; 870 return;
892 } 871 }
893 DoneWritingToEntry(entry, success, transaction); 872 DoneWritingToEntry(entry, success);
894 return; 873 } else {
874 DoneReadingFromEntry(entry, trans);
895 } 875 }
896
897 // Transaction is reading from the entry.
898 DoneReadingFromEntry(entry, transaction);
899 } 876 }
900 877
901 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, 878 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
902 bool success, 879 DCHECK(entry->readers.empty());
903 Transaction* transaction) {
904 DCHECK(transaction == entry->writer ||
905 transaction == entry->headers_transaction);
906 880
907 if (transaction == entry->writer) 881 entry->writer = NULL;
908 entry->writer = nullptr;
909 else
910 entry->headers_transaction = nullptr;
911 882
912 // If writer fails, restart the headers_transaction by setting its state. 883 if (success) {
913 // Since the headers_transactions is awaiting an asynchronous operation 884 ProcessPendingQueue(entry);
914 // completion, when it's IO callback is invoked, it will be restarted. 885 } else {
915 if (!success && entry->headers_transaction) { 886 DCHECK(!entry->will_process_pending_queue);
916 entry->headers_transaction->SetValidatingCannotProceed(); 887
917 entry->headers_transaction = nullptr; 888 // We failed to create this entry.
918 DCHECK(entry->HasNoActiveTransactions()); 889 TransactionList pending_queue;
890 pending_queue.swap(entry->pending_queue);
891
892 entry->disk_entry->Doom();
893 DestroyEntry(entry);
894
895 // We need to do something about these pending entries, which now need to
896 // be added to a new entry.
897 while (!pending_queue.empty()) {
898 // ERR_CACHE_RACE causes the transaction to restart the whole process.
899 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
900 pending_queue.pop_front();
901 }
919 } 902 }
920 if (!success)
921 ProcessEntryFailure(entry);
922 else
923 ProcessQueuedTransactions(entry);
924 } 903 }
925 904
926 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, 905 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
927 Transaction* transaction) {
928 DCHECK(!entry->writer); 906 DCHECK(!entry->writer);
929 auto it = entry->readers.find(transaction); 907
908 auto it = entry->readers.find(trans);
930 DCHECK(it != entry->readers.end()); 909 DCHECK(it != entry->readers.end());
910
931 entry->readers.erase(it); 911 entry->readers.erase(it);
932 912
933 ProcessQueuedTransactions(entry); 913 ProcessPendingQueue(entry);
934 } 914 }
935 915
936 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry, 916 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
937 TransactionList* list) { 917 DCHECK(entry->writer);
938 // Process done_headers_queue before add_to_entry_queue to maintain FIFO 918 DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
939 // order. 919 DCHECK(entry->readers.empty());
940 for (auto* transaction : entry->done_headers_queue)
941 list->push_back(transaction);
942 entry->done_headers_queue.clear();
943 920
944 for (auto* transaction : entry->add_to_entry_queue) 921 Transaction* trans = entry->writer;
945 list->push_back(transaction);
946 entry->add_to_entry_queue.clear();
947 }
948 922
949 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) { 923 entry->writer = NULL;
950 // Failure case is either writer failing to completely write the response to 924 entry->readers.insert(trans);
951 // the cache or validating transaction received a non-304 response.
952 TransactionList list;
953 if (entry->HasNoActiveTransactions() &&
954 !entry->will_process_queued_transactions) {
955 entry->disk_entry->Doom();
956 RemoveAllQueuedTransactions(entry, &list);
957 DestroyEntry(entry);
958 } else {
959 DoomActiveEntry(entry->disk_entry->GetKey());
960 RemoveAllQueuedTransactions(entry, &list);
961 }
962 // ERR_CACHE_RACE causes the transaction to restart the whole process.
963 for (auto* transaction : list)
964 transaction->io_callback().Run(net::ERR_CACHE_RACE);
965 }
966 925
967 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) { 926 ProcessPendingQueue(entry);
968 // Multiple readers may finish with an entry at once, so we want to batch up
969 // calls to OnProcessQueuedTransactions. This flag also tells us that we
970 // should not delete the entry before OnProcessQueuedTransactions runs.
971 if (entry->will_process_queued_transactions)
972 return;
973
974 entry->will_process_queued_transactions = true;
975
976 // Post a task instead of invoking the io callback of another transaction here
977 // to avoid re-entrancy.
978 base::ThreadTaskRunnerHandle::Get()->PostTask(
979 FROM_HERE,
980 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
981 }
982
983 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
984 DCHECK(!entry->add_to_entry_queue.empty());
985
986 // Note the entry may be new or may already have a response body written to
987 // it. In both cases, a transaction needs to wait since only one transaction
988 // can be in the headers phase at a time.
989 if (entry->headers_transaction) {
990 return;
991 }
992 Transaction* transaction = entry->add_to_entry_queue.front();
993 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
994 entry->headers_transaction = transaction;
995
996 transaction->io_callback().Run(OK);
997 }
998
999 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1000 DCHECK(!entry->writer);
1001 DCHECK(!entry->done_headers_queue.empty());
1002
1003 Transaction* transaction = entry->done_headers_queue.front();
1004
1005 // If this transaction is responsible for writing the response body.
1006 if (transaction->mode() & Transaction::WRITE) {
1007 entry->writer = transaction;
1008 } else {
1009 // If a transaction is in front of this queue with only read mode set and
1010 // there is no writer, it implies response body is already written, convert
1011 // to a reader.
1012 auto return_val = entry->readers.insert(transaction);
1013 DCHECK_EQ(return_val.second, true);
1014 }
1015
1016 // Post another task to give a chance to more transactions to either join
1017 // readers or another transaction to start parallel validation.
1018 ProcessQueuedTransactions(entry);
1019
1020 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
1021 transaction->io_callback().Run(OK);
1022 }
1023
1024 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
1025 Transaction* transaction,
1026 bool is_match) const {
1027 if (transaction != entry->headers_transaction)
1028 return false;
1029
1030 if (!(transaction->mode() & Transaction::WRITE))
1031 return false;
1032
1033 // If its not a match then check if it is the transaction responsible for
1034 // writing the response body.
1035 if (!is_match) {
1036 return !entry->writer && entry->done_headers_queue.empty() &&
1037 entry->readers.empty();
1038 }
1039
1040 return true;
1041 }
1042
1043 bool HttpCache::IsTransactionWritingIncomplete(
1044 ActiveEntry* entry,
1045 Transaction* transaction,
1046 const std::string& method) const {
1047 if (transaction == entry->writer)
1048 return true;
1049
1050 if (method == "HEAD" || method == "DELETE")
1051 return false;
1052
1053 // Check if transaction is about to start writing to the cache.
1054
1055 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1056 if (!(transaction->mode() & Transaction::WRITE ||
1057 transaction->mode() == Transaction::NONE)) {
1058 return false;
1059 }
1060
1061 // If a transaction is completing headers or done with headers phase with
1062 // write mode then it should be the future writer. Just checking the front of
1063 // done_headers_queue since the rest should anyways be READ mode transactions
1064 // as they would be a result of validation match.
1065 return transaction == entry->headers_transaction ||
1066 transaction == entry->done_headers_queue.front();
1067 }
1068
1069 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1070 return entry->writer != nullptr;
1071 } 927 }
1072 928
1073 LoadState HttpCache::GetLoadStateForPendingTransaction( 929 LoadState HttpCache::GetLoadStateForPendingTransaction(
1074 const Transaction* trans) { 930 const Transaction* trans) {
1075 auto i = active_entries_.find(trans->key()); 931 auto i = active_entries_.find(trans->key());
1076 if (i == active_entries_.end()) { 932 if (i == active_entries_.end()) {
1077 // If this is really a pending transaction, and it is not part of 933 // If this is really a pending transaction, and it is not part of
1078 // active_entries_, we should be creating the backend or the entry. 934 // active_entries_, we should be creating the backend or the entry.
1079 return LOAD_STATE_WAITING_FOR_CACHE; 935 return LOAD_STATE_WAITING_FOR_CACHE;
1080 } 936 }
(...skipping 29 matching lines...) Expand all
1110 966
1111 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 967 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
1112 ++k) { 968 ++k) {
1113 found = RemovePendingTransactionFromEntry(k->first, trans); 969 found = RemovePendingTransactionFromEntry(k->first, trans);
1114 } 970 }
1115 971
1116 DCHECK(found) << "Pending transaction not found"; 972 DCHECK(found) << "Pending transaction not found";
1117 } 973 }
1118 974
1119 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 975 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
1120 Transaction* transaction) { 976 Transaction* trans) {
1121 TransactionList& add_to_entry_queue = entry->add_to_entry_queue; 977 TransactionList& pending_queue = entry->pending_queue;
1122 978
1123 auto j = 979 auto j = find(pending_queue.begin(), pending_queue.end(), trans);
1124 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction); 980 if (j == pending_queue.end())
1125 if (j == add_to_entry_queue.end())
1126 return false; 981 return false;
1127 982
1128 add_to_entry_queue.erase(j); 983 pending_queue.erase(j);
1129 return true; 984 return true;
1130 } 985 }
1131 986
1132 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 987 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1133 Transaction* trans) { 988 Transaction* trans) {
1134 if (pending_op->writer->Matches(trans)) { 989 if (pending_op->writer->Matches(trans)) {
1135 pending_op->writer->ClearTransaction(); 990 pending_op->writer->ClearTransaction();
1136 pending_op->writer->ClearEntry(); 991 pending_op->writer->ClearEntry();
1137 return true; 992 return true;
1138 } 993 }
1139 WorkItemList& pending_queue = pending_op->pending_queue; 994 WorkItemList& pending_queue = pending_op->pending_queue;
1140 995
1141 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 996 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1142 if ((*it)->Matches(trans)) { 997 if ((*it)->Matches(trans)) {
1143 pending_queue.erase(it); 998 pending_queue.erase(it);
1144 return true; 999 return true;
1145 } 1000 }
1146 } 1001 }
1147 return false; 1002 return false;
1148 } 1003 }
1149 1004
1150 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) { 1005 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
1151 entry->will_process_queued_transactions = false; 1006 // Multiple readers may finish with an entry at once, so we want to batch up
1007 // calls to OnProcessPendingQueue. This flag also tells us that we should
1008 // not delete the entry before OnProcessPendingQueue runs.
1009 if (entry->will_process_pending_queue)
1010 return;
1011 entry->will_process_pending_queue = true;
1152 1012
1153 // Note that this function should only invoke one transaction's IO callback 1013 base::ThreadTaskRunnerHandle::Get()->PostTask(
1154 // since its possible for IO callbacks' consumers to destroy the cache/entry. 1014 FROM_HERE,
1015 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1016 }
1017
1018 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1019 entry->will_process_pending_queue = false;
1020 DCHECK(!entry->writer);
1155 1021
1156 // If no one is interested in this entry, then we can deactivate it. 1022 // If no one is interested in this entry, then we can deactivate it.
1157 if (entry->HasNoTransactions()) { 1023 if (entry->HasNoTransactions()) {
1158 DestroyEntry(entry); 1024 DestroyEntry(entry);
1159 return; 1025 return;
1160 } 1026 }
1161 1027
1162 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty()) 1028 if (entry->pending_queue.empty())
1163 return; 1029 return;
1164 1030
1165 // To maintain FIFO order of transactions, done_headers_queue should be 1031 // Promote next transaction from the pending queue.
1166 // checked for processing before add_to_entry_queue. 1032 Transaction* next = entry->pending_queue.front();
1033 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1034 return; // Have to wait.
1167 1035
1168 // If another transaction is writing the response, let validated transactions 1036 entry->pending_queue.erase(entry->pending_queue.begin());
1169 // wait till the response is complete. If the response is not yet started, the 1037
1170 // done_headers_queue transaction should start writing it. 1038 int rv = AddTransactionToEntry(entry, next);
1171 if (!entry->writer && !entry->done_headers_queue.empty()) { 1039 if (rv != ERR_IO_PENDING) {
1172 ProcessDoneHeadersQueue(entry); 1040 next->io_callback().Run(rv);
1173 return;
1174 } 1041 }
1175
1176 if (!entry->add_to_entry_queue.empty())
1177 ProcessAddToEntryQueue(entry);
1178 } 1042 }
1179 1043
1180 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1044 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1181 WorkItemOperation op = pending_op->writer->operation(); 1045 WorkItemOperation op = pending_op->writer->operation();
1182 1046
1183 // Completing the creation of the backend is simpler than the other cases. 1047 // Completing the creation of the backend is simpler than the other cases.
1184 if (op == WI_CREATE_BACKEND) 1048 if (op == WI_CREATE_BACKEND)
1185 return OnBackendCreated(result, pending_op); 1049 return OnBackendCreated(result, pending_op);
1186 1050
1187 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1051 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 building_backend_ = false; 1178 building_backend_ = false;
1315 DeletePendingOp(pending_op); 1179 DeletePendingOp(pending_op);
1316 } 1180 }
1317 1181
1318 // The cache may be gone when we return from the callback. 1182 // The cache may be gone when we return from the callback.
1319 if (!item->DoCallback(result, disk_cache_.get())) 1183 if (!item->DoCallback(result, disk_cache_.get()))
1320 item->NotifyTransaction(result, NULL); 1184 item->NotifyTransaction(result, NULL);
1321 } 1185 }
1322 1186
1323 } // namespace net 1187 } // 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