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

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

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

Powered by Google App Engine
This is Rietveld 408576698