Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/chromeos/base/file_flusher.h" | |
| 6 | |
| 7 #include <set> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/files/file.h" | |
| 11 #include "base/files/file_enumerator.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/synchronization/cancellation_flag.h" | |
| 14 #include "content/public/browser/browser_thread.h" | |
| 15 | |
| 16 namespace chromeos { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 std::set<base::FilePath> MakeAbsoutePathSet( | |
| 21 const base::FilePath& base, | |
| 22 const std::vector<base::FilePath>& paths) { | |
| 23 std::set<base::FilePath> result; | |
| 24 for (const auto& path : paths) { | |
| 25 result.insert(path.IsAbsolute() ? path : base.Append(path)); | |
| 26 } | |
| 27 return result; | |
| 28 } | |
| 29 | |
| 30 } // namespace | |
| 31 | |
| 32 //////////////////////////////////////////////////////////////////////////////// | |
| 33 // FileFlusher::Job | |
| 34 | |
| 35 class FileFlusher::Job { | |
| 36 public: | |
| 37 Job(const base::WeakPtr<FileFlusher>& master, | |
| 38 const base::FilePath& path, | |
| 39 const std::vector<base::FilePath>& excludes); | |
| 40 ~Job() = default; | |
| 41 | |
| 42 void Start(); | |
| 43 void Cancel(); | |
| 44 | |
| 45 const base::FilePath& path() const { return path_; } | |
| 46 bool started() const { return started_; } | |
| 47 | |
| 48 private: | |
| 49 void FlushOnBlockingPool(); | |
| 50 bool ShouldExclude(const base::FilePath& path) const; | |
| 51 | |
| 52 void ScheduleFinishOnUIThread(); | |
|
achuithb
2016/03/21 17:45:41
Maybe add a comment to say that the Schedule call
xiyuan
2016/03/21 22:14:54
Done.
| |
| 53 void FinishOnUIThread(); | |
| 54 | |
| 55 base::WeakPtr<FileFlusher> master_; | |
| 56 const base::FilePath path_; | |
| 57 const std::set<base::FilePath> excludes_; | |
| 58 | |
| 59 bool started_ = false; | |
| 60 base::CancellationFlag cancel_flag_; | |
| 61 | |
| 62 DISALLOW_COPY_AND_ASSIGN(Job); | |
| 63 }; | |
| 64 | |
| 65 FileFlusher::Job::Job(const base::WeakPtr<FileFlusher>& master, | |
| 66 const base::FilePath& path, | |
| 67 const std::vector<base::FilePath>& excludes) | |
| 68 : master_(master), | |
| 69 path_(path), | |
| 70 excludes_(MakeAbsoutePathSet(path, excludes)) {} | |
| 71 | |
| 72 void FileFlusher::Job::Start() { | |
| 73 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 74 DCHECK(!started()); | |
| 75 | |
| 76 started_ = true; | |
| 77 | |
| 78 if (cancel_flag_.IsSet()) { | |
| 79 ScheduleFinishOnUIThread(); | |
| 80 return; | |
| 81 } | |
| 82 | |
| 83 content::BrowserThread::PostBlockingPoolTaskAndReply( | |
| 84 FROM_HERE, base::Bind(&FileFlusher::Job::FlushOnBlockingPool, | |
| 85 base::Unretained(this)), | |
| 86 base::Bind(&FileFlusher::Job::FinishOnUIThread, base::Unretained(this))); | |
| 87 } | |
| 88 | |
| 89 void FileFlusher::Job::Cancel() { | |
| 90 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 91 | |
| 92 cancel_flag_.Set(); | |
| 93 | |
| 94 // Cancel() could be called in an iterator/range loop in master thus don't | |
| 95 // invoke FinishOnUIThread in-place. | |
| 96 if (!started()) | |
| 97 ScheduleFinishOnUIThread(); | |
| 98 } | |
| 99 | |
| 100 void FileFlusher::Job::FlushOnBlockingPool() { | |
| 101 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
| 102 | |
|
achuithb
2016/03/21 17:45:41
Would a VLOG(1) logging statement be useful here?
xiyuan
2016/03/21 22:14:54
Done.
| |
| 103 const bool kRecursive = true; | |
|
achuithb
2016/03/21 17:45:41
Is kRecursive appropriate for const stack variable
xiyuan
2016/03/21 22:14:54
Personally prefer to use a const bool instead of u
| |
| 104 base::FileEnumerator traversal(path_, kRecursive, | |
| 105 base::FileEnumerator::FILES); | |
| 106 for (base::FilePath current = traversal.Next(); | |
| 107 !current.empty() && !cancel_flag_.IsSet(); current = traversal.Next()) { | |
| 108 if (ShouldExclude(current)) | |
| 109 continue; | |
| 110 | |
| 111 base::File currentFile(current, | |
| 112 base::File::FLAG_OPEN | base::File::FLAG_WRITE); | |
| 113 if (!currentFile.IsValid()) { | |
| 114 VLOG(1) << "Unable to flush file:" << current.value(); | |
| 115 continue; | |
| 116 } | |
| 117 | |
| 118 currentFile.Flush(); | |
| 119 currentFile.Close(); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 bool FileFlusher::Job::ShouldExclude(const base::FilePath& path) const { | |
| 124 return excludes_.find(path) != excludes_.end(); | |
| 125 } | |
| 126 | |
| 127 void FileFlusher::Job::ScheduleFinishOnUIThread() { | |
| 128 content::BrowserThread::PostTask( | |
|
achuithb
2016/03/21 17:45:41
DCHECK_CURRENTLY_ON(content::BrowserThread::UI)?
xiyuan
2016/03/21 22:14:54
The name is misleading. It schedules "FinishOnUITh
| |
| 129 content::BrowserThread::UI, FROM_HERE, | |
| 130 base::Bind(&FileFlusher::Job::FinishOnUIThread, base::Unretained(this))); | |
| 131 } | |
| 132 | |
| 133 void FileFlusher::Job::FinishOnUIThread() { | |
| 134 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 135 | |
| 136 if (master_) | |
| 137 master_->OnJobDone(this); | |
| 138 | |
| 139 delete this; | |
| 140 } | |
| 141 | |
| 142 //////////////////////////////////////////////////////////////////////////////// | |
| 143 // FileFlusher | |
| 144 | |
| 145 FileFlusher::FileFlusher() : weak_factory_(this) {} | |
| 146 | |
| 147 FileFlusher::~FileFlusher() { | |
| 148 for (const auto& job : jobs_) | |
|
achuithb
2016/03/21 17:45:41
are we allowed to drop {} here?
xiyuan
2016/03/21 22:14:54
Cancel() does not remove it from the vector. It sc
achuithb
2016/03/21 22:32:56
I didn't realize that braces were optional for sin
xiyuan
2016/03/22 18:41:33
I completely mis-understood to comment. :p
And ye
| |
| 149 job->Cancel(); | |
| 150 } | |
| 151 | |
| 152 void FileFlusher::RequestFlush(const base::FilePath& path, | |
| 153 const std::vector<base::FilePath>& excludes) { | |
| 154 for (const auto& job : jobs_) { | |
| 155 if (path == job->path() || path.IsParent(job->path())) | |
| 156 job->Cancel(); | |
| 157 } | |
| 158 | |
| 159 jobs_.push_back(new Job(weak_factory_.GetWeakPtr(), path, excludes)); | |
| 160 ScheduleJob(); | |
| 161 } | |
| 162 | |
| 163 void FileFlusher::ScheduleJob() { | |
| 164 if (jobs_.empty()) | |
| 165 return; | |
| 166 | |
| 167 auto job = jobs_.front(); | |
| 168 if (!job->started()) | |
| 169 job->Start(); | |
| 170 } | |
| 171 | |
| 172 void FileFlusher::OnJobDone(FileFlusher::Job* job) { | |
| 173 for (auto it = jobs_.begin(); it != jobs_.end(); ++it) { | |
|
achuithb
2016/03/21 17:45:41
for (auto job : jobs_)?
xiyuan
2016/03/21 22:14:54
Need the iterator to remove |job| from |jobs_| so
achuithb
2016/03/21 22:32:56
Acknowledged.
| |
| 174 if (*it == job) { | |
| 175 jobs_.erase(it); | |
| 176 break; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 ScheduleJob(); | |
| 181 } | |
| 182 | |
| 183 } // namespace chromeos | |
| OLD | NEW |