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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Feedback addressed, more tests and refactoring 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 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 validated_queue.empty() && !validating_transaction;
118 }
119
120 bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
121 return !writer && readers.empty() && !validating_transaction;
122 }
123
124 bool HttpCache::ActiveEntry::IsReader(Transaction* transaction) {
125 return readers.count(transaction);
121 } 126 }
122 127
123 //----------------------------------------------------------------------------- 128 //-----------------------------------------------------------------------------
124 129
125 // This structure keeps track of work items that are attempting to create or 130 // This structure keeps track of work items that are attempting to create or
126 // open cache entries or the backend itself. 131 // open cache entries or the backend itself.
127 struct HttpCache::PendingOp { 132 struct HttpCache::PendingOp {
128 PendingOp() : disk_entry(NULL) {} 133 PendingOp() : disk_entry(NULL) {}
129 ~PendingOp() {} 134 ~PendingOp() {}
130 135
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 } 358 }
354 } 359 }
355 } 360 }
356 361
357 HttpCache::~HttpCache() { 362 HttpCache::~HttpCache() {
358 // Transactions should see an invalid cache after this point; otherwise they 363 // Transactions should see an invalid cache after this point; otherwise they
359 // could see an inconsistent object (half destroyed). 364 // could see an inconsistent object (half destroyed).
360 weak_factory_.InvalidateWeakPtrs(); 365 weak_factory_.InvalidateWeakPtrs();
361 366
362 // If we have any active entries remaining, then we need to deactivate them. 367 // 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 368 // We may have some pending tasks to process pending queue for reading or
364 // won't run (due to our destruction), we can simply ignore the corresponding 369 // parallel validation, but since those won't run (due to our destruction),
365 // will_process_pending_queue flag. 370 // we can simply ignore the corresponding flags.
366 while (!active_entries_.empty()) { 371 while (!active_entries_.empty()) {
367 ActiveEntry* entry = active_entries_.begin()->second.get(); 372 ActiveEntry* entry = active_entries_.begin()->second.get();
368 entry->will_process_pending_queue = false; 373 entry->will_process_waiting_transactions = false;
369 entry->pending_queue.clear(); 374 entry->will_process_parallel_validation = false;
375 entry->add_to_entry_queue.clear();
370 entry->readers.clear(); 376 entry->readers.clear();
371 entry->writer = NULL; 377 entry->validated_queue.clear();
378 entry->validating_transaction = nullptr;
379 entry->writer = nullptr;
372 DeactivateEntry(entry); 380 DeactivateEntry(entry);
373 } 381 }
374 382
375 doomed_entries_.clear(); 383 doomed_entries_.clear();
376 384
377 // Before deleting pending_ops_, we have to make sure that the disk cache is 385 // 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. 386 // done with said operations, or it will attempt to use deleted data.
379 disk_cache_.reset(); 387 disk_cache_.reset();
380 388
381 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 389 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 629 // We keep track of doomed entries so that we can ensure that they are
622 // cleaned up properly when the cache is destroyed. 630 // cleaned up properly when the cache is destroyed.
623 ActiveEntry* entry_ptr = entry.get(); 631 ActiveEntry* entry_ptr = entry.get();
624 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 632 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
625 doomed_entries_[entry_ptr] = std::move(entry); 633 doomed_entries_[entry_ptr] = std::move(entry);
626 634
627 entry_ptr->disk_entry->Doom(); 635 entry_ptr->disk_entry->Doom();
628 entry_ptr->doomed = true; 636 entry_ptr->doomed = true;
629 637
630 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 638 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
631 entry_ptr->will_process_pending_queue); 639 !entry_ptr->validated_queue.empty() ||
640 entry_ptr->validating_transaction ||
641 entry_ptr->will_process_waiting_transactions ||
642 entry_ptr->will_process_parallel_validation);
632 return OK; 643 return OK;
633 } 644 }
634 645
635 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 646 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
636 std::unique_ptr<WorkItem> item = 647 std::unique_ptr<WorkItem> item =
637 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 648 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
638 PendingOp* pending_op = GetPendingOp(key); 649 PendingOp* pending_op = GetPendingOp(key);
639 if (pending_op->writer) { 650 if (pending_op->writer) {
640 pending_op->pending_queue.push_back(std::move(item)); 651 pending_op->pending_queue.push_back(std::move(item));
641 return ERR_IO_PENDING; 652 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 DCHECK(entry->doomed); 688 DCHECK(entry->doomed);
678 DCHECK(entry->HasNoTransactions()); 689 DCHECK(entry->HasNoTransactions());
679 690
680 auto it = doomed_entries_.find(entry); 691 auto it = doomed_entries_.find(entry);
681 DCHECK(it != doomed_entries_.end()); 692 DCHECK(it != doomed_entries_.end());
682 doomed_entries_.erase(it); 693 doomed_entries_.erase(it);
683 } 694 }
684 695
685 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 696 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
686 auto it = active_entries_.find(key); 697 auto it = active_entries_.find(key);
687 return it != active_entries_.end() ? it->second.get() : NULL; 698 return it != active_entries_.end() ? it->second.get() : nullptr;
699 }
700
701 bool HttpCache::IsEntryAlive(const std::string& key, ActiveEntry* entry) {
702 ActiveEntry* active_entry = FindActiveEntry(key);
703 if (active_entry && active_entry == entry)
704 return true;
705 return doomed_entries_.count(entry);
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);
700 DCHECK(!entry->doomed); 717 DCHECK(!entry->doomed);
701 DCHECK(entry->disk_entry); 718 DCHECK(entry->disk_entry);
702 DCHECK(entry->HasNoTransactions()); 719 DCHECK(entry->HasNoTransactions());
703 720
704 std::string key = entry->disk_entry->GetKey(); 721 std::string key = entry->disk_entry->GetKey();
705 if (key.empty()) 722 if (key.empty())
706 return SlowDeactivateEntry(entry); 723 return SlowDeactivateEntry(entry);
707 724
708 auto it = active_entries_.find(key); 725 auto it = active_entries_.find(key);
709 DCHECK(it != active_entries_.end()); 726 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 836 }
820 837
821 void HttpCache::DestroyEntry(ActiveEntry* entry) { 838 void HttpCache::DestroyEntry(ActiveEntry* entry) {
822 if (entry->doomed) { 839 if (entry->doomed) {
823 FinalizeDoomedEntry(entry); 840 FinalizeDoomedEntry(entry);
824 } else { 841 } else {
825 DeactivateEntry(entry); 842 DeactivateEntry(entry);
826 } 843 }
827 } 844 }
828 845
829 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 846 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
847 Transaction* transaction) {
830 DCHECK(entry); 848 DCHECK(entry);
831 DCHECK(entry->disk_entry); 849 DCHECK(entry->disk_entry);
832 850
833 // We implement a basic reader/writer lock for the disk cache entry. If 851 // If a pending queue processing task is posted, then this transaction
834 // there is already a writer, then everyone has to wait for the writer to 852 // should be added after the queue task is processed, to maintain FIFO
835 // finish before they can access the cache entry. There can be multiple 853 // ordering.
836 // readers. 854 if (entry->will_process_waiting_transactions ||
837 // 855 entry->will_process_parallel_validation) {
838 // NOTE: If the transaction can only write, then the entry should not be in 856 entry->add_to_entry_queue.push_back(transaction);
839 // use (since any existing entry should have already been doomed).
840
841 if (entry->writer || entry->will_process_pending_queue) {
842 entry->pending_queue.push_back(trans);
843 return ERR_IO_PENDING; 857 return ERR_IO_PENDING;
844 } 858 }
845 859
846 if (trans->mode() & Transaction::WRITE) { 860 int rv = AddTransactionToEntryImpl(entry, transaction);
847 // transaction needs exclusive access to the entry 861 if (rv == ERR_IO_PENDING)
848 if (entry->readers.empty()) { 862 entry->add_to_entry_queue.push_back(transaction);
849 entry->writer = trans; 863 return rv;
850 } else { 864 }
851 entry->pending_queue.push_back(trans); 865
852 return ERR_IO_PENDING; 866 // We implement a basic reader/writer lock for the disk cache entry. If there
853 } 867 // is a writer, then all read-only transactions must wait. Non read-only
854 } else { 868 // transactions can proceed to their validation phase. Validation is allowed
855 // transaction needs read access to the entry 869 // for one transaction at a time so that we do not end up with wasted network
856 entry->readers.insert(trans); 870 // requests.
871 int HttpCache::AddTransactionToEntryImpl(ActiveEntry* entry,
872 Transaction* transaction) {
873 if (transaction->mode() & Transaction::WRITE)
874 return AddTransactionToEntryForWrite(entry, transaction);
875 return AddTransactionToEntryForRead(entry, transaction);
876 }
877
878 int HttpCache::AddTransactionToEntryForRead(ActiveEntry* entry,
879 Transaction* transaction) {
880 if (entry->writer) {
881 return ERR_IO_PENDING;
857 } 882 }
858 883 entry->readers.insert(transaction);
859 // We do this before calling EntryAvailable to force any further calls to 884 if (!entry->add_to_entry_queue.empty())
860 // AddTransactionToEntry to add their transaction to the pending queue, which 885 ProcessWaitingTransactions(entry);
861 // ensures FIFO ordering.
862 if (!entry->writer && !entry->pending_queue.empty())
863 ProcessPendingQueue(entry);
864
865 return OK; 886 return OK;
866 } 887 }
867 888
868 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 889 int HttpCache::AddTransactionToEntryForWrite(ActiveEntry* entry,
890 Transaction* transaction) {
891 // A transaction that has the write mode can become the next validating
892 // transaction. It can also become the writer if there is no active writer at
893 // this time.
894 if (entry->validating_transaction) {
895 return ERR_IO_PENDING;
896 }
897 entry->validating_transaction = transaction;
898 if (!entry->writer && entry->readers.empty()) {
899 entry->writer = transaction;
900 }
901
902 // If there is no writer, we can add more readers.
903 if (!entry->writer && !entry->add_to_entry_queue.empty())
904 ProcessWaitingTransactions(entry);
905 return OK;
906 }
907
908 int HttpCache::DoneValidationWithEntry(ActiveEntry* entry,
909 Transaction* transaction,
910 bool is_match) {
911 DCHECK(entry->writer == transaction ||
912 entry->validating_transaction == transaction);
913 entry->validating_transaction = nullptr;
914
915 if (!is_match) {
916 if (entry->writer == transaction)
917 entry->writer = nullptr;
918 if (entry->HasNoActiveTransactions())
919 DestroyEntryRestartPendingTransactions(entry);
920 else
921 DoomEntryRestartPendingTransactions(entry);
922 return OK;
923 }
924
925 int rv = OK;
926 // If another transaction is writing the response, let this transaction wait
927 // till the response is complete.
928 if (entry->writer != transaction) {
929 entry->validated_queue.push_back(transaction);
930 rv = ERR_IO_PENDING;
931 }
932 // Else the transaction should either be the writer if its responsible for
933 // writing the response or should have been converted to a reader.
934
935 // In all cases another transaction can start its validation phase.
936 ProcessParallelValidation(entry);
937 return rv;
938 }
939
940 void HttpCache::DoneValidationWriteEntry(ActiveEntry* entry,
941 Transaction* transaction) {
942 entry->validating_transaction = nullptr;
943 ProcessParallelValidation(entry);
944 }
945
946 void HttpCache::DoneWithEntry(ActiveEntry* entry,
947 Transaction* transaction,
869 bool cancel) { 948 bool cancel) {
870 // If we already posted a task to move on to the next transaction and this was 949 // If we already posted a task to move on to the next transaction and this was
871 // the writer, there is nothing to cancel. 950 // the writer, there is nothing to cancel.
872 if (entry->will_process_pending_queue && entry->readers.empty()) 951 if (entry->will_process_waiting_transactions && entry->writer == transaction)
873 return; 952 return;
874 953
875 if (entry->writer) { 954 // Transaction is waiting in the validated_queue.
876 DCHECK(trans == entry->writer); 955 auto i = std::find(entry->validated_queue.begin(),
956 entry->validated_queue.end(), transaction);
957 if (i != entry->validated_queue.end()) {
958 entry->validated_queue.erase(i);
959 return;
960 }
877 961
878 // Assume there was a failure. 962 // Assume there was a failure.
879 bool success = false; 963 bool success = false;
880 if (cancel) { 964 if (transaction == entry->writer && cancel) {
881 DCHECK(entry->disk_entry); 965 DCHECK(entry->disk_entry);
882 // This is a successful operation in the sense that we want to keep the 966 // This is a successful operation in the sense that we want to keep the
883 // entry. 967 // entry.
884 success = trans->AddTruncatedFlag(); 968 success = transaction->AddTruncatedFlag();
885 // The previous operation may have deleted the entry. 969 // The previous operation may have deleted the entry.
886 if (!trans->entry()) 970 if (!transaction->entry())
887 return; 971 return;
888 }
889 DoneWritingToEntry(entry, success);
890 } else {
891 DoneReadingFromEntry(entry, trans);
892 } 972 }
973
974 // Transaction is writing to the entry, either in the validation phase or
975 // response-body phase.
976 if (transaction == entry->writer ||
977 transaction == entry->validating_transaction) {
978 DoneWritingToEntry(entry, success, transaction);
979 return;
980 }
981
982 // Transaction is reading from the entry.
983 DoneReadingFromEntry(entry, transaction);
893 } 984 }
894 985
895 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 986 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
896 DCHECK(entry->readers.empty()); 987 bool success,
988 Transaction* transaction) {
989 DCHECK(transaction == entry->writer ||
990 transaction == entry->validating_transaction);
897 991
898 entry->writer = NULL; 992 if (transaction == entry->writer)
993 entry->writer = nullptr;
899 994
995 // Transaction is done writing to entry in the validation phase.
996 if (transaction == entry->validating_transaction) {
997 entry->validating_transaction = nullptr;
998
999 if (!entry->writer)
1000 DoneWritingToEntryProcessOtherTransactions(entry, success);
1001 return;
1002 }
1003
1004 // Transaction is done writing to entry in the response body phase.
1005 // Whether its a failure or success, validating transaction can be the new
1006 // writer.
1007 if (entry->validating_transaction) {
1008 entry->writer = entry->validating_transaction;
1009 return;
1010 }
1011
1012 DoneWritingToEntryProcessOtherTransactions(entry, success);
1013 }
1014
1015 void HttpCache::DoneWritingToEntryProcessOtherTransactions(ActiveEntry* entry,
1016 bool success) {
900 if (success) { 1017 if (success) {
901 ProcessPendingQueue(entry); 1018 DCHECK(entry->readers.empty());
902 } else { 1019 ProcessWaitingTransactions(entry);
903 DCHECK(!entry->will_process_pending_queue); 1020 return;
1021 }
904 1022
905 // We failed to create this entry. 1023 DestroyEntryRestartPendingTransactions(entry);
906 TransactionList pending_queue;
907 pending_queue.swap(entry->pending_queue);
908
909 entry->disk_entry->Doom();
910 DestroyEntry(entry);
911
912 // We need to do something about these pending entries, which now need to
913 // be added to a new entry.
914 while (!pending_queue.empty()) {
915 // ERR_CACHE_RACE causes the transaction to restart the whole process.
916 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
917 pending_queue.pop_front();
918 }
919 }
920 } 1024 }
921 1025
922 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 1026 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
923 DCHECK(!entry->writer); 1027 DCHECK(!entry->writer);
924 1028
925 auto it = entry->readers.find(trans); 1029 auto it = entry->readers.find(trans);
926 DCHECK(it != entry->readers.end()); 1030 DCHECK(it != entry->readers.end());
927 1031
928 entry->readers.erase(it); 1032 entry->readers.erase(it);
929 1033
930 ProcessPendingQueue(entry); 1034 ProcessWaitingTransactions(entry);
931 } 1035 }
932 1036
933 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1037 bool HttpCache::ConvertWriterToReader(ActiveEntry* entry,
934 DCHECK(entry->writer); 1038 Transaction* transaction) {
935 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1039 DCHECK_EQ(entry->validating_transaction, transaction);
936 DCHECK(entry->readers.empty()); 1040 DCHECK_EQ(transaction->mode(), Transaction::READ_WRITE);
937 1041
938 Transaction* trans = entry->writer; 1042 // We need to differentiate between the scenarios when the entry is already
1043 // written to the cache vs. when the entry is not completely written and this
1044 // is a validating transaction. In the latter case, it cannot become the
1045 // reader and will be added to the validated_queue when
1046 // DoneValidationWithEntry will be called for this transaction.
939 1047
940 entry->writer = NULL; 1048 // Entry is not completely written yet.
941 entry->readers.insert(trans); 1049 if (entry->writer && entry->writer != transaction)
1050 return false;
942 1051
943 ProcessPendingQueue(entry); 1052 entry->validating_transaction = nullptr;
1053 entry->writer = nullptr;
1054 entry->readers.insert(transaction);
1055 ProcessWaitingTransactions(entry);
1056 return true;
944 } 1057 }
945 1058
946 LoadState HttpCache::GetLoadStateForPendingTransaction( 1059 LoadState HttpCache::GetLoadStateForPendingTransaction(
947 const Transaction* trans) { 1060 const Transaction* trans) {
948 auto i = active_entries_.find(trans->key()); 1061 auto i = active_entries_.find(trans->key());
949 if (i == active_entries_.end()) { 1062 if (i == active_entries_.end()) {
950 // If this is really a pending transaction, and it is not part of 1063 // 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. 1064 // active_entries_, we should be creating the backend or the entry.
952 return LOAD_STATE_WAITING_FOR_CACHE; 1065 return LOAD_STATE_WAITING_FOR_CACHE;
953 } 1066 }
(...skipping 29 matching lines...) Expand all
983 1096
984 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1097 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
985 ++k) { 1098 ++k) {
986 found = RemovePendingTransactionFromEntry(k->first, trans); 1099 found = RemovePendingTransactionFromEntry(k->first, trans);
987 } 1100 }
988 1101
989 DCHECK(found) << "Pending transaction not found"; 1102 DCHECK(found) << "Pending transaction not found";
990 } 1103 }
991 1104
992 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1105 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
993 Transaction* trans) { 1106 Transaction* transaction) {
994 TransactionList& pending_queue = entry->pending_queue; 1107 TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
995 1108
996 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1109 auto j =
997 if (j == pending_queue.end()) 1110 find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
1111 if (j == add_to_entry_queue.end())
998 return false; 1112 return false;
999 1113
1000 pending_queue.erase(j); 1114 add_to_entry_queue.erase(j);
1001 return true; 1115 return true;
1002 } 1116 }
1003 1117
1004 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1118 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1005 Transaction* trans) { 1119 Transaction* trans) {
1006 if (pending_op->writer->Matches(trans)) { 1120 if (pending_op->writer->Matches(trans)) {
1007 pending_op->writer->ClearTransaction(); 1121 pending_op->writer->ClearTransaction();
1008 pending_op->writer->ClearEntry(); 1122 pending_op->writer->ClearEntry();
1009 return true; 1123 return true;
1010 } 1124 }
1011 WorkItemList& pending_queue = pending_op->pending_queue; 1125 WorkItemList& pending_queue = pending_op->pending_queue;
1012 1126
1013 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) { 1127 for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1014 if ((*it)->Matches(trans)) { 1128 if ((*it)->Matches(trans)) {
1015 pending_queue.erase(it); 1129 pending_queue.erase(it);
1016 return true; 1130 return true;
1017 } 1131 }
1018 } 1132 }
1019 return false; 1133 return false;
1020 } 1134 }
1021 1135
1022 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1136 void HttpCache::ProcessWaitingTransactions(ActiveEntry* entry) {
1023 // Multiple readers may finish with an entry at once, so we want to batch up 1137 // 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 1138 // calls to OnProcessWaitingTransactions. This flag also tells us that we
1025 // not delete the entry before OnProcessPendingQueue runs. 1139 // should not delete the entry before OnProcessWaitingTransactions runs.
1026 if (entry->will_process_pending_queue) 1140 if (entry->will_process_waiting_transactions)
1027 return; 1141 return;
1028 entry->will_process_pending_queue = true;
1029 1142
1143 entry->will_process_waiting_transactions = true;
1144
1145 // Post a task instead of invoking the io callback of another transaction here
1146 // to avoid re-entrancy.
1030 base::ThreadTaskRunnerHandle::Get()->PostTask( 1147 base::ThreadTaskRunnerHandle::Get()->PostTask(
1031 FROM_HERE, 1148 FROM_HERE, base::Bind(&HttpCache::OnProcessWaitingTransactions,
1032 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); 1149 GetWeakPtr(), entry->disk_entry->GetKey(), entry));
1033 } 1150 }
1034 1151
1035 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { 1152 void HttpCache::OnProcessWaitingTransactions(const std::string& key,
1036 entry->will_process_pending_queue = false; 1153 ActiveEntry* entry) {
1037 DCHECK(!entry->writer); 1154 // Check if the entry is still alive either as an active entry or doomed
1155 // entry.
1156 if (!IsEntryAlive(key, entry))
1157 return;
1158
1159 entry->will_process_waiting_transactions = false;
1038 1160
1039 // If no one is interested in this entry, then we can deactivate it. 1161 // If no one is interested in this entry, then we can deactivate it.
1040 if (entry->HasNoTransactions()) { 1162 if (entry->HasNoTransactions()) {
1163 DestroyEntry(entry);
1164 return;
1165 }
1166
1167 if (entry->validated_queue.empty() && entry->add_to_entry_queue.empty())
1168 return;
1169
1170 Transaction* next = nullptr;
1171 TransactionList* list = nullptr;
1172 int rv = OK;
1173
1174 // To maintain FIFO order of transactions, validated_queue should be processed
1175 // first and then add_to_entry_queue.
1176 if (!entry->validated_queue.empty()) {
1177 next = entry->validated_queue.front();
1178 list = &entry->validated_queue;
1179 rv = AddTransactionToEntryForRead(entry, next);
1180 } else {
1181 // Promote next transaction from the pending queue.
1182 next = entry->add_to_entry_queue.front();
1183 list = &entry->add_to_entry_queue;
1184 rv = AddTransactionToEntryImpl(entry, next);
1185 }
1186
1187 if (rv != ERR_IO_PENDING) {
1188 list->erase(list->begin());
1189 next->io_callback().Run(rv);
1190 }
1191 }
1192
1193 void HttpCache::ProcessParallelValidation(ActiveEntry* entry) {
1194 if (entry->will_process_parallel_validation)
1195 return;
1196
1197 entry->will_process_parallel_validation = true;
1198
1199 // Post a task instead of invoking the io callback of another transaction here
1200 // to avoid re-entrancy.
1201 base::ThreadTaskRunnerHandle::Get()->PostTask(
1202 FROM_HERE, base::Bind(&HttpCache::OnProcessParallelValidation,
1203 GetWeakPtr(), entry->disk_entry->GetKey(), entry));
1204 }
1205
1206 void HttpCache::OnProcessParallelValidation(const std::string& key,
1207 ActiveEntry* entry) {
1208 // Check if the entry is still alive either as an active entry or doomed
1209 // entry.
1210 if (!IsEntryAlive(key, entry))
1211 return;
1212
1213 entry->will_process_parallel_validation = false;
1214
1215 // A ProcessWaitingTransactions task before this may add a
1216 // validating_transaction. In that case, do nothing.
1217 if (entry->validating_transaction)
1218 return;
1219
1220 // If no one is interested in this entry, then we can deactivate it.
1221 if (entry->HasNoTransactions()) {
1041 DestroyEntry(entry); 1222 DestroyEntry(entry);
1042 return; 1223 return;
1043 } 1224 }
1044 1225
1045 if (entry->pending_queue.empty()) 1226 if (entry->add_to_entry_queue.empty())
1046 return; 1227 return;
1047 1228
1048 // Promote next transaction from the pending queue. 1229 Transaction* next = entry->add_to_entry_queue.front();
1049 Transaction* next = entry->pending_queue.front();
1050 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1051 return; // Have to wait.
1052 1230
1053 entry->pending_queue.erase(entry->pending_queue.begin()); 1231 int rv = AddTransactionToEntryImpl(entry, next);
1054 1232
1055 int rv = AddTransactionToEntry(entry, next); 1233 // Read only transaction cannot validate the entry.
1234 if (!(next->mode() & Transaction::WRITE))
1235 return;
1236
1056 if (rv != ERR_IO_PENDING) { 1237 if (rv != ERR_IO_PENDING) {
1238 entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
1057 next->io_callback().Run(rv); 1239 next->io_callback().Run(rv);
1058 } 1240 }
1059 } 1241 }
1060 1242
1243 void HttpCache::DoomEntryRestartPendingTransactions(ActiveEntry* entry) {
1244 DoomActiveEntry(entry->disk_entry->GetKey());
1245 TransactionList list = GetAllPendingTransactions(entry);
1246 RestartPendingTransactions(list);
1247 }
1248
1249 void HttpCache::DestroyEntryRestartPendingTransactions(ActiveEntry* entry) {
1250 entry->disk_entry->Doom();
1251 TransactionList list = GetAllPendingTransactions(entry);
1252 DestroyEntry(entry);
1253 RestartPendingTransactions(list);
1254 }
1255
1256 HttpCache::TransactionList HttpCache::GetAllPendingTransactions(
1257 ActiveEntry* entry) {
1258 TransactionList list;
1259 for (auto* transaction : entry->validated_queue)
1260 list.push_back(transaction);
1261 entry->validated_queue.clear();
1262
1263 for (auto* transaction : entry->add_to_entry_queue)
1264 list.push_back(transaction);
1265 entry->add_to_entry_queue.clear();
1266
1267 return list;
1268 }
1269
1270 void HttpCache::RestartPendingTransactions(const TransactionList& list) {
1271 // ERR_CACHE_RACE causes the transaction to restart the whole process.
1272 for (auto* transaction : list)
1273 transaction->io_callback().Run(ERR_CACHE_RACE);
1274 }
1275
1061 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1276 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1062 WorkItemOperation op = pending_op->writer->operation(); 1277 WorkItemOperation op = pending_op->writer->operation();
1063 1278
1064 // Completing the creation of the backend is simpler than the other cases. 1279 // Completing the creation of the backend is simpler than the other cases.
1065 if (op == WI_CREATE_BACKEND) 1280 if (op == WI_CREATE_BACKEND)
1066 return OnBackendCreated(result, pending_op); 1281 return OnBackendCreated(result, pending_op);
1067 1282
1068 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1283 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
1069 bool fail_requests = false; 1284 bool fail_requests = false;
1070 1285
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 building_backend_ = false; 1410 building_backend_ = false;
1196 DeletePendingOp(pending_op); 1411 DeletePendingOp(pending_op);
1197 } 1412 }
1198 1413
1199 // The cache may be gone when we return from the callback. 1414 // The cache may be gone when we return from the callback.
1200 if (!item->DoCallback(result, disk_cache_.get())) 1415 if (!item->DoCallback(result, disk_cache_.get()))
1201 item->NotifyTransaction(result, NULL); 1416 item->NotifyTransaction(result, NULL);
1202 } 1417 }
1203 1418
1204 } // namespace net 1419 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698