| Index: chrome/browser/chromeos/base/file_flusher.cc
|
| diff --git a/chrome/browser/chromeos/base/file_flusher.cc b/chrome/browser/chromeos/base/file_flusher.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4315dbf2d4f2f78267a53acd63ee9bdf8a1ccca9
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/base/file_flusher.cc
|
| @@ -0,0 +1,206 @@
|
| +// 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 "chrome/browser/chromeos/base/file_flusher.h"
|
| +
|
| +#include <set>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/files/file.h"
|
| +#include "base/files/file_enumerator.h"
|
| +#include "base/logging.h"
|
| +#include "base/synchronization/cancellation_flag.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace {
|
| +
|
| +std::set<base::FilePath> MakeAbsoutePathSet(
|
| + const base::FilePath& base,
|
| + const std::vector<base::FilePath>& paths) {
|
| + std::set<base::FilePath> result;
|
| + for (const auto& path : paths) {
|
| + result.insert(path.IsAbsolute() ? path : base.Append(path));
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// FileFlusher::Job
|
| +
|
| +class FileFlusher::Job {
|
| + public:
|
| + Job(const base::WeakPtr<FileFlusher>& master,
|
| + const base::FilePath& path,
|
| + const std::vector<base::FilePath>& excludes,
|
| + const FileFlusher::OnFlushCallback& on_flush_callback,
|
| + const base::Closure& callback);
|
| + ~Job() = default;
|
| +
|
| + void Start();
|
| + void Cancel();
|
| +
|
| + const base::FilePath& path() const { return path_; }
|
| + bool started() const { return started_; }
|
| +
|
| + private:
|
| + // Flush files on a blocking pool thread.
|
| + void FlushOnBlockingPool();
|
| +
|
| + // Whether to exclude the |path| from flushing.
|
| + bool ShouldExclude(const base::FilePath& path) const;
|
| +
|
| + // Schedule a FinishOnUIThread task to run on the UI thread.
|
| + void ScheduleFinish();
|
| +
|
| + // Finish the job by notifying |master_| and self destruct on the UI thread.
|
| + void FinishOnUIThread();
|
| +
|
| + base::WeakPtr<FileFlusher> master_;
|
| + const base::FilePath path_;
|
| + const std::set<base::FilePath> excludes_;
|
| + const FileFlusher::OnFlushCallback on_flush_callback_;
|
| + const base::Closure callback_;
|
| +
|
| + bool started_ = false;
|
| + base::CancellationFlag cancel_flag_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Job);
|
| +};
|
| +
|
| +FileFlusher::Job::Job(const base::WeakPtr<FileFlusher>& master,
|
| + const base::FilePath& path,
|
| + const std::vector<base::FilePath>& excludes,
|
| + const FileFlusher::OnFlushCallback& on_flush_callback,
|
| + const base::Closure& callback)
|
| + : master_(master),
|
| + path_(path),
|
| + excludes_(MakeAbsoutePathSet(path, excludes)),
|
| + on_flush_callback_(on_flush_callback),
|
| + callback_(callback) {}
|
| +
|
| +void FileFlusher::Job::Start() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| + DCHECK(!started());
|
| +
|
| + started_ = true;
|
| +
|
| + if (cancel_flag_.IsSet()) {
|
| + ScheduleFinish();
|
| + return;
|
| + }
|
| +
|
| + content::BrowserThread::PostBlockingPoolTaskAndReply(
|
| + FROM_HERE, base::Bind(&FileFlusher::Job::FlushOnBlockingPool,
|
| + base::Unretained(this)),
|
| + base::Bind(&FileFlusher::Job::FinishOnUIThread, base::Unretained(this)));
|
| +}
|
| +
|
| +void FileFlusher::Job::Cancel() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + cancel_flag_.Set();
|
| +
|
| + // Cancel() could be called in an iterator/range loop in master thus don't
|
| + // invoke FinishOnUIThread in-place.
|
| + if (!started())
|
| + ScheduleFinish();
|
| +}
|
| +
|
| +void FileFlusher::Job::FlushOnBlockingPool() {
|
| + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
|
| +
|
| + VLOG(1) << "Flushing files under " << path_.value();
|
| +
|
| + base::FileEnumerator traversal(path_, true /* recursive */,
|
| + base::FileEnumerator::FILES);
|
| + for (base::FilePath current = traversal.Next();
|
| + !current.empty() && !cancel_flag_.IsSet(); current = traversal.Next()) {
|
| + if (ShouldExclude(current))
|
| + continue;
|
| +
|
| + base::File currentFile(current,
|
| + base::File::FLAG_OPEN | base::File::FLAG_WRITE);
|
| + if (!currentFile.IsValid()) {
|
| + VLOG(1) << "Unable to flush file:" << current.value();
|
| + continue;
|
| + }
|
| +
|
| + currentFile.Flush();
|
| + currentFile.Close();
|
| +
|
| + if (!on_flush_callback_.is_null())
|
| + on_flush_callback_.Run(current);
|
| + }
|
| +}
|
| +
|
| +bool FileFlusher::Job::ShouldExclude(const base::FilePath& path) const {
|
| + return excludes_.find(path) != excludes_.end();
|
| +}
|
| +
|
| +void FileFlusher::Job::ScheduleFinish() {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&Job::FinishOnUIThread, base::Unretained(this)));
|
| +}
|
| +
|
| +void FileFlusher::Job::FinishOnUIThread() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + if (!callback_.is_null())
|
| + callback_.Run();
|
| +
|
| + if (master_)
|
| + master_->OnJobDone(this);
|
| +
|
| + delete this;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// FileFlusher
|
| +
|
| +FileFlusher::FileFlusher() : weak_factory_(this) {}
|
| +
|
| +FileFlusher::~FileFlusher() {
|
| + for (const auto& job : jobs_)
|
| + job->Cancel();
|
| +}
|
| +
|
| +void FileFlusher::RequestFlush(const base::FilePath& path,
|
| + const std::vector<base::FilePath>& excludes,
|
| + const base::Closure& callback) {
|
| + for (const auto& job : jobs_) {
|
| + if (path == job->path() || path.IsParent(job->path()))
|
| + job->Cancel();
|
| + }
|
| +
|
| + jobs_.push_back(new Job(weak_factory_.GetWeakPtr(), path, excludes,
|
| + on_flush_callback_for_test_, callback));
|
| + ScheduleJob();
|
| +}
|
| +
|
| +void FileFlusher::ScheduleJob() {
|
| + if (jobs_.empty())
|
| + return;
|
| +
|
| + auto job = jobs_.front();
|
| + if (!job->started())
|
| + job->Start();
|
| +}
|
| +
|
| +void FileFlusher::OnJobDone(FileFlusher::Job* job) {
|
| + for (auto it = jobs_.begin(); it != jobs_.end(); ++it) {
|
| + if (*it == job) {
|
| + jobs_.erase(it);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + ScheduleJob();
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|