Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: net/http/http_cache.cc

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

Powered by Google App Engine
This is Rietveld 408576698