| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/drive/file_write_watcher.h" | 5 #include "components/drive/file_write_watcher.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <map> | 10 #include <map> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/callback.h" | 14 #include "base/callback.h" |
| 15 #include "base/files/file_path_watcher.h" | 15 #include "base/files/file_path_watcher.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/stl_util.h" | 17 #include "base/memory/ptr_util.h" |
| 18 #include "base/timer/timer.h" | 18 #include "base/timer/timer.h" |
| 19 #include "google_apis/drive/task_util.h" | 19 #include "google_apis/drive/task_util.h" |
| 20 | 20 |
| 21 namespace drive { | 21 namespace drive { |
| 22 namespace internal { | 22 namespace internal { |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 const int64_t kWriteEventDelayInSeconds = 5; | 25 const int64_t kWriteEventDelayInSeconds = 5; |
| 26 } // namespace | 26 } // namespace |
| 27 | 27 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 base::FilePathWatcher watcher; | 63 base::FilePathWatcher watcher; |
| 64 base::Timer timer; | 64 base::Timer timer; |
| 65 | 65 |
| 66 explicit PathWatchInfo(const base::Closure& on_write_callback) | 66 explicit PathWatchInfo(const base::Closure& on_write_callback) |
| 67 : on_write_callbacks(1, on_write_callback), | 67 : on_write_callbacks(1, on_write_callback), |
| 68 timer(false /* retain_closure_on_reset */, false /* is_repeating */) { | 68 timer(false /* retain_closure_on_reset */, false /* is_repeating */) { |
| 69 } | 69 } |
| 70 }; | 70 }; |
| 71 | 71 |
| 72 base::TimeDelta delay_; | 72 base::TimeDelta delay_; |
| 73 std::map<base::FilePath, PathWatchInfo*> watchers_; | 73 std::map<base::FilePath, std::unique_ptr<PathWatchInfo>> watchers_; |
| 74 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; | 74 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; |
| 75 | 75 |
| 76 base::ThreadChecker thread_checker_; | 76 base::ThreadChecker thread_checker_; |
| 77 | 77 |
| 78 // Note: This should remain the last member so it'll be destroyed and | 78 // Note: This should remain the last member so it'll be destroyed and |
| 79 // invalidate its weak pointers before any other members are destroyed. | 79 // invalidate its weak pointers before any other members are destroyed. |
| 80 base::WeakPtrFactory<FileWriteWatcherImpl> weak_ptr_factory_; | 80 base::WeakPtrFactory<FileWriteWatcherImpl> weak_ptr_factory_; |
| 81 DISALLOW_COPY_AND_ASSIGN(FileWriteWatcherImpl); | 81 DISALLOW_COPY_AND_ASSIGN(FileWriteWatcherImpl); |
| 82 }; | 82 }; |
| 83 | 83 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 107 file_task_runner_->PostTask( | 107 file_task_runner_->PostTask( |
| 108 FROM_HERE, | 108 FROM_HERE, |
| 109 base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread, | 109 base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread, |
| 110 base::Unretained(this), path, | 110 base::Unretained(this), path, |
| 111 google_apis::CreateRelayCallback(on_start_callback), | 111 google_apis::CreateRelayCallback(on_start_callback), |
| 112 google_apis::CreateRelayCallback(on_write_callback))); | 112 google_apis::CreateRelayCallback(on_write_callback))); |
| 113 } | 113 } |
| 114 | 114 |
| 115 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() { | 115 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() { |
| 116 DCHECK(file_task_runner_->BelongsToCurrentThread()); | 116 DCHECK(file_task_runner_->BelongsToCurrentThread()); |
| 117 | |
| 118 base::STLDeleteContainerPairSecondPointers(watchers_.begin(), | |
| 119 watchers_.end()); | |
| 120 } | 117 } |
| 121 | 118 |
| 122 void FileWriteWatcher::FileWriteWatcherImpl::DestroyOnFileThread() { | 119 void FileWriteWatcher::FileWriteWatcherImpl::DestroyOnFileThread() { |
| 123 DCHECK(file_task_runner_->BelongsToCurrentThread()); | 120 DCHECK(file_task_runner_->BelongsToCurrentThread()); |
| 124 | 121 |
| 125 delete this; | 122 delete this; |
| 126 } | 123 } |
| 127 | 124 |
| 128 void FileWriteWatcher::FileWriteWatcherImpl::StartWatchOnFileThread( | 125 void FileWriteWatcher::FileWriteWatcherImpl::StartWatchOnFileThread( |
| 129 const base::FilePath& path, | 126 const base::FilePath& path, |
| 130 const StartWatchCallback& on_start_callback, | 127 const StartWatchCallback& on_start_callback, |
| 131 const base::Closure& on_write_callback) { | 128 const base::Closure& on_write_callback) { |
| 132 DCHECK(file_task_runner_->BelongsToCurrentThread()); | 129 DCHECK(file_task_runner_->BelongsToCurrentThread()); |
| 133 | 130 |
| 134 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path); | 131 auto it = watchers_.find(path); |
| 135 if (it != watchers_.end()) { | 132 if (it != watchers_.end()) { |
| 136 // We are already watching the path. | 133 // We are already watching the path. |
| 137 on_start_callback.Run(true); | 134 on_start_callback.Run(true); |
| 138 it->second->on_write_callbacks.push_back(on_write_callback); | 135 it->second->on_write_callbacks.push_back(on_write_callback); |
| 139 return; | 136 return; |
| 140 } | 137 } |
| 141 | 138 |
| 142 // Start watching |path|. | 139 // Start watching |path|. |
| 143 std::unique_ptr<PathWatchInfo> info(new PathWatchInfo(on_write_callback)); | 140 std::unique_ptr<PathWatchInfo> info = |
| 141 base::MakeUnique<PathWatchInfo>(on_write_callback); |
| 144 bool ok = info->watcher.Watch( | 142 bool ok = info->watcher.Watch( |
| 145 path, | 143 path, |
| 146 false, // recursive | 144 false, // recursive |
| 147 base::Bind(&FileWriteWatcherImpl::OnWriteEvent, | 145 base::Bind(&FileWriteWatcherImpl::OnWriteEvent, |
| 148 weak_ptr_factory_.GetWeakPtr())); | 146 weak_ptr_factory_.GetWeakPtr())); |
| 149 watchers_[path] = info.release(); | 147 watchers_[path] = std::move(info); |
| 150 on_start_callback.Run(ok); | 148 on_start_callback.Run(ok); |
| 151 } | 149 } |
| 152 | 150 |
| 153 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent( | 151 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent( |
| 154 const base::FilePath& path, | 152 const base::FilePath& path, |
| 155 bool error) { | 153 bool error) { |
| 156 DCHECK(file_task_runner_->BelongsToCurrentThread()); | 154 DCHECK(file_task_runner_->BelongsToCurrentThread()); |
| 157 | 155 |
| 158 if (error) | 156 if (error) |
| 159 return; | 157 return; |
| 160 | 158 |
| 161 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path); | 159 auto it = watchers_.find(path); |
| 162 DCHECK(it != watchers_.end()); | 160 DCHECK(it != watchers_.end()); |
| 163 | 161 |
| 164 // Heuristics for detecting the end of successive write operations. | 162 // Heuristics for detecting the end of successive write operations. |
| 165 // Delay running on_write_event_callback by |delay_| time, and if OnWriteEvent | 163 // Delay running on_write_event_callback by |delay_| time, and if OnWriteEvent |
| 166 // is called again in the period, the timer is reset. In other words, we | 164 // is called again in the period, the timer is reset. In other words, we |
| 167 // invoke callback when |delay_| has passed after the last OnWriteEvent(). | 165 // invoke callback when |delay_| has passed after the last OnWriteEvent(). |
| 168 it->second->timer.Start(FROM_HERE, | 166 it->second->timer.Start(FROM_HERE, |
| 169 delay_, | 167 delay_, |
| 170 base::Bind(&FileWriteWatcherImpl::InvokeCallback, | 168 base::Bind(&FileWriteWatcherImpl::InvokeCallback, |
| 171 weak_ptr_factory_.GetWeakPtr(), | 169 weak_ptr_factory_.GetWeakPtr(), |
| 172 path)); | 170 path)); |
| 173 } | 171 } |
| 174 | 172 |
| 175 void FileWriteWatcher::FileWriteWatcherImpl::InvokeCallback( | 173 void FileWriteWatcher::FileWriteWatcherImpl::InvokeCallback( |
| 176 const base::FilePath& path) { | 174 const base::FilePath& path) { |
| 177 DCHECK(file_task_runner_->BelongsToCurrentThread()); | 175 DCHECK(file_task_runner_->BelongsToCurrentThread()); |
| 178 | 176 |
| 179 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path); | 177 auto it = watchers_.find(path); |
| 180 DCHECK(it != watchers_.end()); | 178 DCHECK(it != watchers_.end()); |
| 181 | 179 |
| 182 std::vector<base::Closure> callbacks; | 180 std::vector<base::Closure> callbacks; |
| 183 callbacks.swap(it->second->on_write_callbacks); | 181 callbacks.swap(it->second->on_write_callbacks); |
| 184 delete it->second; | |
| 185 watchers_.erase(it); | 182 watchers_.erase(it); |
| 186 | 183 |
| 187 for (size_t i = 0; i < callbacks.size(); ++i) | 184 for (const auto& callback : callbacks) |
| 188 callbacks[i].Run(); | 185 callback.Run(); |
| 189 } | 186 } |
| 190 | 187 |
| 191 FileWriteWatcher::FileWriteWatcher( | 188 FileWriteWatcher::FileWriteWatcher( |
| 192 base::SingleThreadTaskRunner* file_task_runner) | 189 base::SingleThreadTaskRunner* file_task_runner) |
| 193 : watcher_impl_(new FileWriteWatcherImpl(file_task_runner)) { | 190 : watcher_impl_(new FileWriteWatcherImpl(file_task_runner)) { |
| 194 } | 191 } |
| 195 | 192 |
| 196 FileWriteWatcher::~FileWriteWatcher() { | 193 FileWriteWatcher::~FileWriteWatcher() { |
| 197 DCHECK(thread_checker_.CalledOnValidThread()); | 194 DCHECK(thread_checker_.CalledOnValidThread()); |
| 198 } | 195 } |
| 199 | 196 |
| 200 void FileWriteWatcher::StartWatch(const base::FilePath& file_path, | 197 void FileWriteWatcher::StartWatch(const base::FilePath& file_path, |
| 201 const StartWatchCallback& on_start_callback, | 198 const StartWatchCallback& on_start_callback, |
| 202 const base::Closure& on_write_callback) { | 199 const base::Closure& on_write_callback) { |
| 203 DCHECK(thread_checker_.CalledOnValidThread()); | 200 DCHECK(thread_checker_.CalledOnValidThread()); |
| 204 watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback); | 201 watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback); |
| 205 } | 202 } |
| 206 | 203 |
| 207 void FileWriteWatcher::DisableDelayForTesting() { | 204 void FileWriteWatcher::DisableDelayForTesting() { |
| 208 watcher_impl_->set_delay(base::TimeDelta()); | 205 watcher_impl_->set_delay(base::TimeDelta()); |
| 209 } | 206 } |
| 210 | 207 |
| 211 } // namespace internal | 208 } // namespace internal |
| 212 } // namespace drive | 209 } // namespace drive |
| OLD | NEW |