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

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

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Josh's early feedback addressed. Created 3 years, 10 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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698