| 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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 | 335 |
| 335 // If we have any active entries remaining, then we need to deactivate them. | 336 // If we have any active entries remaining, then we need to deactivate them. |
| 336 // We may have some pending calls to OnProcessPendingQueue, but since those | 337 // We may have some pending calls to OnProcessPendingQueue, but since those |
| 337 // won't run (due to our destruction), we can simply ignore the corresponding | 338 // won't run (due to our destruction), we can simply ignore the corresponding |
| 338 // will_process_pending_queue flag. | 339 // will_process_pending_queue flag. |
| 339 while (!active_entries_.empty()) { | 340 while (!active_entries_.empty()) { |
| 340 ActiveEntry* entry = active_entries_.begin()->second.get(); | 341 ActiveEntry* entry = active_entries_.begin()->second.get(); |
| 341 entry->will_process_pending_queue = false; | 342 entry->will_process_pending_queue = false; |
| 342 entry->pending_queue.clear(); | 343 entry->pending_queue.clear(); |
| 343 entry->readers.clear(); | 344 entry->readers.clear(); |
| 344 entry->writer = NULL; | 345 entry->writer = nullptr; |
| 346 entry->shared_writers.reset(); |
| 345 DeactivateEntry(entry); | 347 DeactivateEntry(entry); |
| 346 } | 348 } |
| 347 | 349 |
| 348 doomed_entries_.clear(); | 350 doomed_entries_.clear(); |
| 349 | 351 |
| 350 // Before deleting pending_ops_, we have to make sure that the disk cache is | 352 // Before deleting pending_ops_, we have to make sure that the disk cache is |
| 351 // done with said operations, or it will attempt to use deleted data. | 353 // done with said operations, or it will attempt to use deleted data. |
| 352 disk_cache_.reset(); | 354 disk_cache_.reset(); |
| 353 | 355 |
| 354 for (auto pending_it = pending_ops_.begin(); pending_it != pending_ops_.end(); | 356 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... |
| 446 } | 448 } |
| 447 | 449 |
| 448 int HttpCache::CreateTransaction(RequestPriority priority, | 450 int HttpCache::CreateTransaction(RequestPriority priority, |
| 449 std::unique_ptr<HttpTransaction>* trans) { | 451 std::unique_ptr<HttpTransaction>* trans) { |
| 450 // Do lazy initialization of disk cache if needed. | 452 // Do lazy initialization of disk cache if needed. |
| 451 if (!disk_cache_.get()) { | 453 if (!disk_cache_.get()) { |
| 452 // We don't care about the result. | 454 // We don't care about the result. |
| 453 CreateBackend(NULL, CompletionCallback()); | 455 CreateBackend(NULL, CompletionCallback()); |
| 454 } | 456 } |
| 455 | 457 |
| 456 HttpCache::Transaction* transaction = | 458 HttpCache::Transaction* transaction = |
| 457 new HttpCache::Transaction(priority, this); | 459 new HttpCache::Transaction(priority, this); |
| 458 if (bypass_lock_for_test_) | 460 if (bypass_lock_for_test_) |
| 459 transaction->BypassLockForTest(); | 461 transaction->BypassLockForTest(); |
| 460 if (fail_conditionalization_for_test_) | 462 if (fail_conditionalization_for_test_) |
| 461 transaction->FailConditionalizationForTest(); | 463 transaction->FailConditionalizationForTest(); |
| 462 | 464 |
| 463 trans->reset(transaction); | 465 trans->reset(transaction); |
| 464 return OK; | 466 return OK; |
| 465 } | 467 } |
| 466 | 468 |
| 467 HttpCache* HttpCache::GetCache() { | 469 HttpCache* HttpCache::GetCache() { |
| 468 return this; | 470 return this; |
| 469 } | 471 } |
| 470 | 472 |
| 471 HttpNetworkSession* HttpCache::GetSession() { | 473 HttpNetworkSession* HttpCache::GetSession() { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 | 579 |
| 578 // We keep track of doomed entries so that we can ensure that they are | 580 // We keep track of doomed entries so that we can ensure that they are |
| 579 // cleaned up properly when the cache is destroyed. | 581 // cleaned up properly when the cache is destroyed. |
| 580 ActiveEntry* entry_ptr = entry.get(); | 582 ActiveEntry* entry_ptr = entry.get(); |
| 581 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); | 583 DCHECK_EQ(0u, doomed_entries_.count(entry_ptr)); |
| 582 doomed_entries_[entry_ptr] = std::move(entry); | 584 doomed_entries_[entry_ptr] = std::move(entry); |
| 583 | 585 |
| 584 entry_ptr->disk_entry->Doom(); | 586 entry_ptr->disk_entry->Doom(); |
| 585 entry_ptr->doomed = true; | 587 entry_ptr->doomed = true; |
| 586 | 588 |
| 587 DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() || | 589 DCHECK(entry_ptr->writer || entry_ptr->shared_writers || |
| 588 entry_ptr->will_process_pending_queue); | 590 !entry_ptr->readers.empty() || entry_ptr->will_process_pending_queue); |
| 589 return OK; | 591 return OK; |
| 590 } | 592 } |
| 591 | 593 |
| 592 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { | 594 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { |
| 593 std::unique_ptr<WorkItem> item = | 595 std::unique_ptr<WorkItem> item = |
| 594 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); | 596 base::MakeUnique<WorkItem>(WI_DOOM_ENTRY, trans, nullptr); |
| 595 PendingOp* pending_op = GetPendingOp(key); | 597 PendingOp* pending_op = GetPendingOp(key); |
| 596 if (pending_op->writer) { | 598 if (pending_op->writer) { |
| 597 pending_op->pending_queue.push_back(std::move(item)); | 599 pending_op->pending_queue.push_back(std::move(item)); |
| 598 return ERR_IO_PENDING; | 600 return ERR_IO_PENDING; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 625 // Defer to DoomEntry if there is an active entry, otherwise call | 627 // Defer to DoomEntry if there is an active entry, otherwise call |
| 626 // AsyncDoomEntry without triggering a callback. | 628 // AsyncDoomEntry without triggering a callback. |
| 627 if (active_entries_.count(key)) | 629 if (active_entries_.count(key)) |
| 628 DoomEntry(key, NULL); | 630 DoomEntry(key, NULL); |
| 629 else | 631 else |
| 630 AsyncDoomEntry(key, NULL); | 632 AsyncDoomEntry(key, NULL); |
| 631 } | 633 } |
| 632 | 634 |
| 633 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { | 635 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { |
| 634 DCHECK(entry->doomed); | 636 DCHECK(entry->doomed); |
| 635 DCHECK(!entry->writer); | 637 DCHECK(!entry->writer && !entry->shared_writers); |
| 636 DCHECK(entry->readers.empty()); | 638 DCHECK(entry->readers.empty()); |
| 637 DCHECK(entry->pending_queue.empty()); | 639 DCHECK(entry->pending_queue.empty()); |
| 638 | 640 |
| 639 auto it = doomed_entries_.find(entry); | 641 auto it = doomed_entries_.find(entry); |
| 640 DCHECK(it != doomed_entries_.end()); | 642 DCHECK(it != doomed_entries_.end()); |
| 641 doomed_entries_.erase(it); | 643 doomed_entries_.erase(it); |
| 642 } | 644 } |
| 643 | 645 |
| 644 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { | 646 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { |
| 645 auto it = active_entries_.find(key); | 647 auto it = active_entries_.find(key); |
| 646 return it != active_entries_.end() ? it->second.get() : NULL; | 648 return it != active_entries_.end() ? it->second.get() : NULL; |
| 647 } | 649 } |
| 648 | 650 |
| 649 HttpCache::ActiveEntry* HttpCache::ActivateEntry( | 651 HttpCache::ActiveEntry* HttpCache::ActivateEntry( |
| 650 disk_cache::Entry* disk_entry) { | 652 disk_cache::Entry* disk_entry) { |
| 651 DCHECK(!FindActiveEntry(disk_entry->GetKey())); | 653 DCHECK(!FindActiveEntry(disk_entry->GetKey())); |
| 652 ActiveEntry* entry = new ActiveEntry(disk_entry); | 654 ActiveEntry* entry = new ActiveEntry(disk_entry); |
| 653 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); | 655 active_entries_[disk_entry->GetKey()] = base::WrapUnique(entry); |
| 654 return entry; | 656 return entry; |
| 655 } | 657 } |
| 656 | 658 |
| 657 void HttpCache::DeactivateEntry(ActiveEntry* entry) { | 659 void HttpCache::DeactivateEntry(ActiveEntry* entry) { |
| 658 DCHECK(!entry->will_process_pending_queue); | 660 DCHECK(!entry->will_process_pending_queue); |
| 659 DCHECK(!entry->doomed); | 661 DCHECK(!entry->doomed); |
| 660 DCHECK(!entry->writer); | 662 DCHECK(!entry->writer && !entry->shared_writers); |
| 661 DCHECK(entry->disk_entry); | 663 DCHECK(entry->disk_entry); |
| 662 DCHECK(entry->readers.empty()); | 664 DCHECK(entry->readers.empty()); |
| 663 DCHECK(entry->pending_queue.empty()); | 665 DCHECK(entry->pending_queue.empty()); |
| 664 | 666 |
| 665 std::string key = entry->disk_entry->GetKey(); | 667 std::string key = entry->disk_entry->GetKey(); |
| 666 if (key.empty()) | 668 if (key.empty()) |
| 667 return SlowDeactivateEntry(entry); | 669 return SlowDeactivateEntry(entry); |
| 668 | 670 |
| 669 auto it = active_entries_.find(key); | 671 auto it = active_entries_.find(key); |
| 670 DCHECK(it != active_entries_.end()); | 672 DCHECK(it != active_entries_.end()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 FinalizeDoomedEntry(entry); | 786 FinalizeDoomedEntry(entry); |
| 785 } else { | 787 } else { |
| 786 DeactivateEntry(entry); | 788 DeactivateEntry(entry); |
| 787 } | 789 } |
| 788 } | 790 } |
| 789 | 791 |
| 790 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { | 792 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { |
| 791 DCHECK(entry); | 793 DCHECK(entry); |
| 792 DCHECK(entry->disk_entry); | 794 DCHECK(entry->disk_entry); |
| 793 | 795 |
| 794 // We implement a basic reader/writer lock for the disk cache entry. If | 796 // If a writer is in the validation stage, all other transactions need to wait |
| 795 // there is already a writer, then everyone has to wait for the writer to | 797 // before they can access the cache entry. Once the validation stage is over |
| 796 // finish before they can access the cache entry. There can be multiple | 798 // and if the writer creates a SharedWriters object, other eligible |
| 797 // readers. | 799 // transactions will become equally privileged to be able to read from the |
| 800 // network and write to the cache. |
| 798 // | 801 // |
| 799 // NOTE: If the transaction can only write, then the entry should not be in | 802 // NOTE: If the transaction can only write, then the entry should not be in |
| 800 // use (since any existing entry should have already been doomed). | 803 // use (since any existing entry should have already been doomed). |
| 801 | |
| 802 if (entry->writer || entry->will_process_pending_queue) { | 804 if (entry->writer || entry->will_process_pending_queue) { |
| 803 entry->pending_queue.push_back(trans); | 805 entry->pending_queue.push_back(trans); |
| 804 return ERR_IO_PENDING; | 806 return ERR_IO_PENDING; |
| 805 } | 807 } |
| 806 | 808 |
| 807 if (trans->mode() & Transaction::WRITE) { | 809 if (entry->shared_writers) { |
| 810 DCHECK(!entry->writer); |
| 811 if (!trans->IsEligibleForSharedWriting() || |
| 812 !entry->shared_writers->CanAddNewTransaction()) { |
| 813 entry->pending_queue.push_back(trans); |
| 814 return ERR_IO_PENDING; |
| 815 } else { |
| 816 return entry->shared_writers->AddTransaction(trans); |
| 817 } |
| 818 } else if (trans->mode() & Transaction::WRITE) { // No SharedWriters. |
| 808 // transaction needs exclusive access to the entry | 819 // transaction needs exclusive access to the entry |
| 809 if (entry->readers.empty()) { | 820 if (entry->readers.empty()) { |
| 810 entry->writer = trans; | 821 entry->writer = trans; |
| 811 } else { | 822 } else { |
| 812 entry->pending_queue.push_back(trans); | 823 entry->pending_queue.push_back(trans); |
| 813 return ERR_IO_PENDING; | 824 return ERR_IO_PENDING; |
| 814 } | 825 } |
| 815 } else { | 826 } else { |
| 816 // transaction needs read access to the entry | 827 // transaction needs read access to the entry |
| 817 entry->readers.push_back(trans); | 828 entry->readers.insert(trans); |
| 818 } | 829 } |
| 819 | 830 |
| 820 // We do this before calling EntryAvailable to force any further calls to | 831 // We do this before calling EntryAvailable to force any further calls to |
| 821 // AddTransactionToEntry to add their transaction to the pending queue, which | 832 // AddTransactionToEntry to add their transaction to the pending queue, which |
| 822 // ensures FIFO ordering. | 833 // ensures FIFO ordering. |
| 823 if (!entry->writer && !entry->pending_queue.empty()) | 834 if (!entry->writer && !entry->pending_queue.empty()) |
| 824 ProcessPendingQueue(entry); | 835 ProcessPendingQueue(entry); |
| 825 | 836 |
| 826 return OK; | 837 return OK; |
| 827 } | 838 } |
| 828 | 839 |
| 829 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, | 840 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, |
| 830 bool cancel) { | 841 bool cancel) { |
| 842 DCHECK(!trans->shared()); |
| 843 |
| 831 // If we already posted a task to move on to the next transaction and this was | 844 // If we already posted a task to move on to the next transaction and this was |
| 832 // the writer, there is nothing to cancel. | 845 // the writer, there is nothing to cancel. |
| 833 if (entry->will_process_pending_queue && entry->readers.empty()) | 846 if (entry->will_process_pending_queue && entry->readers.empty()) |
| 834 return; | 847 return; |
| 835 | 848 |
| 836 if (entry->writer) { | 849 if (entry->writer) { |
| 837 DCHECK(trans == entry->writer); | 850 DCHECK(trans == entry->writer); |
| 838 | |
| 839 // Assume there was a failure. | 851 // Assume there was a failure. |
| 840 bool success = false; | 852 bool success = false; |
| 841 if (cancel) { | 853 if (cancel) { |
| 842 DCHECK(entry->disk_entry); | 854 DCHECK(entry->disk_entry); |
| 843 // This is a successful operation in the sense that we want to keep the | 855 // This is a successful operation in the sense that we want to keep the |
| 844 // entry. | 856 // entry. |
| 845 success = trans->AddTruncatedFlag(); | 857 success = trans->AddTruncatedFlag(); |
| 846 // The previous operation may have deleted the entry. | 858 // The previous operation may have deleted the entry. |
| 847 if (!trans->entry()) | 859 if (!trans->entry()) |
| 848 return; | 860 return; |
| 849 } | 861 } |
| 850 DoneWritingToEntry(entry, success); | 862 DoneWritingToEntry(entry, success); |
| 851 } else { | 863 } else { |
| 852 DoneReadingFromEntry(entry, trans); | 864 DoneReadingFromEntry(entry, trans); |
| 853 } | 865 } |
| 854 } | 866 } |
| 855 | 867 |
| 856 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { | 868 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { |
| 857 DCHECK(entry->readers.empty()); | 869 DCHECK(entry->readers.empty()); |
| 870 DCHECK(!entry->shared_writers); |
| 858 | 871 |
| 859 entry->writer = NULL; | 872 entry->writer = NULL; |
| 860 | 873 |
| 861 if (success) { | 874 if (success) { |
| 862 ProcessPendingQueue(entry); | 875 ProcessPendingQueue(entry); |
| 863 } else { | 876 } else { |
| 864 DCHECK(!entry->will_process_pending_queue); | 877 DestroyEntryRestartPendingQueue(entry); |
| 878 } |
| 879 } |
| 865 | 880 |
| 866 // We failed to create this entry. | 881 void HttpCache::DestroyEntryRestartPendingQueue(ActiveEntry* entry) { |
| 867 TransactionList pending_queue; | 882 DCHECK(!entry->will_process_pending_queue); |
| 868 pending_queue.swap(entry->pending_queue); | |
| 869 | 883 |
| 870 entry->disk_entry->Doom(); | 884 // We failed to create this entry. |
| 871 DestroyEntry(entry); | 885 TransactionList pending_queue; |
| 886 pending_queue.swap(entry->pending_queue); |
| 872 | 887 |
| 873 // We need to do something about these pending entries, which now need to | 888 entry->disk_entry->Doom(); |
| 874 // be added to a new entry. | 889 |
| 875 while (!pending_queue.empty()) { | 890 DestroyEntry(entry); |
| 876 // ERR_CACHE_RACE causes the transaction to restart the whole process. | 891 |
| 877 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); | 892 // We need to do something about these pending entries, which now need to |
| 878 pending_queue.pop_front(); | 893 // be added to a new entry. |
| 879 } | 894 while (!pending_queue.empty()) { |
| 895 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 896 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 897 pending_queue.pop_front(); |
| 880 } | 898 } |
| 881 } | 899 } |
| 882 | 900 |
| 883 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { | 901 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { |
| 884 DCHECK(!entry->writer); | 902 DCHECK(!entry->writer && !entry->shared_writers); |
| 885 | 903 |
| 886 auto it = std::find(entry->readers.begin(), entry->readers.end(), trans); | 904 auto it = entry->readers.find(trans); |
| 887 DCHECK(it != entry->readers.end()); | 905 DCHECK(it != entry->readers.end()); |
| 888 | 906 |
| 889 entry->readers.erase(it); | 907 entry->readers.erase(it); |
| 890 | 908 |
| 891 ProcessPendingQueue(entry); | 909 ProcessPendingQueue(entry); |
| 892 } | 910 } |
| 893 | 911 |
| 894 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { | 912 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { |
| 895 DCHECK(entry->writer); | 913 DCHECK(entry->writer); |
| 896 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); | 914 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); |
| 897 DCHECK(entry->readers.empty()); | 915 DCHECK(entry->readers.empty()); |
| 898 | 916 |
| 899 Transaction* trans = entry->writer; | 917 Transaction* trans = entry->writer; |
| 900 | 918 |
| 901 entry->writer = NULL; | 919 entry->writer = NULL; |
| 902 entry->readers.push_back(trans); | 920 entry->readers.insert(trans); |
| 903 | 921 |
| 904 ProcessPendingQueue(entry); | 922 ProcessPendingQueue(entry); |
| 905 } | 923 } |
| 906 | 924 |
| 907 LoadState HttpCache::GetLoadStateForPendingTransaction( | 925 LoadState HttpCache::GetLoadStateForPendingTransaction( |
| 908 const Transaction* trans) { | 926 const Transaction* trans) { |
| 909 auto i = active_entries_.find(trans->key()); | 927 auto i = active_entries_.find(trans->key()); |
| 910 if (i == active_entries_.end()) { | 928 if (i == active_entries_.end()) { |
| 911 // If this is really a pending transaction, and it is not part of | 929 // If this is really a pending transaction, and it is not part of |
| 912 // active_entries_, we should be creating the backend or the entry. | 930 // active_entries_, we should be creating the backend or the entry. |
| 913 return LOAD_STATE_WAITING_FOR_CACHE; | 931 return LOAD_STATE_WAITING_FOR_CACHE; |
| 914 } | 932 } |
| 915 | 933 |
| 916 Transaction* writer = i->second->writer; | 934 Transaction* writer = i->second->writer; |
| 917 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; | 935 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; |
| 918 } | 936 } |
| 919 | 937 |
| 920 void HttpCache::RemovePendingTransaction(Transaction* trans) { | 938 void HttpCache::RemovePendingTransaction(Transaction* trans) { |
| 939 bool found = false; |
| 940 |
| 921 auto i = active_entries_.find(trans->key()); | 941 auto i = active_entries_.find(trans->key()); |
| 922 bool found = false; | |
| 923 if (i != active_entries_.end()) | 942 if (i != active_entries_.end()) |
| 924 found = RemovePendingTransactionFromEntry(i->second.get(), trans); | 943 found = RemovePendingTransactionFromEntry(i->second.get(), trans); |
| 925 | 944 |
| 926 if (found) | 945 if (found) |
| 927 return; | 946 return; |
| 928 | 947 |
| 929 if (building_backend_) { | 948 if (building_backend_) { |
| 930 auto j = pending_ops_.find(std::string()); | 949 auto j = pending_ops_.find(std::string()); |
| 931 if (j != pending_ops_.end()) | 950 if (j != pending_ops_.end()) |
| 932 found = RemovePendingTransactionFromPendingOp(j->second, trans); | 951 found = RemovePendingTransactionFromPendingOp(j->second, trans); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 945 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; | 964 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; |
| 946 ++k) { | 965 ++k) { |
| 947 found = RemovePendingTransactionFromEntry(k->first, trans); | 966 found = RemovePendingTransactionFromEntry(k->first, trans); |
| 948 } | 967 } |
| 949 | 968 |
| 950 DCHECK(found) << "Pending transaction not found"; | 969 DCHECK(found) << "Pending transaction not found"; |
| 951 } | 970 } |
| 952 | 971 |
| 953 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, | 972 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, |
| 954 Transaction* trans) { | 973 Transaction* trans) { |
| 974 if (trans->shared()) |
| 975 return entry->shared_writers->RemoveWaitingForValidationTransaction(trans); |
| 976 |
| 955 TransactionList& pending_queue = entry->pending_queue; | 977 TransactionList& pending_queue = entry->pending_queue; |
| 956 | |
| 957 auto j = find(pending_queue.begin(), pending_queue.end(), trans); | 978 auto j = find(pending_queue.begin(), pending_queue.end(), trans); |
| 958 if (j == pending_queue.end()) | 979 if (j == pending_queue.end()) |
| 959 return false; | 980 return false; |
| 960 | |
| 961 pending_queue.erase(j); | 981 pending_queue.erase(j); |
| 962 return true; | 982 return true; |
| 963 } | 983 } |
| 964 | 984 |
| 965 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, | 985 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, |
| 966 Transaction* trans) { | 986 Transaction* trans) { |
| 967 if (pending_op->writer->Matches(trans)) { | 987 if (pending_op->writer->Matches(trans)) { |
| 968 pending_op->writer->ClearTransaction(); | 988 pending_op->writer->ClearTransaction(); |
| 969 pending_op->writer->ClearEntry(); | 989 pending_op->writer->ClearEntry(); |
| 970 return true; | 990 return true; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 988 return; | 1008 return; |
| 989 entry->will_process_pending_queue = true; | 1009 entry->will_process_pending_queue = true; |
| 990 | 1010 |
| 991 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1011 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 992 FROM_HERE, | 1012 FROM_HERE, |
| 993 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1013 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 994 } | 1014 } |
| 995 | 1015 |
| 996 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1016 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 997 entry->will_process_pending_queue = false; | 1017 entry->will_process_pending_queue = false; |
| 998 DCHECK(!entry->writer); | 1018 DCHECK(!entry->writer && !entry->shared_writers); |
| 999 | 1019 |
| 1000 // If no one is interested in this entry, then we can deactivate it. | 1020 // If no one is interested in this entry, then we can deactivate it. |
| 1001 if (entry->pending_queue.empty()) { | 1021 if (entry->pending_queue.empty()) { |
| 1002 if (entry->readers.empty()) | 1022 if (entry->readers.empty()) |
| 1003 DestroyEntry(entry); | 1023 DestroyEntry(entry); |
| 1004 return; | 1024 return; |
| 1005 } | 1025 } |
| 1006 | 1026 |
| 1007 // Promote next transaction from the pending queue. | 1027 // Promote next transaction from the pending queue. |
| 1008 Transaction* next = entry->pending_queue.front(); | 1028 Transaction* next = entry->pending_queue.front(); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 } else { | 1173 } else { |
| 1154 building_backend_ = false; | 1174 building_backend_ = false; |
| 1155 DeletePendingOp(pending_op); | 1175 DeletePendingOp(pending_op); |
| 1156 } | 1176 } |
| 1157 | 1177 |
| 1158 // The cache may be gone when we return from the callback. | 1178 // The cache may be gone when we return from the callback. |
| 1159 if (!item->DoCallback(result, disk_cache_.get())) | 1179 if (!item->DoCallback(result, disk_cache_.get())) |
| 1160 item->NotifyTransaction(result, NULL); | 1180 item->NotifyTransaction(result, NULL); |
| 1161 } | 1181 } |
| 1162 | 1182 |
| 1183 bool HttpCache::IsResponseCompleted(const ActiveEntry* entry, |
| 1184 const HttpResponseInfo* response_info) { |
| 1185 int current_size = entry->disk_entry->GetDataSize(kResponseContentIndex); |
| 1186 int64_t content_length = response_info->headers->GetContentLength(); |
| 1187 if ((content_length >= 0 && content_length <= current_size) || |
| 1188 content_length < 0) |
| 1189 return true; |
| 1190 return false; |
| 1191 } |
| 1192 |
| 1193 int HttpCache::WriteResponseInfo(ActiveEntry* entry, |
| 1194 const HttpResponseInfo* response, |
| 1195 CompletionCallback& callback, |
| 1196 bool truncated, |
| 1197 int* io_buf_len) { |
| 1198 // When writing headers, we normally only write the non-transient headers. |
| 1199 bool skip_transient_headers = true; |
| 1200 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
| 1201 response->Persist(data->pickle(), skip_transient_headers, truncated); |
| 1202 data->Done(); |
| 1203 |
| 1204 *io_buf_len = data->pickle()->size(); |
| 1205 return entry->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), |
| 1206 *io_buf_len, callback, true); |
| 1207 } |
| 1208 |
| 1209 // Histogram data from the end of 2010 show the following distribution of |
| 1210 // response headers: |
| 1211 // |
| 1212 // Content-Length............... 87% |
| 1213 // Date......................... 98% |
| 1214 // Last-Modified................ 49% |
| 1215 // Etag......................... 19% |
| 1216 // Accept-Ranges: bytes......... 25% |
| 1217 // Accept-Ranges: none.......... 0.4% |
| 1218 // Strong Validator............. 50% |
| 1219 // Strong Validator + ranges.... 24% |
| 1220 // Strong Validator + CL........ 49% |
| 1221 // |
| 1222 bool HttpCache::CanResumeEntry(bool has_data, |
| 1223 const std::string& method, |
| 1224 const HttpResponseInfo* response, |
| 1225 ActiveEntry* entry) { |
| 1226 // Double check that there is something worth keeping. |
| 1227 if (has_data && !entry->disk_entry->GetDataSize(kResponseContentIndex)) |
| 1228 return false; |
| 1229 |
| 1230 if (method != "GET") |
| 1231 return false; |
| 1232 |
| 1233 // Note that if this is a 206, content-length was already fixed after calling |
| 1234 // PartialData::ResponseHeadersOK(). |
| 1235 if (response->headers->GetContentLength() <= 0 || |
| 1236 response->headers->HasHeaderValue("Accept-Ranges", "none") || |
| 1237 !response->headers->HasStrongValidators()) { |
| 1238 return false; |
| 1239 } |
| 1240 |
| 1241 return true; |
| 1242 } |
| 1243 |
| 1244 void HttpCache::ResponseDoneSharedWriters(ActiveEntry* entry, |
| 1245 bool success, |
| 1246 bool* destroyed) { |
| 1247 DCHECK(entry->shared_writers->empty()); |
| 1248 entry->shared_writers.reset(); |
| 1249 *destroyed = true; |
| 1250 |
| 1251 if (success) |
| 1252 ProcessPendingQueue(entry); |
| 1253 else |
| 1254 DestroyEntryRestartPendingQueue(entry); |
| 1255 } |
| 1256 |
| 1257 void HttpCache::ResetSharedWriters(ActiveEntry* entry) { |
| 1258 DCHECK(entry->shared_writers->empty()); |
| 1259 entry->shared_writers.reset(); |
| 1260 } |
| 1261 |
| 1262 void HttpCache::DoomEntryRestartPendingQueue(const std::string& key, |
| 1263 ActiveEntry* entry) { |
| 1264 DoomActiveEntry(key); |
| 1265 // We need to do something about these pending entries, which now need to |
| 1266 // be added to a new entry. |
| 1267 while (!entry->pending_queue.empty()) { |
| 1268 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 1269 entry->pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 1270 entry->pending_queue.pop_front(); |
| 1271 } |
| 1272 } |
| 1273 |
| 1274 void HttpCache::ResetSharedWritersProcessPendingQueue(ActiveEntry* entry) { |
| 1275 if (entry->shared_writers->empty()) { |
| 1276 entry->shared_writers.reset(); |
| 1277 DCHECK(!entry->writer); |
| 1278 ProcessPendingQueue(entry); |
| 1279 } |
| 1280 } |
| 1281 |
| 1282 void HttpCache::RemovedSharedWriterTransaction(Transaction* transaction, |
| 1283 ActiveEntry* entry) { |
| 1284 if (entry->shared_writers->empty()) { |
| 1285 bool success = false; |
| 1286 success = transaction->AddTruncatedFlag(); |
| 1287 if (success) { |
| 1288 ResetSharedWritersProcessPendingQueue(entry); |
| 1289 } else { |
| 1290 entry->shared_writers.reset(); |
| 1291 DestroyEntryRestartPendingQueue(entry); |
| 1292 } |
| 1293 } |
| 1294 } |
| 1295 |
| 1163 } // namespace net | 1296 } // namespace net |
| OLD | NEW |