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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Moved DeferNetworkStart, fixed a bot failure 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 this is not the first transaction in done_headers_queue, it should be a
852 entry->pending_queue.push_back(trans); 857 // read-mode transaction.
853 return ERR_IO_PENDING; 858 if (!entry->done_headers_queue.empty())
854 } 859 DCHECK(!(transaction->mode() & Transaction::WRITE));
jkarlin 2017/04/13 15:05:52 DCHECK(entry->done_headers_queue.empty() || !(tran
shivanisha 2017/04/13 16:54:53 done
855 } else { 860
856 // transaction needs read access to the entry 861 entry->done_headers_queue.push_back(transaction);
857 entry->readers.insert(trans); 862 ProcessQueuedTransactions(entry);
858 } 863 return ERR_IO_PENDING;
859 864 }
860 // We do this before calling EntryAvailable to force any further calls to 865
861 // AddTransactionToEntry to add their transaction to the pending queue, which 866 void HttpCache::DoneWithEntry(ActiveEntry* entry,
862 // ensures FIFO ordering. 867 Transaction* transaction,
863 if (!entry->writer && !entry->pending_queue.empty())
864 ProcessPendingQueue(entry);
865
866 return OK;
867 }
868
869 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
870 bool cancel) { 868 bool cancel) {
871 // If we already posted a task to move on to the next transaction and this was 869 // Transaction is waiting in the done_headers_queue.
872 // the writer, there is nothing to cancel. 870 auto it = std::find(entry->done_headers_queue.begin(),
873 if (entry->will_process_pending_queue && entry->readers.empty()) 871 entry->done_headers_queue.end(), transaction);
874 return; 872 if (it != entry->done_headers_queue.end()) {
875 873 entry->done_headers_queue.erase(it);
876 if (entry->writer) { 874 if (cancel)
877 DCHECK(trans == entry->writer); 875 ProcessEntryFailure(entry);
878 876 return;
877 }
878
879 // Transaction is removed in the headers phase.
880 if (transaction == entry->headers_transaction) {
881 // If the response is not written (cancel is true), consider it a failure.
882 DoneWritingToEntry(entry, !cancel, transaction);
883 return;
884 }
885
886 // Transaction is removed in the writing phase.
887 if (transaction == entry->writer) {
879 // Assume there was a failure. 888 // Assume there was a failure.
880 bool success = false; 889 bool success = false;
881 if (cancel) { 890 if (cancel) {
882 DCHECK(entry->disk_entry); 891 DCHECK(entry->disk_entry);
883 // This is a successful operation in the sense that we want to keep the 892 // This is a successful operation in the sense that we want to keep the
884 // entry. 893 // entry.
885 success = trans->AddTruncatedFlag(); 894 success = transaction->AddTruncatedFlag();
886 // The previous operation may have deleted the entry. 895 // The previous operation may have deleted the entry.
887 if (!trans->entry()) 896 if (!transaction->entry())
888 return; 897 return;
889 } 898 }
890 DoneWritingToEntry(entry, success); 899 DoneWritingToEntry(entry, success, transaction);
900 return;
901 }
902
903 // Transaction is reading from the entry.
904 DoneReadingFromEntry(entry, transaction);
905 }
906
907 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
908 bool success,
909 Transaction* transaction) {
910 DCHECK(transaction == entry->writer ||
911 transaction == entry->headers_transaction);
912
913 if (transaction == entry->writer)
914 entry->writer = nullptr;
915 else
916 entry->headers_transaction = nullptr;
917
918 // If writer fails, all transactions restart the headers_transaction.
919 if (!success && entry->headers_transaction) {
920 entry->headers_transaction->SetValidatingCannotProceed();
921 entry->headers_transaction = nullptr;
922 DCHECK(entry->HasNoActiveTransactions());
923 }
924 if (!success)
925 ProcessEntryFailure(entry);
926 else
927 ProcessQueuedTransactions(entry);
928 }
929
930 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
931 Transaction* transaction) {
932 DCHECK(!entry->writer);
933 auto it = entry->readers.find(transaction);
934 DCHECK(it != entry->readers.end());
935 entry->readers.erase(it);
936
937 ProcessQueuedTransactions(entry);
938 }
939
940 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
jkarlin 2017/04/13 15:05:52 Can be in anonymous namespace
shivanisha 2017/04/13 16:54:53 ActiveEntry is private to HttpCache, so cannot mov
941 TransactionList* list) {
942 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
943 // order.
944 for (auto* transaction : entry->done_headers_queue)
945 list->push_back(transaction);
946 entry->done_headers_queue.clear();
947
948 for (auto* transaction : entry->add_to_entry_queue)
949 list->push_back(transaction);
950 entry->add_to_entry_queue.clear();
951 }
952
953 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
954 // Failure case is either writer failing to completely write the response to
955 // the cache or validating transaction received a non-304 response.
956 TransactionList list;
957 if (entry->HasNoActiveTransactions() &&
958 !entry->will_process_queued_transactions) {
959 entry->disk_entry->Doom();
960 RemoveAllQueuedTransactions(entry, &list);
961 DestroyEntry(entry);
891 } else { 962 } else {
892 DoneReadingFromEntry(entry, trans); 963 DoomActiveEntry(entry->disk_entry->GetKey());
893 } 964 RemoveAllQueuedTransactions(entry, &list);
894 } 965 }
895 966 // ERR_CACHE_RACE causes the transaction to restart the whole process.
896 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 967 for (auto* transaction : list)
897 DCHECK(entry->readers.empty()); 968 transaction->io_callback().Run(net::ERR_CACHE_RACE);
898 969 }
899 entry->writer = NULL; 970
900 971 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
jkarlin 2017/04/13 15:05:52 This can be in the anonymous namespace. Doing so a
jkarlin 2017/04/13 15:09:20 Ah, to do that you'd need to pass a WeakPtr<HttpCa
901 if (success) { 972 // Multiple readers may finish with an entry at once, so we want to batch up
902 ProcessPendingQueue(entry); 973 // calls to OnProcessQueuedTransactions. This flag also tells us that we
974 // should not delete the entry before OnProcessQueuedTransactions runs.
975 if (entry->will_process_queued_transactions)
976 return;
977
978 entry->will_process_queued_transactions = true;
979
980 // Post a task instead of invoking the io callback of another transaction here
981 // to avoid re-entrancy.
982 base::ThreadTaskRunnerHandle::Get()->PostTask(
983 FROM_HERE,
984 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
985 }
986
987 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
988 DCHECK(!entry->add_to_entry_queue.empty());
989
990 // Note the entry may be new or may already have a response body written to
991 // it. In both cases, a transaction needs to wait since only one transaction
992 // can be in the headers phase at a time.
993 if (entry->headers_transaction) {
994 return;
995 }
996 Transaction* transaction = entry->add_to_entry_queue.front();
997 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
998 entry->headers_transaction = transaction;
999
1000 transaction->io_callback().Run(OK);
1001 }
1002
1003 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1004 DCHECK(!entry->writer);
1005 DCHECK(!entry->done_headers_queue.empty());
1006
1007 Transaction* transaction = entry->done_headers_queue.front();
1008
1009 // If this transaction is responsible for writing the response body.
1010 if (transaction->mode() & Transaction::WRITE) {
1011 entry->writer = transaction;
903 } else { 1012 } else {
904 DCHECK(!entry->will_process_pending_queue); 1013 // If a transaction is in front of this queue with only read mode set and
905 1014 // there is no writer, it implies response body is already written, convert
906 // We failed to create this entry. 1015 // to a reader.
907 TransactionList pending_queue; 1016 auto return_val = entry->readers.insert(transaction);
908 pending_queue.swap(entry->pending_queue); 1017 DCHECK_EQ(return_val.second, true);
909 1018 }
910 entry->disk_entry->Doom(); 1019
911 DestroyEntry(entry); 1020 // Post another task to give a chance to more transactions to either join
912 1021 // readers or another transaction to start parallel validation.
913 // We need to do something about these pending entries, which now need to 1022 ProcessQueuedTransactions(entry);
914 // be added to a new entry. 1023
915 while (!pending_queue.empty()) { 1024 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
916 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1025 transaction->io_callback().Run(OK);
917 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1026 }
918 pending_queue.pop_front(); 1027
919 } 1028 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
920 } 1029 Transaction* transaction,
921 } 1030 int response_code) const {
922 1031 if (transaction != entry->headers_transaction)
923 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1032 return false;
924 DCHECK(!entry->writer); 1033
925 1034 if (!(transaction->mode() & Transaction::WRITE))
926 auto it = entry->readers.find(trans); 1035 return false;
927 DCHECK(it != entry->readers.end()); 1036
928 1037 // If its not a match then check if it is the transaction responsible for
929 entry->readers.erase(it); 1038 // writing the response body.
930 1039 if (response_code != 304) {
931 ProcessPendingQueue(entry); 1040 return !entry->writer && entry->done_headers_queue.empty() &&
932 } 1041 entry->readers.empty();
933 1042 }
934 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1043
935 DCHECK(entry->writer); 1044 return true;
936 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1045 }
937 DCHECK(entry->readers.empty()); 1046
938 1047 bool HttpCache::IsTransactionWritingIncomplete(
939 Transaction* trans = entry->writer; 1048 ActiveEntry* entry,
940 1049 Transaction* transaction,
941 entry->writer = NULL; 1050 const std::string& method) const {
942 entry->readers.insert(trans); 1051 if (transaction == entry->writer)
943 1052 return true;
944 ProcessPendingQueue(entry); 1053
945 } 1054 if (method == "HEAD" || method == "DELETE")
946 1055 return false;
1056
1057 // Check if transaction is about to start writing to the cache.
1058
1059 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1060 if (!(transaction->mode() & Transaction::WRITE ||
1061 transaction->mode() == Transaction::NONE)) {
1062 return false;
1063 }
1064
1065 // If a transaction is completing headers or done with headers phase with
1066 // Write mode then it should be the future writer. Just checking the front of
jkarlin 2017/04/13 15:05:52 lowercase Write
shivanisha 2017/04/13 16:54:53 done
1067 // done_headers_queue since the rest should anyways be READ mode transactions
1068 // as they would be a result of validation match.
1069 if (transaction == entry->headers_transaction ||
1070 transaction == entry->done_headers_queue.front()) {
1071 return true;
1072 }
1073
1074 return false;
1075 }
947 LoadState HttpCache::GetLoadStateForPendingTransaction( 1076 LoadState HttpCache::GetLoadStateForPendingTransaction(
948 const Transaction* trans) { 1077 const Transaction* trans) {
949 auto i = active_entries_.find(trans->key()); 1078 auto i = active_entries_.find(trans->key());
950 if (i == active_entries_.end()) { 1079 if (i == active_entries_.end()) {
951 // If this is really a pending transaction, and it is not part of 1080 // 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. 1081 // active_entries_, we should be creating the backend or the entry.
953 return LOAD_STATE_WAITING_FOR_CACHE; 1082 return LOAD_STATE_WAITING_FOR_CACHE;
954 } 1083 }
955 1084
956 Transaction* writer = i->second->writer; 1085 Transaction* writer = i->second->writer;
(...skipping 27 matching lines...) Expand all
984 1113
985 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1114 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
986 ++k) { 1115 ++k) {
987 found = RemovePendingTransactionFromEntry(k->first, trans); 1116 found = RemovePendingTransactionFromEntry(k->first, trans);
988 } 1117 }
989 1118
990 DCHECK(found) << "Pending transaction not found"; 1119 DCHECK(found) << "Pending transaction not found";
991 } 1120 }
992 1121
993 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1122 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
994 Transaction* trans) { 1123 Transaction* transaction) {
995 TransactionList& pending_queue = entry->pending_queue; 1124 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
996 1125
997 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1126 auto j =
998 if (j == pending_queue.end()) 1127 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1128 if (j == add_to_entry_queue.end())
999 return false; 1129 return false;
1000 1130
1001 pending_queue.erase(j); 1131 add_to_entry_queue.erase(j);
1002 return true; 1132 return true;
1003 } 1133 }
1004 1134
1005 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1135 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1006 Transaction* trans) { 1136 Transaction* trans) {
1007 if (pending_op->writer->Matches(trans)) { 1137 if (pending_op->writer->Matches(trans)) {
1008 pending_op->writer->ClearTransaction(); 1138 pending_op->writer->ClearTransaction();
1009 pending_op->writer->ClearEntry(); 1139 pending_op->writer->ClearEntry();
1010 return true; 1140 return true;
1011 } 1141 }
1012 WorkItemList& pending_queue = pending_op->pending_queue; 1142 WorkItemList& pending_queue = pending_op->pending_queue;
1013 1143
1014 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1144 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1015 if ((*it)->Matches(trans)) { 1145 if ((*it)->Matches(trans)) {
1016 pending_queue.erase(it); 1146 pending_queue.erase(it);
1017 return true; 1147 return true;
1018 } 1148 }
1019 } 1149 }
1020 return false; 1150 return false;
1021 } 1151 }
1022 1152
1023 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1153 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1024 // Multiple readers may finish with an entry at once, so we want to batch up 1154 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 1155
1031 base::ThreadTaskRunnerHandle::Get()->PostTask( 1156 // Note that this function should only invoke one transaction's IO callback
1032 FROM_HERE, 1157 // 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 1158
1040 // If no one is interested in this entry, then we can deactivate it. 1159 // If no one is interested in this entry, then we can deactivate it.
1041 if (entry->HasNoTransactions()) { 1160 if (entry->HasNoTransactions()) {
1042 DestroyEntry(entry); 1161 DestroyEntry(entry);
1043 return; 1162 return;
1044 } 1163 }
1045 1164
1046 if (entry->pending_queue.empty()) 1165 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1047 return; 1166 return;
1048 1167
1049 // Promote next transaction from the pending queue. 1168 // To maintain FIFO order of transactions, done_headers_queue should be
1050 Transaction* next = entry->pending_queue.front(); 1169 // checked for processing before add_to_entry_queue.
1051 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1052 return; // Have to wait.
1053 1170
1054 entry->pending_queue.erase(entry->pending_queue.begin()); 1171 // If another transaction is writing the response, let validated transactions
1172 // wait till the response is complete. If the response is not yet started, the
1173 // done_headers_queue transaction should start writing it.
1174 if (!entry->writer && !entry->done_headers_queue.empty()) {
1175 ProcessDoneHeadersQueue(entry);
1176 return;
1177 }
1055 1178
1056 int rv = AddTransactionToEntry(entry, next); 1179 if (!entry->add_to_entry_queue.empty())
1057 if (rv != ERR_IO_PENDING) { 1180 ProcessAddToEntryQueue(entry);
1058 next->io_callback().Run(rv);
1059 }
1060 } 1181 }
1061 1182
1062 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1183 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1063 WorkItemOperation op = pending_op->writer->operation(); 1184 WorkItemOperation op = pending_op->writer->operation();
1064 1185
1065 // Completing the creation of the backend is simpler than the other cases. 1186 // Completing the creation of the backend is simpler than the other cases.
1066 if (op == WI_CREATE_BACKEND) 1187 if (op == WI_CREATE_BACKEND)
1067 return OnBackendCreated(result, pending_op); 1188 return OnBackendCreated(result, pending_op);
1068 1189
1069 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1190 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; 1317 building_backend_ = false;
1197 DeletePendingOp(pending_op); 1318 DeletePendingOp(pending_op);
1198 } 1319 }
1199 1320
1200 // The cache may be gone when we return from the callback. 1321 // The cache may be gone when we return from the callback.
1201 if (!item->DoCallback(result, disk_cache_.get())) 1322 if (!item->DoCallback(result, disk_cache_.get()))
1202 item->NotifyTransaction(result, NULL); 1323 item->NotifyTransaction(result, NULL);
1203 } 1324 }
1204 1325
1205 } // namespace net 1326 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698