| 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 17 matching lines...) Expand all Loading... |
| 28 #include "base/threading/worker_pool.h" | 28 #include "base/threading/worker_pool.h" |
| 29 #include "base/time/default_clock.h" | 29 #include "base/time/default_clock.h" |
| 30 #include "base/time/time.h" | 30 #include "base/time/time.h" |
| 31 #include "net/base/cache_type.h" | 31 #include "net/base/cache_type.h" |
| 32 #include "net/base/io_buffer.h" | 32 #include "net/base/io_buffer.h" |
| 33 #include "net/base/load_flags.h" | 33 #include "net/base/load_flags.h" |
| 34 #include "net/base/net_errors.h" | 34 #include "net/base/net_errors.h" |
| 35 #include "net/base/upload_data_stream.h" | 35 #include "net/base/upload_data_stream.h" |
| 36 #include "net/disk_cache/disk_cache.h" | 36 #include "net/disk_cache/disk_cache.h" |
| 37 #include "net/http/disk_cache_based_quic_server_info.h" | 37 #include "net/http/disk_cache_based_quic_server_info.h" |
| 38 #include "net/http/http_cache_shared_writers.h" |
| 38 #include "net/http/http_cache_transaction.h" | 39 #include "net/http/http_cache_transaction.h" |
| 39 #include "net/http/http_network_layer.h" | 40 #include "net/http/http_network_layer.h" |
| 40 #include "net/http/http_network_session.h" | 41 #include "net/http/http_network_session.h" |
| 41 #include "net/http/http_request_info.h" | 42 #include "net/http/http_request_info.h" |
| 42 #include "net/http/http_response_headers.h" | 43 #include "net/http/http_response_headers.h" |
| 43 #include "net/http/http_response_info.h" | 44 #include "net/http/http_response_info.h" |
| 44 #include "net/http/http_util.h" | 45 #include "net/http/http_util.h" |
| 45 #include "net/log/net_log_with_source.h" | 46 #include "net/log/net_log_with_source.h" |
| 46 #include "net/quic/chromium/quic_server_info.h" | 47 #include "net/quic/chromium/quic_server_info.h" |
| 47 | 48 |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 | 333 |
| 333 // If we have any active entries remaining, then we need to deactivate them. | 334 // If we have any active entries remaining, then we need to deactivate them. |
| 334 // We may have some pending calls to OnProcessPendingQueue, but since those | 335 // We may have some pending calls to OnProcessPendingQueue, but since those |
| 335 // won't run (due to our destruction), we can simply ignore the corresponding | 336 // won't run (due to our destruction), we can simply ignore the corresponding |
| 336 // will_process_pending_queue flag. | 337 // will_process_pending_queue flag. |
| 337 while (!active_entries_.empty()) { | 338 while (!active_entries_.empty()) { |
| 338 ActiveEntry* entry = active_entries_.begin()->second.get(); | 339 ActiveEntry* entry = active_entries_.begin()->second.get(); |
| 339 entry->will_process_pending_queue = false; | 340 entry->will_process_pending_queue = false; |
| 340 entry->pending_queue.clear(); | 341 entry->pending_queue.clear(); |
| 341 entry->readers.clear(); | 342 entry->readers.clear(); |
| 342 entry->writer = NULL; | 343 entry->writer = nullptr; |
| 344 entry->shared_writers.reset(); |
| 343 DeactivateEntry(entry); | 345 DeactivateEntry(entry); |
| 344 } | 346 } |
| 345 | 347 |
| 346 doomed_entries_.clear(); | 348 doomed_entries_.clear(); |
| 347 | 349 |
| 348 // Before deleting pending_ops_, we have to make sure that the disk cache is | 350 // Before deleting pending_ops_, we have to make sure that the disk cache is |
| 349 // done with said operations, or it will attempt to use deleted data. | 351 // done with said operations, or it will attempt to use deleted data. |
| 350 disk_cache_.reset(); | 352 disk_cache_.reset(); |
| 351 | 353 |
| 352 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); | 354 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 } | 446 } |
| 445 | 447 |
| 446 int HttpCache::CreateTransaction(RequestPriority priority, | 448 int HttpCache::CreateTransaction(RequestPriority priority, |
| 447 std::unique_ptr<HttpTransaction>* trans) { | 449 std::unique_ptr<HttpTransaction>* trans) { |
| 448 // Do lazy initialization of disk cache if needed. | 450 // Do lazy initialization of disk cache if needed. |
| 449 if (!disk_cache_.get()) { | 451 if (!disk_cache_.get()) { |
| 450 // We don't care about the result. | 452 // We don't care about the result. |
| 451 CreateBackend(NULL, CompletionCallback()); | 453 CreateBackend(NULL, CompletionCallback()); |
| 452 } | 454 } |
| 453 | 455 |
| 454 HttpCache::Transaction* transaction = | 456 HttpCache::Transaction* transaction = |
| 455 new HttpCache::Transaction(priority, this); | 457 new HttpCache::Transaction(priority, this); |
| 456 if (bypass_lock_for_test_) | 458 if (bypass_lock_for_test_) |
| 457 transaction->BypassLockForTest(); | 459 transaction->BypassLockForTest(); |
| 458 if (fail_conditionalization_for_test_) | 460 if (fail_conditionalization_for_test_) |
| 459 transaction->FailConditionalizationForTest(); | 461 transaction->FailConditionalizationForTest(); |
| 460 | 462 |
| 461 trans->reset(transaction); | 463 trans->reset(transaction); |
| 462 return OK; | 464 return OK; |
| 463 } | 465 } |
| 464 | 466 |
| 465 HttpCache* HttpCache::GetCache() { | 467 HttpCache* HttpCache::GetCache() { |
| 466 return this; | 468 return this; |
| 467 } | 469 } |
| 468 | 470 |
| 469 HttpNetworkSession* HttpCache::GetSession() { | 471 HttpNetworkSession* HttpCache::GetSession() { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 | 577 |
| 576 // We keep track of doomed entries so that we can ensure that they are | 578 // We keep track of doomed entries so that we can ensure that they are |
| 577 // cleaned up properly when the cache is destroyed. | 579 // cleaned up properly when the cache is destroyed. |
| 578 ActiveEntry* entry_ptr = entry.get(); | 580 ActiveEntry* entry_ptr = entry.get(); |
| 579 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); | 581 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); |
| 580 doomed_entries_[entry_ptr] = std::move(entry); | 582 doomed_entries_[entry_ptr] = std::move(entry); |
| 581 | 583 |
| 582 entry_ptr->disk_entry->Doom(); | 584 entry_ptr->disk_entry->Doom(); |
| 583 entry_ptr->doomed = true; | 585 entry_ptr->doomed = true; |
| 584 | 586 |
| 585 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || | 587 DCHECK(entry_ptr->writer || entry_ptr->shared_writers || |
| 586 entry_ptr->will_process_pending_queue); | 588 !entry_ptr->readers.empty() || entry_ptr->will_process_pending_queue); |
| 587 return OK; | 589 return OK; |
| 588 } | 590 } |
| 589 | 591 |
| 590 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { | 592 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { |
| 591 std::unique_ptr<WorkItem> item = | 593 std::unique_ptr<WorkItem> item = |
| 592 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); | 594 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); |
| 593 PendingOp* pending_op = GetPendingOp(key); | 595 PendingOp* pending_op = GetPendingOp(key); |
| 594 if (pending_op->writer) { | 596 if (pending_op->writer) { |
| 595 pending_op->pending_queue.push_back(std::move(item)); | 597 pending_op->pending_queue.push_back(std::move(item)); |
| 596 return ERR_IO_PENDING; | 598 return ERR_IO_PENDING; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 623 // Defer to DoomEntry if there is an active entry, otherwise call | 625 // Defer to DoomEntry if there is an active entry, otherwise call |
| 624 // AsyncDoomEntry without triggering a callback. | 626 // AsyncDoomEntry without triggering a callback. |
| 625 if (active_entries_.count(key)) | 627 if (active_entries_.count(key)) |
| 626 DoomEntry(key, NULL); | 628 DoomEntry(key, NULL); |
| 627 else | 629 else |
| 628 AsyncDoomEntry(key, NULL); | 630 AsyncDoomEntry(key, NULL); |
| 629 } | 631 } |
| 630 | 632 |
| 631 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { | 633 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { |
| 632 DCHECK(entry->doomed); | 634 DCHECK(entry->doomed); |
| 633 DCHECK(!entry->writer); | 635 DCHECK(!entry->writer && !entry->shared_writers); |
| 634 DCHECK(entry->readers.empty()); | 636 DCHECK(entry->readers.empty()); |
| 635 DCHECK(entry->pending_queue.empty()); | 637 DCHECK(entry->pending_queue.empty()); |
| 636 | 638 |
| 637 auto it = doomed_entries_.find(entry); | 639 auto it = doomed_entries_.find(entry); |
| 638 DCHECK(it != doomed_entries_.end()); | 640 DCHECK(it != doomed_entries_.end()); |
| 639 doomed_entries_.erase(it); | 641 doomed_entries_.erase(it); |
| 640 } | 642 } |
| 641 | 643 |
| 642 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { | 644 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { |
| 643 auto it = active_entries_.find(key); | 645 auto it = active_entries_.find(key); |
| 644 return it != active_entries_.end() ? it->second.get() : NULL; | 646 return it != active_entries_.end() ? it->second.get() : NULL; |
| 645 } | 647 } |
| 646 | 648 |
| 647 HttpCache::ActiveEntry* HttpCache::ActivateEntry( | 649 HttpCache::ActiveEntry* HttpCache::ActivateEntry( |
| 648 disk_cache::Entry* disk_entry) { | 650 disk_cache::Entry* disk_entry) { |
| 649 DCHECK(!FindActiveEntry(disk_entry->GetKey())); | 651 DCHECK(!FindActiveEntry(disk_entry->GetKey())); |
| 650 ActiveEntry* entry = new ActiveEntry(disk_entry); | 652 ActiveEntry* entry = new ActiveEntry(disk_entry); |
| 651 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); | 653 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); |
| 652 return entry; | 654 return entry; |
| 653 } | 655 } |
| 654 | 656 |
| 655 void HttpCache::DeactivateEntry(ActiveEntry* entry) { | 657 void HttpCache::DeactivateEntry(ActiveEntry* entry) { |
| 656 DCHECK(!entry->will_process_pending_queue); | 658 DCHECK(!entry->will_process_pending_queue); |
| 657 DCHECK(!entry->doomed); | 659 DCHECK(!entry->doomed); |
| 658 DCHECK(!entry->writer); | 660 DCHECK(!entry->writer && !entry->shared_writers); |
| 659 DCHECK(entry->disk_entry); | 661 DCHECK(entry->disk_entry); |
| 660 DCHECK(entry->readers.empty()); | 662 DCHECK(entry->readers.empty()); |
| 661 DCHECK(entry->pending_queue.empty()); | 663 DCHECK(entry->pending_queue.empty()); |
| 662 | 664 |
| 663 std::string key = entry->disk_entry->GetKey(); | 665 std::string key = entry->disk_entry->GetKey(); |
| 664 if (key.empty()) | 666 if (key.empty()) |
| 665 return SlowDeactivateEntry(entry); | 667 return SlowDeactivateEntry(entry); |
| 666 | 668 |
| 667 auto it = active_entries_.find(key); | 669 auto it = active_entries_.find(key); |
| 668 DCHECK(it != active_entries_.end()); | 670 DCHECK(it != active_entries_.end()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 FinalizeDoomedEntry(entry); | 784 FinalizeDoomedEntry(entry); |
| 783 } else { | 785 } else { |
| 784 DeactivateEntry(entry); | 786 DeactivateEntry(entry); |
| 785 } | 787 } |
| 786 } | 788 } |
| 787 | 789 |
| 788 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { | 790 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { |
| 789 DCHECK(entry); | 791 DCHECK(entry); |
| 790 DCHECK(entry->disk_entry); | 792 DCHECK(entry->disk_entry); |
| 791 | 793 |
| 792 // We implement a basic reader/writer lock for the disk cache entry. If | 794 // If a writer is in the validation stage, all other transactions need to wait |
| 793 // there is already a writer, then everyone has to wait for the writer to | 795 // before they can access the cache entry. Once the validation stage is over |
| 794 // finish before they can access the cache entry. There can be multiple | 796 // and if the writer creates a SharedWriters object, other eligible |
| 795 // readers. | 797 // transactions will become equally privileged to be able to read from the |
| 798 // network and write to the cache. |
| 796 // | 799 // |
| 797 // NOTE: If the transaction can only write, then the entry should not be in | 800 // NOTE: If the transaction can only write, then the entry should not be in |
| 798 // use (since any existing entry should have already been doomed). | 801 // use (since any existing entry should have already been doomed). |
| 799 | |
| 800 if (entry->writer || entry->will_process_pending_queue) { | 802 if (entry->writer || entry->will_process_pending_queue) { |
| 801 entry->pending_queue.push_back(trans); | 803 entry->pending_queue.push_back(trans); |
| 802 return ERR_IO_PENDING; | 804 return ERR_IO_PENDING; |
| 803 } | 805 } |
| 804 | 806 |
| 805 if (trans->mode() & Transaction::WRITE) { | 807 if (entry->shared_writers) { |
| 808 DCHECK(!entry->writer); |
| 809 if (!trans->IsEligibleForSharedWriting()) { |
| 810 entry->pending_queue.push_back(trans); |
| 811 return ERR_IO_PENDING; |
| 812 } else { |
| 813 if (entry->shared_writers->AddTransaction(trans)) { |
| 814 return OK; |
| 815 } else { |
| 816 // Another transaction is in the process of validation, wait for it and |
| 817 // any other transactions already in the queue to complete. |
| 818 return ERR_IO_PENDING; |
| 819 } |
| 820 } |
| 821 } else if (trans->mode() & Transaction::WRITE) { // No SharedWriters. |
| 806 // transaction needs exclusive access to the entry | 822 // transaction needs exclusive access to the entry |
| 807 if (entry->readers.empty()) { | 823 if (entry->readers.empty()) { |
| 808 entry->writer = trans; | 824 entry->writer = trans; |
| 809 } else { | 825 } else { |
| 810 entry->pending_queue.push_back(trans); | 826 entry->pending_queue.push_back(trans); |
| 811 return ERR_IO_PENDING; | 827 return ERR_IO_PENDING; |
| 812 } | 828 } |
| 813 } else { | 829 } else { |
| 814 // transaction needs read access to the entry | 830 // transaction needs read access to the entry |
| 815 entry->readers.push_back(trans); | 831 entry->readers.insert(trans); |
| 816 } | 832 } |
| 817 | 833 |
| 818 // We do this before calling EntryAvailable to force any further calls to | 834 // We do this before calling EntryAvailable to force any further calls to |
| 819 // AddTransactionToEntry to add their transaction to the pending queue, which | 835 // AddTransactionToEntry to add their transaction to the pending queue, which |
| 820 // ensures FIFO ordering. | 836 // ensures FIFO ordering. |
| 821 if (!entry->writer && !entry->pending_queue.empty()) | 837 if (!entry->writer && !entry->pending_queue.empty()) |
| 822 ProcessPendingQueue(entry); | 838 ProcessPendingQueue(entry); |
| 823 | 839 |
| 824 return OK; | 840 return OK; |
| 825 } | 841 } |
| 826 | 842 |
| 827 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, | 843 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, |
| 828 bool cancel) { | 844 bool cancel) { |
| 845 // This is not expected to be called for shared writing transactions. |
| 846 DCHECK(!trans->shared()); |
| 847 |
| 829 // If we already posted a task to move on to the next transaction and this was | 848 // If we already posted a task to move on to the next transaction and this was |
| 830 // the writer, there is nothing to cancel. | 849 // the writer, there is nothing to cancel. |
| 831 if (entry->will_process_pending_queue && entry->readers.empty()) | 850 if (entry->will_process_pending_queue && entry->readers.empty()) |
| 832 return; | 851 return; |
| 833 | 852 |
| 834 if (entry->writer) { | 853 if (entry->writer) { |
| 835 DCHECK(trans == entry->writer); | 854 DCHECK(trans == entry->writer); |
| 836 | |
| 837 // Assume there was a failure. | 855 // Assume there was a failure. |
| 838 bool success = false; | 856 bool success = false; |
| 839 if (cancel) { | 857 if (cancel) { |
| 840 DCHECK(entry->disk_entry); | 858 DCHECK(entry->disk_entry); |
| 841 // This is a successful operation in the sense that we want to keep the | 859 // This is a successful operation in the sense that we want to keep the |
| 842 // entry. | 860 // entry. |
| 843 success = trans->AddTruncatedFlag(); | 861 success = trans->AddTruncatedFlag(); |
| 844 // The previous operation may have deleted the entry. | 862 // The previous operation may have deleted the entry. |
| 845 if (!trans->entry()) | 863 if (!trans->entry()) |
| 846 return; | 864 return; |
| 847 } | 865 } |
| 848 DoneWritingToEntry(entry, success); | 866 DoneWritingToEntry(entry, success); |
| 849 } else { | 867 } else { |
| 850 DoneReadingFromEntry(entry, trans); | 868 DoneReadingFromEntry(entry, trans); |
| 851 } | 869 } |
| 852 } | 870 } |
| 853 | 871 |
| 854 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { | 872 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { |
| 855 DCHECK(entry->readers.empty()); | 873 DCHECK(entry->readers.empty()); |
| 874 DCHECK(!entry->shared_writers); |
| 856 | 875 |
| 857 entry->writer = NULL; | 876 entry->writer = NULL; |
| 858 | 877 |
| 859 if (success) { | 878 if (success) { |
| 860 ProcessPendingQueue(entry); | 879 ProcessPendingQueue(entry); |
| 861 } else { | 880 } else { |
| 862 DCHECK(!entry->will_process_pending_queue); | 881 DestroyEntryAndRestartPendingQueueTransactions(entry); |
| 882 } |
| 883 } |
| 863 | 884 |
| 864 // We failed to create this entry. | 885 void HttpCache::DestroyEntryAndRestartPendingQueueTransactions( |
| 865 TransactionList pending_queue; | 886 ActiveEntry* entry) { |
| 866 pending_queue.swap(entry->pending_queue); | 887 DCHECK(!entry->will_process_pending_queue); |
| 867 | 888 |
| 868 entry->disk_entry->Doom(); | 889 // We failed to create this entry. |
| 869 DestroyEntry(entry); | 890 TransactionList pending_queue; |
| 891 pending_queue.swap(entry->pending_queue); |
| 870 | 892 |
| 871 // We need to do something about these pending entries, which now need to | 893 entry->disk_entry->Doom(); |
| 872 // be added to a new entry. | 894 |
| 873 while (!pending_queue.empty()) { | 895 DestroyEntry(entry); |
| 874 // ERR_CACHE_RACE causes the transaction to restart the whole process. | 896 |
| 875 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); | 897 // We need to do something about these pending entries, which now need to |
| 876 pending_queue.pop_front(); | 898 // be added to a new entry. |
| 877 } | 899 while (!pending_queue.empty()) { |
| 900 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 901 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 902 pending_queue.pop_front(); |
| 878 } | 903 } |
| 879 } | 904 } |
| 880 | 905 |
| 881 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { | 906 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { |
| 882 DCHECK(!entry->writer); | 907 DCHECK(!entry->writer && !entry->shared_writers); |
| 883 | 908 |
| 884 auto it = std::find(entry->readers.begin(), entry->readers.end(), trans); | 909 auto it = entry->readers.find(trans); |
| 885 DCHECK(it != entry->readers.end()); | 910 DCHECK(it != entry->readers.end()); |
| 886 | 911 |
| 887 entry->readers.erase(it); | 912 entry->readers.erase(it); |
| 888 | 913 |
| 889 ProcessPendingQueue(entry); | 914 ProcessPendingQueue(entry); |
| 890 } | 915 } |
| 891 | 916 |
| 892 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { | 917 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { |
| 893 DCHECK(entry->writer); | 918 DCHECK(entry->writer); |
| 894 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); | 919 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); |
| 895 DCHECK(entry->readers.empty()); | 920 DCHECK(entry->readers.empty()); |
| 896 | 921 |
| 897 Transaction* trans = entry->writer; | 922 Transaction* trans = entry->writer; |
| 898 | 923 |
| 899 entry->writer = NULL; | 924 entry->writer = NULL; |
| 900 entry->readers.push_back(trans); | 925 entry->readers.insert(trans); |
| 901 | 926 |
| 902 ProcessPendingQueue(entry); | 927 ProcessPendingQueue(entry); |
| 903 } | 928 } |
| 904 | 929 |
| 905 LoadState HttpCache::GetLoadStateForPendingTransaction( | 930 LoadState HttpCache::GetLoadStateForPendingTransaction( |
| 906 const Transaction* trans) { | 931 const Transaction* trans) { |
| 907 auto i = active_entries_.find(trans->key()); | 932 auto i = active_entries_.find(trans->key()); |
| 908 if (i == active_entries_.end()) { | 933 if (i == active_entries_.end()) { |
| 909 // 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 |
| 910 // active_entries_, we should be creating the backend or the entry. | 935 // active_entries_, we should be creating the backend or the entry. |
| 911 return LOAD_STATE_WAITING_FOR_CACHE; | 936 return LOAD_STATE_WAITING_FOR_CACHE; |
| 912 } | 937 } |
| 913 | 938 |
| 914 Transaction* writer = i->second->writer; | 939 Transaction* writer = i->second->writer; |
| 915 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; | 940 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; |
| 916 } | 941 } |
| 917 | 942 |
| 918 void HttpCache::RemovePendingTransaction(Transaction* trans) { | 943 void HttpCache::RemovePendingTransaction(Transaction* trans) { |
| 944 bool found = false; |
| 945 |
| 919 auto i = active_entries_.find(trans->key()); | 946 auto i = active_entries_.find(trans->key()); |
| 920 bool found = false; | |
| 921 if (i != active_entries_.end()) | 947 if (i != active_entries_.end()) |
| 922 found = RemovePendingTransactionFromEntry(i->second.get(), trans); | 948 found = RemovePendingTransactionFromEntry(i->second.get(), trans); |
| 923 | 949 |
| 924 if (found) | 950 if (found) |
| 925 return; | 951 return; |
| 926 | 952 |
| 927 if (building_backend_) { | 953 if (building_backend_) { |
| 928 auto j = pending_ops_.find(std::string()); | 954 auto j = pending_ops_.find(std::string()); |
| 929 if (j != pending_ops_.end()) | 955 if (j != pending_ops_.end()) |
| 930 found = RemovePendingTransactionFromPendingOp(j->second, trans); | 956 found = RemovePendingTransactionFromPendingOp(j->second, trans); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 943 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; | 969 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; |
| 944 ++k) { | 970 ++k) { |
| 945 found = RemovePendingTransactionFromEntry(k->first, trans); | 971 found = RemovePendingTransactionFromEntry(k->first, trans); |
| 946 } | 972 } |
| 947 | 973 |
| 948 DCHECK(found) << "Pending transaction not found"; | 974 DCHECK(found) << "Pending transaction not found"; |
| 949 } | 975 } |
| 950 | 976 |
| 951 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, | 977 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, |
| 952 Transaction* trans) { | 978 Transaction* trans) { |
| 979 if (trans->shared()) |
| 980 return entry->shared_writers->RemoveWaitingTransaction(trans); |
| 981 |
| 953 TransactionList& pending_queue = entry->pending_queue; | 982 TransactionList& pending_queue = entry->pending_queue; |
| 954 | |
| 955 auto j = find(pending_queue.begin(), pending_queue.end(), trans); | 983 auto j = find(pending_queue.begin(), pending_queue.end(), trans); |
| 956 if (j == pending_queue.end()) | 984 if (j == pending_queue.end()) |
| 957 return false; | 985 return false; |
| 958 | |
| 959 pending_queue.erase(j); | 986 pending_queue.erase(j); |
| 960 return true; | 987 return true; |
| 961 } | 988 } |
| 962 | 989 |
| 963 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, | 990 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, |
| 964 Transaction* trans) { | 991 Transaction* trans) { |
| 965 if (pending_op->writer->Matches(trans)) { | 992 if (pending_op->writer->Matches(trans)) { |
| 966 pending_op->writer->ClearTransaction(); | 993 pending_op->writer->ClearTransaction(); |
| 967 pending_op->writer->ClearEntry(); | 994 pending_op->writer->ClearEntry(); |
| 968 return true; | 995 return true; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 986 return; | 1013 return; |
| 987 entry->will_process_pending_queue = true; | 1014 entry->will_process_pending_queue = true; |
| 988 | 1015 |
| 989 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1016 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 990 FROM_HERE, | 1017 FROM_HERE, |
| 991 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1018 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 992 } | 1019 } |
| 993 | 1020 |
| 994 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1021 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 995 entry->will_process_pending_queue = false; | 1022 entry->will_process_pending_queue = false; |
| 996 DCHECK(!entry->writer); | 1023 DCHECK(!entry->writer && !entry->shared_writers); |
| 997 | 1024 |
| 998 // If no one is interested in this entry, then we can deactivate it. | 1025 // If no one is interested in this entry, then we can deactivate it. |
| 999 if (entry->pending_queue.empty()) { | 1026 if (entry->pending_queue.empty()) { |
| 1000 if (entry->readers.empty()) | 1027 if (entry->readers.empty()) |
| 1001 DestroyEntry(entry); | 1028 DestroyEntry(entry); |
| 1002 return; | 1029 return; |
| 1003 } | 1030 } |
| 1004 | 1031 |
| 1005 // Promote next transaction from the pending queue. | 1032 // Promote next transaction from the pending queue. |
| 1006 Transaction* next = entry->pending_queue.front(); | 1033 Transaction* next = entry->pending_queue.front(); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 } else { | 1178 } else { |
| 1152 building_backend_ = false; | 1179 building_backend_ = false; |
| 1153 DeletePendingOp(pending_op); | 1180 DeletePendingOp(pending_op); |
| 1154 } | 1181 } |
| 1155 | 1182 |
| 1156 // The cache may be gone when we return from the callback. | 1183 // The cache may be gone when we return from the callback. |
| 1157 if (!item->DoCallback(result, disk_cache_.get())) | 1184 if (!item->DoCallback(result, disk_cache_.get())) |
| 1158 item->NotifyTransaction(result, NULL); | 1185 item->NotifyTransaction(result, NULL); |
| 1159 } | 1186 } |
| 1160 | 1187 |
| 1188 bool HttpCache::IsResponseCompleted(const ActiveEntry* entry, |
| 1189 const HttpResponseInfo* response_info) { |
| 1190 int current_size = entry->disk_entry->GetDataSize(kResponseContentIndex); |
| 1191 int64_t content_length = response_info->headers->GetContentLength(); |
| 1192 if ((content_length >= 0 && content_length <= current_size) || |
| 1193 content_length < 0) |
| 1194 return true; |
| 1195 return false; |
| 1196 } |
| 1197 |
| 1198 int HttpCache::WriteResponseInfo(ActiveEntry* entry, |
| 1199 const HttpResponseInfo* response, |
| 1200 CompletionCallback& callback, |
| 1201 bool truncated, |
| 1202 int* io_buf_len) { |
| 1203 // When writing headers, we normally only write the non-transient headers. |
| 1204 bool skip_transient_headers = true; |
| 1205 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
| 1206 response->Persist(data->pickle(), skip_transient_headers, truncated); |
| 1207 data->Done(); |
| 1208 |
| 1209 *io_buf_len = data->pickle()->size(); |
| 1210 return entry->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), |
| 1211 *io_buf_len, callback, true); |
| 1212 } |
| 1213 |
| 1214 // Histogram data from the end of 2010 show the following distribution of |
| 1215 // response headers: |
| 1216 // |
| 1217 // Content-Length............... 87% |
| 1218 // Date......................... 98% |
| 1219 // Last-Modified................ 49% |
| 1220 // Etag......................... 19% |
| 1221 // Accept-Ranges: bytes......... 25% |
| 1222 // Accept-Ranges: none.......... 0.4% |
| 1223 // Strong Validator............. 50% |
| 1224 // Strong Validator + ranges.... 24% |
| 1225 // Strong Validator + CL........ 49% |
| 1226 // |
| 1227 bool HttpCache::CanResumeEntry(bool has_data, |
| 1228 const std::string& method, |
| 1229 const HttpResponseInfo* response, |
| 1230 ActiveEntry* entry) { |
| 1231 // Double check that there is something worth keeping. |
| 1232 if (has_data && !entry->disk_entry->GetDataSize(kResponseContentIndex)) |
| 1233 return false; |
| 1234 |
| 1235 if (method != "GET") |
| 1236 return false; |
| 1237 |
| 1238 // Note that if this is a 206, content-length was already fixed after calling |
| 1239 // PartialData::ResponseHeadersOK(). |
| 1240 if (response->headers->GetContentLength() <= 0 || |
| 1241 response->headers->HasHeaderValue("Accept-Ranges", "none") || |
| 1242 !response->headers->HasStrongValidators()) { |
| 1243 return false; |
| 1244 } |
| 1245 |
| 1246 return true; |
| 1247 } |
| 1248 |
| 1249 void HttpCache::CreateSharedWriters( |
| 1250 Transaction* cache_transaction, |
| 1251 std::unique_ptr<HttpTransaction> network_transaction, |
| 1252 RequestPriority priority) { |
| 1253 ActiveEntry* entry = cache_transaction->entry(); |
| 1254 DCHECK(!entry->shared_writers); |
| 1255 DCHECK_EQ(entry->writer, cache_transaction); |
| 1256 DCHECK(entry->readers.empty()); |
| 1257 entry->shared_writers.reset( |
| 1258 new HttpCache::SharedWriters(this, entry, cache_transaction, priority, |
| 1259 std::move(network_transaction))); |
| 1260 |
| 1261 // entry->writer should no longer exist as it is moved to |
| 1262 // shared_writers. |
| 1263 entry->writer = nullptr; |
| 1264 |
| 1265 // Add the eligible transactions to waiting_for_validation_ and process the |
| 1266 // first among them. After this, pending_queue will only contain transactions |
| 1267 // that are not eligible for shared writing. |
| 1268 entry->shared_writers->MoveFromPendingQueue(); |
| 1269 entry->shared_writers->ProcessFirstWaitingValidation(); |
| 1270 } |
| 1271 |
| 1272 void HttpCache::ResponseCompleteSharedWriters(ActiveEntry* entry) { |
| 1273 DCHECK(entry->shared_writers->empty()); |
| 1274 entry->shared_writers.release(); |
| 1275 ProcessPendingQueue(entry); |
| 1276 } |
| 1277 |
| 1278 void HttpCache::ResponseFailedSharedWriters(bool success, ActiveEntry* entry) { |
| 1279 DCHECK(entry->shared_writers->empty()); |
| 1280 entry->shared_writers.release(); |
| 1281 |
| 1282 if (success) |
| 1283 ProcessPendingQueue(entry); |
| 1284 else |
| 1285 DestroyEntryAndRestartPendingQueueTransactions(entry); |
| 1286 } |
| 1287 |
| 1288 void HttpCache::DoneReadingSharedWriters(Transaction* transaction, |
| 1289 ActiveEntry* entry) { |
| 1290 entry->shared_writers->DoneReading(transaction); |
| 1291 |
| 1292 ResetSharedWritersProcessPendingQueue(entry); |
| 1293 } |
| 1294 |
| 1295 void HttpCache::StopCachingSharedWriters(Transaction* transaction, |
| 1296 ActiveEntry* entry) { |
| 1297 bool stopped = entry->shared_writers->StopCaching(transaction); |
| 1298 |
| 1299 if (stopped) { |
| 1300 DCHECK(entry->shared_writers->empty()); |
| 1301 DCHECK_EQ(entry->writer, transaction); |
| 1302 entry->shared_writers.reset(); |
| 1303 } |
| 1304 } |
| 1305 |
| 1306 std::unique_ptr<HttpTransaction> HttpCache::ValidationNoMatchSharedWriters( |
| 1307 const std::string& key, |
| 1308 Transaction* transaction, |
| 1309 std::unique_ptr<HttpTransaction> network_transaction, |
| 1310 RequestPriority priority, |
| 1311 ActiveEntry* entry) { |
| 1312 // This will either return the ownership of the network transaction so that |
| 1313 // this transaction can continue reading from the network or not, if this is |
| 1314 // the only transaction in SharedWriters. |
| 1315 std::unique_ptr<HttpTransaction> nw_transaction = |
| 1316 entry->shared_writers->OnValidationNoMatch( |
| 1317 transaction, std::move(network_transaction), priority); |
| 1318 if (nw_transaction) { |
| 1319 DCHECK(!transaction->shared()); |
| 1320 DoomActiveEntry(key); |
| 1321 // We need to do something about these pending entries, which now need to |
| 1322 // be added to a new entry. |
| 1323 while (!entry->pending_queue.empty()) { |
| 1324 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 1325 entry->pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 1326 entry->pending_queue.pop_front(); |
| 1327 } |
| 1328 } |
| 1329 return nw_transaction; |
| 1330 } |
| 1331 |
| 1332 void HttpCache::ResetSharedWritersProcessPendingQueue(ActiveEntry* entry) { |
| 1333 if (entry->shared_writers->empty()) { |
| 1334 ResetOrReleaseSharedWriters(entry); |
| 1335 DCHECK(!entry->writer); |
| 1336 ProcessPendingQueue(entry); |
| 1337 } |
| 1338 } |
| 1339 |
| 1340 void HttpCache::RemoveCurrentSharedWriter(Transaction* transaction, |
| 1341 ActiveEntry* entry) { |
| 1342 entry->shared_writers->RemoveCurrentWriter(transaction); |
| 1343 ResetSharedWritersProcessPendingQueue(entry); |
| 1344 } |
| 1345 |
| 1346 void HttpCache::ResetOrReleaseSharedWriters(ActiveEntry* entry) { |
| 1347 if (entry->shared_writers->CanReset()) |
| 1348 entry->shared_writers.reset(); |
| 1349 else |
| 1350 entry->shared_writers.release(); |
| 1351 } |
| 1352 |
| 1353 void HttpCache::RemoveIdleSharedWriter(Transaction* transaction, |
| 1354 ActiveEntry* entry) { |
| 1355 entry->shared_writers->RemoveIdleWriter(transaction); |
| 1356 |
| 1357 if (entry->shared_writers->empty()) { |
| 1358 bool success = false; |
| 1359 success = transaction->AddTruncatedFlag(); |
| 1360 if (success) { |
| 1361 ResetSharedWritersProcessPendingQueue(entry); |
| 1362 } else { |
| 1363 ResetOrReleaseSharedWriters(entry); |
| 1364 DestroyEntryAndRestartPendingQueueTransactions(entry); |
| 1365 } |
| 1366 } |
| 1367 } |
| 1368 |
| 1369 void HttpCache::RemoveValidatingTransSharedWriters(Transaction* transaction, |
| 1370 ActiveEntry* entry) { |
| 1371 entry->shared_writers->RemoveValidatingTransaction(transaction); |
| 1372 ResetSharedWritersProcessPendingQueue(entry); |
| 1373 } |
| 1374 |
| 1375 void HttpCache::NotifyTransaction(base::WeakPtr<Transaction> transaction, |
| 1376 int result) { |
| 1377 if (transaction) { |
| 1378 transaction->io_callback().Run(result); |
| 1379 } |
| 1380 } |
| 1381 |
| 1161 } // namespace net | 1382 } // namespace net |
| OLD | NEW |