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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Feedback addressed 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;
122 }
123
124 int32_t HttpCache::ActiveEntry::GetDataSize(int index,
125 Transaction* transaction) const {
126 if (index == kResponseContentIndex)
jkarlin 2017/04/25 16:00:52 What about other indexes? The header comment says
shivanisha 2017/04/26 16:22:30 As discussed f2f, removing the getter functions ad
127 DCHECK(!writer || writer == transaction);
128 return disk_entry->GetDataSize(index);
129 }
130
131 base::Time HttpCache::ActiveEntry::GetLastUsed(Transaction* transaction) const {
132 DCHECK(!writer || writer == transaction);
133 return disk_entry->GetLastUsed();
134 }
135
136 base::Time HttpCache::ActiveEntry::GetLastModified(
137 Transaction* transaction) const {
138 DCHECK(!writer || writer == transaction);
139 return disk_entry->GetLastModified();
121 } 140 }
122 141
123 //----------------------------------------------------------------------------- 142 //-----------------------------------------------------------------------------
124 143
125 // This structure keeps track of work items that are attempting to create or 144 // This structure keeps track of work items that are attempting to create or
126 // open cache entries or the backend itself. 145 // open cache entries or the backend itself.
127 struct HttpCache::PendingOp { 146 struct HttpCache::PendingOp {
128 PendingOp() : disk_entry(NULL) {} 147 PendingOp() : disk_entry(NULL) {}
129 ~PendingOp() {} 148 ~PendingOp() {}
130 149
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 session->SetServerPushDelegate( 354 session->SetServerPushDelegate(
336 base::MakeUnique<HttpCacheLookupManager>(this)); 355 base::MakeUnique<HttpCacheLookupManager>(this));
337 } 356 }
338 357
339 HttpCache::~HttpCache() { 358 HttpCache::~HttpCache() {
340 // Transactions should see an invalid cache after this point; otherwise they 359 // Transactions should see an invalid cache after this point; otherwise they
341 // could see an inconsistent object (half destroyed). 360 // could see an inconsistent object (half destroyed).
342 weak_factory_.InvalidateWeakPtrs(); 361 weak_factory_.InvalidateWeakPtrs();
343 362
344 // 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.
345 // We may have some pending calls to OnProcessPendingQueue, but since those 364 // We may have some pending tasks to process queued transactions ,but since
346 // 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
347 // will_process_pending_queue flag. 366 // corresponding flags.
348 while (!active_entries_.empty()) { 367 while (!active_entries_.empty()) {
349 ActiveEntry* entry = active_entries_.begin()->second.get(); 368 ActiveEntry* entry = active_entries_.begin()->second.get();
350 entry->will_process_pending_queue = false; 369 entry->will_process_queued_transactions = false;
351 entry->pending_queue.clear(); 370 entry->add_to_entry_queue.clear();
352 entry->readers.clear(); 371 entry->readers.clear();
353 entry->writer = NULL; 372 entry->done_headers_queue.clear();
373 entry->headers_transaction = nullptr;
374 entry->writer = nullptr;
354 DeactivateEntry(entry); 375 DeactivateEntry(entry);
355 } 376 }
356 377
357 doomed_entries_.clear(); 378 doomed_entries_.clear();
358 379
359 // 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
360 // 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.
361 disk_cache_.reset(); 382 disk_cache_.reset();
362 383
363 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
604 // 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
605 // cleaned up properly when the cache is destroyed. 626 // cleaned up properly when the cache is destroyed.
606 ActiveEntry* entry_ptr = entry.get(); 627 ActiveEntry* entry_ptr = entry.get();
607 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 628 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
608 doomed_entries_[entry_ptr] = std::move(entry); 629 doomed_entries_[entry_ptr] = std::move(entry);
609 630
610 entry_ptr->disk_entry->Doom(); 631 entry_ptr->disk_entry->Doom();
611 entry_ptr->doomed = true; 632 entry_ptr->doomed = true;
612 633
613 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 634 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
614 entry_ptr->will_process_pending_queue); 635 entry_ptr->headers_transaction ||
636 entry_ptr->will_process_queued_transactions);
615 return OK; 637 return OK;
616 } 638 }
617 639
618 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 640 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
619 std::unique_ptr<WorkItem> item = 641 std::unique_ptr<WorkItem> item =
620 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 642 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
621 PendingOp* pending_op = GetPendingOp(key); 643 PendingOp* pending_op = GetPendingOp(key);
622 if (pending_op->writer) { 644 if (pending_op->writer) {
623 pending_op->pending_queue.push_back(std::move(item)); 645 pending_op->pending_queue.push_back(std::move(item));
624 return ERR_IO_PENDING; 646 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 DCHECK(entry->doomed); 682 DCHECK(entry->doomed);
661 DCHECK(entry->HasNoTransactions()); 683 DCHECK(entry->HasNoTransactions());
662 684
663 auto it = doomed_entries_.find(entry); 685 auto it = doomed_entries_.find(entry);
664 DCHECK(it != doomed_entries_.end()); 686 DCHECK(it != doomed_entries_.end());
665 doomed_entries_.erase(it); 687 doomed_entries_.erase(it);
666 } 688 }
667 689
668 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 690 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
669 auto it = active_entries_.find(key); 691 auto it = active_entries_.find(key);
670 return it != active_entries_.end() ? it->second.get() : NULL; 692 return it != active_entries_.end() ? it->second.get() : nullptr;
671 } 693 }
672 694
673 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 695 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
674 disk_cache::Entry* disk_entry) { 696 disk_cache::Entry* disk_entry) {
675 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 697 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
676 ActiveEntry* entry = new ActiveEntry(disk_entry); 698 ActiveEntry* entry = new ActiveEntry(disk_entry);
677 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 699 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
678 return entry; 700 return entry;
679 } 701 }
680 702
681 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 703 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
682 DCHECK(!entry->will_process_pending_queue); 704 DCHECK(!entry->will_process_queued_transactions);
683 DCHECK(!entry->doomed); 705 DCHECK(!entry->doomed);
684 DCHECK(entry->disk_entry); 706 DCHECK(entry->disk_entry);
685 DCHECK(entry->HasNoTransactions()); 707 DCHECK(entry->HasNoTransactions());
686 708
687 std::string key = entry->disk_entry->GetKey(); 709 std::string key = entry->disk_entry->GetKey();
688 if (key.empty()) 710 if (key.empty())
689 return SlowDeactivateEntry(entry); 711 return SlowDeactivateEntry(entry);
690 712
691 auto it = active_entries_.find(key); 713 auto it = active_entries_.find(key);
692 DCHECK(it != active_entries_.end()); 714 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 } 824 }
803 825
804 void HttpCache::DestroyEntry(ActiveEntry* entry) { 826 void HttpCache::DestroyEntry(ActiveEntry* entry) {
805 if (entry->doomed) { 827 if (entry->doomed) {
806 FinalizeDoomedEntry(entry); 828 FinalizeDoomedEntry(entry);
807 } else { 829 } else {
808 DeactivateEntry(entry); 830 DeactivateEntry(entry);
809 } 831 }
810 } 832 }
811 833
812 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 834 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
835 Transaction* transaction) {
813 DCHECK(entry); 836 DCHECK(entry);
814 DCHECK(entry->disk_entry); 837 DCHECK(entry->disk_entry);
815 838 // Always add a new transaction to the queue to maintain FIFO order.
816 // We implement a basic reader/writer lock for the disk cache entry. If 839 entry->add_to_entry_queue.push_back(transaction);
817 // there is already a writer, then everyone has to wait for the writer to 840 ProcessQueuedTransactions(entry);
818 // finish before they can access the cache entry. There can be multiple 841 return ERR_IO_PENDING;
819 // readers. 842 }
820 // 843
821 // NOTE: If the transaction can only write, then the entry should not be in 844 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
822 // use (since any existing entry should have already been doomed). 845 Transaction* transaction) {
823 846 // If |transaction| is the current writer, do nothing. This can happen for
824 if (entry->writer || entry->will_process_pending_queue) { 847 // range requests since they can go back to headers phase after starting to
825 entry->pending_queue.push_back(trans); 848 // write.
826 return ERR_IO_PENDING; 849 if (entry->writer == transaction)
827 } 850 return OK;
828 851
829 if (trans->mode() & Transaction::WRITE) { 852 DCHECK_EQ(entry->headers_transaction, transaction);
830 // transaction needs exclusive access to the entry 853
831 if (entry->readers.empty()) { 854 entry->headers_transaction = nullptr;
832 entry->writer = trans; 855
833 } else { 856 // If transaction is responsible for writing the response body, then do not go
834 entry->pending_queue.push_back(trans); 857 // through done_headers_queue for performance benefit. (Also, in case of
835 return ERR_IO_PENDING; 858 // writer transaction, the consumer sometimes depend on synchronous behaviour
836 } 859 // e.g. while computing raw headers size. (crbug.com/711766))
837 } else { 860 if (transaction->mode() & Transaction::WRITE) {
838 // transaction needs read access to the entry 861 DCHECK(entry->done_headers_queue.empty());
839 entry->readers.insert(trans); 862 DCHECK(!entry->writer);
840 } 863 entry->writer = transaction;
841 864 ProcessQueuedTransactions(entry);
842 // We do this before calling EntryAvailable to force any further calls to 865 return OK;
843 // AddTransactionToEntry to add their transaction to the pending queue, which 866 }
844 // ensures FIFO ordering. 867
845 if (!entry->writer && !entry->pending_queue.empty()) 868 // If this is not the first transaction in done_headers_queue, it should be a
846 ProcessPendingQueue(entry); 869 // read-mode transaction.
847 870 DCHECK(entry->done_headers_queue.empty() ||
848 return OK; 871 !(transaction->mode() & Transaction::WRITE));
849 } 872
850 873 entry->done_headers_queue.push_back(transaction);
851 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,
852 bool cancel) { 880 bool cancel) {
853 // 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.
854 // the writer, there is nothing to cancel. 882 auto it = std::find(entry->done_headers_queue.begin(),
855 if (entry->will_process_pending_queue && entry->readers.empty()) 883 entry->done_headers_queue.end(), transaction);
856 return; 884 if (it != entry->done_headers_queue.end()) {
857 885 entry->done_headers_queue.erase(it);
858 if (entry->writer) { 886 if (cancel)
859 DCHECK(trans == entry->writer); 887 ProcessEntryFailure(entry);
860 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) {
861 // Assume there was a failure. 900 // Assume there was a failure.
862 bool success = false; 901 bool success = false;
863 if (cancel) { 902 if (cancel) {
864 DCHECK(entry->disk_entry); 903 DCHECK(entry->disk_entry);
865 // 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
866 // entry. 905 // entry.
867 success = trans->AddTruncatedFlag(); 906 success = transaction->AddTruncatedFlag();
868 // The previous operation may have deleted the entry. 907 // The previous operation may have deleted the entry.
869 if (!trans->entry()) 908 if (!transaction->entry())
870 return; 909 return;
871 } 910 }
872 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, restart the headers_transaction by setting its state.
931 // Since the headers_transactions is awaiting an asynchronous operation
932 // completion, when it's IO callback is invoked, it will be restarted.
933 if (!success && entry->headers_transaction) {
934 entry->headers_transaction->SetValidatingCannotProceed();
935 entry->headers_transaction = nullptr;
936 DCHECK(entry->HasNoActiveTransactions());
937 }
938 if (!success)
939 ProcessEntryFailure(entry);
940 else
941 ProcessQueuedTransactions(entry);
942 }
943
944 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
945 Transaction* transaction) {
946 DCHECK(!entry->writer);
947 auto it = entry->readers.find(transaction);
948 DCHECK(it != entry->readers.end());
949 entry->readers.erase(it);
950
951 ProcessQueuedTransactions(entry);
952 }
953
954 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
955 TransactionList* list) {
956 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
957 // order.
958 for (auto* transaction : entry->done_headers_queue)
959 list->push_back(transaction);
960 entry->done_headers_queue.clear();
961
962 for (auto* transaction : entry->add_to_entry_queue)
963 list->push_back(transaction);
964 entry->add_to_entry_queue.clear();
965 }
966
967 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
968 // Failure case is either writer failing to completely write the response to
969 // the cache or validating transaction received a non-304 response.
970 TransactionList list;
971 if (entry->HasNoActiveTransactions() &&
972 !entry->will_process_queued_transactions) {
973 entry->disk_entry->Doom();
974 RemoveAllQueuedTransactions(entry, &list);
975 DestroyEntry(entry);
873 } else { 976 } else {
874 DoneReadingFromEntry(entry, trans); 977 DoomActiveEntry(entry->disk_entry->GetKey());
875 } 978 RemoveAllQueuedTransactions(entry, &list);
876 } 979 }
877 980 // ERR_CACHE_RACE causes the transaction to restart the whole process.
878 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 981 for (auto* transaction : list)
879 DCHECK(entry->readers.empty()); 982 transaction->io_callback().Run(net::ERR_CACHE_RACE);
880 983 }
881 entry->writer = NULL; 984
882 985 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
883 if (success) { 986 // Multiple readers may finish with an entry at once, so we want to batch up
884 ProcessPendingQueue(entry); 987 // calls to OnProcessQueuedTransactions. This flag also tells us that we
988 // should not delete the entry before OnProcessQueuedTransactions runs.
989 if (entry->will_process_queued_transactions)
990 return;
991
992 entry->will_process_queued_transactions = true;
993
994 // Post a task instead of invoking the io callback of another transaction here
995 // to avoid re-entrancy.
996 base::ThreadTaskRunnerHandle::Get()->PostTask(
997 FROM_HERE,
998 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
999 }
1000
1001 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
1002 DCHECK(!entry->add_to_entry_queue.empty());
1003
1004 // Note the entry may be new or may already have a response body written to
1005 // it. In both cases, a transaction needs to wait since only one transaction
1006 // can be in the headers phase at a time.
1007 if (entry->headers_transaction) {
1008 return;
1009 }
1010 Transaction* transaction = entry->add_to_entry_queue.front();
1011 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1012 entry->headers_transaction = transaction;
1013
1014 transaction->io_callback().Run(OK);
1015 }
1016
1017 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1018 DCHECK(!entry->writer);
1019 DCHECK(!entry->done_headers_queue.empty());
1020
1021 Transaction* transaction = entry->done_headers_queue.front();
1022
1023 // If this transaction is responsible for writing the response body.
1024 if (transaction->mode() & Transaction::WRITE) {
1025 entry->writer = transaction;
885 } else { 1026 } else {
886 DCHECK(!entry->will_process_pending_queue); 1027 // If a transaction is in front of this queue with only read mode set and
887 1028 // there is no writer, it implies response body is already written, convert
888 // We failed to create this entry. 1029 // to a reader.
889 TransactionList pending_queue; 1030 auto return_val = entry->readers.insert(transaction);
890 pending_queue.swap(entry->pending_queue); 1031 DCHECK_EQ(return_val.second, true);
891 1032 }
892 entry->disk_entry->Doom(); 1033
893 DestroyEntry(entry); 1034 // Post another task to give a chance to more transactions to either join
894 1035 // readers or another transaction to start parallel validation.
895 // We need to do something about these pending entries, which now need to 1036 ProcessQueuedTransactions(entry);
896 // be added to a new entry. 1037
897 while (!pending_queue.empty()) { 1038 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
898 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1039 transaction->io_callback().Run(OK);
899 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1040 }
900 pending_queue.pop_front(); 1041
901 } 1042 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
902 } 1043 Transaction* transaction,
903 } 1044 bool is_match) const {
904 1045 if (transaction != entry->headers_transaction)
905 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1046 return false;
906 DCHECK(!entry->writer); 1047
907 1048 if (!(transaction->mode() & Transaction::WRITE))
908 auto it = entry->readers.find(trans); 1049 return false;
909 DCHECK(it != entry->readers.end()); 1050
910 1051 // If its not a match then check if it is the transaction responsible for
911 entry->readers.erase(it); 1052 // writing the response body.
912 1053 if (!is_match) {
913 ProcessPendingQueue(entry); 1054 return !entry->writer && entry->done_headers_queue.empty() &&
914 } 1055 entry->readers.empty();
915 1056 }
916 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1057
917 DCHECK(entry->writer); 1058 return true;
918 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1059 }
919 DCHECK(entry->readers.empty()); 1060
920 1061 bool HttpCache::IsTransactionWritingIncomplete(
921 Transaction* trans = entry->writer; 1062 ActiveEntry* entry,
922 1063 Transaction* transaction,
923 entry->writer = NULL; 1064 const std::string& method) const {
924 entry->readers.insert(trans); 1065 if (transaction == entry->writer)
925 1066 return true;
926 ProcessPendingQueue(entry); 1067
1068 if (method == "HEAD" || method == "DELETE")
1069 return false;
1070
1071 // Check if transaction is about to start writing to the cache.
1072
1073 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1074 if (!(transaction->mode() & Transaction::WRITE ||
1075 transaction->mode() == Transaction::NONE)) {
1076 return false;
1077 }
1078
1079 // If a transaction is completing headers or done with headers phase with
1080 // write mode then it should be the future writer. Just checking the front of
1081 // done_headers_queue since the rest should anyways be READ mode transactions
1082 // as they would be a result of validation match.
1083 return transaction == entry->headers_transaction ||
1084 transaction == entry->done_headers_queue.front();
1085 }
1086
1087 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1088 return entry->writer != nullptr;
927 } 1089 }
928 1090
929 LoadState HttpCache::GetLoadStateForPendingTransaction( 1091 LoadState HttpCache::GetLoadStateForPendingTransaction(
930 const Transaction* trans) { 1092 const Transaction* trans) {
931 auto i = active_entries_.find(trans->key()); 1093 auto i = active_entries_.find(trans->key());
932 if (i == active_entries_.end()) { 1094 if (i == active_entries_.end()) {
933 // If this is really a pending transaction, and it is not part of 1095 // If this is really a pending transaction, and it is not part of
934 // active_entries_, we should be creating the backend or the entry. 1096 // active_entries_, we should be creating the backend or the entry.
935 return LOAD_STATE_WAITING_FOR_CACHE; 1097 return LOAD_STATE_WAITING_FOR_CACHE;
936 } 1098 }
(...skipping 29 matching lines...) Expand all
966 1128
967 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1129 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
968 ++k) { 1130 ++k) {
969 found = RemovePendingTransactionFromEntry(k->first, trans); 1131 found = RemovePendingTransactionFromEntry(k->first, trans);
970 } 1132 }
971 1133
972 DCHECK(found) << "Pending transaction not found"; 1134 DCHECK(found) << "Pending transaction not found";
973 } 1135 }
974 1136
975 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1137 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
976 Transaction* trans) { 1138 Transaction* transaction) {
977 TransactionList& pending_queue = entry->pending_queue; 1139 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
978 1140
979 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1141 auto j =
980 if (j == pending_queue.end()) 1142 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1143 if (j == add_to_entry_queue.end())
981 return false; 1144 return false;
982 1145
983 pending_queue.erase(j); 1146 add_to_entry_queue.erase(j);
984 return true; 1147 return true;
985 } 1148 }
986 1149
987 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1150 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
988 Transaction* trans) { 1151 Transaction* trans) {
989 if (pending_op->writer->Matches(trans)) { 1152 if (pending_op->writer->Matches(trans)) {
990 pending_op->writer->ClearTransaction(); 1153 pending_op->writer->ClearTransaction();
991 pending_op->writer->ClearEntry(); 1154 pending_op->writer->ClearEntry();
992 return true; 1155 return true;
993 } 1156 }
994 WorkItemList& pending_queue = pending_op->pending_queue; 1157 WorkItemList& pending_queue = pending_op->pending_queue;
995 1158
996 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1159 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
997 if ((*it)->Matches(trans)) { 1160 if ((*it)->Matches(trans)) {
998 pending_queue.erase(it); 1161 pending_queue.erase(it);
999 return true; 1162 return true;
1000 } 1163 }
1001 } 1164 }
1002 return false; 1165 return false;
1003 } 1166 }
1004 1167
1005 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1168 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1006 // Multiple readers may finish with an entry at once, so we want to batch up 1169 entry->will_process_queued_transactions = false;
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;
1012 1170
1013 base::ThreadTaskRunnerHandle::Get()->PostTask( 1171 // Note that this function should only invoke one transaction's IO callback
1014 FROM_HERE, 1172 // since its possible for IO callbacks' consumers to destroy the cache/entry.
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);
1021 1173
1022 // If no one is interested in this entry, then we can deactivate it. 1174 // If no one is interested in this entry, then we can deactivate it.
1023 if (entry->HasNoTransactions()) { 1175 if (entry->HasNoTransactions()) {
1024 DestroyEntry(entry); 1176 DestroyEntry(entry);
1025 return; 1177 return;
1026 } 1178 }
1027 1179
1028 if (entry->pending_queue.empty()) 1180 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1029 return; 1181 return;
1030 1182
1031 // Promote next transaction from the pending queue. 1183 // To maintain FIFO order of transactions, done_headers_queue should be
1032 Transaction* next = entry->pending_queue.front(); 1184 // checked for processing before add_to_entry_queue.
1033 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1034 return; // Have to wait.
1035 1185
1036 entry->pending_queue.erase(entry->pending_queue.begin()); 1186 // If another transaction is writing the response, let validated transactions
1187 // wait till the response is complete. If the response is not yet started, the
1188 // done_headers_queue transaction should start writing it.
1189 if (!entry->writer && !entry->done_headers_queue.empty()) {
1190 ProcessDoneHeadersQueue(entry);
1191 return;
1192 }
1037 1193
1038 int rv = AddTransactionToEntry(entry, next); 1194 if (!entry->add_to_entry_queue.empty())
1039 if (rv != ERR_IO_PENDING) { 1195 ProcessAddToEntryQueue(entry);
1040 next->io_callback().Run(rv);
1041 }
1042 } 1196 }
1043 1197
1044 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1198 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1045 WorkItemOperation op = pending_op->writer->operation(); 1199 WorkItemOperation op = pending_op->writer->operation();
1046 1200
1047 // Completing the creation of the backend is simpler than the other cases. 1201 // Completing the creation of the backend is simpler than the other cases.
1048 if (op == WI_CREATE_BACKEND) 1202 if (op == WI_CREATE_BACKEND)
1049 return OnBackendCreated(result, pending_op); 1203 return OnBackendCreated(result, pending_op);
1050 1204
1051 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1205 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1178 building_backend_ = false; 1332 building_backend_ = false;
1179 DeletePendingOp(pending_op); 1333 DeletePendingOp(pending_op);
1180 } 1334 }
1181 1335
1182 // The cache may be gone when we return from the callback. 1336 // The cache may be gone when we return from the callback.
1183 if (!item->DoCallback(result, disk_cache_.get())) 1337 if (!item->DoCallback(result, disk_cache_.get()))
1184 item->NotifyTransaction(result, NULL); 1338 item->NotifyTransaction(result, NULL);
1185 } 1339 }
1186 1340
1187 } // namespace net 1341 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698