Index: components/browsing_data/content/conditional_cache_counting_helper.cc |
diff --git a/components/browsing_data/content/conditional_cache_counting_helper.cc b/components/browsing_data/content/conditional_cache_counting_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8abbc5145b62ab1a08945371badab123004d9153 |
--- /dev/null |
+++ b/components/browsing_data/content/conditional_cache_counting_helper.cc |
@@ -0,0 +1,220 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/browsing_data/content/conditional_cache_counting_helper.h" |
+ |
+#include "base/callback.h" |
+#include "base/single_thread_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/storage_partition.h" |
+#include "net/disk_cache/disk_cache.h" |
+#include "net/http/http_cache.h" |
+#include "net/url_request/url_request_context.h" |
+#include "net/url_request/url_request_context_getter.h" |
+ |
+using content::BrowserThread; |
+ |
+namespace browsing_data { |
+ |
+// static. |
+ConditionalCacheCountingHelper* ConditionalCacheCountingHelper::CreateForRange( |
+ content::StoragePartition* storage_partition, |
+ base::Time begin_time, |
+ base::Time end_time) { |
+ return new ConditionalCacheCountingHelper( |
+ begin_time, end_time, storage_partition->GetURLRequestContext(), |
+ storage_partition->GetMediaURLRequestContext()); |
+} |
+ |
+ConditionalCacheCountingHelper::ConditionalCacheCountingHelper( |
+ base::Time begin_time, |
+ base::Time end_time, |
+ net::URLRequestContextGetter* main_context_getter, |
+ net::URLRequestContextGetter* media_context_getter) |
+ : calculation_result_(0), |
+ begin_time_(begin_time), |
+ end_time_(end_time), |
+ is_cancelled_(false), |
+ is_finished_(false), |
+ main_context_getter_(main_context_getter), |
+ media_context_getter_(media_context_getter), |
+ next_cache_state_(CacheState::NONE), |
+ cache_(nullptr), |
+ iterator_(nullptr), |
+ current_entry_(nullptr), |
+ weak_ptr_factory_(this) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+} |
+ |
+ConditionalCacheCountingHelper::~ConditionalCacheCountingHelper() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+} |
+ |
+base::WeakPtr<ConditionalCacheCountingHelper> |
+ConditionalCacheCountingHelper::CountAndDestroySelfWhenFinished( |
+ const CacheCountCallback& result_callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ DCHECK(!result_callback.is_null()); |
+ result_callback_ = result_callback; |
+ calculation_result_ = 0; |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&ConditionalCacheCountingHelper::CountHttpCacheOnIOThread, |
+ base::Unretained(this))); |
+ return weak_ptr_factory_.GetWeakPtr(); |
+} |
+ |
+void ConditionalCacheCountingHelper::CancelCounting() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(!is_finished_); |
+ is_cancelled_ = true; |
+} |
+ |
+bool ConditionalCacheCountingHelper::IsFinished() { |
+ return is_finished_; |
+} |
+ |
+void ConditionalCacheCountingHelper::Finished() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ DCHECK(!is_finished_); |
+ is_finished_ = true; |
+ result_callback_.Run(calculation_result_); |
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); |
+} |
+ |
+void ConditionalCacheCountingHelper::CountHttpCacheOnIOThread() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ next_cache_state_ = CacheState::NONE; |
+ DCHECK_EQ(CacheState::NONE, next_cache_state_); |
+ DCHECK(main_context_getter_.get()); |
+ DCHECK(media_context_getter_.get()); |
+ |
+ next_cache_state_ = CacheState::CREATE_MAIN; |
+ DoCountCache(net::OK); |
+} |
+ |
+// The expected state sequence is CacheState::NONE --> CacheState::CREATE_MAIN |
+// --> |
msramek
2016/12/20 01:03:00
nit: Why the line break?
dullweber
2016/12/21 10:29:19
Oh, I guess changing to an enum class made the lin
|
+// CacheState::PROCESS_MAIN --> CacheState::CREATE_MEDIA --> |
+// CacheState::PROCESS_MEDIA --> |
+// CacheState::DONE. On error, we jump directly to CacheState::DONE. |
+void ConditionalCacheCountingHelper::DoCountCache(int rv) { |
+ DCHECK_NE(CacheState::NONE, next_cache_state_); |
+ while (rv != net::ERR_IO_PENDING && next_cache_state_ != CacheState::NONE) { |
+ // On error, finish and return the error code. A valid result value might |
+ // be of two types - either net::OK from the CREATE states, or the result |
+ // of calculation from the PROCESS states. Since net::OK == 0, it is valid |
+ // to simply add the value to the final calculation result. |
+ if (rv < 0) { |
+ calculation_result_ = rv; |
+ next_cache_state_ = CacheState::DONE; |
+ } else { |
+ DCHECK_EQ(0, net::OK); |
+ calculation_result_ += rv; |
+ } |
+ |
+ switch (next_cache_state_) { |
+ case CacheState::CREATE_MAIN: |
+ case CacheState::CREATE_MEDIA: { |
+ // Get a pointer to the cache. |
+ net::URLRequestContextGetter* getter = |
+ (next_cache_state_ == CacheState::CREATE_MAIN) |
+ ? main_context_getter_.get() |
+ : media_context_getter_.get(); |
+ net::HttpCache* http_cache = getter->GetURLRequestContext() |
+ ->http_transaction_factory() |
+ ->GetCache(); |
+ |
+ next_cache_state_ = (next_cache_state_ == CacheState::CREATE_MAIN) |
+ ? CacheState::COUNT_MAIN |
+ : CacheState::COUNT_MEDIA; |
+ |
+ rv = http_cache->GetBackend( |
+ &cache_, base::Bind(&ConditionalCacheCountingHelper::DoCountCache, |
+ base::Unretained(this))); |
+ break; |
+ } |
+ case CacheState::COUNT_MAIN: |
+ case CacheState::COUNT_MEDIA: { |
+ next_cache_state_ = (next_cache_state_ == CacheState::COUNT_MAIN) |
+ ? CacheState::CREATE_MEDIA |
+ : CacheState::DONE; |
+ |
+ // |cache_| can be null if it cannot be initialized. |
+ if (cache_) { |
+ if (begin_time_.is_null() && end_time_.is_max()) { |
+ rv = cache_->CalculateSizeOfAllEntries( |
+ base::Bind(&ConditionalCacheCountingHelper::DoCountCache, |
+ base::Unretained(this))); |
+ } else { |
+ // TODO(dullweber): Implement faster counting for SimpleBackendImpl. |
+ rv = CountEntries(cache_); |
+ } |
+ cache_ = NULL; |
+ } |
+ break; |
+ } |
+ case CacheState::DONE: { |
+ cache_ = NULL; |
+ next_cache_state_ = CacheState::NONE; |
+ // Notify the UI thread that we are done. |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&ConditionalCacheCountingHelper::Finished, |
+ base::Unretained(this))); |
+ return; |
+ } |
+ case CacheState::NONE: { |
+ NOTREACHED() << "bad state"; |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
+int ConditionalCacheCountingHelper::CountEntries(disk_cache::Backend* backend) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ iterator_ = backend->CreateIterator(); |
+ current_entry_ = nullptr; |
+ IterateOverEntries(net::OK); |
+ return net::ERR_IO_PENDING; |
+} |
+ |
+void ConditionalCacheCountingHelper::IterateOverEntries(int error) { |
+ while (error != net::ERR_IO_PENDING) { |
+ if (is_cancelled_) { |
+ if (current_entry_) |
+ current_entry_->Close(); |
+ iterator_.reset(); |
+ DoCountCache(net::ERR_ABORTED); |
+ return; |
+ } |
+ if (error == net::ERR_FAILED) { |
+ // The iteration finished successfully or we can no longer iterate |
+ // (e.g. the cache was destroyed). We cannot distinguish between the two, |
+ // but we know that there is nothing more that we can do, so we return to |
+ // the main calculation loop. |
+ iterator_.reset(); |
+ DoCountCache(net::OK); |
+ return; |
+ } |
+ |
+ if (current_entry_) { |
+ if (current_entry_->GetLastUsed() >= begin_time_ && |
+ current_entry_->GetLastUsed() < end_time_) { |
+ calculation_result_ += current_entry_->GetEntrySize(); |
+ } |
+ current_entry_->Close(); |
+ } |
+ |
+ error = iterator_->OpenNextEntry( |
+ ¤t_entry_, |
+ base::Bind(&ConditionalCacheCountingHelper::IterateOverEntries, |
+ base::Unretained(this))); |
+ } |
+} |
+ |
+} // namespace browsing_data |