OLD | NEW |
---|---|
(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 "base/bind.h" | |
8 #include "base/files/file_enumerator.h" | |
9 #include "base/files/file_path.h" | |
10 #include "base/files/file_path_watcher.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 | |
14 using content::BrowserThread; | |
15 | |
16 // DevToolsFileWatcher::SharedFileWatcher -------------------------------------- | |
17 | |
18 class DevToolsFileWatcher::SharedFileWatcher : | |
19 public base::RefCountedThreadSafe<SharedFileWatcher> { | |
20 public: | |
21 typedef base::Callback<void(const base::FilePath&, int)> WatchCallback; | |
dgozman
2015/11/04 20:11:29
There is exactly same WatchCallback in DevToolsFil
pfeldman
2015/11/05 00:18:42
Done.
| |
22 SharedFileWatcher(); | |
23 | |
24 void AddListener(DevToolsFileWatcher* watcher); | |
25 void RemoveListener(DevToolsFileWatcher* watcher); | |
26 void AddWatch(const base::FilePath& path); | |
27 void RemoveWatch(const base::FilePath& path); | |
28 | |
29 private: | |
30 friend class base::RefCountedThreadSafe< | |
31 DevToolsFileWatcher::SharedFileWatcher>; | |
32 ~SharedFileWatcher(); | |
33 | |
34 void DirectoryChanged(const base::FilePath& path, bool error); | |
35 | |
36 std::vector<DevToolsFileWatcher*> listeners_; | |
37 std::map<base::FilePath, base::FilePathWatcher> watchers_; | |
38 typedef std::map<base::FilePath, base::Time> FilePathTimesMap; | |
dgozman
2015/11/04 20:11:29
using
pfeldman
2015/11/05 00:18:41
Done.
| |
39 FilePathTimesMap file_path_times_; | |
40 }; | |
41 | |
42 DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher() { | |
43 DevToolsFileWatcher::s_shared_watcher_ = this; | |
44 } | |
45 | |
46 DevToolsFileWatcher::SharedFileWatcher::~SharedFileWatcher() { | |
47 DevToolsFileWatcher::s_shared_watcher_ = nullptr; | |
48 } | |
49 | |
50 void DevToolsFileWatcher::SharedFileWatcher::AddListener( | |
51 DevToolsFileWatcher* watcher) { | |
52 listeners_.push_back(watcher); | |
53 } | |
54 | |
55 void DevToolsFileWatcher::SharedFileWatcher::RemoveListener( | |
56 DevToolsFileWatcher* watcher) { | |
57 auto it = std::find(listeners_.begin(), listeners_.end(), watcher); | |
58 listeners_.erase(it); | |
59 } | |
60 | |
61 void DevToolsFileWatcher::SharedFileWatcher::AddWatch( | |
62 const base::FilePath& path) { | |
63 if (watchers_.find(path) != watchers_.end()) | |
64 return; | |
65 if (!base::FilePathWatcher::RecursiveWatchAvailable()) | |
66 return; | |
67 bool success = watchers_[path].Watch( | |
68 path, true, | |
69 base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this))); | |
70 if (!success) | |
71 return; | |
72 | |
73 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | |
dgozman
2015/11/04 20:11:29
How does this perform on large workspaces?
pfeldman
2015/11/05 00:18:42
MBP, SSD, 25K files
cold: 1532
hot: 210
All FILE
| |
74 base::FilePath file_path = enumerator.Next(); | |
75 while (!file_path.empty()) { | |
76 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | |
77 file_path_times_[file_path] = file_info.GetLastModifiedTime(); | |
78 file_path = enumerator.Next(); | |
79 } | |
80 } | |
81 | |
82 void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( | |
83 const base::FilePath& path) { | |
84 watchers_.erase(path); | |
85 } | |
86 | |
87 void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( | |
88 const base::FilePath& path, | |
89 bool error) { | |
90 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
91 base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); | |
92 base::FilePath file_path = enumerator.Next(); | |
93 while (!file_path.empty()) { | |
94 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); | |
95 base::Time new_time = file_info.GetLastModifiedTime(); | |
96 if (file_path_times_[file_path] != new_time) { | |
97 file_path_times_[file_path] = new_time; | |
98 for (auto watcher : listeners_) { | |
99 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
dgozman
2015/11/04 20:11:29
I think we'll need a batch and progress indicator
pfeldman
2015/11/05 00:18:42
Let me instead
1) throttle it so that i was not re
| |
100 base::Bind(watcher->callback_, file_path, | |
101 error)); | |
102 | |
103 } | |
104 } | |
105 file_path = enumerator.Next(); | |
106 } | |
107 } | |
108 | |
109 // static | |
110 DevToolsFileWatcher::SharedFileWatcher* | |
111 DevToolsFileWatcher::s_shared_watcher_ = nullptr; | |
112 | |
113 // DevToolsFileWatcher --------------------------------------------------------- | |
114 | |
115 DevToolsFileWatcher::DevToolsFileWatcher(const WatchCallback& callback) | |
116 : callback_(callback) { | |
117 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
118 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
119 base::Bind(&DevToolsFileWatcher::InitSharedWatcher, | |
120 base::Unretained(this))); | |
121 } | |
122 | |
123 DevToolsFileWatcher::~DevToolsFileWatcher() { | |
124 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
125 shared_watcher_->RemoveListener(this); | |
dgozman
2015/11/04 20:11:29
Why refcounting if you remove listener in destruct
pfeldman
2015/11/05 00:18:42
Done.
| |
126 } | |
127 | |
128 void DevToolsFileWatcher::InitSharedWatcher() { | |
129 if (!DevToolsFileWatcher::s_shared_watcher_) | |
130 new SharedFileWatcher(); | |
131 shared_watcher_ = DevToolsFileWatcher::s_shared_watcher_; | |
132 shared_watcher_->AddListener(this); | |
133 } | |
134 | |
135 void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { | |
136 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
137 shared_watcher_->AddWatch(path); | |
138 } | |
139 | |
140 void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { | |
141 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
142 shared_watcher_->RemoveWatch(path); | |
143 } | |
OLD | NEW |