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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Fixed partial transactions handling in ActiveEntry Created 3 years, 7 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
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 session->SetServerPushDelegate( 336 session->SetServerPushDelegate(
336 base::MakeUnique<HttpCacheLookupManager>(this)); 337 base::MakeUnique<HttpCacheLookupManager>(this));
337 } 338 }
338 339
339 HttpCache::~HttpCache() { 340 HttpCache::~HttpCache() {
340 // Transactions should see an invalid cache after this point; otherwise they 341 // Transactions should see an invalid cache after this point; otherwise they
341 // could see an inconsistent object (half destroyed). 342 // could see an inconsistent object (half destroyed).
342 weak_factory_.InvalidateWeakPtrs(); 343 weak_factory_.InvalidateWeakPtrs();
343 344
344 // If we have any active entries remaining, then we need to deactivate them. 345 // If we have any active entries remaining, then we need to deactivate them.
345 // We may have some pending calls to OnProcessPendingQueue, but since those 346 // We may have some pending tasks to process queued transactions ,but since
346 // won't run (due to our destruction), we can simply ignore the corresponding 347 // those won't run (due to our destruction), we can simply ignore the
347 // will_process_pending_queue flag. 348 // corresponding flags.
348 while (!active_entries_.empty()) { 349 while (!active_entries_.empty()) {
349 ActiveEntry* entry = active_entries_.begin()->second.get(); 350 ActiveEntry* entry = active_entries_.begin()->second.get();
350 entry->will_process_pending_queue = false; 351 entry->will_process_queued_transactions = false;
351 entry->pending_queue.clear(); 352 entry->add_to_entry_queue.clear();
352 entry->readers.clear(); 353 entry->readers.clear();
353 entry->writer = NULL; 354 entry->done_headers_queue.clear();
355 entry->headers_transaction = nullptr;
356 entry->writer = nullptr;
354 DeactivateEntry(entry); 357 DeactivateEntry(entry);
355 } 358 }
356 359
357 doomed_entries_.clear(); 360 doomed_entries_.clear();
358 361
359 // Before deleting pending_ops_, we have to make sure that the disk cache is 362 // Before deleting pending_ops_, we have to make sure that the disk cache is
360 // done with said operations, or it will attempt to use deleted data. 363 // done with said operations, or it will attempt to use deleted data.
361 disk_cache_.reset(); 364 disk_cache_.reset();
362 365
363 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 366 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // We keep track of doomed entries so that we can ensure that they are 607 // We keep track of doomed entries so that we can ensure that they are
605 // cleaned up properly when the cache is destroyed. 608 // cleaned up properly when the cache is destroyed.
606 ActiveEntry* entry_ptr = entry.get(); 609 ActiveEntry* entry_ptr = entry.get();
607 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 610 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
608 doomed_entries_[entry_ptr] = std::move(entry); 611 doomed_entries_[entry_ptr] = std::move(entry);
609 612
610 entry_ptr->disk_entry->Doom(); 613 entry_ptr->disk_entry->Doom();
611 entry_ptr->doomed = true; 614 entry_ptr->doomed = true;
612 615
613 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 616 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
614 entry_ptr->will_process_pending_queue); 617 entry_ptr->headers_transaction ||
618 entry_ptr->will_process_queued_transactions);
615 return OK; 619 return OK;
616 } 620 }
617 621
618 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 622 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
619 std::unique_ptr<WorkItem> item = 623 std::unique_ptr<WorkItem> item =
620 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 624 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
621 PendingOp* pending_op = GetPendingOp(key); 625 PendingOp* pending_op = GetPendingOp(key);
622 if (pending_op->writer) { 626 if (pending_op->writer) {
623 pending_op->pending_queue.push_back(std::move(item)); 627 pending_op->pending_queue.push_back(std::move(item));
624 return ERR_IO_PENDING; 628 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 DCHECK(entry->doomed); 664 DCHECK(entry->doomed);
661 DCHECK(entry->HasNoTransactions()); 665 DCHECK(entry->HasNoTransactions());
662 666
663 auto it = doomed_entries_.find(entry); 667 auto it = doomed_entries_.find(entry);
664 DCHECK(it != doomed_entries_.end()); 668 DCHECK(it != doomed_entries_.end());
665 doomed_entries_.erase(it); 669 doomed_entries_.erase(it);
666 } 670 }
667 671
668 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 672 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
669 auto it = active_entries_.find(key); 673 auto it = active_entries_.find(key);
670 return it != active_entries_.end() ? it->second.get() : NULL; 674 return it != active_entries_.end() ? it->second.get() : nullptr;
671 } 675 }
672 676
673 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 677 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
674 disk_cache::Entry* disk_entry) { 678 disk_cache::Entry* disk_entry) {
675 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 679 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
676 ActiveEntry* entry = new ActiveEntry(disk_entry); 680 ActiveEntry* entry = new ActiveEntry(disk_entry);
677 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 681 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
678 return entry; 682 return entry;
679 } 683 }
680 684
681 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 685 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
682 DCHECK(!entry->will_process_pending_queue); 686 DCHECK(!entry->will_process_queued_transactions);
683 DCHECK(!entry->doomed); 687 DCHECK(!entry->doomed);
684 DCHECK(entry->disk_entry); 688 DCHECK(entry->disk_entry);
685 DCHECK(entry->HasNoTransactions()); 689 DCHECK(entry->HasNoTransactions());
686 690
687 std::string key = entry->disk_entry->GetKey(); 691 std::string key = entry->disk_entry->GetKey();
688 if (key.empty()) 692 if (key.empty())
689 return SlowDeactivateEntry(entry); 693 return SlowDeactivateEntry(entry);
690 694
691 auto it = active_entries_.find(key); 695 auto it = active_entries_.find(key);
692 DCHECK(it != active_entries_.end()); 696 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 } 806 }
803 807
804 void HttpCache::DestroyEntry(ActiveEntry* entry) { 808 void HttpCache::DestroyEntry(ActiveEntry* entry) {
805 if (entry->doomed) { 809 if (entry->doomed) {
806 FinalizeDoomedEntry(entry); 810 FinalizeDoomedEntry(entry);
807 } else { 811 } else {
808 DeactivateEntry(entry); 812 DeactivateEntry(entry);
809 } 813 }
810 } 814 }
811 815
812 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 816 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
817 Transaction* transaction) {
813 DCHECK(entry); 818 DCHECK(entry);
814 DCHECK(entry->disk_entry); 819 DCHECK(entry->disk_entry);
815 820 // Always add a new transaction to the queue to maintain FIFO order.
816 // We implement a basic reader/writer lock for the disk cache entry. If 821 entry->add_to_entry_queue.push_back(transaction);
817 // there is already a writer, then everyone has to wait for the writer to 822 ProcessQueuedTransactions(entry);
818 // finish before they can access the cache entry. There can be multiple 823 return ERR_IO_PENDING;
819 // readers. 824 }
820 // 825
821 // NOTE: If the transaction can only write, then the entry should not be in 826 int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
822 // use (since any existing entry should have already been doomed). 827 Transaction* transaction,
823 828 bool is_partial) {
824 if (entry->writer || entry->will_process_pending_queue) { 829 // If |transaction| is the current writer, do nothing. This can happen for
825 entry->pending_queue.push_back(trans); 830 // range requests since they can go back to headers phase after starting to
826 return ERR_IO_PENDING; 831 // write.
827 } 832 if (entry->writer == transaction)
828 833 return OK;
829 if (trans->mode() & Transaction::WRITE) { 834
830 // transaction needs exclusive access to the entry 835 DCHECK_EQ(entry->headers_transaction, transaction);
831 if (entry->readers.empty()) { 836
832 entry->writer = trans; 837 entry->headers_transaction = nullptr;
833 } else { 838
834 entry->pending_queue.push_back(trans); 839 // If transaction is responsible for writing the response body, then do not go
835 return ERR_IO_PENDING; 840 // through done_headers_queue for performance benefit. (Also, in case of
841 // writer transaction, the consumer sometimes depend on synchronous behaviour
842 // e.g. while computing raw headers size. (crbug.com/711766))
843 if (transaction->mode() & Transaction::WRITE) {
844 DCHECK(entry->done_headers_queue.empty());
845
846 // Partial requests may have write mode even when there is a writer present
847 // since they may be reader for a particular range and writer for another
848 // range.
849 DCHECK(is_partial || !entry->writer);
850
851 if (!entry->writer) {
852 entry->writer = transaction;
853 ProcessQueuedTransactions(entry);
854 return OK;
836 } 855 }
837 } else { 856 }
838 // transaction needs read access to the entry 857
839 entry->readers.insert(trans); 858 // If this is not the first transaction in done_headers_queue, it should be a
840 } 859 // read-mode transaction except if it is a partial request.
841 860 DCHECK(is_partial || (entry->done_headers_queue.empty() ||
842 // We do this before calling EntryAvailable to force any further calls to 861 !(transaction->mode() & Transaction::WRITE)));
843 // AddTransactionToEntry to add their transaction to the pending queue, which 862
844 // ensures FIFO ordering. 863 entry->done_headers_queue.push_back(transaction);
845 if (!entry->writer && !entry->pending_queue.empty()) 864 ProcessQueuedTransactions(entry);
846 ProcessPendingQueue(entry); 865 return ERR_IO_PENDING;
847 866 }
848 return OK; 867
849 } 868 void HttpCache::DoneWithEntry(ActiveEntry* entry,
850 869 Transaction* transaction,
851 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
852 bool cancel) { 870 bool cancel) {
853 // If we already posted a task to move on to the next transaction and this was 871 // Transaction is waiting in the done_headers_queue.
854 // the writer, there is nothing to cancel. 872 auto it = std::find(entry->done_headers_queue.begin(),
855 if (entry->will_process_pending_queue && entry->readers.empty()) 873 entry->done_headers_queue.end(), transaction);
856 return; 874 if (it != entry->done_headers_queue.end()) {
857 875 entry->done_headers_queue.erase(it);
858 if (entry->writer) { 876 if (cancel)
859 DCHECK(trans == entry->writer); 877 ProcessEntryFailure(entry);
860 878 return;
879 }
880
881 // Transaction is removed in the headers phase.
882 if (transaction == entry->headers_transaction) {
883 // If the response is not written (cancel is true), consider it a failure.
884 DoneWritingToEntry(entry, !cancel, transaction);
885 return;
886 }
887
888 // Transaction is removed in the writing phase.
889 if (transaction == entry->writer) {
861 // Assume there was a failure. 890 // Assume there was a failure.
862 bool success = false; 891 bool success = false;
863 if (cancel) { 892 if (cancel) {
864 DCHECK(entry->disk_entry); 893 DCHECK(entry->disk_entry);
865 // This is a successful operation in the sense that we want to keep the 894 // This is a successful operation in the sense that we want to keep the
866 // entry. 895 // entry.
867 success = trans->AddTruncatedFlag(); 896 success = transaction->AddTruncatedFlag();
868 // The previous operation may have deleted the entry. 897 // The previous operation may have deleted the entry.
869 if (!trans->entry()) 898 if (!transaction->entry())
870 return; 899 return;
871 } 900 }
872 DoneWritingToEntry(entry, success); 901 DoneWritingToEntry(entry, success, transaction);
902 return;
903 }
904
905 // Transaction is reading from the entry.
906 DoneReadingFromEntry(entry, transaction);
907 }
908
909 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
910 bool success,
911 Transaction* transaction) {
912 DCHECK(transaction == entry->writer ||
913 transaction == entry->headers_transaction);
914
915 if (transaction == entry->writer)
916 entry->writer = nullptr;
917 else
918 entry->headers_transaction = nullptr;
919
920 // If writer fails, restart the headers_transaction by setting its state.
921 // Since the headers_transactions is awaiting an asynchronous operation
922 // completion, when it's IO callback is invoked, it will be restarted.
923 if (!success && entry->headers_transaction) {
924 entry->headers_transaction->SetValidatingCannotProceed();
925 entry->headers_transaction = nullptr;
926 DCHECK(entry->HasNoActiveTransactions());
927 }
928 if (!success)
929 ProcessEntryFailure(entry);
930 else
931 ProcessQueuedTransactions(entry);
932 }
933
934 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
935 Transaction* transaction) {
936 DCHECK(!entry->writer);
937 auto it = entry->readers.find(transaction);
938 DCHECK(it != entry->readers.end());
939 entry->readers.erase(it);
940
941 ProcessQueuedTransactions(entry);
942 }
943
944 void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
945 TransactionList* list) {
946 // Process done_headers_queue before add_to_entry_queue to maintain FIFO
947 // order.
948 for (auto* transaction : entry->done_headers_queue)
949 list->push_back(transaction);
950 entry->done_headers_queue.clear();
951
952 for (auto* transaction : entry->add_to_entry_queue)
953 list->push_back(transaction);
954 entry->add_to_entry_queue.clear();
955 }
956
957 void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
958 // Failure case is either writer failing to completely write the response to
959 // the cache or validating transaction received a non-304 response.
960 TransactionList list;
961 if (entry->HasNoActiveTransactions() &&
962 !entry->will_process_queued_transactions) {
963 entry->disk_entry->Doom();
964 RemoveAllQueuedTransactions(entry, &list);
965 DestroyEntry(entry);
873 } else { 966 } else {
874 DoneReadingFromEntry(entry, trans); 967 DoomActiveEntry(entry->disk_entry->GetKey());
875 } 968 RemoveAllQueuedTransactions(entry, &list);
876 } 969 }
877 970 // ERR_CACHE_RACE causes the transaction to restart the whole process.
878 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 971 for (auto* transaction : list)
879 DCHECK(entry->readers.empty()); 972 transaction->io_callback().Run(net::ERR_CACHE_RACE);
880 973 }
881 entry->writer = NULL; 974
882 975 void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
883 if (success) { 976 // Multiple readers may finish with an entry at once, so we want to batch up
884 ProcessPendingQueue(entry); 977 // calls to OnProcessQueuedTransactions. This flag also tells us that we
978 // should not delete the entry before OnProcessQueuedTransactions runs.
979 if (entry->will_process_queued_transactions)
980 return;
981
982 entry->will_process_queued_transactions = true;
983
984 // Post a task instead of invoking the io callback of another transaction here
985 // to avoid re-entrancy.
986 base::ThreadTaskRunnerHandle::Get()->PostTask(
987 FROM_HERE,
988 base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
989 }
990
991 void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
992 DCHECK(!entry->add_to_entry_queue.empty());
993
994 // Note the entry may be new or may already have a response body written to
995 // it. In both cases, a transaction needs to wait since only one transaction
996 // can be in the headers phase at a time.
997 if (entry->headers_transaction) {
998 return;
999 }
1000 Transaction* transaction = entry->add_to_entry_queue.front();
1001 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1002 entry->headers_transaction = transaction;
1003
1004 transaction->io_callback().Run(OK);
1005 }
1006
1007 void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
1008 DCHECK(!entry->writer);
1009 DCHECK(!entry->done_headers_queue.empty());
1010
1011 Transaction* transaction = entry->done_headers_queue.front();
1012
1013 // If this transaction is responsible for writing the response body.
1014 if (transaction->mode() & Transaction::WRITE) {
1015 entry->writer = transaction;
885 } else { 1016 } else {
886 DCHECK(!entry->will_process_pending_queue); 1017 // If a transaction is in front of this queue with only read mode set and
887 1018 // there is no writer, it implies response body is already written, convert
888 // We failed to create this entry. 1019 // to a reader.
889 TransactionList pending_queue; 1020 auto return_val = entry->readers.insert(transaction);
890 pending_queue.swap(entry->pending_queue); 1021 DCHECK_EQ(return_val.second, true);
891 1022 }
892 entry->disk_entry->Doom(); 1023
893 DestroyEntry(entry); 1024 // Post another task to give a chance to more transactions to either join
894 1025 // readers or another transaction to start parallel validation.
895 // We need to do something about these pending entries, which now need to 1026 ProcessQueuedTransactions(entry);
896 // be added to a new entry. 1027
897 while (!pending_queue.empty()) { 1028 entry->done_headers_queue.erase(entry->done_headers_queue.begin());
898 // ERR_CACHE_RACE causes the transaction to restart the whole process. 1029 transaction->io_callback().Run(OK);
899 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 1030 }
900 pending_queue.pop_front(); 1031
901 } 1032 bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
902 } 1033 Transaction* transaction,
903 } 1034 bool is_match) const {
904 1035 if (transaction != entry->headers_transaction)
905 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1036 return false;
906 DCHECK(!entry->writer); 1037
907 1038 if (!(transaction->mode() & Transaction::WRITE))
908 auto it = entry->readers.find(trans); 1039 return false;
909 DCHECK(it != entry->readers.end()); 1040
910 1041 // If its not a match then check if it is the transaction responsible for
911 entry->readers.erase(it); 1042 // writing the response body.
912 1043 if (!is_match) {
913 ProcessPendingQueue(entry); 1044 return !entry->writer && entry->done_headers_queue.empty() &&
914 } 1045 entry->readers.empty();
915 1046 }
916 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1047
917 DCHECK(entry->writer); 1048 return true;
918 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1049 }
919 DCHECK(entry->readers.empty()); 1050
920 1051 bool HttpCache::IsTransactionWritingIncomplete(
921 Transaction* trans = entry->writer; 1052 ActiveEntry* entry,
922 1053 Transaction* transaction,
923 entry->writer = NULL; 1054 const std::string& method) const {
924 entry->readers.insert(trans); 1055 if (transaction == entry->writer)
925 1056 return true;
926 ProcessPendingQueue(entry); 1057
1058 if (entry->writer)
1059 return false;
Randy Smith (Not in Mondays) 2017/05/03 16:16:00 I'm trying to wrap my head around this change, and
shivanisha 2017/05/03 19:50:18 This condition is basically saying that: if there
Randy Smith (Not in Mondays) 2017/05/09 23:20:32 Acknowledged.
1060
1061 if (method == "HEAD" || method == "DELETE")
1062 return false;
1063
1064 // Check if transaction is about to start writing to the cache.
1065
1066 // Transaction's mode may have been set to NONE if StopCaching was invoked.
1067 if (!(transaction->mode() & Transaction::WRITE ||
1068 transaction->mode() == Transaction::NONE)) {
1069 return false;
1070 }
1071
1072 // If a transaction is completing headers or done with headers phase with
1073 // write mode then it should be the future writer. Just checking the front of
1074 // done_headers_queue since the rest should anyways be READ mode transactions
1075 // as they would be a result of validation match.
1076 return transaction == entry->headers_transaction ||
1077 transaction == entry->done_headers_queue.front();
1078 }
1079
1080 bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
1081 return entry->writer != nullptr;
927 } 1082 }
928 1083
929 LoadState HttpCache::GetLoadStateForPendingTransaction( 1084 LoadState HttpCache::GetLoadStateForPendingTransaction(
930 const Transaction* trans) { 1085 const Transaction* trans) {
931 auto i = active_entries_.find(trans->key()); 1086 auto i = active_entries_.find(trans->key());
932 if (i == active_entries_.end()) { 1087 if (i == active_entries_.end()) {
933 // If this is really a pending transaction, and it is not part of 1088 // If this is really a pending transaction, and it is not part of
934 // active_entries_, we should be creating the backend or the entry. 1089 // active_entries_, we should be creating the backend or the entry.
935 return LOAD_STATE_WAITING_FOR_CACHE; 1090 return LOAD_STATE_WAITING_FOR_CACHE;
936 } 1091 }
(...skipping 29 matching lines...) Expand all
966 1121
967 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1122 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
968 ++k) { 1123 ++k) {
969 found = RemovePendingTransactionFromEntry(k->first, trans); 1124 found = RemovePendingTransactionFromEntry(k->first, trans);
970 } 1125 }
971 1126
972 DCHECK(found) << "Pending transaction not found"; 1127 DCHECK(found) << "Pending transaction not found";
973 } 1128 }
974 1129
975 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1130 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
976 Transaction* trans) { 1131 Transaction* transaction) {
977 TransactionList& pending_queue = entry->pending_queue; 1132 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
978 1133
979 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1134 auto j =
980 if (j == pending_queue.end()) 1135 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1136 if (j == add_to_entry_queue.end())
981 return false; 1137 return false;
982 1138
983 pending_queue.erase(j); 1139 add_to_entry_queue.erase(j);
984 return true; 1140 return true;
985 } 1141 }
986 1142
987 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1143 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
988 Transaction* trans) { 1144 Transaction* trans) {
989 if (pending_op->writer->Matches(trans)) { 1145 if (pending_op->writer->Matches(trans)) {
990 pending_op->writer->ClearTransaction(); 1146 pending_op->writer->ClearTransaction();
991 pending_op->writer->ClearEntry(); 1147 pending_op->writer->ClearEntry();
992 return true; 1148 return true;
993 } 1149 }
994 WorkItemList& pending_queue = pending_op->pending_queue; 1150 WorkItemList& pending_queue = pending_op->pending_queue;
995 1151
996 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1152 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
997 if ((*it)->Matches(trans)) { 1153 if ((*it)->Matches(trans)) {
998 pending_queue.erase(it); 1154 pending_queue.erase(it);
999 return true; 1155 return true;
1000 } 1156 }
1001 } 1157 }
1002 return false; 1158 return false;
1003 } 1159 }
1004 1160
1005 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1161 void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
1006 // Multiple readers may finish with an entry at once, so we want to batch up 1162 entry->will_process_queued_transactions = false;
1007 // calls to OnProcessPendingQueue. This flag also tells us that we should
1008 // not delete the entry before OnProcessPendingQueue runs.
1009 if (entry->will_process_pending_queue)
1010 return;
1011 entry->will_process_pending_queue = true;
1012 1163
1013 base::ThreadTaskRunnerHandle::Get()->PostTask( 1164 // Note that this function should only invoke one transaction's IO callback
1014 FROM_HERE, 1165 // since its possible for IO callbacks' consumers to destroy the cache/entry.
1015 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1016 }
1017
1018 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1019 entry->will_process_pending_queue = false;
1020 DCHECK(!entry->writer);
1021 1166
1022 // If no one is interested in this entry, then we can deactivate it. 1167 // If no one is interested in this entry, then we can deactivate it.
1023 if (entry->HasNoTransactions()) { 1168 if (entry->HasNoTransactions()) {
1024 DestroyEntry(entry); 1169 DestroyEntry(entry);
1025 return; 1170 return;
1026 } 1171 }
1027 1172
1028 if (entry->pending_queue.empty()) 1173 if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
1029 return; 1174 return;
1030 1175
1031 // Promote next transaction from the pending queue. 1176 // To maintain FIFO order of transactions, done_headers_queue should be
1032 Transaction* next = entry->pending_queue.front(); 1177 // checked for processing before add_to_entry_queue.
1033 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1034 return; // Have to wait.
1035 1178
1036 entry->pending_queue.erase(entry->pending_queue.begin()); 1179 // If another transaction is writing the response, let validated transactions
1180 // wait till the response is complete. If the response is not yet started, the
1181 // done_headers_queue transaction should start writing it.
1182 if (!entry->writer && !entry->done_headers_queue.empty()) {
1183 ProcessDoneHeadersQueue(entry);
1184 return;
1185 }
1037 1186
1038 int rv = AddTransactionToEntry(entry, next); 1187 if (!entry->add_to_entry_queue.empty())
1039 if (rv != ERR_IO_PENDING) { 1188 ProcessAddToEntryQueue(entry);
1040 next->io_callback().Run(rv);
1041 }
1042 } 1189 }
1043 1190
1044 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1191 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1045 WorkItemOperation op = pending_op->writer->operation(); 1192 WorkItemOperation op = pending_op->writer->operation();
1046 1193
1047 // Completing the creation of the backend is simpler than the other cases. 1194 // Completing the creation of the backend is simpler than the other cases.
1048 if (op == WI_CREATE_BACKEND) 1195 if (op == WI_CREATE_BACKEND)
1049 return OnBackendCreated(result, pending_op); 1196 return OnBackendCreated(result, pending_op);
1050 1197
1051 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1198 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1178 building_backend_ = false; 1325 building_backend_ = false;
1179 DeletePendingOp(pending_op); 1326 DeletePendingOp(pending_op);
1180 } 1327 }
1181 1328
1182 // The cache may be gone when we return from the callback. 1329 // The cache may be gone when we return from the callback.
1183 if (!item->DoCallback(result, disk_cache_.get())) 1330 if (!item->DoCallback(result, disk_cache_.get()))
1184 item->NotifyTransaction(result, NULL); 1331 item->NotifyTransaction(result, NULL);
1185 } 1332 }
1186 1333
1187 } // namespace net 1334 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_cache.h ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698