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 FilePathTimesMap times_map; | |
91 GetModificationTimes(path, ×_map); | |
dgozman
2016/10/04 02:26:41
One line, avoids copying:
GetModificationTimes(pa
lushnikov
2016/10/04 02:51:59
Done.
| |
92 file_path_times_[path] = times_map; | |
93 } | |
94 | |
95 void DevToolsFileWatcher::SharedFileWatcher::GetModificationTimes( | |
96 const base::FilePath& path, | |
97 FilePathTimesMap* times_map) { | |
87 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | 98 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); |
88 base::FilePath file_path = enumerator.Next(); | 99 base::FilePath file_path = enumerator.Next(); |
89 while (!file_path.empty()) { | 100 while (!file_path.empty()) { |
90 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | 101 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); |
91 file_path_times_[file_path] = file_info.GetLastModifiedTime(); | 102 (*times_map)[file_path] = file_info.GetLastModifiedTime(); |
92 file_path = enumerator.Next(); | 103 file_path = enumerator.Next(); |
93 } | 104 } |
94 } | 105 } |
95 | 106 |
96 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( | 107 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( |
97 const base::FilePath& path) { | 108 const base::FilePath& path) { |
98 watchers_.erase(path); | 109 watchers_.erase(path); |
99 } | 110 } |
100 | 111 |
101 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( | 112 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( |
(...skipping 12 matching lines...) Expand all Loading... | |
114 last_dispatch_cost_ * 2; | 125 last_dispatch_cost_ * 2; |
115 | 126 |
116 BrowserThread::PostDelayedTask( | 127 BrowserThread::PostDelayedTask( |
117 BrowserThread::FILE, FROM_HERE, | 128 BrowserThread::FILE, FROM_HERE, |
118 base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications, | 129 base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications, |
119 this), shedule_for); | 130 this), shedule_for); |
120 last_event_time_ = now; | 131 last_event_time_ = now; |
121 } | 132 } |
122 | 133 |
123 void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() { | 134 void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() { |
135 if (!pending_paths_.size()) | |
136 return; | |
124 base::Time start = base::Time::Now(); | 137 base::Time start = base::Time::Now(); |
138 std::vector<std::string> added_paths; | |
139 std::vector<std::string> removed_paths; | |
125 std::vector<std::string> changed_paths; | 140 std::vector<std::string> changed_paths; |
126 for (auto path : pending_paths_) { | 141 |
127 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | 142 for (const auto& path : pending_paths_) { |
128 base::FilePath file_path = enumerator.Next(); | 143 FilePathTimesMap& old_times = file_path_times_[path]; |
129 while (!file_path.empty()) { | 144 FilePathTimesMap current_times; |
130 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | 145 GetModificationTimes(path, ¤t_times); |
131 base::Time new_time = file_info.GetLastModifiedTime(); | 146 for (auto it = current_times.begin(); it != current_times.end(); ++it) { |
dgozman
2016/10/04 02:26:41
for (const auto& pair : current_times)
lushnikov
2016/10/04 02:51:59
Done.
| |
132 if (file_path_times_[file_path] != new_time) { | 147 auto old_timestamp = old_times.find(it->first); |
133 file_path_times_[file_path] = new_time; | 148 if (old_timestamp == old_times.end()) { |
134 changed_paths.push_back(file_path.AsUTF8Unsafe()); | 149 old_times[it->first] = it->second; |
150 added_paths.push_back(it->first.AsUTF8Unsafe()); | |
151 } else if (old_timestamp->second != it->second) { | |
152 old_timestamp->second = it->second; | |
153 changed_paths.push_back(it->first.AsUTF8Unsafe()); | |
135 } | 154 } |
136 file_path = enumerator.Next(); | 155 } |
156 for (auto it = old_times.begin(); it != old_times.end();) { | |
dgozman
2016/10/04 02:26:41
ditto
lushnikov
2016/10/04 02:51:59
Done.
| |
157 auto new_timestamp = current_times.find(it->first); | |
158 if (new_timestamp == current_times.end()) { | |
159 removed_paths.push_back(it->first.AsUTF8Unsafe()); | |
160 old_times.erase(it++); | |
dgozman
2016/10/04 02:26:41
Don't do this. Just |old_times.swap(current_times)
lushnikov
2016/10/04 02:51:59
Done.
| |
161 } else { | |
162 ++it; | |
163 } | |
137 } | 164 } |
138 } | 165 } |
139 pending_paths_.clear(); | 166 pending_paths_.clear(); |
140 | 167 |
141 for (auto* watcher : listeners_) { | 168 for (auto* watcher : listeners_) { |
142 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 169 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
143 base::Bind(watcher->callback_, changed_paths)); | 170 base::Bind(watcher->callback_, changed_paths, |
171 added_paths, removed_paths)); | |
144 } | 172 } |
145 last_dispatch_cost_ = base::Time::Now() - start; | 173 last_dispatch_cost_ = base::Time::Now() - start; |
146 } | 174 } |
147 | 175 |
148 // static | 176 // static |
149 DevToolsFileWatcher::SharedFileWatcher* | 177 DevToolsFileWatcher::SharedFileWatcher* |
150 DevToolsFileWatcher::s_shared_watcher_ = nullptr; | 178 DevToolsFileWatcher::s_shared_watcher_ = nullptr; |
151 | 179 |
152 // DevToolsFileWatcher --------------------------------------------------------- | 180 // DevToolsFileWatcher --------------------------------------------------------- |
153 | 181 |
(...skipping 19 matching lines...) Expand all Loading... | |
173 | 201 |
174 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { | 202 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { |
175 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 203 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
176 shared_watcher_->AddWatch(path); | 204 shared_watcher_->AddWatch(path); |
177 } | 205 } |
178 | 206 |
179 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { | 207 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { |
180 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 208 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
181 shared_watcher_->RemoveWatch(path); | 209 shared_watcher_->RemoveWatch(path); |
182 } | 210 } |
OLD | NEW |