OLD | NEW |
---|---|
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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 "chrome/browser/devtools/devtools_file_watcher.h" | 5 #include "chrome/browser/devtools/devtools_file_watcher.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <memory> | 9 #include <memory> |
10 #include <set> | 10 #include <set> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/files/file_enumerator.h" | 13 #include "base/files/file_enumerator.h" |
14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
15 #include "base/files/file_path_watcher.h" | 15 #include "base/files/file_path_watcher.h" |
16 #include "base/files/file_util.h" | |
16 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
17 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
18 | 19 |
19 using content::BrowserThread; | 20 using content::BrowserThread; |
20 | 21 |
21 static int kFirstThrottleTimeout = 10; | 22 static int kFirstThrottleTimeout = 10; |
22 static int kDefaultThrottleTimeout = 200; | 23 static int kDefaultThrottleTimeout = 200; |
23 | 24 |
24 // DevToolsFileWatcher::SharedFileWatcher -------------------------------------- | 25 // DevToolsFileWatcher::SharedFileWatcher -------------------------------------- |
25 | 26 |
26 class DevToolsFileWatcher::SharedFileWatcher : | 27 class DevToolsFileWatcher::SharedFileWatcher : |
27 public base::RefCounted<SharedFileWatcher> { | 28 public base::RefCounted<SharedFileWatcher> { |
28 public: | 29 public: |
29 SharedFileWatcher(); | 30 SharedFileWatcher(); |
30 | 31 |
31 void AddListener(DevToolsFileWatcher* watcher); | 32 void AddListener(DevToolsFileWatcher* watcher); |
32 void RemoveListener(DevToolsFileWatcher* watcher); | 33 void RemoveListener(DevToolsFileWatcher* watcher); |
33 void AddWatch(const base::FilePath& path); | 34 void AddWatch(const base::FilePath& path); |
34 void RemoveWatch(const base::FilePath& path); | 35 void RemoveWatch(const base::FilePath& path); |
35 | 36 |
36 private: | 37 private: |
37 friend class base::RefCounted< | 38 friend class base::RefCounted< |
38 DevToolsFileWatcher::SharedFileWatcher>; | 39 DevToolsFileWatcher::SharedFileWatcher>; |
39 ~SharedFileWatcher(); | 40 ~SharedFileWatcher(); |
40 | 41 |
42 using FilePathTimesMap = std::map<base::FilePath, base::Time>; | |
43 void GetModificationTimes(const base::FilePath& path, | |
44 FilePathTimesMap* file_path_times); | |
41 void DirectoryChanged(const base::FilePath& path, bool error); | 45 void DirectoryChanged(const base::FilePath& path, bool error); |
42 void DispatchNotifications(); | 46 void DispatchNotifications(); |
43 | 47 |
44 std::vector<DevToolsFileWatcher*> listeners_; | 48 std::vector<DevToolsFileWatcher*> listeners_; |
45 std::map<base::FilePath, std::unique_ptr<base::FilePathWatcher>> watchers_; | 49 std::map<base::FilePath, std::unique_ptr<base::FilePathWatcher>> watchers_; |
46 using FilePathTimesMap = std::map<base::FilePath, base::Time>; | 50 std::map<base::FilePath, FilePathTimesMap> file_path_times_; |
47 FilePathTimesMap file_path_times_; | |
48 std::set<base::FilePath> pending_paths_; | 51 std::set<base::FilePath> pending_paths_; |
49 base::Time last_event_time_; | 52 base::Time last_event_time_; |
50 base::TimeDelta last_dispatch_cost_; | 53 base::TimeDelta last_dispatch_cost_; |
51 }; | 54 }; |
52 | 55 |
53 DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher() | 56 DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher() |
54 : last_dispatch_cost_( | 57 : last_dispatch_cost_( |
55 base::TimeDelta::FromMilliseconds(kDefaultThrottleTimeout)) { | 58 base::TimeDelta::FromMilliseconds(kDefaultThrottleTimeout)) { |
56 DevToolsFileWatcher::s_shared_watcher_ = this; | 59 DevToolsFileWatcher::s_shared_watcher_ = this; |
57 } | 60 } |
(...skipping 19 matching lines...) Expand all Loading... | |
77 return; | 80 return; |
78 if (!base::FilePathWatcher::RecursiveWatchAvailable()) | 81 if (!base::FilePathWatcher::RecursiveWatchAvailable()) |
79 return; | 82 return; |
80 watchers_[path].reset(new base::FilePathWatcher()); | 83 watchers_[path].reset(new base::FilePathWatcher()); |
81 bool success = watchers_[path]->Watch( | 84 bool success = watchers_[path]->Watch( |
82 path, true, | 85 path, true, |
83 base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this))); | 86 base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this))); |
84 if (!success) | 87 if (!success) |
85 return; | 88 return; |
86 | 89 |
90 GetModificationTimes(path, &file_path_times_[path]); | |
91 } | |
92 | |
93 void DevToolsFileWatcher::SharedFileWatcher::GetModificationTimes( | |
94 const base::FilePath& path, | |
95 FilePathTimesMap* times_map) { | |
87 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | 96 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); |
88 base::FilePath file_path = enumerator.Next(); | 97 base::FilePath file_path = enumerator.Next(); |
89 while (!file_path.empty()) { | 98 while (!file_path.empty()) { |
90 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | 99 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); |
91 file_path_times_[file_path] = file_info.GetLastModifiedTime(); | 100 (*times_map)[file_path] = file_info.GetLastModifiedTime(); |
92 file_path = enumerator.Next(); | 101 file_path = enumerator.Next(); |
93 } | 102 } |
94 } | 103 } |
95 | 104 |
96 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( | 105 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( |
97 const base::FilePath& path) { | 106 const base::FilePath& path) { |
98 watchers_.erase(path); | 107 watchers_.erase(path); |
99 } | 108 } |
100 | 109 |
101 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( | 110 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( |
(...skipping 12 matching lines...) Expand all Loading... | |
114 last_dispatch_cost_ * 2; | 123 last_dispatch_cost_ * 2; |
115 | 124 |
116 BrowserThread::PostDelayedTask( | 125 BrowserThread::PostDelayedTask( |
117 BrowserThread::FILE, FROM_HERE, | 126 BrowserThread::FILE, FROM_HERE, |
118 base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications, | 127 base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications, |
119 this), shedule_for); | 128 this), shedule_for); |
120 last_event_time_ = now; | 129 last_event_time_ = now; |
121 } | 130 } |
122 | 131 |
123 void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() { | 132 void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() { |
133 if (!pending_paths_.size()) | |
134 return; | |
124 base::Time start = base::Time::Now(); | 135 base::Time start = base::Time::Now(); |
136 std::vector<std::string> added_paths; | |
137 std::vector<std::string> removed_paths; | |
125 std::vector<std::string> changed_paths; | 138 std::vector<std::string> changed_paths; |
126 for (auto path : pending_paths_) { | 139 |
127 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | 140 for (const auto& path : pending_paths_) { |
128 base::FilePath file_path = enumerator.Next(); | 141 FilePathTimesMap& old_times = file_path_times_[path]; |
129 while (!file_path.empty()) { | 142 FilePathTimesMap current_times; |
130 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | 143 GetModificationTimes(path, ¤t_times); |
131 base::Time new_time = file_info.GetLastModifiedTime(); | 144 for (const auto& it : current_times) { |
dgozman
2016/10/04 04:41:01
I usually call it |pair| or |path_time|.
lushnikov
2016/10/04 15:56:35
|path_time| is really nice, thanks
| |
132 if (file_path_times_[file_path] != new_time) { | 145 auto old_timestamp = old_times.find(it.first); |
133 file_path_times_[file_path] = new_time; | 146 if (old_timestamp == old_times.end()) { |
134 changed_paths.push_back(file_path.AsUTF8Unsafe()); | 147 old_times[it.first] = it.second; |
dgozman
2016/10/04 04:41:01
Don't modify, you do swap below.
lushnikov
2016/10/04 15:56:35
My bad. Done.
| |
148 added_paths.push_back(it.first.AsUTF8Unsafe()); | |
149 } else if (old_timestamp->second != it.second) { | |
150 old_timestamp->second = it.second; | |
dgozman
2016/10/04 04:41:01
ditto
lushnikov
2016/10/04 15:56:35
Done.
| |
151 changed_paths.push_back(it.first.AsUTF8Unsafe()); | |
135 } | 152 } |
136 file_path = enumerator.Next(); | |
137 } | 153 } |
154 for (const auto& it : old_times) { | |
dgozman
2016/10/04 04:41:01
I'd rather do:
for (const auto& path_time : old_t
lushnikov
2016/10/04 15:56:35
This is much more clear, thanks
| |
155 auto new_timestamp = current_times.find(it.first); | |
156 if (new_timestamp == current_times.end()) { | |
157 removed_paths.push_back(it.first.AsUTF8Unsafe()); | |
158 } | |
159 } | |
160 old_times.swap(current_times); | |
138 } | 161 } |
139 pending_paths_.clear(); | 162 pending_paths_.clear(); |
140 | 163 |
141 for (auto* watcher : listeners_) { | 164 for (auto* watcher : listeners_) { |
142 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 165 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
143 base::Bind(watcher->callback_, changed_paths)); | 166 base::Bind(watcher->callback_, changed_paths, |
167 added_paths, removed_paths)); | |
144 } | 168 } |
145 last_dispatch_cost_ = base::Time::Now() - start; | 169 last_dispatch_cost_ = base::Time::Now() - start; |
146 } | 170 } |
147 | 171 |
148 // static | 172 // static |
149 DevToolsFileWatcher::SharedFileWatcher* | 173 DevToolsFileWatcher::SharedFileWatcher* |
150 DevToolsFileWatcher::s_shared_watcher_ = nullptr; | 174 DevToolsFileWatcher::s_shared_watcher_ = nullptr; |
151 | 175 |
152 // DevToolsFileWatcher --------------------------------------------------------- | 176 // DevToolsFileWatcher --------------------------------------------------------- |
153 | 177 |
(...skipping 19 matching lines...) Expand all Loading... | |
173 | 197 |
174 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { | 198 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { |
175 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 199 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
176 shared_watcher_->AddWatch(path); | 200 shared_watcher_->AddWatch(path); |
177 } | 201 } |
178 | 202 |
179 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { | 203 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { |
180 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 204 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
181 shared_watcher_->RemoveWatch(path); | 205 shared_watcher_->RemoveWatch(path); |
182 } | 206 } |
OLD | NEW |