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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Writer returns synchronously from DoneWithResponseHeaders Created 3 years, 8 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 true, 89 true,
90 thread_, 90 thread_,
91 net_log, 91 net_log,
92 backend, 92 backend,
93 callback); 93 callback);
94 } 94 }
95 95
96 //----------------------------------------------------------------------------- 96 //-----------------------------------------------------------------------------
97 97
98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry) 98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
99 : disk_entry(entry), 99 : disk_entry(entry) {}
100 writer(NULL),
101 will_process_pending_queue(false),
102 doomed(false) {
103 }
104 100
105 HttpCache::ActiveEntry::~ActiveEntry() { 101 HttpCache::ActiveEntry::~ActiveEntry() {
106 if (disk_entry) { 102 if (disk_entry) {
107 disk_entry->Close(); 103 disk_entry->Close();
108 disk_entry = NULL; 104 disk_entry = nullptr;
109 } 105 }
110 } 106 }
111 107
112 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const { 108 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
113 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers| 109 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
114 // and |pending_queue| because the Transactions are owned by their respective 110 // and |add_to_entry_queue| because the Transactions are owned by their
115 // URLRequestHttpJobs. 111 // respective URLRequestHttpJobs.
116 return 0; 112 return 0;
117 } 113 }
118 114
119 bool HttpCache::ActiveEntry::HasNoTransactions() { 115 bool HttpCache::ActiveEntry::HasNoTransactions() {
120 return !writer && readers.empty() && pending_queue.empty(); 116 return !writer && readers.empty() && add_to_entry_queue.empty() &&
117 done_headers_queue.empty() && !headers_transaction;
118 }
119
120 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
121 return !writer && readers.empty() && !headers_transaction;
121 } 122 }
122 123
123 //----------------------------------------------------------------------------- 124 //-----------------------------------------------------------------------------
124 125
125 // This structure keeps track of work items that are attempting to create or 126 // This structure keeps track of work items that are attempting to create or
126 // open cache entries or the backend itself. 127 // open cache entries or the backend itself.
127 struct HttpCache::PendingOp { 128 struct HttpCache::PendingOp {
128 PendingOp() : disk_entry(NULL) {} 129 PendingOp() : disk_entry(NULL) {}
129 ~PendingOp() {} 130 ~PendingOp() {}
130 131
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 } 354 }
354 } 355 }
355 } 356 }
356 357
357 HttpCache::~HttpCache() { 358 HttpCache::~HttpCache() {
358 // Transactions should see an invalid cache after this point; otherwise they 359 // Transactions should see an invalid cache after this point; otherwise they
359 // could see an inconsistent object (half destroyed). 360 // could see an inconsistent object (half destroyed).
360 weak_factory_.InvalidateWeakPtrs(); 361 weak_factory_.InvalidateWeakPtrs();
361 362
362 // If we have any active entries remaining, then we need to deactivate them. 363 // If we have any active entries remaining, then we need to deactivate them.
363 // We may have some pending calls to OnProcessPendingQueue, but since those 364 // We may have some pending tasks to process queued transactions ,but since
364 // won't run (due to our destruction), we can simply ignore the corresponding 365 // those won't run (due to our destruction), we can simply ignore the
365 // will_process_pending_queue flag. 366 // corresponding flags.
366 while (!active_entries_.empty()) { 367 while (!active_entries_.empty()) {
367 ActiveEntry* entry = active_entries_.begin()->second.get(); 368 ActiveEntry* entry = active_entries_.begin()->second.get();
368 entry->will_process_pending_queue = false; 369 entry->will_process_queued_transactions = false;
369 entry->pending_queue.clear(); 370 entry->add_to_entry_queue.clear();
370 entry->readers.clear(); 371 entry->readers.clear();
371 entry->writer = NULL; 372 entry->done_headers_queue.clear();
373 entry->headers_transaction = nullptr;
374 entry->writer = nullptr;
372 DeactivateEntry(entry); 375 DeactivateEntry(entry);
373 } 376 }
374 377
375 doomed_entries_.clear(); 378 doomed_entries_.clear();
376 379
377 // Before deleting pending_ops_, we have to make sure that the disk cache is 380 // Before deleting pending_ops_, we have to make sure that the disk cache is
378 // done with said operations, or it will attempt to use deleted data. 381 // done with said operations, or it will attempt to use deleted data.
379 disk_cache_.reset(); 382 disk_cache_.reset();
380 383
381 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 384 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 // We keep track of doomed entries so that we can ensure that they are 625 // We keep track of doomed entries so that we can ensure that they are
623 // cleaned up properly when the cache is destroyed. 626 // cleaned up properly when the cache is destroyed.
624 ActiveEntry* entry_ptr = entry.get(); 627 ActiveEntry* entry_ptr = entry.get();
625 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 628 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
626 doomed_entries_[entry_ptr] = std::move(entry); 629 doomed_entries_[entry_ptr] = std::move(entry);
627 630
628 entry_ptr->disk_entry->Doom(); 631 entry_ptr->disk_entry->Doom();
629 entry_ptr->doomed = true; 632 entry_ptr->doomed = true;
630 633
631 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 634 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
632 entry_ptr->will_process_pending_queue); 635 entry_ptr->headers_transaction ||
636 entry_ptr->will_process_queued_transactions);
633 return OK; 637 return OK;
634 } 638 }
635 639
636 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 640 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
637 std::unique_ptr<WorkItem> item = 641 std::unique_ptr<WorkItem> item =
638 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 642 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
639 PendingOp* pending_op = GetPendingOp(key); 643 PendingOp* pending_op = GetPendingOp(key);
640 if (pending_op->writer) { 644 if (pending_op->writer) {
641 pending_op->pending_queue.push_back(std::move(item)); 645 pending_op->pending_queue.push_back(std::move(item));
642 return ERR_IO_PENDING; 646 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 DCHECK(entry->doomed); 682 DCHECK(entry->doomed);
679 DCHECK(entry->HasNoTransactions()); 683 DCHECK(entry->HasNoTransactions());
680 684
681 auto it = doomed_entries_.find(entry); 685 auto it = doomed_entries_.find(entry);
682 DCHECK(it != doomed_entries_.end()); 686 DCHECK(it != doomed_entries_.end());
683 doomed_entries_.erase(it); 687 doomed_entries_.erase(it);
684 } 688 }
685 689
686 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 690 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
687 auto it = active_entries_.find(key); 691 auto it = active_entries_.find(key);
688 return it != active_entries_.end() ? it->second.get() : NULL; 692 return it != active_entries_.end() ? it->second.get() : nullptr;
689 } 693 }
690 694
691 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 695 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
692 disk_cache::Entry* disk_entry) { 696 disk_cache::Entry* disk_entry) {
693 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 697 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
694 ActiveEntry* entry = new ActiveEntry(disk_entry); 698 ActiveEntry* entry = new ActiveEntry(disk_entry);
695 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 699 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
696 return entry; 700 return entry;
697 } 701 }
698 702
699 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 703 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
700 DCHECK(!entry->will_process_pending_queue); 704 DCHECK(!entry->will_process_queued_transactions);
701 DCHECK(!entry->doomed); 705 DCHECK(!entry->doomed);
702 DCHECK(entry->disk_entry); 706 DCHECK(entry->disk_entry);
703 DCHECK(entry->HasNoTransactions()); 707 DCHECK(entry->HasNoTransactions());
704 708
705 std::string key = entry->disk_entry->GetKey(); 709 std::string key = entry->disk_entry->GetKey();
706 if (key.empty()) 710 if (key.empty())
707 return SlowDeactivateEntry(entry); 711 return SlowDeactivateEntry(entry);
708 712
709 auto it = active_entries_.find(key); 713 auto it = active_entries_.find(key);
710 DCHECK(it != active_entries_.end()); 714 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 } 824 }
821 825
822 void HttpCache::DestroyEntry(ActiveEntry* entry) { 826 void HttpCache::DestroyEntry(ActiveEntry* entry) {
823 if (entry->doomed) { 827 if (entry->doomed) {
824 FinalizeDoomedEntry(entry); 828 FinalizeDoomedEntry(entry);
825 } else { 829 } else {
826 DeactivateEntry(entry); 830 DeactivateEntry(entry);
827 } 831 }
828 } 832 }
829 833
830 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 834 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
835 Transaction* transaction) {
831 DCHECK(entry); 836 DCHECK(entry);
832 DCHECK(entry->disk_entry); 837 DCHECK(entry->disk_entry);
833 838 // Always add a new transaction to the queue to maintain FIFO order.
834 // We implement a basic reader/writer lock for the disk cache entry. If 839 entry->add_to_entry_queue.push_back(transaction);
835 // there is already a writer, then everyone has to wait for the writer to 840 ProcessQueuedTransactions(entry);
836 // finish before they can access the cache entry. There can be multiple 841 return ERR_IO_PENDING;
837 // readers. 842 }
838 // 843
839 // NOTE: If the transaction can only write, then the entry should not be in 844 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
840 // use (since any existing entry should have already been doomed). 845 Transaction* transaction) {
841 846 // If |transaction| is the current writer, do nothing. This can happen for
842 if (entry->writer || entry->will_process_pending_queue) { 847 // range requests since they can go back to headers phase after starting to
843 entry->pending_queue.push_back(trans); 848 // write.
844 return ERR_IO_PENDING; 849 if (entry->writer == transaction)
845 } 850 return OK;
846 851
847 if (trans->mode() & Transaction::WRITE) { 852 DCHECK_EQ(entry->headers_transaction, transaction);
848 // transaction needs exclusive access to the entry 853
849 if (entry->readers.empty()) { 854 entry->headers_transaction = nullptr;
850 entry->writer = trans; 855
851 } else { 856 // If transaction is responsible for writing the response body, then do not go
852 entry->pending_queue.push_back(trans); 857 // through done_headers_queue for performance benefit. (Also, in case of
853 return ERR_IO_PENDING; 858 // writer transaction, the consumer sometimes depend on synchronous behaviour
854 } 859 // e.g. while computing raw headers size.)
Randy Smith (Not in Mondays) 2017/04/19 17:26:34 crbug reference?
shivanisha 2017/04/21 23:06:00 done
855 } else { 860 if (transaction->mode() & Transaction::WRITE) {
856 // transaction needs read access to the entry 861 DCHECK(entry->done_headers_queue.empty());
857 entry->readers.insert(trans); 862 DCHECK(!entry->writer);
858 } 863 entry->writer = transaction;
859 864 ProcessQueuedTransactions(entry);
860 // We do this before calling EntryAvailable to force any further calls to 865 return OK;
861 // AddTransactionToEntry to add their transaction to the pending queue, which 866 }
862 // ensures FIFO ordering. 867
863 if (!entry->writer && !entry->pending_queue.empty()) 868 // If this is not the first transaction in done_headers_queue, it should be a
864 ProcessPendingQueue(entry); 869 // read-mode transaction.
865 870 DCHECK(entry->done_headers_queue.empty() ||
866 return OK; 871 !(transaction->mode() & Transaction::WRITE));
867 } 872
868 873 entry->done_headers_queue.push_back(transaction);
869 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 874 ProcessQueuedTransactions(entry);
875 return ERR_IO_PENDING;
876 }
877
878 void HttpCache::DoneWithEntry(ActiveEntry* entry,
879 Transaction* transaction,
870 bool cancel) { 880 bool cancel) {
871 // If we already posted a task to move on to the next transaction and this was 881 // Transaction is waiting in the done_headers_queue.
872 // the writer, there is nothing to cancel. 882 auto it = std::find(entry->done_headers_queue.begin(),
873 if (entry->will_process_pending_queue && entry->readers.empty()) 883 entry->done_headers_queue.end(), transaction);
874 return; 884 if (it != entry->done_headers_queue.end()) {
875 885 entry->done_headers_queue.erase(it);
876 if (entry->writer) { 886 if (cancel)
877 DCHECK(trans == entry->writer); 887 ProcessEntryFailure(entry);
878 888 return;
889 }
890
891 // Transaction is removed in the headers phase.
892 if (transaction == entry->headers_transaction) {
893 // If the response is not written (cancel is true), consider it a failure.
894 DoneWritingToEntry(entry, !cancel, transaction);
895 return;
896 }
897
898 // Transaction is removed in the writing phase.
899 if (transaction == entry->writer) {
879 // Assume there was a failure. 900 // Assume there was a failure.
880 bool success = false; 901 bool success = false;
881 if (cancel) { 902 if (cancel) {
882 DCHECK(entry->disk_entry); 903 DCHECK(entry->disk_entry);
883 // This is a successful operation in the sense that we want to keep the 904 // This is a successful operation in the sense that we want to keep the
884 // entry. 905 // entry.
885 success = trans->AddTruncatedFlag(); 906 success = transaction->AddTruncatedFlag();
886 // The previous operation may have deleted the entry. 907 // The previous operation may have deleted the entry.
887 if (!trans->entry()) 908 if (!transaction->entry())
888 return; 909 return;
889 } 910 }
890 DoneWritingToEntry(entry, success); 911 DoneWritingToEntry(entry, success, transaction);
912 return;
913 }
914
915 // Transaction is reading from the entry.
916 DoneReadingFromEntry(entry, transaction);
917 }
918
919 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
920 bool success,
921 Transaction* transaction) {
922 DCHECK(transaction == entry->writer ||
923 transaction == entry->headers_transaction);
924
925 if (transaction == entry->writer)
926 entry->writer = nullptr;
927 else
928 entry->headers_transaction = nullptr;
929
930 // If writer fails, all transactions restart the headers_transaction.
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);
891 } else { 974 } else {
892 DoneReadingFromEntry(entry, trans); 975 DoomActiveEntry(entry->disk_entry->GetKey());
893 } 976 RemoveAllQueuedTransactions(entry, &list);
894 } 977 }
895 978 // ERR_CACHE_RACE causes the transaction to restart the whole process.
896 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 979 for (auto* transaction : list)
897 DCHECK(entry->readers.empty()); 980 transaction->io_callback().Run(net::ERR_CACHE_RACE);
898 981 }
899 entry->writer = NULL; 982
900 983 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
901 if (success) { 984 // Multiple readers may finish with an entry at once, so we want to batch up
902 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;
903 } else { 1024 } else {
904 DCHECK(!entry->will_process_pending_queue); 1025 // If a transaction is in front of this queue with only read mode set and
905 1026 // there is no writer, it implies response body is already written, convert
906 // We failed to create this entry. 1027 // to a reader.
907 TransactionList pending_queue; 1028 auto return_val = entry->readers.insert(transaction);
908 pending_queue.swap(entry->pending_queue); 1029 DCHECK_EQ(return_val.second, true);
909 1030 }
910 entry->disk_entry->Doom(); 1031
911 DestroyEntry(entry); 1032 // Post another task to give a chance to more transactions to either join
912 1033 // readers or another transaction to start parallel validation.
913 // We need to do something about these pending entries, which now need to 1034 ProcessQueuedTransactions(entry);
914 // be added to a new entry. 1035
915 while (!pending_queue.empty()) { 1036 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
916 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1037 transaction->io_callback().Run(OK);
917 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1038 }
918 pending_queue.pop_front(); 1039
919 } 1040 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
920 } 1041 Transaction* transaction,
921 } 1042 int response_code) const {
922 1043 if (transaction != entry->headers_transaction)
923 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1044 return false;
924 DCHECK(!entry->writer); 1045
925 1046 if (!(transaction->mode() & Transaction::WRITE))
926 auto it = entry->readers.find(trans); 1047 return false;
927 DCHECK(it != entry->readers.end()); 1048
928 1049 // If its not a match then check if it is the transaction responsible for
929 entry->readers.erase(it); 1050 // writing the response body.
930 1051 if (response_code != 304) {
931 ProcessPendingQueue(entry); 1052 return !entry->writer && entry->done_headers_queue.empty() &&
932 } 1053 entry->readers.empty();
933 1054 }
934 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1055
935 DCHECK(entry->writer); 1056 return true;
936 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1057 }
937 DCHECK(entry->readers.empty()); 1058
938 1059 bool HttpCache::IsTransactionWritingIncomplete(
939 Transaction* trans = entry->writer; 1060 ActiveEntry* entry,
940 1061 Transaction* transaction,
941 entry->writer = NULL; 1062 const std::string& method) const {
942 entry->readers.insert(trans); 1063 if (transaction == entry->writer)
943 1064 return true;
944 ProcessPendingQueue(entry); 1065
945 } 1066 if (method == "HEAD" || method == "DELETE")
946 1067 return false;
1068
1069 // Check if transaction is about to start writing to the cache.
1070
1071 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1072 if (!(transaction->mode() & Transaction::WRITE ||
1073 transaction->mode() == Transaction::NONE)) {
1074 return false;
1075 }
1076
1077 // If a transaction is completing headers or done with headers phase with
1078 // write mode then it should be the future writer. Just checking the front of
1079 // done_headers_queue since the rest should anyways be READ mode transactions
1080 // as they would be a result of validation match.
1081 if (transaction == entry->headers_transaction ||
1082 transaction == entry->done_headers_queue.front()) {
1083 return true;
1084 }
1085
1086 return false;
1087 }
947 LoadState HttpCache::GetLoadStateForPendingTransaction( 1088 LoadState HttpCache::GetLoadStateForPendingTransaction(
948 const Transaction* trans) { 1089 const Transaction* trans) {
949 auto i = active_entries_.find(trans->key()); 1090 auto i = active_entries_.find(trans->key());
950 if (i == active_entries_.end()) { 1091 if (i == active_entries_.end()) {
951 // If this is really a pending transaction, and it is not part of 1092 // If this is really a pending transaction, and it is not part of
952 // active_entries_, we should be creating the backend or the entry. 1093 // active_entries_, we should be creating the backend or the entry.
953 return LOAD_STATE_WAITING_FOR_CACHE; 1094 return LOAD_STATE_WAITING_FOR_CACHE;
954 } 1095 }
955 1096
956 Transaction* writer = i->second->writer; 1097 Transaction* writer = i->second->writer;
(...skipping 27 matching lines...) Expand all
984 1125
985 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1126 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
986 ++k) { 1127 ++k) {
987 found = RemovePendingTransactionFromEntry(k->first, trans); 1128 found = RemovePendingTransactionFromEntry(k->first, trans);
988 } 1129 }
989 1130
990 DCHECK(found) << "Pending transaction not found"; 1131 DCHECK(found) << "Pending transaction not found";
991 } 1132 }
992 1133
993 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1134 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
994 Transaction* trans) { 1135 Transaction* transaction) {
995 TransactionList& pending_queue = entry->pending_queue; 1136 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
996 1137
997 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1138 auto j =
998 if (j == pending_queue.end()) 1139 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1140 if (j == add_to_entry_queue.end())
999 return false; 1141 return false;
1000 1142
1001 pending_queue.erase(j); 1143 add_to_entry_queue.erase(j);
1002 return true; 1144 return true;
1003 } 1145 }
1004 1146
1005 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1147 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1006 Transaction* trans) { 1148 Transaction* trans) {
1007 if (pending_op->writer->Matches(trans)) { 1149 if (pending_op->writer->Matches(trans)) {
1008 pending_op->writer->ClearTransaction(); 1150 pending_op->writer->ClearTransaction();
1009 pending_op->writer->ClearEntry(); 1151 pending_op->writer->ClearEntry();
1010 return true; 1152 return true;
1011 } 1153 }
1012 WorkItemList& pending_queue = pending_op->pending_queue; 1154 WorkItemList& pending_queue = pending_op->pending_queue;
1013 1155
1014 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1156 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1015 if ((*it)->Matches(trans)) { 1157 if ((*it)->Matches(trans)) {
1016 pending_queue.erase(it); 1158 pending_queue.erase(it);
1017 return true; 1159 return true;
1018 } 1160 }
1019 } 1161 }
1020 return false; 1162 return false;
1021 } 1163 }
1022 1164
1023 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1165 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1024 // Multiple readers may finish with an entry at once, so we want to batch up 1166 entry->will_process_queued_transactions = false;
1025 // calls to OnProcessPendingQueue. This flag also tells us that we should
1026 // not delete the entry before OnProcessPendingQueue runs.
1027 if (entry->will_process_pending_queue)
1028 return;
1029 entry->will_process_pending_queue = true;
1030 1167
1031 base::ThreadTaskRunnerHandle::Get()->PostTask( 1168 // Note that this function should only invoke one transaction's IO callback
1032 FROM_HERE, 1169 // since its possible for IO callbacks' consumers to destroy the cache/entry.
1033 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1034 }
1035
1036 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1037 entry->will_process_pending_queue = false;
1038 DCHECK(!entry->writer);
1039 1170
1040 // If no one is interested in this entry, then we can deactivate it. 1171 // If no one is interested in this entry, then we can deactivate it.
1041 if (entry->HasNoTransactions()) { 1172 if (entry->HasNoTransactions()) {
1042 DestroyEntry(entry); 1173 DestroyEntry(entry);
1043 return; 1174 return;
1044 } 1175 }
1045 1176
1046 if (entry->pending_queue.empty()) 1177 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1047 return; 1178 return;
1048 1179
1049 // Promote next transaction from the pending queue. 1180 // To maintain FIFO order of transactions, done_headers_queue should be
1050 Transaction* next = entry->pending_queue.front(); 1181 // checked for processing before add_to_entry_queue.
1051 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1052 return; // Have to wait.
1053 1182
1054 entry->pending_queue.erase(entry->pending_queue.begin()); 1183 // If another transaction is writing the response, let validated transactions
1184 // wait till the response is complete. If the response is not yet started, the
1185 // done_headers_queue transaction should start writing it.
1186 if (!entry->writer && !entry->done_headers_queue.empty()) {
1187 ProcessDoneHeadersQueue(entry);
1188 return;
1189 }
1055 1190
1056 int rv = AddTransactionToEntry(entry, next); 1191 if (!entry->add_to_entry_queue.empty())
1057 if (rv != ERR_IO_PENDING) { 1192 ProcessAddToEntryQueue(entry);
1058 next->io_callback().Run(rv);
1059 }
1060 } 1193 }
1061 1194
1062 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1195 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1063 WorkItemOperation op = pending_op->writer->operation(); 1196 WorkItemOperation op = pending_op->writer->operation();
1064 1197
1065 // Completing the creation of the backend is simpler than the other cases. 1198 // Completing the creation of the backend is simpler than the other cases.
1066 if (op == WI_CREATE_BACKEND) 1199 if (op == WI_CREATE_BACKEND)
1067 return OnBackendCreated(result, pending_op); 1200 return OnBackendCreated(result, pending_op);
1068 1201
1069 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1202 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 building_backend_ = false; 1329 building_backend_ = false;
1197 DeletePendingOp(pending_op); 1330 DeletePendingOp(pending_op);
1198 } 1331 }
1199 1332
1200 // The cache may be gone when we return from the callback. 1333 // The cache may be gone when we return from the callback.
1201 if (!item->DoCallback(result, disk_cache_.get())) 1334 if (!item->DoCallback(result, disk_cache_.get()))
1202 item->NotifyTransaction(result, NULL); 1335 item->NotifyTransaction(result, NULL);
1203 } 1336 }
1204 1337
1205 } // namespace net 1338 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698