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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Simplified ActiveEntry's state transitions Created 3 years, 9 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 #include "net/http/http_response_headers.h" 45 #include "net/http/http_response_headers.h"
46 #include "net/http/http_response_info.h" 46 #include "net/http/http_response_info.h"
47 #include "net/http/http_util.h" 47 #include "net/http/http_util.h"
48 #include "net/log/net_log_with_source.h" 48 #include "net/log/net_log_with_source.h"
49 #include "net/quic/chromium/quic_server_info.h" 49 #include "net/quic/chromium/quic_server_info.h"
50 50
51 #if defined(OS_POSIX) 51 #if defined(OS_POSIX)
52 #include <unistd.h> 52 #include <unistd.h>
53 #endif 53 #endif
54 54
55 // Helper methods.
56 namespace {
57 void RestartPendingTransactions(const net::HttpCache::TransactionList& list) {
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 It looks to me as if this function is the reason w
shivanisha 2017/03/20 16:34:51 Good catch, since this change not only made Transa
58 // ERR_CACHE_RACE causes the transaction to restart the whole process.
59 for (auto* transaction : list)
60 transaction->io_callback().Run(net::ERR_CACHE_RACE);
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 To me, calling a callback on a transaction is sayi
shivanisha 2017/03/20 16:34:51 This routine is now removed and callback is invoke
61 }
62
63 } // namespace
64
55 namespace net { 65 namespace net {
56 66
57 HttpCache::DefaultBackend::DefaultBackend( 67 HttpCache::DefaultBackend::DefaultBackend(
58 CacheType type, 68 CacheType type,
59 BackendType backend_type, 69 BackendType backend_type,
60 const base::FilePath& path, 70 const base::FilePath& path,
61 int max_bytes, 71 int max_bytes,
62 const scoped_refptr<base::SingleThreadTaskRunner>& thread) 72 const scoped_refptr<base::SingleThreadTaskRunner>& thread)
63 : type_(type), 73 : type_(type),
64 backend_type_(backend_type), 74 backend_type_(backend_type),
(...skipping 24 matching lines...) Expand all
89 true, 99 true,
90 thread_, 100 thread_,
91 net_log, 101 net_log,
92 backend, 102 backend,
93 callback); 103 callback);
94 } 104 }
95 105
96 //----------------------------------------------------------------------------- 106 //-----------------------------------------------------------------------------
97 107
98 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry) 108 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
99 : disk_entry(entry), 109 : disk_entry(entry) {}
100 writer(NULL),
101 will_process_pending_queue(false),
102 doomed(false) {
103 }
104 110
105 HttpCache::ActiveEntry::~ActiveEntry() { 111 HttpCache::ActiveEntry::~ActiveEntry() {
106 if (disk_entry) { 112 if (disk_entry) {
107 disk_entry->Close(); 113 disk_entry->Close();
108 disk_entry = NULL; 114 disk_entry = nullptr;
109 } 115 }
110 } 116 }
111 117
112 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const { 118 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
113 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers| 119 // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
114 // and |pending_queue| because the Transactions are owned by their respective 120 // and |add_to_entry_queue| because the Transactions are owned by their
115 // URLRequestHttpJobs. 121 // respective URLRequestHttpJobs.
116 return 0; 122 return 0;
117 } 123 }
118 124
119 bool HttpCache::ActiveEntry::HasNoTransactions() { 125 bool HttpCache::ActiveEntry::HasNoTransactions() {
120 return !writer && readers.empty() && pending_queue.empty(); 126 return !writer && readers.empty() && add_to_entry_queue.empty() &&
127 done_headers_queue.empty() && !headers_transaction;
128 }
129
130 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
131 return !writer && readers.empty() && !headers_transaction;
132 }
133
134 bool HttpCache::ActiveEntry::IsReader(Transaction* transaction) {
135 return readers.count(transaction);
121 } 136 }
122 137
123 //----------------------------------------------------------------------------- 138 //-----------------------------------------------------------------------------
124 139
125 // This structure keeps track of work items that are attempting to create or 140 // This structure keeps track of work items that are attempting to create or
126 // open cache entries or the backend itself. 141 // open cache entries or the backend itself.
127 struct HttpCache::PendingOp { 142 struct HttpCache::PendingOp {
128 PendingOp() : disk_entry(NULL) {} 143 PendingOp() : disk_entry(NULL) {}
129 ~PendingOp() {} 144 ~PendingOp() {}
130 145
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 } 368 }
354 } 369 }
355 } 370 }
356 371
357 HttpCache::~HttpCache() { 372 HttpCache::~HttpCache() {
358 // Transactions should see an invalid cache after this point; otherwise they 373 // Transactions should see an invalid cache after this point; otherwise they
359 // could see an inconsistent object (half destroyed). 374 // could see an inconsistent object (half destroyed).
360 weak_factory_.InvalidateWeakPtrs(); 375 weak_factory_.InvalidateWeakPtrs();
361 376
362 // If we have any active entries remaining, then we need to deactivate them. 377 // 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 378 // 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 379 // those won't run (due to our destruction), we can simply ignore the
365 // will_process_pending_queue flag. 380 // corresponding flags.
366 while (!active_entries_.empty()) { 381 while (!active_entries_.empty()) {
367 ActiveEntry* entry = active_entries_.begin()->second.get(); 382 ActiveEntry* entry = active_entries_.begin()->second.get();
368 entry->will_process_pending_queue = false; 383 entry->will_process_queued_transactions = false;
369 entry->pending_queue.clear(); 384 entry->add_to_entry_queue.clear();
370 entry->readers.clear(); 385 entry->readers.clear();
371 entry->writer = NULL; 386 entry->done_headers_queue.clear();
387 entry->headers_transaction = nullptr;
388 entry->writer = nullptr;
372 DeactivateEntry(entry); 389 DeactivateEntry(entry);
373 } 390 }
374 391
375 doomed_entries_.clear(); 392 doomed_entries_.clear();
376 393
377 // Before deleting pending_ops_, we have to make sure that the disk cache is 394 // 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. 395 // done with said operations, or it will attempt to use deleted data.
379 disk_cache_.reset(); 396 disk_cache_.reset();
380 397
381 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 398 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 // We keep track of doomed entries so that we can ensure that they are 638 // We keep track of doomed entries so that we can ensure that they are
622 // cleaned up properly when the cache is destroyed. 639 // cleaned up properly when the cache is destroyed.
623 ActiveEntry* entry_ptr = entry.get(); 640 ActiveEntry* entry_ptr = entry.get();
624 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 641 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
625 doomed_entries_[entry_ptr] = std::move(entry); 642 doomed_entries_[entry_ptr] = std::move(entry);
626 643
627 entry_ptr->disk_entry->Doom(); 644 entry_ptr->disk_entry->Doom();
628 entry_ptr->doomed = true; 645 entry_ptr->doomed = true;
629 646
630 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 647 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
631 entry_ptr->will_process_pending_queue); 648 entry_ptr->headers_transaction ||
649 entry_ptr->will_process_queued_transactions);
632 return OK; 650 return OK;
633 } 651 }
634 652
635 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 653 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
636 std::unique_ptr<WorkItem> item = 654 std::unique_ptr<WorkItem> item =
637 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 655 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
638 PendingOp* pending_op = GetPendingOp(key); 656 PendingOp* pending_op = GetPendingOp(key);
639 if (pending_op->writer) { 657 if (pending_op->writer) {
640 pending_op->pending_queue.push_back(std::move(item)); 658 pending_op->pending_queue.push_back(std::move(item));
641 return ERR_IO_PENDING; 659 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 DCHECK(entry->doomed); 695 DCHECK(entry->doomed);
678 DCHECK(entry->HasNoTransactions()); 696 DCHECK(entry->HasNoTransactions());
679 697
680 auto it = doomed_entries_.find(entry); 698 auto it = doomed_entries_.find(entry);
681 DCHECK(it != doomed_entries_.end()); 699 DCHECK(it != doomed_entries_.end());
682 doomed_entries_.erase(it); 700 doomed_entries_.erase(it);
683 } 701 }
684 702
685 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 703 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
686 auto it = active_entries_.find(key); 704 auto it = active_entries_.find(key);
687 return it != active_entries_.end() ? it->second.get() : NULL; 705 return it != active_entries_.end() ? it->second.get() : nullptr;
688 } 706 }
689 707
690 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 708 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
691 disk_cache::Entry* disk_entry) { 709 disk_cache::Entry* disk_entry) {
692 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 710 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
693 ActiveEntry* entry = new ActiveEntry(disk_entry); 711 ActiveEntry* entry = new ActiveEntry(disk_entry);
694 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 712 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
695 return entry; 713 return entry;
696 } 714 }
697 715
698 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 716 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
699 DCHECK(!entry->will_process_pending_queue); 717 DCHECK(!entry->will_process_queued_transactions);
700 DCHECK(!entry->doomed); 718 DCHECK(!entry->doomed);
701 DCHECK(entry->disk_entry); 719 DCHECK(entry->disk_entry);
702 DCHECK(entry->HasNoTransactions()); 720 DCHECK(entry->HasNoTransactions());
703 721
704 std::string key = entry->disk_entry->GetKey(); 722 std::string key = entry->disk_entry->GetKey();
705 if (key.empty()) 723 if (key.empty())
706 return SlowDeactivateEntry(entry); 724 return SlowDeactivateEntry(entry);
707 725
708 auto it = active_entries_.find(key); 726 auto it = active_entries_.find(key);
709 DCHECK(it != active_entries_.end()); 727 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 837 }
820 838
821 void HttpCache::DestroyEntry(ActiveEntry* entry) { 839 void HttpCache::DestroyEntry(ActiveEntry* entry) {
822 if (entry->doomed) { 840 if (entry->doomed) {
823 FinalizeDoomedEntry(entry); 841 FinalizeDoomedEntry(entry);
824 } else { 842 } else {
825 DeactivateEntry(entry); 843 DeactivateEntry(entry);
826 } 844 }
827 } 845 }
828 846
829 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 847 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
848 Transaction* transaction) {
830 DCHECK(entry); 849 DCHECK(entry);
831 DCHECK(entry->disk_entry); 850 DCHECK(entry->disk_entry);
832 851 // Always add a new transaction to the queue to maintain FIFO order.
833 // We implement a basic reader/writer lock for the disk cache entry. If 852 entry->add_to_entry_queue.push_back(transaction);
834 // there is already a writer, then everyone has to wait for the writer to 853 ProcessQueuedTransactions(entry);
835 // finish before they can access the cache entry. There can be multiple 854 return ERR_IO_PENDING;
836 // readers. 855 }
837 // 856
838 // NOTE: If the transaction can only write, then the entry should not be in 857 void HttpCache::ProcessAddToEntryTransaction(ActiveEntry* entry) {
839 // use (since any existing entry should have already been doomed). 858 if (entry->headers_transaction) {
840 859 // Note the entry may be new or may already have a response body written to
841 if (entry->writer || entry->will_process_pending_queue) { 860 // it. In both cases, a transaction with write mode set, needs to wait
842 entry->pending_queue.push_back(trans); 861 // because only one transaction is allowed to be validating at a time.
843 return ERR_IO_PENDING; 862 // If transaction is read-only and entry is not yet complete, then it
844 } 863 // needs to wait. If entry is complete, it needs to wait because its
845 864 // possible that the headers_transaction dooms the entry if its not a match.
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Suggestion: Based on the state transitions that yo
shivanisha 2017/03/20 16:34:52 I agree that this comment is basically explaining
846 if (trans->mode() & Transaction::WRITE) { 865 return;
847 // transaction needs exclusive access to the entry 866 }
848 if (entry->readers.empty()) { 867
849 entry->writer = trans; 868 Transaction* transaction = entry->add_to_entry_queue.front();
869 if (entry->writer) {
870 // A transaction either starts validation or waits.
shivanisha 2017/03/16 00:54:54 "A transaction either starts headers phase or wait
shivanisha 2017/03/20 16:34:51 done
871 if (transaction->mode() & Transaction::WRITE) {
872 entry->headers_transaction = transaction;
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Suggestion: Hoist this conditional up above the if
shivanisha 2017/03/20 16:34:51 Here I wanted to emphasize the conceptual differen
850 } else { 873 } else {
851 entry->pending_queue.push_back(trans); 874 return;
852 return ERR_IO_PENDING;
853 } 875 }
854 } else { 876 } else {
855 // transaction needs read access to the entry 877 // This state may be reached either during the start of an entry or when the
856 entry->readers.insert(trans); 878 // response is written.
857 } 879 if (transaction->mode() & Transaction::WRITE) {
858 880 entry->headers_transaction = transaction;
859 // We do this before calling EntryAvailable to force any further calls to 881 } else {
860 // AddTransactionToEntry to add their transaction to the pending queue, which 882 // A read-only transaction can start reading the response.
861 // ensures FIFO ordering. 883 // If a read transaction is here, then it has to be an already created
862 if (!entry->writer && !entry->pending_queue.empty()) 884 // entry as the other case is already handled in the Transaction state
863 ProcessPendingQueue(entry); 885 // machine.
864 886 entry->readers.insert(transaction);
865 return OK; 887
866 } 888 // More readers can join too.
867 889 ProcessQueuedTransactions(entry);
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Suggestion: This routine is already executed after
shivanisha 2017/03/20 16:34:51 Since additional queued transactions should only b
868 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 890 }
891 }
892
893 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
894 transaction->io_callback().Run(OK);
895 }
896
897 void HttpCache::ProcessDoneHeadersTransaction(ActiveEntry* entry) {
898 DCHECK(!entry->writer && !entry->done_headers_queue.empty() &&
899 !entry->headers_transaction);
900 Transaction* transaction = entry->done_headers_queue.front();
901 // If this transaction is responsible for writing the response body.
902 if (transaction->mode() & Transaction::WRITE) {
903 DCHECK_EQ(entry->done_headers_queue.size(), (size_t)1);
904 entry->writer = transaction;
905 } else {
906 // Response body is already written, convert to a reader.
907 auto return_val = entry->readers.insert(transaction);
908 DCHECK_EQ(return_val.second, true);
909 }
910 // Post another task to give a chance to more transactions to either join
911 // readers or another transaction to start parallel validation.
912 ProcessQueuedTransactions(entry);
913 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
914 transaction->io_callback().Run(OK);
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Help me understand why this callback is being run?
shivanisha 2017/03/20 16:34:51 This is indeed the callback of the "other" transac
915 }
916
917 int HttpCache::DoneResponseHeaders(ActiveEntry* entry,
918 Transaction* transaction,
919 bool is_match) {
920 DCHECK_EQ(entry->headers_transaction, transaction);
921 entry->headers_transaction = nullptr;
922
923 if (!is_match) {
924 // Doom or destroy this entry based on whether it has active consumers.
925 ProcessEntryFailure(entry);
926 return OK;
927 }
928
929 entry->done_headers_queue.push_back(transaction);
930 ProcessQueuedTransactions(entry);
931 return ERR_IO_PENDING;
932 }
933
934 HttpCache::TransactionList HttpCache::GetAllPendingTransactions(
shivanisha 2017/03/16 00:54:53 will rename this to GetAllQueuedTransactions and s
shivanisha 2017/03/20 16:34:51 Renamed it to RemoveAllQueuedTransactions to be cl
935 ActiveEntry* entry) {
936 TransactionList list;
937 for (auto* transaction : entry->done_headers_queue)
938 list.push_back(transaction);
939 entry->done_headers_queue.clear();
940
941 for (auto* transaction : entry->add_to_entry_queue)
942 list.push_back(transaction);
943 entry->add_to_entry_queue.clear();
944
945 return list;
946 }
947
948 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
949 // Failure case is either writer failing to completely write the response to
950 // the cache or validating transaction received a non-304 response.
951 if (entry->HasNoActiveTransactions() &&
952 !entry->will_process_queued_transactions) {
953 entry->disk_entry->Doom();
954 TransactionList list = GetAllPendingTransactions(entry);
955 DestroyEntry(entry);
956 RestartPendingTransactions(list);
957 } else {
958 DoomActiveEntry(entry->disk_entry->GetKey());
959 TransactionList list = GetAllPendingTransactions(entry);
960 RestartPendingTransactions(list);
961 }
962 }
963
964 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
965 // Multiple readers may finish with an entry at once, so we want to batch up
966 // calls to OnProcessQueuedTransactions. This flag also tells us that we
967 // should not delete the entry before OnProcessQueuedTransactions runs.
968 if (entry->will_process_queued_transactions)
969 return;
970
971 entry->will_process_queued_transactions = true;
972
973 // Post a task instead of invoking the io callback of another transaction here
974 // to avoid re-entrancy.
975 base::ThreadTaskRunnerHandle::Get()->PostTask(
976 FROM_HERE,
977 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
978 }
979
980 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
981 entry->will_process_queued_transactions = false;
982
983 // If no one is interested in this entry, then we can deactivate it.
984 if (entry->HasNoTransactions()) {
985 DestroyEntry(entry);
986 return;
987 }
988
989 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
990 return;
991
992 // To maintain FIFO order of transactions, done_headers_queue should be
993 // processed first, and then add_to_entry_queue.
994 // If another transaction is writing the response, let validated transactions
995 // wait till the response is complete. If the response is not yet started, the
996 // done_headers_queue transaction should start writing it.
997 if (!entry->writer && !entry->done_headers_queue.empty()) {
998 DCHECK(!entry->headers_transaction);
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Why this invariant? What if we have the writer a
shivanisha 2017/03/20 16:34:51 Good catch, Thanks. Its possible that writer just
999 ProcessDoneHeadersTransaction(entry);
1000 return;
1001 }
1002
1003 if (!entry->add_to_entry_queue.empty())
1004 ProcessAddToEntryTransaction(entry);
Randy Smith (Not in Mondays) 2017/03/17 18:13:05 Comment (not even a suggestion): If I were writing
shivanisha 2017/03/20 16:34:51 Moved the functions to be near each other. My mai
1005 }
1006
1007 void HttpCache::DoneWithEntry(ActiveEntry* entry,
1008 Transaction* transaction,
869 bool cancel) { 1009 bool cancel) {
870 // If we already posted a task to move on to the next transaction and this was 1010 // Transaction is waiting in the done_headers_queue.
871 // the writer, there is nothing to cancel. 1011 if (!entry->done_headers_queue.empty()) {
872 if (entry->will_process_pending_queue && entry->readers.empty()) 1012 auto i = std::find(entry->done_headers_queue.begin(),
873 return; 1013 entry->done_headers_queue.end(), transaction);
874 1014 if (i != entry->done_headers_queue.end()) {
875 if (entry->writer) { 1015 entry->done_headers_queue.erase(i);
876 DCHECK(trans == entry->writer); 1016 return;
877 1017 }
1018 }
1019
1020 // Transaction is removed in the validation phase.
shivanisha 2017/03/16 00:54:53 "Transaction is removed in the headers phase."
shivanisha 2017/03/20 16:34:51 done
1021 if (transaction == entry->headers_transaction) {
1022 entry->headers_transaction = nullptr;
1023 ProcessQueuedTransactions(entry);
1024 return;
1025 }
1026
1027 // Transaction is removed in the writing phase.
1028 if (transaction == entry->writer) {
878 // Assume there was a failure. 1029 // Assume there was a failure.
879 bool success = false; 1030 bool success = false;
880 if (cancel) { 1031 if (cancel) {
881 DCHECK(entry->disk_entry); 1032 DCHECK(entry->disk_entry);
882 // This is a successful operation in the sense that we want to keep the 1033 // This is a successful operation in the sense that we want to keep the
883 // entry. 1034 // entry.
884 success = trans->AddTruncatedFlag(); 1035 success = transaction->AddTruncatedFlag();
885 // The previous operation may have deleted the entry. 1036 // The previous operation may have deleted the entry.
886 if (!trans->entry()) 1037 if (!transaction->entry())
887 return; 1038 return;
888 } 1039 }
889 DoneWritingToEntry(entry, success); 1040 DoneWritingToEntry(entry, success, transaction);
890 } else { 1041 return;
891 DoneReadingFromEntry(entry, trans); 1042 }
892 } 1043
893 } 1044 // Transaction is reading from the entry.
894 1045 DoneReadingFromEntry(entry, transaction);
895 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 1046 }
896 DCHECK(entry->readers.empty()); 1047
897 1048 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
898 entry->writer = NULL; 1049 bool success,
899 1050 Transaction* transaction) {
900 if (success) { 1051 DCHECK(transaction == entry->writer ||
901 ProcessPendingQueue(entry); 1052 transaction == entry->headers_transaction);
902 } else { 1053
903 DCHECK(!entry->will_process_pending_queue); 1054 // Transaction is done writing to entry in the response body phase.
904 1055 if (transaction == entry->writer)
905 // We failed to create this entry. 1056 entry->writer = nullptr;
906 TransactionList pending_queue; 1057 else
907 pending_queue.swap(entry->pending_queue); 1058 entry->headers_transaction = nullptr;
908 1059
909 entry->disk_entry->Doom(); 1060 // If writer fails, all transactions should fail.
910 DestroyEntry(entry); 1061 if (!success && entry->headers_transaction) {
911 1062 entry->headers_transaction->SetValidatingCannotProceed();
912 // We need to do something about these pending entries, which now need to 1063 entry->headers_transaction = nullptr;
913 // be added to a new entry. 1064 DCHECK(entry->HasNoActiveTransactions());
914 while (!pending_queue.empty()) { 1065 }
915 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1066 if (!success)
916 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1067 ProcessEntryFailure(entry);
917 pending_queue.pop_front(); 1068 else
918 } 1069 ProcessQueuedTransactions(entry);
919 } 1070 }
920 } 1071
921 1072 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
922 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1073 Transaction* transaction) {
923 DCHECK(!entry->writer); 1074 DCHECK(!entry->writer);
924 1075 auto it = entry->readers.find(transaction);
925 auto it = entry->readers.find(trans);
926 DCHECK(it != entry->readers.end()); 1076 DCHECK(it != entry->readers.end());
927
928 entry->readers.erase(it); 1077 entry->readers.erase(it);
929 1078
930 ProcessPendingQueue(entry); 1079 ProcessQueuedTransactions(entry);
931 }
932
933 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
934 DCHECK(entry->writer);
935 DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
936 DCHECK(entry->readers.empty());
937
938 Transaction* trans = entry->writer;
939
940 entry->writer = NULL;
941 entry->readers.insert(trans);
942
943 ProcessPendingQueue(entry);
944 } 1080 }
945 1081
946 LoadState HttpCache::GetLoadStateForPendingTransaction( 1082 LoadState HttpCache::GetLoadStateForPendingTransaction(
947 const Transaction* trans) { 1083 const Transaction* trans) {
948 auto i = active_entries_.find(trans->key()); 1084 auto i = active_entries_.find(trans->key());
949 if (i == active_entries_.end()) { 1085 if (i == active_entries_.end()) {
950 // If this is really a pending transaction, and it is not part of 1086 // If this is really a pending transaction, and it is not part of
951 // active_entries_, we should be creating the backend or the entry. 1087 // active_entries_, we should be creating the backend or the entry.
952 return LOAD_STATE_WAITING_FOR_CACHE; 1088 return LOAD_STATE_WAITING_FOR_CACHE;
953 } 1089 }
(...skipping 29 matching lines...) Expand all
983 1119
984 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1120 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
985 ++k) { 1121 ++k) {
986 found = RemovePendingTransactionFromEntry(k->first, trans); 1122 found = RemovePendingTransactionFromEntry(k->first, trans);
987 } 1123 }
988 1124
989 DCHECK(found) << "Pending transaction not found"; 1125 DCHECK(found) << "Pending transaction not found";
990 } 1126 }
991 1127
992 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1128 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
993 Transaction* trans) { 1129 Transaction* transaction) {
994 TransactionList& pending_queue = entry->pending_queue; 1130 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
995 1131
996 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1132 auto j =
997 if (j == pending_queue.end()) 1133 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1134 if (j == add_to_entry_queue.end())
998 return false; 1135 return false;
999 1136
1000 pending_queue.erase(j); 1137 add_to_entry_queue.erase(j);
1001 return true; 1138 return true;
1002 } 1139 }
1003 1140
1004 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1141 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1005 Transaction* trans) { 1142 Transaction* trans) {
1006 if (pending_op->writer->Matches(trans)) { 1143 if (pending_op->writer->Matches(trans)) {
1007 pending_op->writer->ClearTransaction(); 1144 pending_op->writer->ClearTransaction();
1008 pending_op->writer->ClearEntry(); 1145 pending_op->writer->ClearEntry();
1009 return true; 1146 return true;
1010 } 1147 }
1011 WorkItemList& pending_queue = pending_op->pending_queue; 1148 WorkItemList& pending_queue = pending_op->pending_queue;
1012 1149
1013 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1150 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1014 if ((*it)->Matches(trans)) { 1151 if ((*it)->Matches(trans)) {
1015 pending_queue.erase(it); 1152 pending_queue.erase(it);
1016 return true; 1153 return true;
1017 } 1154 }
1018 } 1155 }
1019 return false; 1156 return false;
1020 } 1157 }
1021 1158
1022 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
1023 // Multiple readers may finish with an entry at once, so we want to batch up
1024 // calls to OnProcessPendingQueue. This flag also tells us that we should
1025 // not delete the entry before OnProcessPendingQueue runs.
1026 if (entry->will_process_pending_queue)
1027 return;
1028 entry->will_process_pending_queue = true;
1029
1030 base::ThreadTaskRunnerHandle::Get()->PostTask(
1031 FROM_HERE,
1032 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1033 }
1034
1035 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1036 entry->will_process_pending_queue = false;
1037 DCHECK(!entry->writer);
1038
1039 // If no one is interested in this entry, then we can deactivate it.
1040 if (entry->HasNoTransactions()) {
1041 DestroyEntry(entry);
1042 return;
1043 }
1044
1045 if (entry->pending_queue.empty())
1046 return;
1047
1048 // Promote next transaction from the pending queue.
1049 Transaction* next = entry->pending_queue.front();
1050 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1051 return; // Have to wait.
1052
1053 entry->pending_queue.erase(entry->pending_queue.begin());
1054
1055 int rv = AddTransactionToEntry(entry, next);
1056 if (rv != ERR_IO_PENDING) {
1057 next->io_callback().Run(rv);
1058 }
1059 }
1060
1061 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1159 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1062 WorkItemOperation op = pending_op->writer->operation(); 1160 WorkItemOperation op = pending_op->writer->operation();
1063 1161
1064 // Completing the creation of the backend is simpler than the other cases. 1162 // Completing the creation of the backend is simpler than the other cases.
1065 if (op == WI_CREATE_BACKEND) 1163 if (op == WI_CREATE_BACKEND)
1066 return OnBackendCreated(result, pending_op); 1164 return OnBackendCreated(result, pending_op);
1067 1165
1068 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1166 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
1069 bool fail_requests = false; 1167 bool fail_requests = false;
1070 1168
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 building_backend_ = false; 1293 building_backend_ = false;
1196 DeletePendingOp(pending_op); 1294 DeletePendingOp(pending_op);
1197 } 1295 }
1198 1296
1199 // The cache may be gone when we return from the callback. 1297 // The cache may be gone when we return from the callback.
1200 if (!item->DoCallback(result, disk_cache_.get())) 1298 if (!item->DoCallback(result, disk_cache_.get()))
1201 item->NotifyTransaction(result, NULL); 1299 item->NotifyTransaction(result, NULL);
1202 } 1300 }
1203 1301
1204 } // namespace net 1302 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698