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

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

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: Initial patch 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 |pending_queue| because the Transactions are owned by their respective
115 // URLRequestHttpJobs. 111 // 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() && pending_queue.empty() &&
117 validated_queue.empty() && !validating_transaction;
118 }
119
120 bool HttpCache::ActiveEntry::IsReader(Transaction* transaction) {
121 return readers.count(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 pending queue for reading or
364 // won't run (due to our destruction), we can simply ignore the corresponding 365 // parallel validation, but since those won't run (due to our destruction),
365 // will_process_pending_queue flag. 366 // we can simply ignore the 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_pending_queue = false;
370 entry->will_process_parallel_validation = false;
369 entry->pending_queue.clear(); 371 entry->pending_queue.clear();
370 entry->readers.clear(); 372 entry->readers.clear();
371 entry->writer = NULL; 373 entry->validated_queue.clear();
374 entry->validating_transaction = nullptr;
375 entry->writer = nullptr;
372 DeactivateEntry(entry); 376 DeactivateEntry(entry);
373 } 377 }
374 378
375 doomed_entries_.clear(); 379 doomed_entries_.clear();
376 380
377 // Before deleting pending_ops_, we have to make sure that the disk cache is 381 // 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. 382 // done with said operations, or it will attempt to use deleted data.
379 disk_cache_.reset(); 383 disk_cache_.reset();
380 384
381 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); 385 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end();
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 624
621 // 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
622 // cleaned up properly when the cache is destroyed. 626 // cleaned up properly when the cache is destroyed.
623 ActiveEntry* entry_ptr = entry.get(); 627 ActiveEntry* entry_ptr = entry.get();
624 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); 628 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr));
625 doomed_entries_[entry_ptr] = std::move(entry); 629 doomed_entries_[entry_ptr] = std::move(entry);
626 630
627 entry_ptr->disk_entry->Doom(); 631 entry_ptr->disk_entry->Doom();
628 entry_ptr->doomed = true; 632 entry_ptr->doomed = true;
629 633
630 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || 634 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Do you know what the purpose of this DCHECK is? I
shivanisha 2017/03/08 21:42:12 DoomEntry's consumer is the HttpCache::Transaction
631 entry_ptr->will_process_pending_queue); 635 !entry_ptr->validated_queue.empty() ||
636 entry_ptr->validating_transaction ||
637 entry_ptr->will_process_pending_queue ||
638 entry_ptr->will_process_parallel_validation);
632 return OK; 639 return OK;
633 } 640 }
634 641
635 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 642 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
636 std::unique_ptr<WorkItem> item = 643 std::unique_ptr<WorkItem> item =
637 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); 644 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr);
638 PendingOp* pending_op = GetPendingOp(key); 645 PendingOp* pending_op = GetPendingOp(key);
639 if (pending_op->writer) { 646 if (pending_op->writer) {
640 pending_op->pending_queue.push_back(std::move(item)); 647 pending_op->pending_queue.push_back(std::move(item));
641 return ERR_IO_PENDING; 648 return ERR_IO_PENDING;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 DCHECK(entry->doomed); 684 DCHECK(entry->doomed);
678 DCHECK(entry->HasNoTransactions()); 685 DCHECK(entry->HasNoTransactions());
679 686
680 auto it = doomed_entries_.find(entry); 687 auto it = doomed_entries_.find(entry);
681 DCHECK(it != doomed_entries_.end()); 688 DCHECK(it != doomed_entries_.end());
682 doomed_entries_.erase(it); 689 doomed_entries_.erase(it);
683 } 690 }
684 691
685 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 692 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
686 auto it = active_entries_.find(key); 693 auto it = active_entries_.find(key);
687 return it != active_entries_.end() ? it->second.get() : NULL; 694 return it != active_entries_.end() ? it->second.get() : nullptr;
695 }
696
697 bool HttpCache::IsEntryActive(const std::string& key,
698 const ActiveEntry* entry) {
699 ActiveEntry* entry_alive = FindActiveEntry(key);
700 if (!entry_alive || entry != entry_alive)
jkarlin 2017/03/07 16:45:41 return entry_alive && entry_alive == entry;
shivanisha 2017/03/08 21:42:11 Done. Also renamed entry_alive to active_entry
701 return false;
702 return true;
688 } 703 }
689 704
690 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 705 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
691 disk_cache::Entry* disk_entry) { 706 disk_cache::Entry* disk_entry) {
692 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 707 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
693 ActiveEntry* entry = new ActiveEntry(disk_entry); 708 ActiveEntry* entry = new ActiveEntry(disk_entry);
694 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); 709 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry);
695 return entry; 710 return entry;
696 } 711 }
697 712
698 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 713 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
699 DCHECK(!entry->will_process_pending_queue);
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Why?
shivanisha 2017/03/08 21:42:12 Now that we have 2 types of tasks posted (OnProces
700 DCHECK(!entry->doomed); 714 DCHECK(!entry->doomed);
701 DCHECK(entry->disk_entry); 715 DCHECK(entry->disk_entry);
702 DCHECK(entry->HasNoTransactions()); 716 DCHECK(entry->HasNoTransactions());
703 717
704 std::string key = entry->disk_entry->GetKey(); 718 std::string key = entry->disk_entry->GetKey();
705 if (key.empty()) 719 if (key.empty())
706 return SlowDeactivateEntry(entry); 720 return SlowDeactivateEntry(entry);
707 721
708 auto it = active_entries_.find(key); 722 auto it = active_entries_.find(key);
709 DCHECK(it != active_entries_.end()); 723 DCHECK(it != active_entries_.end());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 833 }
820 834
821 void HttpCache::DestroyEntry(ActiveEntry* entry) { 835 void HttpCache::DestroyEntry(ActiveEntry* entry) {
822 if (entry->doomed) { 836 if (entry->doomed) {
823 FinalizeDoomedEntry(entry); 837 FinalizeDoomedEntry(entry);
824 } else { 838 } else {
825 DeactivateEntry(entry); 839 DeactivateEntry(entry);
826 } 840 }
827 } 841 }
828 842
829 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 843 int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
844 Transaction* transaction,
845 bool validated_queue,
jkarlin 2017/03/07 16:45:41 We discussed this F2F, but can you remove validate
846 bool new_transaction) {
jkarlin 2017/03/07 16:45:40 is new_transaction ever set to true? I don't see i
shivanisha 2017/03/08 21:42:11 Refactored this function into 4 functions: - Alwa
830 DCHECK(entry); 847 DCHECK(entry);
831 DCHECK(entry->disk_entry); 848 DCHECK(entry->disk_entry);
832 849
833 // We implement a basic reader/writer lock for the disk cache entry. If 850 // We implement a basic reader/writer lock for the disk cache entry. If there
834 // there is already a writer, then everyone has to wait for the writer to 851 // is a writer, then all read-only transactions must wait. Non read-only
835 // finish before they can access the cache entry. There can be multiple 852 // transactions can proceed to their validation phase. Validation is allowed
836 // readers. 853 // for one transaction at a time so that we do not end up with wasted network
837 // 854 // requests.
838 // NOTE: If the transaction can only write, then the entry should not be in
839 // use (since any existing entry should have already been doomed).
840 855
841 if (entry->writer || entry->will_process_pending_queue) { 856 // If a pending queue processing task is posted and this is invoked for a
842 entry->pending_queue.push_back(trans); 857 // new transaction as opposed to a queued transaction, then this transaction
858 // should be added after the queue task is processed, to maintain FIFO
859 // ordering.
860 if (new_transaction && (entry->will_process_pending_queue ||
861 entry->will_process_parallel_validation)) {
862 entry->pending_queue.push_back(transaction);
843 return ERR_IO_PENDING; 863 return ERR_IO_PENDING;
844 } 864 }
845 865
846 if (trans->mode() & Transaction::WRITE) { 866 // A transaction that has the write mode and has not already passed the
847 // transaction needs exclusive access to the entry 867 // validation phase can become the next validating transaction. It can also
848 if (entry->readers.empty()) { 868 // become the writer if there is no active writer at this time.
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Is there a reason for it to take up the writer slo
shivanisha 2017/03/08 21:42:12 The writer slot works as a lock (in the existing c
849 entry->writer = trans; 869 if ((transaction->mode() & Transaction::WRITE) && !validated_queue) {
850 } else { 870 if (entry->validating_transaction) {
851 entry->pending_queue.push_back(trans); 871 entry->pending_queue.push_back(transaction);
852 return ERR_IO_PENDING; 872 return ERR_IO_PENDING;
853 } 873 }
854 } else { 874 entry->validating_transaction = transaction;
855 // transaction needs read access to the entry 875 if (!entry->writer && entry->readers.empty()) {
856 entry->readers.insert(trans); 876 entry->writer = transaction;
877 }
878 if (!entry->writer && !entry->pending_queue.empty())
879 ProcessPendingQueue(entry);
880 return OK;
857 } 881 }
858 882
859 // We do this before calling EntryAvailable to force any further calls to 883 // Read-only transactions.
860 // AddTransactionToEntry to add their transaction to the pending queue, which 884 if (entry->writer) {
861 // ensures FIFO ordering. 885 entry->pending_queue.push_back(transaction);
862 if (!entry->writer && !entry->pending_queue.empty()) 886 return ERR_IO_PENDING;
887 }
888 entry->readers.insert(transaction);
889 if (!entry->pending_queue.empty())
863 ProcessPendingQueue(entry); 890 ProcessPendingQueue(entry);
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 nit, suggestion: It feels like this routine might
shivanisha 2017/03/08 21:42:12 I have refactored this function quite a bit in the
864
865 return OK; 891 return OK;
866 } 892 }
867 893
868 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 894 int HttpCache::OnValidationMatch(ActiveEntry* entry,
895 Transaction* transaction,
896 bool write_this_response) {
897 int rv = OK;
898 entry->validating_transaction = nullptr;
899
900 if (entry->writer != transaction) {
901 entry->validated_queue.push_back(transaction);
902 rv = ERR_IO_PENDING;
903 } else if (!write_this_response) {
904 entry->writer = nullptr;
905 entry->readers.insert(transaction);
jkarlin 2017/03/07 16:45:40 We're adding it to readers, but I don't think the
shivanisha 2017/03/08 21:42:11 Actually this should never happen. ConvertWriterTo
906 }
907 ProcessParallelValidation(entry);
908 return rv;
909 }
910
911 void HttpCache::OnValidationNoMatch(ActiveEntry* entry,
912 Transaction* transaction) {
913 entry->validating_transaction = nullptr;
914 DoomEntryRestartPendingTransactions(entry);
915 }
916
917 void HttpCache::DoneWithEntry(ActiveEntry* entry,
918 Transaction* transaction,
869 bool cancel) { 919 bool cancel) {
870 // If we already posted a task to move on to the next transaction and this was 920 // If we already posted a task to move on to the next transaction and this was
871 // the writer, there is nothing to cancel. 921 // the writer, there is nothing to cancel.
872 if (entry->will_process_pending_queue && entry->readers.empty()) 922 if (entry->will_process_pending_queue && entry->writer == transaction)
873 return; 923 return;
874 924
875 if (entry->writer) { 925 // Transaction is waiting in the validated_queue.
876 DCHECK(trans == entry->writer); 926 auto i = std::find(entry->validated_queue.begin(),
jkarlin 2017/03/07 16:45:40 There are a few linear searches in this new code.
927 entry->validated_queue.end(), transaction);
928 if (i != entry->validated_queue.end()) {
929 entry->validated_queue.erase(i);
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Can't it be in the validated queue and be the writ
shivanisha 2017/03/08 21:42:12 That should not be possible. validated_queue inser
930 return;
931 }
877 932
878 // Assume there was a failure. 933 // Assume there was a failure.
879 bool success = false; 934 bool success = false;
880 if (cancel) { 935 if (transaction == entry->writer && cancel) {
881 DCHECK(entry->disk_entry); 936 DCHECK(entry->disk_entry);
882 // This is a successful operation in the sense that we want to keep the 937 // This is a successful operation in the sense that we want to keep the
883 // entry. 938 // entry.
884 success = trans->AddTruncatedFlag(); 939 success = transaction->AddTruncatedFlag();
885 // The previous operation may have deleted the entry. 940 // The previous operation may have deleted the entry.
886 if (!trans->entry()) 941 if (!transaction->entry())
887 return; 942 return;
888 }
889 DoneWritingToEntry(entry, success);
890 } else {
891 DoneReadingFromEntry(entry, trans);
892 } 943 }
944
945 if (transaction == entry->writer ||
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Suggestion: I'd value a comment here, parallel to
shivanisha 2017/03/08 21:42:11 Done.
946 transaction == entry->validating_transaction) {
947 DoneWritingToEntry(entry, success, transaction);
948 return;
949 }
950
951 DoneReadingFromEntry(entry, transaction);
893 } 952 }
894 953
895 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 954 void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
896 DCHECK(entry->readers.empty()); 955 bool success,
956 Transaction* transaction) {
957 // Transaction is done writing to entry in the validation phase.
958 if (transaction == entry->validating_transaction) {
959 entry->validating_transaction = nullptr;
897 960
898 entry->writer = NULL; 961 if (transaction == entry->writer)
962 entry->writer = nullptr;
899 963
964 if (!entry->writer)
965 DoneWritingToEntryProcessOtherTransactions(entry, success);
966 return;
967 }
968
969 // Transaction is done writing to entry in the response body phase.
970 DCHECK_EQ(transaction, entry->writer);
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Suggestion: Hoist this up tot he top of the routin
shivanisha 2017/03/08 21:42:11 Done.
971 entry->writer = nullptr;
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 Suggestion: If you take the above suggestion, you
shivanisha 2017/03/08 21:42:12 done
972
973 // Whether its a failure or success validating transaction can be the new
974 // writer.
975 if (entry->validating_transaction) {
976 entry->writer = entry->validating_transaction;
977 return;
978 }
979
980 DoneWritingToEntryProcessOtherTransactions(entry, success);
981 }
982
983 void HttpCache::DoneWritingToEntryProcessOtherTransactions(ActiveEntry* entry,
984 bool success) {
900 if (success) { 985 if (success) {
986 DCHECK(entry->readers.empty());
901 ProcessPendingQueue(entry); 987 ProcessPendingQueue(entry);
902 } else { 988 return;
903 DCHECK(!entry->will_process_pending_queue); 989 }
904 990
905 // We failed to create this entry. 991 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 } 992 }
921 993
922 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 994 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
923 DCHECK(!entry->writer); 995 DCHECK(!entry->writer);
924 996
925 auto it = entry->readers.find(trans); 997 auto it = entry->readers.find(trans);
926 DCHECK(it != entry->readers.end()); 998 DCHECK(it != entry->readers.end());
927 999
928 entry->readers.erase(it); 1000 entry->readers.erase(it);
929 1001
930 ProcessPendingQueue(entry); 1002 ProcessPendingQueue(entry);
931 } 1003 }
932 1004
933 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 1005 bool HttpCache::ConvertWriterToReader(ActiveEntry* entry,
934 DCHECK(entry->writer); 1006 Transaction* transaction) {
935 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 1007 DCHECK(entry->writer == transaction ||
936 DCHECK(entry->readers.empty()); 1008 entry->validating_transaction == transaction);
1009 DCHECK(transaction->mode() == Transaction::READ_WRITE);
937 1010
938 Transaction* trans = entry->writer; 1011 if (transaction == entry->validating_transaction) {
1012 entry->validating_transaction = nullptr;
1013 if (transaction == entry->writer)
1014 entry->writer = nullptr;
1015 } else {
1016 DCHECK(entry->readers.empty());
1017 DCHECK_EQ(transaction, entry->writer);
1018 entry->writer = nullptr;
1019 }
939 1020
940 entry->writer = NULL; 1021 // If a reader cannot exist at the moment, it will be added to validated queue
941 entry->readers.insert(trans); 1022 // in OnValidationMatch, so return.
1023 if (entry->writer)
1024 return false;
942 1025
1026 entry->readers.insert(transaction);
943 ProcessPendingQueue(entry); 1027 ProcessPendingQueue(entry);
1028 return true;
944 } 1029 }
945 1030
946 LoadState HttpCache::GetLoadStateForPendingTransaction( 1031 LoadState HttpCache::GetLoadStateForPendingTransaction(
947 const Transaction* trans) { 1032 const Transaction* trans) {
948 auto i = active_entries_.find(trans->key()); 1033 auto i = active_entries_.find(trans->key());
949 if (i == active_entries_.end()) { 1034 if (i == active_entries_.end()) {
950 // If this is really a pending transaction, and it is not part of 1035 // 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. 1036 // active_entries_, we should be creating the backend or the entry.
952 return LOAD_STATE_WAITING_FOR_CACHE; 1037 return LOAD_STATE_WAITING_FOR_CACHE;
953 } 1038 }
(...skipping 29 matching lines...) Expand all
983 1068
984 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; 1069 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
985 ++k) { 1070 ++k) {
986 found = RemovePendingTransactionFromEntry(k->first, trans); 1071 found = RemovePendingTransactionFromEntry(k->first, trans);
987 } 1072 }
988 1073
989 DCHECK(found) << "Pending transaction not found"; 1074 DCHECK(found) << "Pending transaction not found";
990 } 1075 }
991 1076
992 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 1077 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
993 Transaction* trans) { 1078 Transaction* transaction) {
994 TransactionList& pending_queue = entry->pending_queue; 1079 TransactionList& pending_queue = entry->pending_queue;
995 1080
996 auto j = find(pending_queue.begin(), pending_queue.end(), trans); 1081 auto j = find(pending_queue.begin(), pending_queue.end(), transaction);
997 if (j == pending_queue.end()) 1082 if (j == pending_queue.end())
998 return false; 1083 return false;
999 1084
1000 pending_queue.erase(j); 1085 pending_queue.erase(j);
1001 return true; 1086 return true;
1002 } 1087 }
1003 1088
1004 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 1089 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1005 Transaction* trans) { 1090 Transaction* trans) {
1006 if (pending_op->writer->Matches(trans)) { 1091 if (pending_op->writer->Matches(trans)) {
(...skipping 11 matching lines...) Expand all
1018 } 1103 }
1019 return false; 1104 return false;
1020 } 1105 }
1021 1106
1022 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1107 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
1023 // Multiple readers may finish with an entry at once, so we want to batch up 1108 // 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 1109 // calls to OnProcessPendingQueue. This flag also tells us that we should
1025 // not delete the entry before OnProcessPendingQueue runs. 1110 // not delete the entry before OnProcessPendingQueue runs.
1026 if (entry->will_process_pending_queue) 1111 if (entry->will_process_pending_queue)
1027 return; 1112 return;
1113
1028 entry->will_process_pending_queue = true; 1114 entry->will_process_pending_queue = true;
1029 1115
1030 base::ThreadTaskRunnerHandle::Get()->PostTask( 1116 base::ThreadTaskRunnerHandle::Get()->PostTask(
1031 FROM_HERE, 1117 FROM_HERE, base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(),
1032 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); 1118 entry->disk_entry->GetKey(), entry));
1033 } 1119 }
1034 1120
1035 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { 1121 void HttpCache::OnProcessPendingQueue(const std::string& key,
1122 ActiveEntry* entry) {
1123 // Check if the entry is still active.
1124 if (!IsEntryActive(key, entry))
1125 return;
1126
1036 entry->will_process_pending_queue = false; 1127 entry->will_process_pending_queue = false;
1037 DCHECK(!entry->writer);
1038 1128
1039 // If no one is interested in this entry, then we can deactivate it. 1129 // If no one is interested in this entry, then we can deactivate it.
1040 if (entry->HasNoTransactions()) { 1130 if (entry->HasNoTransactions()) {
1131 DestroyEntry(entry);
1132 return;
1133 }
1134
1135 if (entry->validated_queue.empty() && entry->pending_queue.empty())
1136 return;
1137
1138 Transaction* next = nullptr;
1139 bool validated_queue = false;
1140
1141 // To maintain FIFO order of transactions, validated_queue should be processed
1142 // first and then pending_queue.
1143 if (!entry->validated_queue.empty()) {
1144 next = entry->validated_queue.front();
1145 validated_queue = true;
1146 entry->validated_queue.erase(entry->validated_queue.begin());
1147 } else {
1148 // Promote next transaction from the pending queue.
1149 next = entry->pending_queue.front();
1150 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1151 return; // Have to wait.
1152 entry->pending_queue.erase(entry->pending_queue.begin());
1153 }
1154
1155 int rv = AddTransactionToEntry(entry, next, validated_queue);
1156 if (rv != ERR_IO_PENDING) {
1157 next->io_callback().Run(rv);
1158 }
1159 }
1160
1161 void HttpCache::ProcessParallelValidation(ActiveEntry* entry) {
1162 if (entry->will_process_parallel_validation)
1163 return;
1164
1165 entry->will_process_parallel_validation = true;
1166
1167 base::ThreadTaskRunnerHandle::Get()->PostTask(
1168 FROM_HERE, base::Bind(&HttpCache::OnProcessParallelValidation,
1169 GetWeakPtr(), entry->disk_entry->GetKey(), entry));
1170 }
1171
1172 void HttpCache::OnProcessParallelValidation(const std::string& key,
1173 ActiveEntry* entry) {
1174 // Check if the entry is still active.
1175 if (!IsEntryActive(key, entry))
1176 return;
1177
1178 entry->will_process_parallel_validation = false;
1179
1180 // A ProcessPendingQueue task before this may add a validating_transaction. In
1181 // that case, do nothing.
1182 if (entry->validating_transaction)
1183 return;
1184
1185 // If no one is interested in this entry, then we can deactivate it.
1186 if (entry->HasNoTransactions()) {
1041 DestroyEntry(entry); 1187 DestroyEntry(entry);
1042 return; 1188 return;
1043 } 1189 }
1044 1190
1045 if (entry->pending_queue.empty()) 1191 if (entry->pending_queue.empty())
1046 return; 1192 return;
1047 1193
1048 // Promote next transaction from the pending queue.
1049 Transaction* next = entry->pending_queue.front(); 1194 Transaction* next = entry->pending_queue.front();
1050 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty()) 1195
1196 // Read-only transactions cannot proceed to do validation.
1197 if (!(next->mode() & Transaction::WRITE) && entry->writer)
1051 return; // Have to wait. 1198 return; // Have to wait.
1052 1199
1053 entry->pending_queue.erase(entry->pending_queue.begin()); 1200 entry->pending_queue.erase(entry->pending_queue.begin());
1054 1201
1055 int rv = AddTransactionToEntry(entry, next); 1202 int rv = AddTransactionToEntry(entry, next);
1056 if (rv != ERR_IO_PENDING) { 1203 if (rv != ERR_IO_PENDING) {
1057 next->io_callback().Run(rv); 1204 next->io_callback().Run(rv);
1058 } 1205 }
1059 } 1206 }
1060 1207
1208 void HttpCache::DoomEntryRestartPendingTransactions(ActiveEntry* entry) {
Randy Smith (Not in Mondays) 2017/03/07 22:54:30 This function and the next one look simple and are
shivanisha 2017/03/08 21:42:11 In the new patch DestroyEntryRestartPendingTransac
1209 DoomActiveEntry(entry->disk_entry->GetKey());
1210 TransactionList list = GetAllPendingTransactions(entry);
1211 RestartPendingTransactions(list);
1212 }
1213
1214 void HttpCache::DestroyEntryRestartPendingTransactions(ActiveEntry* entry) {
1215 entry->disk_entry->Doom();
1216 TransactionList list = GetAllPendingTransactions(entry);
1217 DestroyEntry(entry);
1218 RestartPendingTransactions(list);
1219 }
1220
1221 HttpCache::TransactionList HttpCache::GetAllPendingTransactions(
1222 ActiveEntry* entry) {
1223 TransactionList list;
1224 for (auto* transaction : entry->validated_queue)
1225 list.push_back(transaction);
1226 entry->validated_queue.clear();
1227
1228 for (auto* transaction : entry->pending_queue)
1229 list.push_back(transaction);
1230 entry->pending_queue.clear();
1231
1232 return list;
1233 }
1234
1235 void HttpCache::RestartPendingTransactions(const TransactionList& list) {
1236 // ERR_CACHE_RACE causes the transaction to restart the whole process.
1237 for (auto* transaction : list)
1238 transaction->io_callback().Run(ERR_CACHE_RACE);
1239 }
1240
1061 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1241 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1062 WorkItemOperation op = pending_op->writer->operation(); 1242 WorkItemOperation op = pending_op->writer->operation();
1063 1243
1064 // Completing the creation of the backend is simpler than the other cases. 1244 // Completing the creation of the backend is simpler than the other cases.
1065 if (op == WI_CREATE_BACKEND) 1245 if (op == WI_CREATE_BACKEND)
1066 return OnBackendCreated(result, pending_op); 1246 return OnBackendCreated(result, pending_op);
1067 1247
1068 std::unique_ptr<WorkItem> item = std::move(pending_op->writer); 1248 std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
1069 bool fail_requests = false; 1249 bool fail_requests = false;
1070 1250
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 building_backend_ = false; 1375 building_backend_ = false;
1196 DeletePendingOp(pending_op); 1376 DeletePendingOp(pending_op);
1197 } 1377 }
1198 1378
1199 // The cache may be gone when we return from the callback. 1379 // The cache may be gone when we return from the callback.
1200 if (!item->DoCallback(result, disk_cache_.get())) 1380 if (!item->DoCallback(result, disk_cache_.get()))
1201 item->NotifyTransaction(result, NULL); 1381 item->NotifyTransaction(result, NULL);
1202 } 1382 }
1203 1383
1204 } // namespace net 1384 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698