Chromium Code Reviews| 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 |