Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(792)

Side by Side Diff: chrome/browser/devtools/devtools_file_watcher.cc

Issue 1422463007: DevTools: use inotify to pick changes on the filesystem. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed listener Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/devtools/devtools_file_watcher.h"
6
7 #include <map>
8 #include <set>
9
10 #include "base/bind.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_path_watcher.h"
14 #include "base/memory/ref_counted.h"
15 #include "content/public/browser/browser_thread.h"
16
17 using content::BrowserThread;
18
19 static int kDefaultThrottleTimeout = 200;
20
21 // DevToolsFileWatcher::SharedFileWatcher --------------------------------------
22
23 class DevToolsFileWatcher::SharedFileWatcher :
24 public base::RefCounted<SharedFileWatcher> {
25 public:
26 SharedFileWatcher();
27
28 void AddListener(DevToolsFileWatcher* watcher);
29 void RemoveListener(DevToolsFileWatcher* watcher);
30 void AddWatch(const base::FilePath& path);
31 void RemoveWatch(const base::FilePath& path);
32
33 private:
34 friend class base::RefCounted<
35 DevToolsFileWatcher::SharedFileWatcher>;
36 ~SharedFileWatcher();
37
38 void DirectoryChanged(const base::FilePath& path, bool error);
39 void DispatchNotifications();
40
41 std::vector<DevToolsFileWatcher*> listeners_;
42 std::map<base::FilePath, base::FilePathWatcher> watchers_;
43 using FilePathTimesMap = std::map<base::FilePath, base::Time>;
44 FilePathTimesMap file_path_times_;
45 std::set<base::FilePath> pending_paths_;
46 base::Time last_event_time_;
47 base::TimeDelta last_dispatch_cost_;
48 };
49
50 DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher()
51 : last_dispatch_cost_(
52 base::TimeDelta::FromMilliseconds(kDefaultThrottleTimeout)) {
53 DevToolsFileWatcher::s_shared_watcher_ = this;
54 }
55
56 DevToolsFileWatcher::SharedFileWatcher::~SharedFileWatcher() {
57 DevToolsFileWatcher::s_shared_watcher_ = nullptr;
58 }
59
60 void DevToolsFileWatcher::SharedFileWatcher::AddListener(
61 DevToolsFileWatcher* watcher) {
62 listeners_.push_back(watcher);
63 }
64
65 void DevToolsFileWatcher::SharedFileWatcher::RemoveListener(
66 DevToolsFileWatcher* watcher) {
67 auto it = std::find(listeners_.begin(), listeners_.end(), watcher);
68 listeners_.erase(it);
69 }
70
71 void DevToolsFileWatcher::SharedFileWatcher::AddWatch(
72 const base::FilePath& path) {
73 if (watchers_.find(path) != watchers_.end())
74 return;
75 if (!base::FilePathWatcher::RecursiveWatchAvailable())
76 return;
77 bool success = watchers_[path].Watch(
78 path, true,
79 base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this)));
80 if (!success)
81 return;
82
83 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES);
84 base::FilePath file_path = enumerator.Next();
85 while (!file_path.empty()) {
86 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
87 file_path_times_[file_path] = file_info.GetLastModifiedTime();
88 file_path = enumerator.Next();
89 }
90 }
91
92 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch(
93 const base::FilePath& path) {
94 watchers_.erase(path);
dgozman 2015/11/05 01:13:50 Should we remove subfolders of path from pending_p
95 }
96
97 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged(
98 const base::FilePath& path,
99 bool error) {
100 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
101 pending_paths_.insert(path);
102 if (pending_paths_.size() > 1)
103 return; // PostDelayedTask is already pending.
104
105 base::Time now = base::Time::Now();
106 if (now - last_event_time_ > last_dispatch_cost_) {
107 DispatchNotifications();
108 return; // Immediately dispatch single-file changes.
109 }
110
111 // Throttle batches.
112 last_event_time_ = now;
113 BrowserThread::PostDelayedTask(
114 BrowserThread::FILE, FROM_HERE,
115 base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications,
116 this), last_dispatch_cost_);
117 }
118
119 void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() {
120 base::Time start = base::Time::Now();
121 std::vector<std::string> changed_paths;
122 for (auto path : pending_paths_) {
123 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES);
124 base::FilePath file_path = enumerator.Next();
125 while (!file_path.empty()) {
126 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
127 base::Time new_time = file_info.GetLastModifiedTime();
128 if (file_path_times_[file_path] != new_time) {
129 file_path_times_[file_path] = new_time;
130 changed_paths.push_back(file_path.AsUTF8Unsafe());
131 }
132 file_path = enumerator.Next();
133 }
134 }
135 pending_paths_.clear();
136
137 for (auto watcher : listeners_) {
138 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
139 base::Bind(watcher->callback_, changed_paths));
140 }
141 last_dispatch_cost_ = (base::Time::Now() - start) * 2;
142 }
143
144 // static
145 DevToolsFileWatcher::SharedFileWatcher*
146 DevToolsFileWatcher::s_shared_watcher_ = nullptr;
147
148 // DevToolsFileWatcher ---------------------------------------------------------
149
150 DevToolsFileWatcher::DevToolsFileWatcher(const WatchCallback& callback)
151 : callback_(callback) {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI);
153 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
154 base::Bind(&DevToolsFileWatcher::InitSharedWatcher,
155 base::Unretained(this)));
156 }
157
158 DevToolsFileWatcher::~DevToolsFileWatcher() {
159 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
160 shared_watcher_->RemoveListener(this);
161 }
162
163 void DevToolsFileWatcher::InitSharedWatcher() {
164 if (!DevToolsFileWatcher::s_shared_watcher_)
165 new SharedFileWatcher();
166 shared_watcher_ = DevToolsFileWatcher::s_shared_watcher_;
167 shared_watcher_->AddListener(this);
168 }
169
170 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) {
171 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
172 shared_watcher_->AddWatch(path);
173 }
174
175 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) {
176 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
177 shared_watcher_->RemoveWatch(path);
178 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698