| OLD | NEW |
| 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 // This class encapsulates a transaction whose only purpose is to write metadata | 192 // This class encapsulates a transaction whose only purpose is to write metadata |
| 193 // to a given entry. | 193 // to a given entry. |
| 194 class HttpCache::MetadataWriter { | 194 class HttpCache::MetadataWriter { |
| 195 public: | 195 public: |
| 196 explicit MetadataWriter(HttpCache::Transaction* trans) | 196 explicit MetadataWriter(HttpCache::Transaction* trans) |
| 197 : transaction_(trans), | 197 : transaction_(trans), |
| 198 verified_(false), | 198 verified_(false), |
| 199 buf_len_(0) { | 199 buf_len_(0) { |
| 200 } | 200 } |
| 201 | 201 |
| 202 ~MetadataWriter() {} | 202 ~MetadataWriter() { transaction_->Orphan(std::move(transaction_)); } |
| 203 | 203 |
| 204 // Implements the bulk of HttpCache::WriteMetadata. | 204 // Implements the bulk of HttpCache::WriteMetadata. |
| 205 void Write(const GURL& url, | 205 void Write(const GURL& url, |
| 206 base::Time expected_response_time, | 206 base::Time expected_response_time, |
| 207 IOBuffer* buf, | 207 IOBuffer* buf, |
| 208 int buf_len); | 208 int buf_len); |
| 209 | 209 |
| 210 private: | 210 private: |
| 211 void VerifyResponse(int result); | 211 void VerifyResponse(int result); |
| 212 void SelfDestroy(); | 212 void SelfDestroy(); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 | 331 |
| 332 // If we have any active entries remaining, then we need to deactivate them. | 332 // If we have any active entries remaining, then we need to deactivate them. |
| 333 // We may have some pending calls to OnProcessPendingQueue, but since those | 333 // We may have some pending calls to OnProcessPendingQueue, but since those |
| 334 // won't run (due to our destruction), we can simply ignore the corresponding | 334 // won't run (due to our destruction), we can simply ignore the corresponding |
| 335 // will_process_pending_queue flag. | 335 // will_process_pending_queue flag. |
| 336 while (!active_entries_.empty()) { | 336 while (!active_entries_.empty()) { |
| 337 ActiveEntry* entry = active_entries_.begin()->second.get(); | 337 ActiveEntry* entry = active_entries_.begin()->second.get(); |
| 338 entry->will_process_pending_queue = false; | 338 entry->will_process_pending_queue = false; |
| 339 entry->pending_queue.clear(); | 339 entry->pending_queue.clear(); |
| 340 entry->readers.clear(); | 340 entry->readers.clear(); |
| 341 entry->writer = NULL; | 341 entry->writer = nullptr; |
| 342 entry->shared_writers.reset(); |
| 342 DeactivateEntry(entry); | 343 DeactivateEntry(entry); |
| 343 } | 344 } |
| 344 | 345 |
| 345 doomed_entries_.clear(); | 346 doomed_entries_.clear(); |
| 346 | 347 |
| 347 // Before deleting pending_ops_, we have to make sure that the disk cache is | 348 // Before deleting pending_ops_, we have to make sure that the disk cache is |
| 348 // done with said operations, or it will attempt to use deleted data. | 349 // done with said operations, or it will attempt to use deleted data. |
| 349 disk_cache_.reset(); | 350 disk_cache_.reset(); |
| 350 | 351 |
| 351 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); | 352 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 | 575 |
| 575 // We keep track of doomed entries so that we can ensure that they are | 576 // We keep track of doomed entries so that we can ensure that they are |
| 576 // cleaned up properly when the cache is destroyed. | 577 // cleaned up properly when the cache is destroyed. |
| 577 ActiveEntry* entry_ptr = entry.get(); | 578 ActiveEntry* entry_ptr = entry.get(); |
| 578 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); | 579 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); |
| 579 doomed_entries_[entry_ptr] = std::move(entry); | 580 doomed_entries_[entry_ptr] = std::move(entry); |
| 580 | 581 |
| 581 entry_ptr->disk_entry->Doom(); | 582 entry_ptr->disk_entry->Doom(); |
| 582 entry_ptr->doomed = true; | 583 entry_ptr->doomed = true; |
| 583 | 584 |
| 584 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || | 585 DCHECK(entry_ptr->writer || entry_ptr->shared_writers || |
| 585 entry_ptr->will_process_pending_queue); | 586 !entry_ptr->readers.empty() || entry_ptr->will_process_pending_queue); |
| 586 return OK; | 587 return OK; |
| 587 } | 588 } |
| 588 | 589 |
| 589 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { | 590 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { |
| 590 std::unique_ptr<WorkItem> item = | 591 std::unique_ptr<WorkItem> item = |
| 591 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); | 592 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); |
| 592 PendingOp* pending_op = GetPendingOp(key); | 593 PendingOp* pending_op = GetPendingOp(key); |
| 593 if (pending_op->writer) { | 594 if (pending_op->writer) { |
| 594 pending_op->pending_queue.push_back(std::move(item)); | 595 pending_op->pending_queue.push_back(std::move(item)); |
| 595 return ERR_IO_PENDING; | 596 return ERR_IO_PENDING; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 622 // Defer to DoomEntry if there is an active entry, otherwise call | 623 // Defer to DoomEntry if there is an active entry, otherwise call |
| 623 // AsyncDoomEntry without triggering a callback. | 624 // AsyncDoomEntry without triggering a callback. |
| 624 if (active_entries_.count(key)) | 625 if (active_entries_.count(key)) |
| 625 DoomEntry(key, NULL); | 626 DoomEntry(key, NULL); |
| 626 else | 627 else |
| 627 AsyncDoomEntry(key, NULL); | 628 AsyncDoomEntry(key, NULL); |
| 628 } | 629 } |
| 629 | 630 |
| 630 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { | 631 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { |
| 631 DCHECK(entry->doomed); | 632 DCHECK(entry->doomed); |
| 632 DCHECK(!entry->writer); | 633 DCHECK(!entry->writer && !entry->shared_writers); |
| 633 DCHECK(entry->readers.empty()); | 634 DCHECK(entry->readers.empty()); |
| 634 DCHECK(entry->pending_queue.empty()); | 635 DCHECK(entry->pending_queue.empty()); |
| 635 | 636 |
| 636 auto it = doomed_entries_.find(entry); | 637 auto it = doomed_entries_.find(entry); |
| 637 DCHECK(it != doomed_entries_.end()); | 638 DCHECK(it != doomed_entries_.end()); |
| 638 doomed_entries_.erase(it); | 639 doomed_entries_.erase(it); |
| 639 } | 640 } |
| 640 | 641 |
| 641 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { | 642 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { |
| 642 auto it = active_entries_.find(key); | 643 auto it = active_entries_.find(key); |
| 643 return it != active_entries_.end() ? it->second.get() : NULL; | 644 return it != active_entries_.end() ? it->second.get() : NULL; |
| 644 } | 645 } |
| 645 | 646 |
| 646 HttpCache::ActiveEntry* HttpCache::ActivateEntry( | 647 HttpCache::ActiveEntry* HttpCache::ActivateEntry( |
| 647 disk_cache::Entry* disk_entry) { | 648 disk_cache::Entry* disk_entry) { |
| 648 DCHECK(!FindActiveEntry(disk_entry->GetKey())); | 649 DCHECK(!FindActiveEntry(disk_entry->GetKey())); |
| 649 ActiveEntry* entry = new ActiveEntry(disk_entry); | 650 ActiveEntry* entry = new ActiveEntry(disk_entry); |
| 650 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); | 651 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); |
| 651 return entry; | 652 return entry; |
| 652 } | 653 } |
| 653 | 654 |
| 654 void HttpCache::DeactivateEntry(ActiveEntry* entry) { | 655 void HttpCache::DeactivateEntry(ActiveEntry* entry) { |
| 655 DCHECK(!entry->will_process_pending_queue); | 656 DCHECK(!entry->will_process_pending_queue); |
| 656 DCHECK(!entry->doomed); | 657 DCHECK(!entry->doomed); |
| 657 DCHECK(!entry->writer); | 658 DCHECK(!entry->writer && !entry->shared_writers); |
| 658 DCHECK(entry->disk_entry); | 659 DCHECK(entry->disk_entry); |
| 659 DCHECK(entry->readers.empty()); | 660 DCHECK(entry->readers.empty()); |
| 660 DCHECK(entry->pending_queue.empty()); | 661 DCHECK(entry->pending_queue.empty()); |
| 661 | 662 |
| 662 std::string key = entry->disk_entry->GetKey(); | 663 std::string key = entry->disk_entry->GetKey(); |
| 663 if (key.empty()) | 664 if (key.empty()) |
| 664 return SlowDeactivateEntry(entry); | 665 return SlowDeactivateEntry(entry); |
| 665 | 666 |
| 666 auto it = active_entries_.find(key); | 667 auto it = active_entries_.find(key); |
| 667 DCHECK(it != active_entries_.end()); | 668 DCHECK(it != active_entries_.end()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 FinalizeDoomedEntry(entry); | 782 FinalizeDoomedEntry(entry); |
| 782 } else { | 783 } else { |
| 783 DeactivateEntry(entry); | 784 DeactivateEntry(entry); |
| 784 } | 785 } |
| 785 } | 786 } |
| 786 | 787 |
| 787 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { | 788 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { |
| 788 DCHECK(entry); | 789 DCHECK(entry); |
| 789 DCHECK(entry->disk_entry); | 790 DCHECK(entry->disk_entry); |
| 790 | 791 |
| 791 // We implement a basic reader/writer lock for the disk cache entry. If | 792 // If a writer is in the validation stage, all other transactions need to wait |
| 792 // there is already a writer, then everyone has to wait for the writer to | 793 // before they can access the cache entry. Once the validation stage is over |
| 793 // finish before they can access the cache entry. There can be multiple | 794 // and if the writer creates a SharedWriters object, other eligible |
| 794 // readers. | 795 // transactions will become equally privileged to be able to read from the |
| 796 // network and write to the cache. |
| 795 // | 797 // |
| 796 // NOTE: If the transaction can only write, then the entry should not be in | 798 // NOTE: If the transaction can only write, then the entry should not be in |
| 797 // use (since any existing entry should have already been doomed). | 799 // use (since any existing entry should have already been doomed). |
| 798 | |
| 799 if (entry->writer || entry->will_process_pending_queue) { | 800 if (entry->writer || entry->will_process_pending_queue) { |
| 800 entry->pending_queue.push_back(trans); | 801 entry->pending_queue.push_back(trans); |
| 801 return ERR_IO_PENDING; | 802 return ERR_IO_PENDING; |
| 802 } | 803 } |
| 803 | 804 |
| 804 if (trans->mode() & Transaction::WRITE) { | 805 if (entry->shared_writers) { |
| 806 DCHECK(!entry->writer); |
| 807 if (!trans->IsEligibleForSharedWriting()) { |
| 808 entry->pending_queue.push_back(trans); |
| 809 return ERR_IO_PENDING; |
| 810 } else { |
| 811 if (entry->shared_writers->AddTransaction(trans)) { |
| 812 return OK; |
| 813 } else { |
| 814 // Another transaction is in the process of validation, wait for it and |
| 815 // any other transactions already in the queue to complete. |
| 816 return ERR_IO_PENDING; |
| 817 } |
| 818 } |
| 819 } |
| 820 |
| 821 // No SharedWriters. |
| 822 else if (trans->mode() & Transaction::WRITE) { |
| 805 // transaction needs exclusive access to the entry | 823 // transaction needs exclusive access to the entry |
| 806 if (entry->readers.empty()) { | 824 if (entry->readers.empty()) { |
| 807 entry->writer = trans; | 825 entry->writer = trans; |
| 808 } else { | 826 } else { |
| 809 entry->pending_queue.push_back(trans); | 827 entry->pending_queue.push_back(trans); |
| 810 return ERR_IO_PENDING; | 828 return ERR_IO_PENDING; |
| 811 } | 829 } |
| 812 } else { | 830 } else { |
| 813 // transaction needs read access to the entry | 831 // transaction needs read access to the entry |
| 814 entry->readers.push_back(trans); | 832 entry->readers.insert(trans); |
| 815 } | 833 } |
| 816 | 834 |
| 817 // We do this before calling EntryAvailable to force any further calls to | 835 // We do this before calling EntryAvailable to force any further calls to |
| 818 // AddTransactionToEntry to add their transaction to the pending queue, which | 836 // AddTransactionToEntry to add their transaction to the pending queue, which |
| 819 // ensures FIFO ordering. | 837 // ensures FIFO ordering. |
| 820 if (!entry->writer && !entry->pending_queue.empty()) | 838 if (!entry->writer && !entry->pending_queue.empty()) |
| 821 ProcessPendingQueue(entry); | 839 ProcessPendingQueue(entry); |
| 822 | 840 |
| 823 return OK; | 841 return OK; |
| 824 } | 842 } |
| 825 | 843 |
| 826 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, | 844 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, |
| 827 bool cancel) { | 845 bool cancel) { |
| 846 // This is not expected to be called for shared writing transactions which |
| 847 // have completed their Start state machine. |
| 848 DCHECK(!trans->shared()); |
| 849 |
| 828 // If we already posted a task to move on to the next transaction and this was | 850 // If we already posted a task to move on to the next transaction and this was |
| 829 // the writer, there is nothing to cancel. | 851 // the writer, there is nothing to cancel. |
| 830 if (entry->will_process_pending_queue && entry->readers.empty()) | 852 if (entry->will_process_pending_queue && entry->readers.empty()) |
| 831 return; | 853 return; |
| 832 | 854 |
| 833 if (entry->writer) { | 855 if (entry->writer) { |
| 834 DCHECK(trans == entry->writer); | 856 DCHECK(trans == entry->writer); |
| 835 | |
| 836 // Assume there was a failure. | 857 // Assume there was a failure. |
| 837 bool success = false; | 858 bool success = false; |
| 838 if (cancel) { | 859 if (cancel) { |
| 839 DCHECK(entry->disk_entry); | 860 DCHECK(entry->disk_entry); |
| 840 // This is a successful operation in the sense that we want to keep the | 861 // This is a successful operation in the sense that we want to keep the |
| 841 // entry. | 862 // entry. |
| 842 success = trans->AddTruncatedFlag(); | 863 success = trans->AddTruncatedFlag(); |
| 843 // The previous operation may have deleted the entry. | 864 // The previous operation may have deleted the entry. |
| 844 if (!trans->entry()) | 865 if (!trans->entry()) |
| 845 return; | 866 return; |
| 846 } | 867 } |
| 847 DoneWritingToEntry(entry, success); | 868 DoneWritingToEntry(entry, success); |
| 848 } else { | 869 } else { |
| 849 DoneReadingFromEntry(entry, trans); | 870 DoneReadingFromEntry(entry, trans); |
| 850 } | 871 } |
| 851 } | 872 } |
| 852 | 873 |
| 853 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { | 874 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { |
| 854 DCHECK(entry->readers.empty()); | 875 DCHECK(entry->readers.empty()); |
| 876 DCHECK(!entry->shared_writers); |
| 855 | 877 |
| 856 entry->writer = NULL; | 878 entry->writer = NULL; |
| 857 | 879 |
| 858 if (success) { | 880 if (success) { |
| 859 ProcessPendingQueue(entry); | 881 ProcessPendingQueue(entry); |
| 860 } else { | 882 } else { |
| 861 DCHECK(!entry->will_process_pending_queue); | 883 DestroyEntryAndRestartPendingQueueTxns(entry); |
| 884 } |
| 885 } |
| 862 | 886 |
| 863 // We failed to create this entry. | 887 void HttpCache::DestroyEntryAndRestartPendingQueueTxns(ActiveEntry* entry) { |
| 864 TransactionList pending_queue; | 888 DCHECK(!entry->will_process_pending_queue); |
| 865 pending_queue.swap(entry->pending_queue); | |
| 866 | 889 |
| 867 entry->disk_entry->Doom(); | 890 // We failed to create this entry. |
| 868 DestroyEntry(entry); | 891 TransactionList pending_queue; |
| 892 pending_queue.swap(entry->pending_queue); |
| 869 | 893 |
| 870 // We need to do something about these pending entries, which now need to | 894 entry->disk_entry->Doom(); |
| 871 // be added to a new entry. | 895 |
| 872 while (!pending_queue.empty()) { | 896 DestroyEntry(entry); |
| 873 // ERR_CACHE_RACE causes the transaction to restart the whole process. | 897 |
| 874 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); | 898 // We need to do something about these pending entries, which now need to |
| 875 pending_queue.pop_front(); | 899 // be added to a new entry. |
| 876 } | 900 while (!pending_queue.empty()) { |
| 901 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 902 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 903 pending_queue.pop_front(); |
| 877 } | 904 } |
| 878 } | 905 } |
| 879 | 906 |
| 880 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { | 907 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { |
| 881 DCHECK(!entry->writer); | 908 DCHECK(!entry->writer && !entry->shared_writers); |
| 882 | 909 |
| 883 auto it = std::find(entry->readers.begin(), entry->readers.end(), trans); | 910 auto it = entry->readers.find(trans); |
| 884 DCHECK(it != entry->readers.end()); | 911 DCHECK(it != entry->readers.end()); |
| 885 | 912 |
| 886 entry->readers.erase(it); | 913 entry->readers.erase(it); |
| 887 | 914 |
| 888 ProcessPendingQueue(entry); | 915 ProcessPendingQueue(entry); |
| 889 } | 916 } |
| 890 | 917 |
| 891 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { | 918 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { |
| 892 DCHECK(entry->writer); | |
| 893 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); | 919 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); |
| 894 DCHECK(entry->readers.empty()); | 920 DCHECK(entry->readers.empty()); |
| 895 | 921 |
| 896 Transaction* trans = entry->writer; | 922 Transaction* trans = entry->writer; |
| 897 | 923 |
| 898 entry->writer = NULL; | 924 entry->writer = NULL; |
| 899 entry->readers.push_back(trans); | 925 entry->readers.insert(trans); |
| 900 | 926 |
| 901 ProcessPendingQueue(entry); | 927 ProcessPendingQueue(entry); |
| 902 } | 928 } |
| 903 | 929 |
| 904 LoadState HttpCache::GetLoadStateForPendingTransaction( | 930 LoadState HttpCache::GetLoadStateForPendingTransaction( |
| 905 const Transaction* trans) { | 931 const Transaction* trans) { |
| 906 auto i = active_entries_.find(trans->key()); | 932 auto i = active_entries_.find(trans->key()); |
| 907 if (i == active_entries_.end()) { | 933 if (i == active_entries_.end()) { |
| 908 // If this is really a pending transaction, and it is not part of | 934 // If this is really a pending transaction, and it is not part of |
| 909 // active_entries_, we should be creating the backend or the entry. | 935 // active_entries_, we should be creating the backend or the entry. |
| 910 return LOAD_STATE_WAITING_FOR_CACHE; | 936 return LOAD_STATE_WAITING_FOR_CACHE; |
| 911 } | 937 } |
| 912 | 938 |
| 913 Transaction* writer = i->second->writer; | 939 Transaction* writer = i->second->writer; |
| 914 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; | 940 if (writer) |
| 941 return writer->GetWriterLoadState(); |
| 942 |
| 943 if (i->second->shared_writers) |
| 944 return i->second->shared_writers->GetLoadState(); |
| 945 |
| 946 return LOAD_STATE_WAITING_FOR_CACHE; |
| 915 } | 947 } |
| 916 | 948 |
| 917 void HttpCache::RemovePendingTransaction(Transaction* trans) { | 949 void HttpCache::RemovePendingTransaction(Transaction* trans) { |
| 950 bool found = false; |
| 951 |
| 918 auto i = active_entries_.find(trans->key()); | 952 auto i = active_entries_.find(trans->key()); |
| 919 bool found = false; | |
| 920 if (i != active_entries_.end()) | 953 if (i != active_entries_.end()) |
| 921 found = RemovePendingTransactionFromEntry(i->second.get(), trans); | 954 found = RemovePendingTransactionFromEntry(i->second.get(), trans); |
| 922 | 955 |
| 923 if (found) | 956 if (found) |
| 924 return; | 957 return; |
| 925 | 958 |
| 926 if (building_backend_) { | 959 if (building_backend_) { |
| 927 auto j = pending_ops_.find(std::string()); | 960 auto j = pending_ops_.find(std::string()); |
| 928 if (j != pending_ops_.end()) | 961 if (j != pending_ops_.end()) |
| 929 found = RemovePendingTransactionFromPendingOp(j->second, trans); | 962 found = RemovePendingTransactionFromPendingOp(j->second, trans); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 942 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; | 975 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; |
| 943 ++k) { | 976 ++k) { |
| 944 found = RemovePendingTransactionFromEntry(k->first, trans); | 977 found = RemovePendingTransactionFromEntry(k->first, trans); |
| 945 } | 978 } |
| 946 | 979 |
| 947 DCHECK(found) << "Pending transaction not found"; | 980 DCHECK(found) << "Pending transaction not found"; |
| 948 } | 981 } |
| 949 | 982 |
| 950 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, | 983 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, |
| 951 Transaction* trans) { | 984 Transaction* trans) { |
| 952 TransactionList& pending_queue = entry->pending_queue; | 985 if (trans->shared()) { |
| 953 | 986 return entry->shared_writers->RemoveWaitingTransaction(trans); |
| 954 auto j = find(pending_queue.begin(), pending_queue.end(), trans); | 987 } else { |
| 955 if (j == pending_queue.end()) | 988 TransactionList& pending_queue = entry->pending_queue; |
| 956 return false; | 989 auto j = find(pending_queue.begin(), pending_queue.end(), trans); |
| 957 | 990 if (j == pending_queue.end()) |
| 958 pending_queue.erase(j); | 991 return false; |
| 959 return true; | 992 pending_queue.erase(j); |
| 993 return true; |
| 994 } |
| 960 } | 995 } |
| 961 | 996 |
| 962 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, | 997 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, |
| 963 Transaction* trans) { | 998 Transaction* trans) { |
| 964 if (pending_op->writer->Matches(trans)) { | 999 if (pending_op->writer->Matches(trans)) { |
| 965 pending_op->writer->ClearTransaction(); | 1000 pending_op->writer->ClearTransaction(); |
| 966 pending_op->writer->ClearEntry(); | 1001 pending_op->writer->ClearEntry(); |
| 967 return true; | 1002 return true; |
| 968 } | 1003 } |
| 969 WorkItemList& pending_queue = pending_op->pending_queue; | 1004 WorkItemList& pending_queue = pending_op->pending_queue; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 985 return; | 1020 return; |
| 986 entry->will_process_pending_queue = true; | 1021 entry->will_process_pending_queue = true; |
| 987 | 1022 |
| 988 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1023 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 989 FROM_HERE, | 1024 FROM_HERE, |
| 990 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1025 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 991 } | 1026 } |
| 992 | 1027 |
| 993 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1028 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 994 entry->will_process_pending_queue = false; | 1029 entry->will_process_pending_queue = false; |
| 995 DCHECK(!entry->writer); | 1030 DCHECK(!entry->writer && !entry->shared_writers); |
| 996 | 1031 |
| 997 // If no one is interested in this entry, then we can deactivate it. | 1032 // If no one is interested in this entry, then we can deactivate it. |
| 998 if (entry->pending_queue.empty()) { | 1033 if (entry->pending_queue.empty()) { |
| 999 if (entry->readers.empty()) | 1034 if (entry->readers.empty()) |
| 1000 DestroyEntry(entry); | 1035 DestroyEntry(entry); |
| 1001 return; | 1036 return; |
| 1002 } | 1037 } |
| 1003 | 1038 |
| 1004 // Promote next transaction from the pending queue. | 1039 // Promote next transaction from the pending queue. |
| 1005 Transaction* next = entry->pending_queue.front(); | 1040 Transaction* next = entry->pending_queue.front(); |
| 1041 |
| 1006 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty()) | 1042 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty()) |
| 1007 return; // Have to wait. | 1043 return; // Have to wait. |
| 1008 | 1044 |
| 1009 entry->pending_queue.erase(entry->pending_queue.begin()); | 1045 entry->pending_queue.erase(entry->pending_queue.begin()); |
| 1010 | 1046 |
| 1011 int rv = AddTransactionToEntry(entry, next); | 1047 int rv = AddTransactionToEntry(entry, next); |
| 1012 if (rv != ERR_IO_PENDING) { | 1048 if (rv != ERR_IO_PENDING) { |
| 1013 next->io_callback().Run(rv); | 1049 next->io_callback().Run(rv); |
| 1014 } | 1050 } |
| 1015 } | 1051 } |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 } else { | 1186 } else { |
| 1151 building_backend_ = false; | 1187 building_backend_ = false; |
| 1152 DeletePendingOp(pending_op); | 1188 DeletePendingOp(pending_op); |
| 1153 } | 1189 } |
| 1154 | 1190 |
| 1155 // The cache may be gone when we return from the callback. | 1191 // The cache may be gone when we return from the callback. |
| 1156 if (!item->DoCallback(result, disk_cache_.get())) | 1192 if (!item->DoCallback(result, disk_cache_.get())) |
| 1157 item->NotifyTransaction(result, NULL); | 1193 item->NotifyTransaction(result, NULL); |
| 1158 } | 1194 } |
| 1159 | 1195 |
| 1196 void HttpCache::CreateSharedWriters( |
| 1197 Transaction* cache_trans, |
| 1198 std::unique_ptr<HttpTransaction> network_trans, |
| 1199 RequestPriority priority) { |
| 1200 ActiveEntry* entry = cache_trans->entry(); |
| 1201 DCHECK(!entry->shared_writers); |
| 1202 DCHECK_EQ(entry->writer, cache_trans); |
| 1203 DCHECK(entry->readers.empty()); |
| 1204 entry->shared_writers.reset(new HttpCache::SharedWriters( |
| 1205 this, entry, cache_trans, priority, std::move(network_trans))); |
| 1206 |
| 1207 // entry->writer should no longer exist as it is moved to |
| 1208 // shared_writers. |
| 1209 entry->writer = nullptr; |
| 1210 |
| 1211 // Add the eligible transactions to waiting_for_validation_ and process the |
| 1212 // first among them. Post this, pending_queue will only contain transactions |
| 1213 // that are not eligible for shared writing. |
| 1214 entry->shared_writers->MoveFromPendingQueue(); |
| 1215 entry->shared_writers->ProcessFirstWaitingValidation(); |
| 1216 } |
| 1217 |
| 1218 HttpCache::SharedWriters::SharedWriters( |
| 1219 HttpCache* cache, |
| 1220 ActiveEntry* entry, |
| 1221 Transaction* cache_trans, |
| 1222 RequestPriority priority, |
| 1223 std::unique_ptr<HttpTransaction> transaction) |
| 1224 : cache_(cache->GetWeakPtr()), |
| 1225 entry_(entry), |
| 1226 current_writer_(nullptr), |
| 1227 validating_trans_(nullptr), |
| 1228 priority_(priority), |
| 1229 destroy_entry_(false), |
| 1230 weak_factory_(this) { |
| 1231 cache_trans->SetShared(); |
| 1232 all_writers_.insert(cache_trans); |
| 1233 network_trans_ = std::move(transaction); |
| 1234 } |
| 1235 |
| 1236 HttpCache::SharedWriters::~SharedWriters() { |
| 1237 weak_factory_.InvalidateWeakPtrs(); |
| 1238 } |
| 1239 |
| 1240 std::unique_ptr<HttpTransaction> HttpCache::StopCachingSharedWriters( |
| 1241 Transaction* transaction, |
| 1242 ActiveEntry* entry) { |
| 1243 auto network_trans = entry->shared_writers->StopCaching(transaction); |
| 1244 |
| 1245 if (network_trans) { // stopped |
| 1246 DCHECK(entry->shared_writers->empty()); |
| 1247 DCHECK_EQ(entry->writer, transaction); |
| 1248 entry->shared_writers.reset(); |
| 1249 } |
| 1250 |
| 1251 return network_trans; |
| 1252 } |
| 1253 |
| 1254 std::unique_ptr<HttpTransaction> HttpCache::SharedWriters::StopCaching( |
| 1255 Transaction* transaction) { |
| 1256 bool result = false; |
| 1257 if (transaction == validating_trans_) { |
| 1258 if (all_writers_.empty()) { |
| 1259 result = true; |
| 1260 validating_trans_ = nullptr; |
| 1261 } |
| 1262 } else if (all_writers_.size() == 1 && all_writers_.count(transaction) && |
| 1263 !validating_trans_) { |
| 1264 if (current_writer_ == transaction) { |
| 1265 current_writer_ = nullptr; |
| 1266 } |
| 1267 all_writers_.erase(transaction); |
| 1268 result = true; |
| 1269 } |
| 1270 if (result) { |
| 1271 transaction->ResetShared(true); |
| 1272 entry_->writer = transaction; |
| 1273 MoveToPendingQueue(); |
| 1274 return std::move(network_trans_); |
| 1275 } |
| 1276 return std::unique_ptr<HttpTransaction>(); |
| 1277 } |
| 1278 |
| 1279 HttpTransaction* HttpCache::CacheWriteFailedSharedWriters(Transaction* trans, |
| 1280 ActiveEntry* entry) { |
| 1281 HttpTransaction* network_trans = |
| 1282 entry->shared_writers->OnCacheWriteFailure(trans); |
| 1283 |
| 1284 if (entry->shared_writers->empty()) { |
| 1285 entry->shared_writers.reset(); |
| 1286 DestroyEntryAndRestartPendingQueueTxns(entry); |
| 1287 } |
| 1288 return network_trans; |
| 1289 } |
| 1290 |
| 1291 HttpTransaction* HttpCache::SharedWriters::OnCacheWriteFailure( |
| 1292 Transaction* trans) { |
| 1293 DCHECK_EQ(trans, current_writer_); |
| 1294 |
| 1295 // Now we need to take care of all the transactions in SharedWriters and |
| 1296 // delete SharedWriters as without the cache, we cannot continue the shared |
| 1297 // logic. |
| 1298 ResetAndRemoveCurrentWriter(true); |
| 1299 |
| 1300 // Notify waiting_writers_ of the failure. Tasks will be posted for all the |
| 1301 // transactions. |
| 1302 ProcessWaitingWriters(ERR_CACHE_WRITE_FAILURE); |
| 1303 |
| 1304 // Idle readers should know to fail when Read is invoked by their consumers. |
| 1305 SetIdleWritersFailState(); |
| 1306 DCHECK(all_writers_.empty()); |
| 1307 |
| 1308 // If there is a transaction validating currently, let it continue reading |
| 1309 // from the network without attempting to write to the cache. |
| 1310 if (validating_trans_) { |
| 1311 validating_trans_->ContinueWithoutSharedWriting(); |
| 1312 validating_trans_ = nullptr; |
| 1313 } |
| 1314 MoveToPendingQueue(); |
| 1315 |
| 1316 if (!empty()) { |
| 1317 DCHECK(doomed_writer_); |
| 1318 destroy_entry_ = true; |
| 1319 } |
| 1320 |
| 1321 return network_trans_.release(); |
| 1322 } |
| 1323 |
| 1324 void HttpCache::FinalizeDoomedSharedWriter(ActiveEntry* entry) { |
| 1325 bool destroy_entry = false; |
| 1326 entry->shared_writers->FinalizeDoomedWriter(destroy_entry); |
| 1327 if (destroy_entry) { |
| 1328 DestroyEntryAndRestartPendingQueueTxns(entry); |
| 1329 } else { |
| 1330 ResetSharedWritersProcessPendingQueue(entry); |
| 1331 } |
| 1332 } |
| 1333 |
| 1334 void HttpCache::SharedWriters::FinalizeDoomedWriter(bool& out_destroy_entry) { |
| 1335 if (doomed_writer_) { |
| 1336 DCHECK_EQ(doomed_writer_.get(), current_writer_); |
| 1337 all_writers_.erase(current_writer_); |
| 1338 doomed_writer_.reset(); |
| 1339 current_writer_ = nullptr; |
| 1340 out_destroy_entry = destroy_entry_; |
| 1341 } |
| 1342 } |
| 1343 |
| 1344 void HttpCache::NetworkReadFailedSharedWriters(Transaction* trans, |
| 1345 ActiveEntry* entry, |
| 1346 int result) { |
| 1347 entry->shared_writers->OnNetworkReadFailure(trans, result); |
| 1348 |
| 1349 DCHECK(entry->shared_writers->empty()); |
| 1350 entry->shared_writers.reset(); |
| 1351 |
| 1352 // If entry->writer was set from the SharedWriters' validating_trans_, let it |
| 1353 // run else process pending queue. |
| 1354 if (!entry->writer) { |
| 1355 ProcessPendingQueue(entry); |
| 1356 } |
| 1357 } |
| 1358 |
| 1359 void HttpCache::SharedWriters::OnNetworkReadFailure(const Transaction* trans, |
| 1360 int result) { |
| 1361 DCHECK_EQ(trans, current_writer_); |
| 1362 |
| 1363 // Now we need to take care of all the transactions in SharedWriters and |
| 1364 // delete SharedWriters. |
| 1365 ResetAndRemoveCurrentWriter(); |
| 1366 |
| 1367 // Notify waiting_writers_ of the failure. Tasks will be posted for all the |
| 1368 // transactions. |
| 1369 ProcessWaitingWriters(result); |
| 1370 |
| 1371 // Idle readers should know to fail when Read is invoked by their consumers. |
| 1372 SetIdleWritersFailState(); |
| 1373 DCHECK(all_writers_.empty()); |
| 1374 |
| 1375 // If there is a transaction validating currently, let it continue reading |
| 1376 // from the network without attempting to write to the cache. |
| 1377 if (validating_trans_) { |
| 1378 DCHECK(!entry_->writer); |
| 1379 entry_->writer = validating_trans_; |
| 1380 validating_trans_->ResetShared(true); |
| 1381 validating_trans_ = nullptr; |
| 1382 } |
| 1383 MoveToPendingQueue(); |
| 1384 } |
| 1385 |
| 1386 void HttpCache::SharedWriters::ResetAndRemoveCurrentWriter( |
| 1387 bool continue_network_reading) { |
| 1388 current_writer_->ResetShared(continue_network_reading); |
| 1389 all_writers_.erase(current_writer_); |
| 1390 ResetCurrentWriter(); |
| 1391 } |
| 1392 |
| 1393 void HttpCache::SharedWriters::ResetCurrentWriter() { |
| 1394 // doomed_writer_ will be destroyed after cache transaction is done with its |
| 1395 // processing. |
| 1396 if (doomed_writer_) { |
| 1397 DCHECK_EQ(doomed_writer_.get(), current_writer_); |
| 1398 current_writer_->SetFinalizeDoomed(); |
| 1399 } else { |
| 1400 current_writer_ = nullptr; |
| 1401 } |
| 1402 } |
| 1403 |
| 1404 bool HttpCache::SharedWriters::empty() { |
| 1405 if (doomed_writer_) |
| 1406 return false; |
| 1407 int count = all_writers_.size() + waiting_for_validation_.size() + |
| 1408 (validating_trans_ ? 1 : 0); |
| 1409 return count ? false : true; |
| 1410 } |
| 1411 |
| 1412 void HttpCache::SharedWriters::SetIdleWritersFailState() { |
| 1413 // Since this is only for idle transactions, all waiting_writers_ and |
| 1414 // current_writer_ should be empty. |
| 1415 DCHECK(waiting_writers_.empty()); |
| 1416 DCHECK(!current_writer_); |
| 1417 |
| 1418 for (auto trans : all_writers_) { |
| 1419 trans->SetSharedWritingFailState(); |
| 1420 trans->ResetShared(); |
| 1421 } |
| 1422 |
| 1423 all_writers_.clear(); |
| 1424 } |
| 1425 |
| 1426 bool HttpCache::SharedWriters::AddTransaction(Transaction* transaction) { |
| 1427 transaction->SetShared(); |
| 1428 |
| 1429 if (!validating_trans_) { |
| 1430 validating_trans_ = transaction; |
| 1431 return true; |
| 1432 } else { |
| 1433 waiting_for_validation_.push_back(transaction); |
| 1434 return false; |
| 1435 } |
| 1436 } |
| 1437 |
| 1438 void HttpCache::ValidationMatchSharedWriters(Transaction* transaction, |
| 1439 RequestPriority priority, |
| 1440 ActiveEntry* entry) { |
| 1441 entry->shared_writers->OnValidationMatch(transaction, priority); |
| 1442 if (entry->shared_writers->empty()) { |
| 1443 entry->shared_writers.reset(); |
| 1444 ProcessPendingQueue(entry); |
| 1445 } |
| 1446 } |
| 1447 |
| 1448 void HttpCache::SharedWriters::OnValidationMatch(Transaction* transaction, |
| 1449 RequestPriority priority) { |
| 1450 DCHECK_EQ(validating_trans_, transaction); |
| 1451 validating_trans_ = nullptr; |
| 1452 |
| 1453 ValidationDoneContinue(transaction, priority); |
| 1454 } |
| 1455 |
| 1456 void HttpCache::SharedWriters::ValidationDoneContinue( |
| 1457 Transaction* transaction, |
| 1458 RequestPriority priority) { |
| 1459 validating_trans_ = nullptr; |
| 1460 if (priority > priority_) { |
| 1461 network_trans_->SetPriority(priority); |
| 1462 priority_ = priority; |
| 1463 } |
| 1464 all_writers_.insert(transaction); |
| 1465 transaction->SetShared(); |
| 1466 ProcessFirstWaitingValidation(); |
| 1467 } |
| 1468 |
| 1469 std::unique_ptr<HttpTransaction> HttpCache::ValidationNoMatchSharedWriters( |
| 1470 const std::string& key, |
| 1471 Transaction* transaction, |
| 1472 std::unique_ptr<HttpTransaction> network_trans, |
| 1473 RequestPriority priority, |
| 1474 ActiveEntry* entry) { |
| 1475 // This will either return the ownership of the network transaction so that |
| 1476 // this transaction can continue reading from the network or not, if this is |
| 1477 // the only transaction in SharedWriters. |
| 1478 std::unique_ptr<HttpTransaction> nw_trans = |
| 1479 entry->shared_writers->OnValidationNoMatch( |
| 1480 transaction, std::move(network_trans), priority); |
| 1481 if (nw_trans) { |
| 1482 DCHECK(!transaction->shared()); |
| 1483 DoomActiveEntry(key); |
| 1484 // We need to do something about these pending entries, which now need to |
| 1485 // be added to a new entry. |
| 1486 while (!entry->pending_queue.empty()) { |
| 1487 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 1488 entry->pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 1489 entry->pending_queue.pop_front(); |
| 1490 } |
| 1491 } |
| 1492 return nw_trans; |
| 1493 } |
| 1494 |
| 1495 std::unique_ptr<HttpTransaction> HttpCache::SharedWriters::OnValidationNoMatch( |
| 1496 Transaction* transaction, |
| 1497 std::unique_ptr<HttpTransaction> network_trans, |
| 1498 RequestPriority priority) { |
| 1499 DCHECK_EQ(validating_trans_, transaction); |
| 1500 // If there is no transaction in all_writers_, its ok to rewrite the entry |
| 1501 // response. |
| 1502 if (all_writers_.empty()) { |
| 1503 network_trans_ = std::move(network_trans); |
| 1504 ValidationDoneContinue(transaction, priority); |
| 1505 return std::unique_ptr<HttpTransaction>(); |
| 1506 } |
| 1507 |
| 1508 transaction->ResetShared(); |
| 1509 validating_trans_ = nullptr; |
| 1510 MoveToPendingQueue(); |
| 1511 return network_trans; |
| 1512 } |
| 1513 |
| 1514 int HttpCache::SharedWriters::Read(IOBuffer* buf, |
| 1515 int buf_len, |
| 1516 const CompletionCallback& callback, |
| 1517 Transaction* transaction, |
| 1518 bool& read_in_progress) { |
| 1519 // If another transaction is already reading from the network, then this |
| 1520 // transaction waits for the read to complete and reads from the cache |
| 1521 // instead. |
| 1522 if (current_writer_) { |
| 1523 WaitingWriter waiting_writer(transaction, buf, buf_len); |
| 1524 waiting_writers_.push_back(waiting_writer); |
| 1525 read_in_progress = true; |
| 1526 return ERR_IO_PENDING; |
| 1527 } |
| 1528 current_writer_ = transaction; |
| 1529 return network_trans_->Read(buf, buf_len, callback); |
| 1530 } |
| 1531 |
| 1532 void HttpCache::SharedWriters::OnNetworkReadSuccess(const Transaction* trans, |
| 1533 scoped_refptr<IOBuffer> buf, |
| 1534 int len) { |
| 1535 DCHECK_EQ(trans, current_writer_); |
| 1536 // Save the network read data in all the waiting transactions' read buffers. |
| 1537 for (auto it = waiting_writers_.begin(); it != waiting_writers_.end(); it++) { |
| 1538 it->write_len = std::min(it->read_buf_len, len); |
| 1539 memcpy(it->read_buf->data(), buf->data(), it->write_len); |
| 1540 } |
| 1541 } |
| 1542 |
| 1543 void HttpCache::CacheWriteSuccessSharedWriters(Transaction* trans, |
| 1544 ActiveEntry* entry, |
| 1545 int result) { |
| 1546 entry->shared_writers->OnCacheWriteSuccess(trans, result); |
| 1547 |
| 1548 if (result > 0) // not the end of response. |
| 1549 return; |
| 1550 |
| 1551 ResetSharedWritersProcessPendingQueue(entry); |
| 1552 } |
| 1553 |
| 1554 void HttpCache::DoneReadingSharedWriters(Transaction* trans, |
| 1555 ActiveEntry* entry) { |
| 1556 entry->shared_writers->DoneReading(trans); |
| 1557 |
| 1558 ResetSharedWritersProcessPendingQueue(entry); |
| 1559 } |
| 1560 |
| 1561 void HttpCache::SharedWriters::DoneReading(Transaction* trans) { |
| 1562 // If current_writer_ is set, then wait for current_writer_ to detect the end |
| 1563 // of stream. |
| 1564 if (current_writer_) { |
| 1565 return; |
| 1566 } |
| 1567 DCHECK(waiting_writers_.empty()); |
| 1568 RemoveIdleWriter(trans); |
| 1569 // If there is a transaction validating currently, return. |
| 1570 if (validating_trans_) { |
| 1571 return; |
| 1572 } |
| 1573 |
| 1574 // Else empty the SharedWriters object. |
| 1575 MoveIdleWritersToReaders(); |
| 1576 DCHECK(all_writers_.empty()); |
| 1577 |
| 1578 MoveToPendingQueue(); |
| 1579 } |
| 1580 |
| 1581 void HttpCache::SharedWriters::RemoveIdleWriter(Transaction* trans) { |
| 1582 // The transaction should be part of all_writers. |
| 1583 auto it = all_writers_.find(trans); |
| 1584 DCHECK(it != all_writers_.end()); |
| 1585 all_writers_.erase(trans); |
| 1586 trans->ResetShared(); |
| 1587 } |
| 1588 |
| 1589 void HttpCache::ResetSharedWritersProcessPendingQueue(ActiveEntry* entry) { |
| 1590 if (entry->shared_writers->empty()) { |
| 1591 entry->shared_writers.reset(); |
| 1592 DCHECK(!entry->writer); |
| 1593 ProcessPendingQueue(entry); |
| 1594 } |
| 1595 } |
| 1596 |
| 1597 void HttpCache::SharedWriters::OnCacheWriteSuccess(const Transaction* trans, |
| 1598 int result) { |
| 1599 DCHECK_EQ(trans, current_writer_); |
| 1600 |
| 1601 // Notify waiting_writers_. Tasks will be posted for all the |
| 1602 // transactions. |
| 1603 ProcessWaitingWriters(result); |
| 1604 |
| 1605 if (result > 0) { // not the end of response |
| 1606 ResetCurrentWriter(); |
| 1607 return; |
| 1608 } |
| 1609 |
| 1610 ResetAndRemoveCurrentWriter(); |
| 1611 |
| 1612 // If there is a transaction validating currently, change state and return. |
| 1613 if (validating_trans_) { |
| 1614 return; |
| 1615 } |
| 1616 |
| 1617 // Else empty the SharedWriters object. |
| 1618 MoveIdleWritersToReaders(); |
| 1619 DCHECK(all_writers_.empty()); |
| 1620 |
| 1621 MoveToPendingQueue(); |
| 1622 } |
| 1623 |
| 1624 void HttpCache::SharedWriters::MoveIdleWritersToReaders() { |
| 1625 // Should be invoked after waiting_writers_ are all processed. |
| 1626 DCHECK(waiting_writers_.empty()); |
| 1627 for (auto idle_writer : all_writers_) { |
| 1628 entry_->readers.insert(idle_writer); |
| 1629 idle_writer->ResetShared(false, true); |
| 1630 } |
| 1631 all_writers_.clear(); |
| 1632 } |
| 1633 |
| 1634 void HttpCache::DoomCurrentSharedWriter(std::unique_ptr<HttpTransaction> trans, |
| 1635 ActiveEntry* entry) { |
| 1636 entry->shared_writers->DoomCurrentWriter(std::move(trans)); |
| 1637 ResetSharedWritersProcessPendingQueue(entry); |
| 1638 } |
| 1639 |
| 1640 void HttpCache::SharedWriters::RemoveWaitingWriter(Transaction* trans) { |
| 1641 auto it = waiting_writers_.begin(); |
| 1642 for (; it != waiting_writers_.end(); it++) { |
| 1643 if (trans == it->transaction) { |
| 1644 waiting_writers_.erase(it); |
| 1645 all_writers_.erase(trans); |
| 1646 trans->ResetShared(); |
| 1647 break; |
| 1648 } |
| 1649 } |
| 1650 |
| 1651 // If a waiting_writer_ existed, there should have been a current_writer_. |
| 1652 DCHECK(current_writer_); |
| 1653 } |
| 1654 |
| 1655 void HttpCache::RemoveIdleSharedWriter(Transaction* trans, |
| 1656 ActiveEntry* entry, |
| 1657 bool cancel) { |
| 1658 entry->shared_writers->RemoveIdleWriter(trans); |
| 1659 |
| 1660 bool success = false; |
| 1661 if (cancel) { |
| 1662 success = trans->AddTruncatedFlag(); |
| 1663 } |
| 1664 if (entry->shared_writers->empty()) { |
| 1665 if (!success) { |
| 1666 entry->shared_writers.reset(); |
| 1667 DestroyEntryAndRestartPendingQueueTxns(entry); |
| 1668 } else { |
| 1669 ResetSharedWritersProcessPendingQueue(entry); |
| 1670 } |
| 1671 } |
| 1672 } |
| 1673 |
| 1674 void HttpCache::RemoveValidatingTransSharedWriters(Transaction* trans, |
| 1675 ActiveEntry* entry) { |
| 1676 entry->shared_writers->RemoveValidatingTransaction(trans); |
| 1677 ResetSharedWritersProcessPendingQueue(entry); |
| 1678 } |
| 1679 |
| 1680 void HttpCache::SharedWriters::RemoveValidatingTransaction(Transaction* trans) { |
| 1681 DCHECK_EQ(validating_trans_, trans); |
| 1682 validating_trans_ = nullptr; |
| 1683 trans->ResetShared(); |
| 1684 ProcessFirstWaitingValidation(); |
| 1685 return; |
| 1686 } |
| 1687 |
| 1688 bool HttpCache::SharedWriters::RemoveWaitingTransaction(Transaction* trans) { |
| 1689 auto it = std::find(waiting_for_validation_.begin(), |
| 1690 waiting_for_validation_.end(), trans); |
| 1691 if (it != waiting_for_validation_.end()) { |
| 1692 trans->ResetShared(); |
| 1693 waiting_for_validation_.erase(it); |
| 1694 return true; |
| 1695 } |
| 1696 return false; |
| 1697 } |
| 1698 |
| 1699 void HttpCache::SharedWriters::DoomCurrentWriter( |
| 1700 std::unique_ptr<HttpTransaction> trans) { |
| 1701 DCHECK_EQ(current_writer_, trans.get()); |
| 1702 if (waiting_writers_.empty() && all_writers_.empty()) { |
| 1703 ResetAndRemoveCurrentWriter(); |
| 1704 } else { |
| 1705 doomed_writer_ = std::move(trans); |
| 1706 } |
| 1707 } |
| 1708 |
| 1709 void HttpCache::SharedWriters::ProcessFirstWaitingValidation() { |
| 1710 if (!waiting_for_validation_.empty() || validating_trans_) |
| 1711 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 1712 FROM_HERE, |
| 1713 base::Bind(&HttpCache::SharedWriters::OnProcessFirstWaitingValidation, |
| 1714 weak_factory_.GetWeakPtr())); |
| 1715 } |
| 1716 |
| 1717 void HttpCache::SharedWriters::OnProcessFirstWaitingValidation() { |
| 1718 if (waiting_for_validation_.empty() && !validating_trans_) |
| 1719 return; |
| 1720 |
| 1721 Transaction* trans = nullptr; |
| 1722 if (validating_trans_) { |
| 1723 trans = validating_trans_; |
| 1724 } else { |
| 1725 trans = waiting_for_validation_.front(); |
| 1726 waiting_for_validation_.erase(waiting_for_validation_.begin()); |
| 1727 validating_trans_ = trans; |
| 1728 } |
| 1729 trans->io_callback().Run(OK); |
| 1730 } |
| 1731 |
| 1732 void HttpCache::SharedWriters::ProcessWaitingWriters(int result) { |
| 1733 for (auto it = waiting_writers_.begin(); it != waiting_writers_.end(); it++) { |
| 1734 Transaction* transaction = it->transaction; |
| 1735 |
| 1736 if (result > 0) { // success |
| 1737 // Fill result with the length of buffer filled for this transaction which |
| 1738 // may be different from the transaction that actually wrote to the cache |
| 1739 // based on the buffer size. |
| 1740 // If cache write is completed, then result will be 0. |
| 1741 // That will lead to the transaction calling DoneWritingToEntry(). |
| 1742 result = it->write_len; |
| 1743 } else { |
| 1744 // If its response completion or failure, this transaction needs to be |
| 1745 // removed. |
| 1746 transaction->ResetShared(); |
| 1747 all_writers_.erase(transaction); |
| 1748 } |
| 1749 |
| 1750 // Post task to notify transaction. |
| 1751 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 1752 FROM_HERE, base::Bind(&HttpCache::NotifyTransaction, |
| 1753 cache_->GetWeakPtr(), transaction, result)); |
| 1754 } |
| 1755 |
| 1756 waiting_writers_.clear(); |
| 1757 } |
| 1758 |
| 1759 void HttpCache::NotifyTransaction(Transaction* transaction, int result) { |
| 1760 DCHECK(transaction); |
| 1761 transaction->io_callback().Run(result); |
| 1762 } |
| 1763 |
| 1764 void HttpCache::SharedWriters::MoveFromPendingQueue() { |
| 1765 auto it = entry_->pending_queue.begin(); |
| 1766 while (it != entry_->pending_queue.end()) { |
| 1767 Transaction* transaction = *it; |
| 1768 if (transaction->IsEligibleForSharedWriting()) { |
| 1769 transaction->SetShared(); |
| 1770 waiting_for_validation_.push_back(transaction); |
| 1771 it = entry_->pending_queue.erase(it); |
| 1772 } else { |
| 1773 ++it; |
| 1774 } |
| 1775 } |
| 1776 } |
| 1777 |
| 1778 void HttpCache::SharedWriters::MoveToPendingQueue() { |
| 1779 // For maintaining the order of the transactions as they arrived, append |
| 1780 // these to the front of the pending_queue. Note that the order is preserved |
| 1781 // only among the transactions that are eligible for sharing. For others, they |
| 1782 // may have arrived earlier but may be processed later which is fair since |
| 1783 // they have to anyways wait till the entry is written to the cache. |
| 1784 while (!waiting_for_validation_.empty()) { |
| 1785 Transaction* trans = waiting_for_validation_.back(); |
| 1786 trans->ResetShared(true); |
| 1787 entry_->pending_queue.push_front(trans); |
| 1788 waiting_for_validation_.pop_back(); |
| 1789 } |
| 1790 } |
| 1791 |
| 1792 int HttpCache::SharedWriters::GetTotalReceivedBytes() const { |
| 1793 DCHECK(network_trans_); |
| 1794 return network_trans_->GetTotalReceivedBytes(); |
| 1795 } |
| 1796 |
| 1797 int HttpCache::SharedWriters::GetTotalSentBytes() const { |
| 1798 DCHECK(network_trans_); |
| 1799 return network_trans_->GetTotalSentBytes(); |
| 1800 } |
| 1801 |
| 1802 LoadState HttpCache::SharedWriters::GetLoadState() const { |
| 1803 DCHECK(network_trans_); |
| 1804 return network_trans_->GetLoadState(); |
| 1805 } |
| 1806 |
| 1807 bool HttpCache::SharedWriters::GetFullRequestHeaders( |
| 1808 HttpRequestHeaders* headers) const { |
| 1809 DCHECK(network_trans_); |
| 1810 return network_trans_->GetFullRequestHeaders(headers); |
| 1811 } |
| 1812 |
| 1813 bool HttpCache::SharedWriters::GetLoadTimingInfo( |
| 1814 LoadTimingInfo* load_timing_info) const { |
| 1815 DCHECK(network_trans_); |
| 1816 return network_trans_->GetLoadTimingInfo(load_timing_info); |
| 1817 } |
| 1818 |
| 1819 bool HttpCache::SharedWriters::GetRemoteEndpoint(IPEndPoint* endpoint) const { |
| 1820 DCHECK(network_trans_); |
| 1821 return network_trans_->GetRemoteEndpoint(endpoint); |
| 1822 } |
| 1823 |
| 1824 void HttpCache::SharedWriters::PopulateNetErrorDetails( |
| 1825 NetErrorDetails* details) const { |
| 1826 DCHECK(network_trans_); |
| 1827 return network_trans_->PopulateNetErrorDetails(details); |
| 1828 } |
| 1829 |
| 1830 void HttpCache::SharedWriters::SetPriority(RequestPriority priority) { |
| 1831 DCHECK(network_trans_); |
| 1832 network_trans_->SetPriority(priority_); |
| 1833 } |
| 1834 |
| 1835 void HttpCache::SharedWriters::SetWebSocketHandshakeStreamCreateHelper( |
| 1836 WebSocketHandshakeStreamBase::CreateHelper* create_helper) { |
| 1837 DCHECK(network_trans_); |
| 1838 return network_trans_->SetWebSocketHandshakeStreamCreateHelper(create_helper); |
| 1839 } |
| 1840 |
| 1841 int HttpCache::SharedWriters::ResumeNetworkStart() { |
| 1842 DCHECK(network_trans_); |
| 1843 return network_trans_->ResumeNetworkStart(); |
| 1844 } |
| 1845 |
| 1846 void HttpCache::SharedWriters::GetConnectionAttempts( |
| 1847 ConnectionAttempts* out) const { |
| 1848 DCHECK(network_trans_); |
| 1849 network_trans_->GetConnectionAttempts(out); |
| 1850 } |
| 1851 |
| 1852 HttpCache::SharedWriters::WaitingWriter::WaitingWriter( |
| 1853 Transaction* trans, |
| 1854 scoped_refptr<IOBuffer> buf, |
| 1855 int len) |
| 1856 : transaction(trans), read_buf(buf), read_buf_len(len), write_len(0) {} |
| 1857 |
| 1858 HttpCache::SharedWriters::WaitingWriter::~WaitingWriter() {} |
| 1859 |
| 1860 HttpCache::SharedWriters::WaitingWriter::WaitingWriter(const WaitingWriter&) = |
| 1861 default; |
| 1862 |
| 1160 } // namespace net | 1863 } // namespace net |
| OLD | NEW |