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