| 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 if (entry->shared_writers->AddTransaction(trans)) { |
| 817 return OK; |
| 818 } else { |
| 819 // Another transaction is in the process of validation, wait for it and |
| 820 // any other transactions already in the queue to complete. |
| 821 return ERR_IO_PENDING; |
| 822 } |
| 823 } |
| 824 } else if (trans->mode() & Transaction::WRITE) { // No SharedWriters. |
| 808 // transaction needs exclusive access to the entry | 825 // transaction needs exclusive access to the entry |
| 809 if (entry->readers.empty()) { | 826 if (entry->readers.empty()) { |
| 810 entry->writer = trans; | 827 entry->writer = trans; |
| 811 } else { | 828 } else { |
| 812 entry->pending_queue.push_back(trans); | 829 entry->pending_queue.push_back(trans); |
| 813 return ERR_IO_PENDING; | 830 return ERR_IO_PENDING; |
| 814 } | 831 } |
| 815 } else { | 832 } else { |
| 816 // transaction needs read access to the entry | 833 // transaction needs read access to the entry |
| 817 entry->readers.push_back(trans); | 834 entry->readers.insert(trans); |
| 818 } | 835 } |
| 819 | 836 |
| 820 // We do this before calling EntryAvailable to force any further calls to | 837 // We do this before calling EntryAvailable to force any further calls to |
| 821 // AddTransactionToEntry to add their transaction to the pending queue, which | 838 // AddTransactionToEntry to add their transaction to the pending queue, which |
| 822 // ensures FIFO ordering. | 839 // ensures FIFO ordering. |
| 823 if (!entry->writer && !entry->pending_queue.empty()) | 840 if (!entry->writer && !entry->pending_queue.empty()) |
| 824 ProcessPendingQueue(entry); | 841 ProcessPendingQueue(entry); |
| 825 | 842 |
| 826 return OK; | 843 return OK; |
| 827 } | 844 } |
| 828 | 845 |
| 829 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, | 846 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, |
| 830 bool cancel) { | 847 bool cancel) { |
| 848 DCHECK(!trans->shared()); |
| 849 |
| 831 // 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 |
| 832 // the writer, there is nothing to cancel. | 851 // the writer, there is nothing to cancel. |
| 833 if (entry->will_process_pending_queue && entry->readers.empty()) | 852 if (entry->will_process_pending_queue && entry->readers.empty()) |
| 834 return; | 853 return; |
| 835 | 854 |
| 836 if (entry->writer) { | 855 if (entry->writer) { |
| 837 DCHECK(trans == entry->writer); | 856 DCHECK(trans == entry->writer); |
| 838 | |
| 839 // Assume there was a failure. | 857 // Assume there was a failure. |
| 840 bool success = false; | 858 bool success = false; |
| 841 if (cancel) { | 859 if (cancel) { |
| 842 DCHECK(entry->disk_entry); | 860 DCHECK(entry->disk_entry); |
| 843 // 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 |
| 844 // entry. | 862 // entry. |
| 845 success = trans->AddTruncatedFlag(); | 863 success = trans->AddTruncatedFlag(); |
| 846 // The previous operation may have deleted the entry. | 864 // The previous operation may have deleted the entry. |
| 847 if (!trans->entry()) | 865 if (!trans->entry()) |
| 848 return; | 866 return; |
| 849 } | 867 } |
| 850 DoneWritingToEntry(entry, success); | 868 DoneWritingToEntry(entry, success); |
| 851 } else { | 869 } else { |
| 852 DoneReadingFromEntry(entry, trans); | 870 DoneReadingFromEntry(entry, trans); |
| 853 } | 871 } |
| 854 } | 872 } |
| 855 | 873 |
| 856 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { | 874 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { |
| 857 DCHECK(entry->readers.empty()); | 875 DCHECK(entry->readers.empty()); |
| 876 DCHECK(!entry->shared_writers); |
| 858 | 877 |
| 859 entry->writer = NULL; | 878 entry->writer = NULL; |
| 860 | 879 |
| 861 if (success) { | 880 if (success) { |
| 862 ProcessPendingQueue(entry); | 881 ProcessPendingQueue(entry); |
| 863 } else { | 882 } else { |
| 864 DCHECK(!entry->will_process_pending_queue); | 883 DestroyEntryRestartPendingQueue(entry); |
| 884 } |
| 885 } |
| 865 | 886 |
| 866 // We failed to create this entry. | 887 void HttpCache::DestroyEntryRestartPendingQueue(ActiveEntry* entry) { |
| 867 TransactionList pending_queue; | 888 DCHECK(!entry->will_process_pending_queue); |
| 868 pending_queue.swap(entry->pending_queue); | |
| 869 | 889 |
| 870 entry->disk_entry->Doom(); | 890 // We failed to create this entry. |
| 871 DestroyEntry(entry); | 891 TransactionList pending_queue; |
| 892 pending_queue.swap(entry->pending_queue); |
| 872 | 893 |
| 873 // We need to do something about these pending entries, which now need to | 894 entry->disk_entry->Doom(); |
| 874 // be added to a new entry. | 895 |
| 875 while (!pending_queue.empty()) { | 896 DestroyEntry(entry); |
| 876 // ERR_CACHE_RACE causes the transaction to restart the whole process. | 897 |
| 877 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); | 898 // We need to do something about these pending entries, which now need to |
| 878 pending_queue.pop_front(); | 899 // be added to a new entry. |
| 879 } | 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(); |
| 880 } | 904 } |
| 881 } | 905 } |
| 882 | 906 |
| 883 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { | 907 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { |
| 884 DCHECK(!entry->writer); | 908 DCHECK(!entry->writer && !entry->shared_writers); |
| 885 | 909 |
| 886 auto it = std::find(entry->readers.begin(), entry->readers.end(), trans); | 910 auto it = entry->readers.find(trans); |
| 887 DCHECK(it != entry->readers.end()); | 911 DCHECK(it != entry->readers.end()); |
| 888 | 912 |
| 889 entry->readers.erase(it); | 913 entry->readers.erase(it); |
| 890 | 914 |
| 891 ProcessPendingQueue(entry); | 915 ProcessPendingQueue(entry); |
| 892 } | 916 } |
| 893 | 917 |
| 894 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { | 918 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { |
| 895 DCHECK(entry->writer); | 919 DCHECK(entry->writer); |
| 896 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); | 920 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); |
| 897 DCHECK(entry->readers.empty()); | 921 DCHECK(entry->readers.empty()); |
| 898 | 922 |
| 899 Transaction* trans = entry->writer; | 923 Transaction* trans = entry->writer; |
| 900 | 924 |
| 901 entry->writer = NULL; | 925 entry->writer = NULL; |
| 902 entry->readers.push_back(trans); | 926 entry->readers.insert(trans); |
| 903 | 927 |
| 904 ProcessPendingQueue(entry); | 928 ProcessPendingQueue(entry); |
| 905 } | 929 } |
| 906 | 930 |
| 907 LoadState HttpCache::GetLoadStateForPendingTransaction( | 931 LoadState HttpCache::GetLoadStateForPendingTransaction( |
| 908 const Transaction* trans) { | 932 const Transaction* trans) { |
| 909 auto i = active_entries_.find(trans->key()); | 933 auto i = active_entries_.find(trans->key()); |
| 910 if (i == active_entries_.end()) { | 934 if (i == active_entries_.end()) { |
| 911 // If this is really a pending transaction, and it is not part of | 935 // 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. | 936 // active_entries_, we should be creating the backend or the entry. |
| 913 return LOAD_STATE_WAITING_FOR_CACHE; | 937 return LOAD_STATE_WAITING_FOR_CACHE; |
| 914 } | 938 } |
| 915 | 939 |
| 916 Transaction* writer = i->second->writer; | 940 Transaction* writer = i->second->writer; |
| 917 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; | 941 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; |
| 918 } | 942 } |
| 919 | 943 |
| 920 void HttpCache::RemovePendingTransaction(Transaction* trans) { | 944 void HttpCache::RemovePendingTransaction(Transaction* trans) { |
| 945 bool found = false; |
| 946 |
| 921 auto i = active_entries_.find(trans->key()); | 947 auto i = active_entries_.find(trans->key()); |
| 922 bool found = false; | |
| 923 if (i != active_entries_.end()) | 948 if (i != active_entries_.end()) |
| 924 found = RemovePendingTransactionFromEntry(i->second.get(), trans); | 949 found = RemovePendingTransactionFromEntry(i->second.get(), trans); |
| 925 | 950 |
| 926 if (found) | 951 if (found) |
| 927 return; | 952 return; |
| 928 | 953 |
| 929 if (building_backend_) { | 954 if (building_backend_) { |
| 930 auto j = pending_ops_.find(std::string()); | 955 auto j = pending_ops_.find(std::string()); |
| 931 if (j != pending_ops_.end()) | 956 if (j != pending_ops_.end()) |
| 932 found = RemovePendingTransactionFromPendingOp(j->second, trans); | 957 found = RemovePendingTransactionFromPendingOp(j->second, trans); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 945 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; | 970 for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found; |
| 946 ++k) { | 971 ++k) { |
| 947 found = RemovePendingTransactionFromEntry(k->first, trans); | 972 found = RemovePendingTransactionFromEntry(k->first, trans); |
| 948 } | 973 } |
| 949 | 974 |
| 950 DCHECK(found) << "Pending transaction not found"; | 975 DCHECK(found) << "Pending transaction not found"; |
| 951 } | 976 } |
| 952 | 977 |
| 953 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, | 978 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, |
| 954 Transaction* trans) { | 979 Transaction* trans) { |
| 980 if (trans->shared()) |
| 981 return entry->shared_writers->RemoveWaitingTransaction(trans); |
| 982 |
| 955 TransactionList& pending_queue = entry->pending_queue; | 983 TransactionList& pending_queue = entry->pending_queue; |
| 956 | |
| 957 auto j = find(pending_queue.begin(), pending_queue.end(), trans); | 984 auto j = find(pending_queue.begin(), pending_queue.end(), trans); |
| 958 if (j == pending_queue.end()) | 985 if (j == pending_queue.end()) |
| 959 return false; | 986 return false; |
| 960 | |
| 961 pending_queue.erase(j); | 987 pending_queue.erase(j); |
| 962 return true; | 988 return true; |
| 963 } | 989 } |
| 964 | 990 |
| 965 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, | 991 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, |
| 966 Transaction* trans) { | 992 Transaction* trans) { |
| 967 if (pending_op->writer->Matches(trans)) { | 993 if (pending_op->writer->Matches(trans)) { |
| 968 pending_op->writer->ClearTransaction(); | 994 pending_op->writer->ClearTransaction(); |
| 969 pending_op->writer->ClearEntry(); | 995 pending_op->writer->ClearEntry(); |
| 970 return true; | 996 return true; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 988 return; | 1014 return; |
| 989 entry->will_process_pending_queue = true; | 1015 entry->will_process_pending_queue = true; |
| 990 | 1016 |
| 991 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1017 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 992 FROM_HERE, | 1018 FROM_HERE, |
| 993 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1019 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 994 } | 1020 } |
| 995 | 1021 |
| 996 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1022 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 997 entry->will_process_pending_queue = false; | 1023 entry->will_process_pending_queue = false; |
| 998 DCHECK(!entry->writer); | 1024 DCHECK(!entry->writer && !entry->shared_writers); |
| 999 | 1025 |
| 1000 // If no one is interested in this entry, then we can deactivate it. | 1026 // If no one is interested in this entry, then we can deactivate it. |
| 1001 if (entry->pending_queue.empty()) { | 1027 if (entry->pending_queue.empty()) { |
| 1002 if (entry->readers.empty()) | 1028 if (entry->readers.empty()) |
| 1003 DestroyEntry(entry); | 1029 DestroyEntry(entry); |
| 1004 return; | 1030 return; |
| 1005 } | 1031 } |
| 1006 | 1032 |
| 1007 // Promote next transaction from the pending queue. | 1033 // Promote next transaction from the pending queue. |
| 1008 Transaction* next = entry->pending_queue.front(); | 1034 Transaction* next = entry->pending_queue.front(); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 } else { | 1179 } else { |
| 1154 building_backend_ = false; | 1180 building_backend_ = false; |
| 1155 DeletePendingOp(pending_op); | 1181 DeletePendingOp(pending_op); |
| 1156 } | 1182 } |
| 1157 | 1183 |
| 1158 // The cache may be gone when we return from the callback. | 1184 // The cache may be gone when we return from the callback. |
| 1159 if (!item->DoCallback(result, disk_cache_.get())) | 1185 if (!item->DoCallback(result, disk_cache_.get())) |
| 1160 item->NotifyTransaction(result, NULL); | 1186 item->NotifyTransaction(result, NULL); |
| 1161 } | 1187 } |
| 1162 | 1188 |
| 1189 bool HttpCache::IsResponseCompleted(const ActiveEntry* entry, |
| 1190 const HttpResponseInfo* response_info) { |
| 1191 int current_size = entry->disk_entry->GetDataSize(kResponseContentIndex); |
| 1192 int64_t content_length = response_info->headers->GetContentLength(); |
| 1193 if ((content_length >= 0 && content_length <= current_size) || |
| 1194 content_length < 0) |
| 1195 return true; |
| 1196 return false; |
| 1197 } |
| 1198 |
| 1199 int HttpCache::WriteResponseInfo(ActiveEntry* entry, |
| 1200 const HttpResponseInfo* response, |
| 1201 CompletionCallback& callback, |
| 1202 bool truncated, |
| 1203 int* io_buf_len) { |
| 1204 // When writing headers, we normally only write the non-transient headers. |
| 1205 bool skip_transient_headers = true; |
| 1206 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
| 1207 response->Persist(data->pickle(), skip_transient_headers, truncated); |
| 1208 data->Done(); |
| 1209 |
| 1210 *io_buf_len = data->pickle()->size(); |
| 1211 return entry->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), |
| 1212 *io_buf_len, callback, true); |
| 1213 } |
| 1214 |
| 1215 // Histogram data from the end of 2010 show the following distribution of |
| 1216 // response headers: |
| 1217 // |
| 1218 // Content-Length............... 87% |
| 1219 // Date......................... 98% |
| 1220 // Last-Modified................ 49% |
| 1221 // Etag......................... 19% |
| 1222 // Accept-Ranges: bytes......... 25% |
| 1223 // Accept-Ranges: none.......... 0.4% |
| 1224 // Strong Validator............. 50% |
| 1225 // Strong Validator + ranges.... 24% |
| 1226 // Strong Validator + CL........ 49% |
| 1227 // |
| 1228 bool HttpCache::CanResumeEntry(bool has_data, |
| 1229 const std::string& method, |
| 1230 const HttpResponseInfo* response, |
| 1231 ActiveEntry* entry) { |
| 1232 // Double check that there is something worth keeping. |
| 1233 if (has_data && !entry->disk_entry->GetDataSize(kResponseContentIndex)) |
| 1234 return false; |
| 1235 |
| 1236 if (method != "GET") |
| 1237 return false; |
| 1238 |
| 1239 // Note that if this is a 206, content-length was already fixed after calling |
| 1240 // PartialData::ResponseHeadersOK(). |
| 1241 if (response->headers->GetContentLength() <= 0 || |
| 1242 response->headers->HasHeaderValue("Accept-Ranges", "none") || |
| 1243 !response->headers->HasStrongValidators()) { |
| 1244 return false; |
| 1245 } |
| 1246 |
| 1247 return true; |
| 1248 } |
| 1249 |
| 1250 void HttpCache::CreateSharedWriters( |
| 1251 Transaction* cache_transaction, |
| 1252 std::unique_ptr<HttpTransaction> network_transaction, |
| 1253 RequestPriority priority) { |
| 1254 ActiveEntry* entry = cache_transaction->entry(); |
| 1255 DCHECK(!entry->shared_writers); |
| 1256 DCHECK_EQ(entry->writer, cache_transaction); |
| 1257 DCHECK(entry->readers.empty()); |
| 1258 entry->shared_writers.reset( |
| 1259 new HttpCache::SharedWriters(this, entry, cache_transaction, priority, |
| 1260 std::move(network_transaction))); |
| 1261 |
| 1262 // entry->writer should no longer exist as it is moved to |
| 1263 // shared_writers. |
| 1264 entry->writer = nullptr; |
| 1265 |
| 1266 // Add the eligible transactions to waiting_for_validation_ and process the |
| 1267 // first among them. After this, pending_queue will only contain transactions |
| 1268 // that are not eligible for shared writing. |
| 1269 entry->shared_writers->MoveFromPendingQueue(); |
| 1270 entry->shared_writers->ProcessFirstWaitingValidation(); |
| 1271 } |
| 1272 |
| 1273 void HttpCache::ResponseDoneSharedWriters(ActiveEntry* entry, |
| 1274 bool success, |
| 1275 bool* destroyed) { |
| 1276 DCHECK(entry->shared_writers->empty()); |
| 1277 entry->shared_writers.reset(); |
| 1278 *destroyed = true; |
| 1279 |
| 1280 if (success) |
| 1281 ProcessPendingQueue(entry); |
| 1282 else |
| 1283 DestroyEntryRestartPendingQueue(entry); |
| 1284 } |
| 1285 |
| 1286 void HttpCache::ResetSharedWriters(ActiveEntry* entry) { |
| 1287 DCHECK(entry->shared_writers->empty()); |
| 1288 entry->shared_writers.reset(); |
| 1289 } |
| 1290 |
| 1291 void HttpCache::DoomEntryRestartPendingQueue(const std::string& key, |
| 1292 ActiveEntry* entry) { |
| 1293 DoomActiveEntry(key); |
| 1294 // We need to do something about these pending entries, which now need to |
| 1295 // be added to a new entry. |
| 1296 while (!entry->pending_queue.empty()) { |
| 1297 // ERR_CACHE_RACE causes the transaction to restart the whole process. |
| 1298 entry->pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); |
| 1299 entry->pending_queue.pop_front(); |
| 1300 } |
| 1301 } |
| 1302 |
| 1303 void HttpCache::ResetSharedWritersProcessPendingQueue(ActiveEntry* entry) { |
| 1304 if (entry->shared_writers->empty()) { |
| 1305 entry->shared_writers.reset(); |
| 1306 DCHECK(!entry->writer); |
| 1307 ProcessPendingQueue(entry); |
| 1308 } |
| 1309 } |
| 1310 |
| 1311 void HttpCache::RemovedSharedWriterTransaction(Transaction* transaction, |
| 1312 ActiveEntry* entry) { |
| 1313 if (entry->shared_writers->empty()) { |
| 1314 bool success = false; |
| 1315 success = transaction->AddTruncatedFlag(); |
| 1316 if (success) { |
| 1317 ResetSharedWritersProcessPendingQueue(entry); |
| 1318 } else { |
| 1319 entry->shared_writers.reset(); |
| 1320 DestroyEntryRestartPendingQueue(entry); |
| 1321 } |
| 1322 } |
| 1323 } |
| 1324 |
| 1163 } // namespace net | 1325 } // namespace net |
| OLD | NEW |