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..bf1a9a57652942dd2c10fc82ba33b7ffd3b4d7a7 |
--- /dev/null |
+++ b/components/browsing_data/content/conditional_cache_counting_helper.cc |
@@ -0,0 +1,219 @@ |
+// 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_(STATE_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_ = STATE_NONE; |
+ DCHECK_EQ(STATE_NONE, next_cache_state_); |
+ DCHECK(main_context_getter_.get()); |
+ DCHECK(media_context_getter_.get()); |
+ |
+ next_cache_state_ = STATE_CREATE_MAIN; |
+ DoCountCache(net::OK); |
+} |
+ |
+// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN --> |
+// STATE_PROCESS_MAIN --> STATE_CREATE_MEDIA --> STATE_PROCESS_MEDIA --> |
+// STATE_DONE. On error, we jump directly to STATE_DONE. |
+void ConditionalCacheCountingHelper::DoCountCache(int rv) { |
+ DCHECK_NE(STATE_NONE, next_cache_state_); |
+ while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_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_ = STATE_DONE; |
+ } else { |
+ DCHECK_EQ(0, net::OK); |
+ calculation_result_ += rv; |
+ } |
+ |
+ switch (next_cache_state_) { |
+ case STATE_CREATE_MAIN: |
+ case STATE_CREATE_MEDIA: { |
+ // Get a pointer to the cache. |
+ net::URLRequestContextGetter* getter = |
+ (next_cache_state_ == STATE_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_ == STATE_CREATE_MAIN) |
+ ? STATE_PROCESS_MAIN |
+ : STATE_PROCESS_MEDIA; |
+ |
+ rv = http_cache->GetBackend( |
+ &cache_, base::Bind(&ConditionalCacheCountingHelper::DoCountCache, |
+ base::Unretained(this))); |
+ break; |
+ } |
+ case STATE_PROCESS_MAIN: |
+ case STATE_PROCESS_MEDIA: { |
+ next_cache_state_ = (next_cache_state_ == STATE_PROCESS_MAIN) |
+ ? STATE_CREATE_MEDIA |
+ : STATE_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. |
msramek
2016/12/15 15:58:51
You already implemented it in this CL, just didn't
dullweber
2016/12/16 16:41:11
I added the code to get the size of a single entry
msramek
2016/12/20 01:02:59
You seem not to have finished that sentence; howev
dullweber
2016/12/21 10:29:19
I created a separate cl and moved the GetEntrySize
|
+ rv = CountEntries(cache_); |
+ } |
+ cache_ = NULL; |
+ } |
+ break; |
+ } |
+ case STATE_DONE: { |
+ cache_ = NULL; |
+ next_cache_state_ = STATE_NONE; |
+ // Notify the UI thread that we are done. |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&ConditionalCacheCountingHelper::Finished, |
+ base::Unretained(this))); |
+ return; |
+ } |
+ default: { |
msramek
2016/12/15 15:58:51
Instead of default: NOTREACHED(), we could just re
dullweber
2016/12/16 16:41:11
Done.
|
+ NOTREACHED() << "bad state"; |
+ next_cache_state_ = STATE_NONE; // Stop looping. |
+ 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(nullptr); |
msramek
2016/12/15 15:58:50
nit: reset()
dullweber
2016/12/16 16:41:11
Done.
|
+ 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(nullptr); |
+ 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 |