blob: 9e97b8e3d520440bf5276731d0d1235e7de8bf16 [file] [log] [blame]
[email protected]200bd332013-08-05 16:19:111// Copyright 2013 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_system_indexer.h"
6
avie4d7b6f2015-12-26 00:59:187#include <stddef.h>
8
[email protected]200bd332013-08-05 16:19:119#include <iterator>
10
11#include "base/bind.h"
12#include "base/callback.h"
[email protected]200bd332013-08-05 16:19:1113#include "base/files/file_enumerator.h"
thestig18dfb7a52014-08-26 10:44:0414#include "base/files/file_util.h"
[email protected]200bd332013-08-05 16:19:1115#include "base/lazy_instance.h"
16#include "base/logging.h"
avie4d7b6f2015-12-26 00:59:1817#include "base/macros.h"
Andrey Kosyakov6d214b212017-06-23 22:47:0818#include "base/sequence_checker.h"
[email protected]09f3fde82014-05-14 15:08:1519#include "base/stl_util.h"
zhongyi23960342016-04-12 23:13:2020#include "base/strings/string_util.h"
[email protected]200bd332013-08-05 16:19:1121#include "base/strings/utf_string_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3322#include "base/task/lazy_task_runner.h"
23#include "base/task/post_task.h"
Eric Seckler8652dcd52018-09-20 10:42:2824#include "content/public/browser/browser_task_traits.h"
Andrey Kosyakov6d214b212017-06-23 22:47:0825
[email protected]200bd332013-08-05 16:19:1126#include "content/public/browser/browser_thread.h"
27
28using base::Bind;
29using base::Callback;
30using base::FileEnumerator;
31using base::FilePath;
[email protected]200bd332013-08-05 16:19:1132using base::Time;
33using base::TimeDelta;
34using base::TimeTicks;
[email protected]200bd332013-08-05 16:19:1135using content::BrowserThread;
36using std::map;
[email protected]200bd332013-08-05 16:19:1137using std::string;
38using std::vector;
39
40namespace {
41
Maksim Sisov63c4dc412017-08-16 10:56:5842using std::set;
43
Andrey Kosyakov6d214b212017-06-23 22:47:0844base::SequencedTaskRunner* impl_task_runner() {
Gabriel Charetteb10aeebc2018-07-26 20:15:0045 constexpr base::TaskTraits kBlockingTraits = {
Sami Kyostilac9580452019-06-17 12:26:2746 base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT};
Andrey Kosyakovf9e21f72017-07-06 17:38:1947 static base::LazySequencedTaskRunner s_sequenced_task_task_runner =
Andrey Kosyakov6d214b212017-06-23 22:47:0848 LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(kBlockingTraits);
Andrey Kosyakovf9e21f72017-07-06 17:38:1949 return s_sequenced_task_task_runner.Get().get();
Andrey Kosyakov6d214b212017-06-23 22:47:0850}
51
avie4d7b6f2015-12-26 00:59:1852typedef int32_t Trigram;
[email protected]200bd332013-08-05 16:19:1153typedef char TrigramChar;
avie4d7b6f2015-12-26 00:59:1854typedef uint16_t FileId;
[email protected]200bd332013-08-05 16:19:1155
56const int kMinTimeoutBetweenWorkedNitification = 200;
57// Trigram characters include all ASCII printable characters (32-126) except for
58// the capital letters, because the index is case insensitive.
59const size_t kTrigramCharacterCount = 126 - 'Z' - 1 + 'A' - ' ' + 1;
60const size_t kTrigramCount =
61 kTrigramCharacterCount * kTrigramCharacterCount * kTrigramCharacterCount;
62const int kMaxReadLength = 10 * 1024;
63const TrigramChar kUndefinedTrigramChar = -1;
vsevik3ef1c9d2014-10-23 14:17:3564const TrigramChar kBinaryTrigramChar = -2;
[email protected]200bd332013-08-05 16:19:1165const Trigram kUndefinedTrigram = -1;
66
[email protected]200bd332013-08-05 16:19:1167class Index {
68 public:
69 Index();
raphael.kubo.da.costa65005e82016-11-16 11:17:2670 // Index is only instantiated as a leak LazyInstance, so the destructor is
71 // never called.
72 ~Index() = delete;
73
[email protected]200bd332013-08-05 16:19:1174 Time LastModifiedTimeForFile(const FilePath& file_path);
75 void SetTrigramsForFile(const FilePath& file_path,
76 const vector<Trigram>& index,
77 const Time& time);
Andrey Kosyakov6d214b212017-06-23 22:47:0878 vector<FilePath> Search(const string& query);
[email protected]200bd332013-08-05 16:19:1179 void NormalizeVectors();
Andrey Lushnikov5955e512018-03-20 22:19:0580 void Reset();
81 void EnsureInitialized();
[email protected]200bd332013-08-05 16:19:1182
83 private:
[email protected]200bd332013-08-05 16:19:1184 FileId GetFileId(const FilePath& file_path);
85
86 typedef map<FilePath, FileId> FileIdsMap;
87 FileIdsMap file_ids_;
88 FileId last_file_id_;
89 // The index in this vector is the trigram id.
90 vector<vector<FileId> > index_;
91 typedef map<FilePath, Time> IndexedFilesMap;
92 IndexedFilesMap index_times_;
93 vector<bool> is_normalized_;
Andrey Kosyakov6d214b212017-06-23 22:47:0894 SEQUENCE_CHECKER(sequence_checker_);
[email protected]200bd332013-08-05 16:19:1195
96 DISALLOW_COPY_AND_ASSIGN(Index);
97};
98
99base::LazyInstance<Index>::Leaky g_trigram_index = LAZY_INSTANCE_INITIALIZER;
100
[email protected]200bd332013-08-05 16:19:11101TrigramChar TrigramCharForChar(char c) {
vsevik3ef1c9d2014-10-23 14:17:35102 static TrigramChar* trigram_chars = nullptr;
103 if (!trigram_chars) {
104 trigram_chars = new TrigramChar[256];
105 for (size_t i = 0; i < 256; ++i) {
106 if (i > 127) {
107 trigram_chars[i] = kUndefinedTrigramChar;
108 continue;
109 }
110 char ch = static_cast<char>(i);
111 if (ch == '\t')
112 ch = ' ';
zhongyi23960342016-04-12 23:13:20113 if (base::IsAsciiUpper(ch))
vsevik3ef1c9d2014-10-23 14:17:35114 ch = ch - 'A' + 'a';
115
116 bool is_binary_char = ch < 9 || (ch >= 14 && ch < 32) || ch == 127;
117 if (is_binary_char) {
118 trigram_chars[i] = kBinaryTrigramChar;
119 continue;
120 }
121
122 if (ch < ' ') {
123 trigram_chars[i] = kUndefinedTrigramChar;
124 continue;
125 }
126
127 if (ch >= 'Z')
128 ch = ch - 'Z' - 1 + 'A';
129 ch -= ' ';
130 char signed_trigram_count = static_cast<char>(kTrigramCharacterCount);
131 CHECK(ch >= 0 && ch < signed_trigram_count);
132 trigram_chars[i] = ch;
133 }
134 }
[email protected]200bd332013-08-05 16:19:11135 unsigned char uc = static_cast<unsigned char>(c);
vsevik3ef1c9d2014-10-23 14:17:35136 return trigram_chars[uc];
[email protected]200bd332013-08-05 16:19:11137}
138
[email protected]8f8304732013-08-05 22:25:52139Trigram TrigramAtIndex(const vector<TrigramChar>& trigram_chars, size_t index) {
[email protected]200bd332013-08-05 16:19:11140 static int kTrigramCharacterCountSquared =
141 kTrigramCharacterCount * kTrigramCharacterCount;
142 if (trigram_chars[index] == kUndefinedTrigramChar ||
143 trigram_chars[index + 1] == kUndefinedTrigramChar ||
144 trigram_chars[index + 2] == kUndefinedTrigramChar)
145 return kUndefinedTrigram;
146 Trigram trigram = kTrigramCharacterCountSquared * trigram_chars[index] +
147 kTrigramCharacterCount * trigram_chars[index + 1] +
148 trigram_chars[index + 2];
149 return trigram;
150}
151
152Index::Index() : last_file_id_(0) {
Andrey Lushnikov5955e512018-03-20 22:19:05153 Reset();
154}
155
156void Index::Reset() {
157 file_ids_.clear();
158 index_.clear();
159 index_times_.clear();
160 is_normalized_.clear();
161 last_file_id_ = 0;
162}
163
164void Index::EnsureInitialized() {
Zinovy Nisdcc844d2019-02-28 07:11:29165 if (!index_.empty())
Andrey Lushnikov5955e512018-03-20 22:19:05166 return;
[email protected]200bd332013-08-05 16:19:11167 index_.resize(kTrigramCount);
168 is_normalized_.resize(kTrigramCount);
169 std::fill(is_normalized_.begin(), is_normalized_.end(), true);
170}
171
[email protected]200bd332013-08-05 16:19:11172Time Index::LastModifiedTimeForFile(const FilePath& file_path) {
Andrey Kosyakov6d214b212017-06-23 22:47:08173 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Andrey Lushnikov5955e512018-03-20 22:19:05174 EnsureInitialized();
[email protected]200bd332013-08-05 16:19:11175 Time last_modified_time;
176 if (index_times_.find(file_path) != index_times_.end())
177 last_modified_time = index_times_[file_path];
178 return last_modified_time;
179}
180
181void Index::SetTrigramsForFile(const FilePath& file_path,
182 const vector<Trigram>& index,
183 const Time& time) {
Andrey Kosyakov6d214b212017-06-23 22:47:08184 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Andrey Lushnikov5955e512018-03-20 22:19:05185 EnsureInitialized();
[email protected]200bd332013-08-05 16:19:11186 FileId file_id = GetFileId(file_path);
jdoerriec6fe63e2018-10-03 20:53:40187 auto it = index.begin();
[email protected]200bd332013-08-05 16:19:11188 for (; it != index.end(); ++it) {
189 Trigram trigram = *it;
190 index_[trigram].push_back(file_id);
191 is_normalized_[trigram] = false;
192 }
193 index_times_[file_path] = time;
194}
195
Andrey Kosyakov6d214b212017-06-23 22:47:08196vector<FilePath> Index::Search(const string& query) {
197 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Andrey Lushnikov5955e512018-03-20 22:19:05198 EnsureInitialized();
[email protected]200bd332013-08-05 16:19:11199 const char* data = query.c_str();
200 vector<TrigramChar> trigram_chars;
201 trigram_chars.reserve(query.size());
vsevik3ef1c9d2014-10-23 14:17:35202 for (size_t i = 0; i < query.size(); ++i) {
203 TrigramChar trigram_char = TrigramCharForChar(data[i]);
204 if (trigram_char == kBinaryTrigramChar)
205 trigram_char = kUndefinedTrigramChar;
206 trigram_chars.push_back(trigram_char);
207 }
[email protected]200bd332013-08-05 16:19:11208 vector<Trigram> trigrams;
209 for (size_t i = 0; i + 2 < query.size(); ++i) {
210 Trigram trigram = TrigramAtIndex(trigram_chars, i);
211 if (trigram != kUndefinedTrigram)
212 trigrams.push_back(trigram);
213 }
214 set<FileId> file_ids;
215 bool first = true;
216 vector<Trigram>::const_iterator it = trigrams.begin();
217 for (; it != trigrams.end(); ++it) {
218 Trigram trigram = *it;
219 if (first) {
220 std::copy(index_[trigram].begin(),
221 index_[trigram].end(),
222 std::inserter(file_ids, file_ids.begin()));
223 first = false;
224 continue;
225 }
[email protected]09f3fde82014-05-14 15:08:15226 set<FileId> intersection = base::STLSetIntersection<set<FileId> >(
227 file_ids, index_[trigram]);
[email protected]200bd332013-08-05 16:19:11228 file_ids.swap(intersection);
229 }
230 vector<FilePath> result;
231 FileIdsMap::const_iterator ids_it = file_ids_.begin();
232 for (; ids_it != file_ids_.end(); ++ids_it) {
Zinovy Nisdcc844d2019-02-28 07:11:29233 if (trigrams.empty() || file_ids.find(ids_it->second) != file_ids.end()) {
[email protected]200bd332013-08-05 16:19:11234 result.push_back(ids_it->first);
235 }
236 }
237 return result;
238}
239
240FileId Index::GetFileId(const FilePath& file_path) {
Andrey Kosyakov6d214b212017-06-23 22:47:08241 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Andrey Lushnikov5955e512018-03-20 22:19:05242 EnsureInitialized();
[email protected]200bd332013-08-05 16:19:11243 string file_path_str = file_path.AsUTF8Unsafe();
244 if (file_ids_.find(file_path) != file_ids_.end())
245 return file_ids_[file_path];
246 file_ids_[file_path] = ++last_file_id_;
247 return last_file_id_;
248}
249
250void Index::NormalizeVectors() {
Andrey Kosyakov6d214b212017-06-23 22:47:08251 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Andrey Lushnikov5955e512018-03-20 22:19:05252 EnsureInitialized();
[email protected]200bd332013-08-05 16:19:11253 for (size_t i = 0; i < kTrigramCount; ++i) {
254 if (!is_normalized_[i]) {
255 std::sort(index_[i].begin(), index_[i].end());
256 if (index_[i].capacity() > index_[i].size())
257 vector<FileId>(index_[i]).swap(index_[i]);
258 is_normalized_[i] = true;
259 }
260 }
261}
262
[email protected]200bd332013-08-05 16:19:11263typedef Callback<void(bool, const vector<bool>&)> IndexerCallback;
264
265} // namespace
266
267DevToolsFileSystemIndexer::FileSystemIndexingJob::FileSystemIndexingJob(
268 const FilePath& file_system_path,
Andrey Lushnikov007878862018-03-21 19:12:00269 const std::vector<base::FilePath>& excluded_folders,
[email protected]200bd332013-08-05 16:19:11270 const TotalWorkCallback& total_work_callback,
271 const WorkedCallback& worked_callback,
272 const DoneCallback& done_callback)
273 : file_system_path_(file_system_path),
Andrey Lushnikov007878862018-03-21 19:12:00274 excluded_folders_(excluded_folders),
[email protected]200bd332013-08-05 16:19:11275 total_work_callback_(total_work_callback),
276 worked_callback_(worked_callback),
277 done_callback_(done_callback),
[email protected]200bd332013-08-05 16:19:11278 files_indexed_(0),
279 stopped_(false) {
280 current_trigrams_set_.resize(kTrigramCount);
281 current_trigrams_.reserve(kTrigramCount);
Andrey Lushnikov007878862018-03-21 19:12:00282 pending_folders_.push_back(file_system_path);
[email protected]200bd332013-08-05 16:19:11283}
284
285DevToolsFileSystemIndexer::FileSystemIndexingJob::~FileSystemIndexingJob() {}
286
287void DevToolsFileSystemIndexer::FileSystemIndexingJob::Start() {
mostynb13260d52015-03-26 09:12:09288 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakov6d214b212017-06-23 22:47:08289 impl_task_runner()->PostTask(
290 FROM_HERE, BindOnce(&FileSystemIndexingJob::CollectFilesToIndex, this));
[email protected]200bd332013-08-05 16:19:11291}
292
293void DevToolsFileSystemIndexer::FileSystemIndexingJob::Stop() {
mostynb13260d52015-03-26 09:12:09294 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakov6d214b212017-06-23 22:47:08295 impl_task_runner()->PostTask(
296 FROM_HERE, BindOnce(&FileSystemIndexingJob::StopOnImplSequence, this));
[email protected]200bd332013-08-05 16:19:11297}
298
Andrey Kosyakov6d214b212017-06-23 22:47:08299void DevToolsFileSystemIndexer::FileSystemIndexingJob::StopOnImplSequence() {
[email protected]200bd332013-08-05 16:19:11300 stopped_ = true;
301}
302
303void DevToolsFileSystemIndexer::FileSystemIndexingJob::CollectFilesToIndex() {
Andrey Kosyakov6d214b212017-06-23 22:47:08304 DCHECK(impl_task_runner()->RunsTasksInCurrentSequence());
[email protected]200bd332013-08-05 16:19:11305 if (stopped_)
306 return;
307 if (!file_enumerator_) {
Andrey Lushnikov007878862018-03-21 19:12:00308 file_enumerator_.reset(new FileEnumerator(
309 pending_folders_.back(), false,
310 FileEnumerator::FILES | FileEnumerator::DIRECTORIES));
311 pending_folders_.pop_back();
[email protected]200bd332013-08-05 16:19:11312 }
313 FilePath file_path = file_enumerator_->Next();
Andrey Lushnikov007878862018-03-21 19:12:00314 if (file_path.empty() && !pending_folders_.empty()) {
315 file_enumerator_.reset(new FileEnumerator(
316 pending_folders_.back(), false,
317 FileEnumerator::FILES | FileEnumerator::DIRECTORIES));
318 pending_folders_.pop_back();
319 impl_task_runner()->PostTask(
320 FROM_HERE, BindOnce(&FileSystemIndexingJob::CollectFilesToIndex, this));
321 return;
322 }
323
[email protected]200bd332013-08-05 16:19:11324 if (file_path.empty()) {
Sami Kyostila4ba007d2019-08-14 12:03:14325 base::PostTask(FROM_HERE, {BrowserThread::UI},
326 BindOnce(total_work_callback_, file_path_times_.size()));
[email protected]200bd332013-08-05 16:19:11327 indexing_it_ = file_path_times_.begin();
328 IndexFiles();
329 return;
330 }
Andrey Lushnikov007878862018-03-21 19:12:00331 if (file_enumerator_->GetInfo().IsDirectory()) {
332 bool excluded = false;
333 for (const FilePath& excluded_folder : excluded_folders_) {
334 excluded = excluded_folder.IsParent(file_path);
335 if (excluded)
336 break;
337 }
338 if (!excluded)
339 pending_folders_.push_back(file_path);
340 impl_task_runner()->PostTask(
341 FROM_HERE, BindOnce(&FileSystemIndexingJob::CollectFilesToIndex, this));
342 return;
343 }
344
[email protected]200bd332013-08-05 16:19:11345 Time saved_last_modified_time =
346 g_trigram_index.Get().LastModifiedTimeForFile(file_path);
347 FileEnumerator::FileInfo file_info = file_enumerator_->GetInfo();
348 Time current_last_modified_time = file_info.GetLastModifiedTime();
349 if (current_last_modified_time > saved_last_modified_time) {
350 file_path_times_[file_path] = current_last_modified_time;
351 }
Andrey Kosyakov6d214b212017-06-23 22:47:08352 impl_task_runner()->PostTask(
353 FROM_HERE, BindOnce(&FileSystemIndexingJob::CollectFilesToIndex, this));
[email protected]200bd332013-08-05 16:19:11354}
355
356void DevToolsFileSystemIndexer::FileSystemIndexingJob::IndexFiles() {
Andrey Kosyakov6d214b212017-06-23 22:47:08357 DCHECK(impl_task_runner()->RunsTasksInCurrentSequence());
[email protected]200bd332013-08-05 16:19:11358 if (stopped_)
359 return;
360 if (indexing_it_ == file_path_times_.end()) {
361 g_trigram_index.Get().NormalizeVectors();
Sami Kyostila4ba007d2019-08-14 12:03:14362 base::PostTask(FROM_HERE, {BrowserThread::UI}, done_callback_);
[email protected]200bd332013-08-05 16:19:11363 return;
364 }
365 FilePath file_path = indexing_it_->first;
Andrey Kosyakovc1f83c1e2017-06-27 00:28:13366 current_file_.Initialize(file_path,
367 base::File::FLAG_OPEN | base::File::FLAG_READ);
[email protected]200bd332013-08-05 16:19:11368
[email protected]bda135f2014-04-10 21:55:06369 if (!current_file_.IsValid()) {
[email protected]200bd332013-08-05 16:19:11370 FinishFileIndexing(false);
371 return;
372 }
[email protected]200bd332013-08-05 16:19:11373 current_file_offset_ = 0;
374 current_trigrams_.clear();
375 std::fill(current_trigrams_set_.begin(), current_trigrams_set_.end(), false);
376 ReadFromFile();
377}
378
379void DevToolsFileSystemIndexer::FileSystemIndexingJob::ReadFromFile() {
380 if (stopped_) {
381 CloseFile();
382 return;
383 }
Andrey Kosyakovc1f83c1e2017-06-27 00:28:13384 std::unique_ptr<char[]> data_ptr(new char[kMaxReadLength]);
385 const char* const data = data_ptr.get();
386 int bytes_read =
387 current_file_.Read(current_file_offset_, data_ptr.get(), kMaxReadLength);
388 if (bytes_read < 0) {
[email protected]200bd332013-08-05 16:19:11389 FinishFileIndexing(false);
390 return;
391 }
392
Andrey Kosyakovc1f83c1e2017-06-27 00:28:13393 if (bytes_read < 3) {
[email protected]200bd332013-08-05 16:19:11394 FinishFileIndexing(true);
395 return;
396 }
397
398 size_t size = static_cast<size_t>(bytes_read);
399 vector<TrigramChar> trigram_chars;
400 trigram_chars.reserve(size);
401 for (size_t i = 0; i < size; ++i) {
vsevik3ef1c9d2014-10-23 14:17:35402 TrigramChar trigram_char = TrigramCharForChar(data[i]);
403 if (trigram_char == kBinaryTrigramChar) {
[email protected]200bd332013-08-05 16:19:11404 current_trigrams_.clear();
405 FinishFileIndexing(true);
406 return;
407 }
vsevik3ef1c9d2014-10-23 14:17:35408 trigram_chars.push_back(trigram_char);
[email protected]200bd332013-08-05 16:19:11409 }
410
411 for (size_t i = 0; i + 2 < size; ++i) {
412 Trigram trigram = TrigramAtIndex(trigram_chars, i);
413 if ((trigram != kUndefinedTrigram) && !current_trigrams_set_[trigram]) {
414 current_trigrams_set_[trigram] = true;
415 current_trigrams_.push_back(trigram);
416 }
417 }
418 current_file_offset_ += bytes_read - 2;
Andrey Kosyakovc1f83c1e2017-06-27 00:28:13419 impl_task_runner()->PostTask(
420 FROM_HERE, base::BindOnce(&FileSystemIndexingJob::ReadFromFile, this));
[email protected]200bd332013-08-05 16:19:11421}
422
423void DevToolsFileSystemIndexer::FileSystemIndexingJob::FinishFileIndexing(
424 bool success) {
Andrey Kosyakov6d214b212017-06-23 22:47:08425 DCHECK(impl_task_runner()->RunsTasksInCurrentSequence());
[email protected]200bd332013-08-05 16:19:11426 CloseFile();
427 if (success) {
428 FilePath file_path = indexing_it_->first;
429 g_trigram_index.Get().SetTrigramsForFile(
430 file_path, current_trigrams_, file_path_times_[file_path]);
431 }
432 ReportWorked();
433 ++indexing_it_;
Andrey Kosyakovf9e21f72017-07-06 17:38:19434 impl_task_runner()->PostTask(
435 FROM_HERE, base::BindOnce(&FileSystemIndexingJob::IndexFiles, this));
[email protected]200bd332013-08-05 16:19:11436}
437
438void DevToolsFileSystemIndexer::FileSystemIndexingJob::CloseFile() {
[email protected]bda135f2014-04-10 21:55:06439 if (current_file_.IsValid())
Andrey Kosyakovc1f83c1e2017-06-27 00:28:13440 current_file_.Close();
[email protected]200bd332013-08-05 16:19:11441}
442
[email protected]200bd332013-08-05 16:19:11443void DevToolsFileSystemIndexer::FileSystemIndexingJob::ReportWorked() {
444 TimeTicks current_time = TimeTicks::Now();
445 bool should_send_worked_nitification = true;
446 if (!last_worked_notification_time_.is_null()) {
447 TimeDelta delta = current_time - last_worked_notification_time_;
448 if (delta.InMilliseconds() < kMinTimeoutBetweenWorkedNitification)
449 should_send_worked_nitification = false;
450 }
451 ++files_indexed_;
452 if (should_send_worked_nitification) {
453 last_worked_notification_time_ = current_time;
Sami Kyostila4ba007d2019-08-14 12:03:14454 base::PostTask(FROM_HERE, {BrowserThread::UI},
455 BindOnce(worked_callback_, files_indexed_));
[email protected]200bd332013-08-05 16:19:11456 files_indexed_ = 0;
457 }
458}
459
Andrey Lushnikov5955e512018-03-20 22:19:05460static int g_instance_count = 0;
[email protected]200bd332013-08-05 16:19:11461
Andrey Lushnikov5955e512018-03-20 22:19:05462DevToolsFileSystemIndexer::DevToolsFileSystemIndexer() {
Andrey Lushnikov6986cc22018-03-21 22:06:28463 impl_task_runner()->PostTask(FROM_HERE,
464 base::BindOnce([]() { ++g_instance_count; }));
Andrey Lushnikov5955e512018-03-20 22:19:05465}
466
467DevToolsFileSystemIndexer::~DevToolsFileSystemIndexer() {
Andrey Lushnikov6986cc22018-03-21 22:06:28468 impl_task_runner()->PostTask(FROM_HERE, base::BindOnce([]() {
469 --g_instance_count;
470 if (!g_instance_count)
471 g_trigram_index.Get().Reset();
472 }));
Andrey Lushnikov5955e512018-03-20 22:19:05473}
[email protected]200bd332013-08-05 16:19:11474
475scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>
476DevToolsFileSystemIndexer::IndexPath(
477 const string& file_system_path,
Andrey Lushnikov007878862018-03-21 19:12:00478 const vector<string>& excluded_folders,
[email protected]200bd332013-08-05 16:19:11479 const TotalWorkCallback& total_work_callback,
480 const WorkedCallback& worked_callback,
481 const DoneCallback& done_callback) {
mostynb13260d52015-03-26 09:12:09482 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Lushnikov007878862018-03-21 19:12:00483 vector<base::FilePath> paths;
484 for (const string& path : excluded_folders) {
485 paths.push_back(FilePath::FromUTF8Unsafe(path));
486 }
487 scoped_refptr<FileSystemIndexingJob> indexing_job = new FileSystemIndexingJob(
488 FilePath::FromUTF8Unsafe(file_system_path), paths, total_work_callback,
489 worked_callback, done_callback);
[email protected]200bd332013-08-05 16:19:11490 indexing_job->Start();
491 return indexing_job;
492}
493
Andrey Kosyakov6d214b212017-06-23 22:47:08494void DevToolsFileSystemIndexer::SearchInPath(
495 const std::string& file_system_path,
496 const std::string& query,
497 const SearchCallback& callback) {
mostynb13260d52015-03-26 09:12:09498 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakov6d214b212017-06-23 22:47:08499 impl_task_runner()->PostTask(
500 FROM_HERE,
501 BindOnce(&DevToolsFileSystemIndexer::SearchInPathOnImplSequence, this,
tzik93bf8a72017-04-24 18:53:30502 file_system_path, query, callback));
[email protected]200bd332013-08-05 16:19:11503}
504
Andrey Kosyakov6d214b212017-06-23 22:47:08505void DevToolsFileSystemIndexer::SearchInPathOnImplSequence(
506 const std::string& file_system_path,
507 const std::string& query,
[email protected]200bd332013-08-05 16:19:11508 const SearchCallback& callback) {
Andrey Kosyakov6d214b212017-06-23 22:47:08509 DCHECK(impl_task_runner()->RunsTasksInCurrentSequence());
[email protected]200bd332013-08-05 16:19:11510 vector<FilePath> file_paths = g_trigram_index.Get().Search(query);
511 vector<string> result;
512 FilePath path = FilePath::FromUTF8Unsafe(file_system_path);
513 vector<FilePath>::const_iterator it = file_paths.begin();
514 for (; it != file_paths.end(); ++it) {
515 if (path.IsParent(*it))
516 result.push_back(it->AsUTF8Unsafe());
517 }
Sami Kyostila4ba007d2019-08-14 12:03:14518 base::PostTask(FROM_HERE, {BrowserThread::UI},
519 BindOnce(callback, std::move(result)));
[email protected]200bd332013-08-05 16:19:11520}