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

Side by Side Diff: components/visitedlink/browser/visitedlink_master.cc

Issue 1417943002: Load the table of visited links from database file asynchronously. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Load the table of visited links asynchronously and inform render about finish loading process. 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "components/visitedlink/browser/visitedlink_master.h" 5 #include "components/visitedlink/browser/visitedlink_master.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <windows.h> 8 #include <windows.h>
9 #include <io.h> 9 #include <io.h>
10 #include <shlobj.h> 10 #include <shlobj.h>
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 // of FILE* value. Double pointer to FILE is used because file may still not 109 // of FILE* value. Double pointer to FILE is used because file may still not
110 // be opened by the time of scheduling the task for execution. 110 // be opened by the time of scheduling the task for execution.
111 void AsyncClose(FILE** file) { 111 void AsyncClose(FILE** file) {
112 if (*file) 112 if (*file)
113 base::IgnoreResult(fclose(*file)); 113 base::IgnoreResult(fclose(*file));
114 free(file); 114 free(file);
115 } 115 }
116 116
117 } // namespace 117 } // namespace
118 118
119 struct VisitedLinkMaster::LoadFromFileResult
120 : public base::RefCountedThreadSafe<LoadFromFileResult> {
121 LoadFromFileResult(base::ScopedFILE file,
122 scoped_ptr<base::SharedMemory> shared_memory,
123 Fingerprint* hash_table,
124 int32 num_entries,
125 int32 used_count,
126 uint8 salt[LINK_SALT_LENGTH]);
127
128 base::ScopedFILE file;
129 scoped_ptr<base::SharedMemory> shared_memory;
130 Fingerprint* hash_table;
131 int32 num_entries;
132 int32 used_count;
133 uint8 salt[LINK_SALT_LENGTH];
134
135 private:
136 friend class base::RefCountedThreadSafe<LoadFromFileResult>;
137 virtual ~LoadFromFileResult();
138
139 DISALLOW_COPY_AND_ASSIGN(LoadFromFileResult);
140 };
141
142 VisitedLinkMaster::LoadFromFileResult::LoadFromFileResult(
143 base::ScopedFILE file,
144 scoped_ptr<base::SharedMemory> shared_memory,
145 Fingerprint* hash_table,
146 int32 num_entries,
147 int32 used_count,
148 uint8 salt[LINK_SALT_LENGTH])
149 : file(file.Pass()),
150 shared_memory(shared_memory.Pass()),
151 hash_table(hash_table),
152 num_entries(num_entries),
153 used_count(used_count) {
154 memcpy(this->salt, salt, LINK_SALT_LENGTH);
155 }
156
157 VisitedLinkMaster::LoadFromFileResult::~LoadFromFileResult() {
158 }
159
119 // TableBuilder --------------------------------------------------------------- 160 // TableBuilder ---------------------------------------------------------------
120 161
121 // How rebuilding from history works 162 // How rebuilding from history works
122 // --------------------------------- 163 // ---------------------------------
123 // 164 //
124 // We mark that we're rebuilding from history by setting the table_builder_ 165 // We mark that we're rebuilding from history by setting the table_builder_
125 // member in VisitedLinkMaster to the TableBuilder we create. This builder 166 // member in VisitedLinkMaster to the TableBuilder we create. This builder
126 // will be called on the history thread by the history system for every URL 167 // will be called on the history thread by the history system for every URL
127 // in the database. 168 // in the database.
128 // 169 //
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 }; 215 };
175 216
176 // VisitedLinkMaster ---------------------------------------------------------- 217 // VisitedLinkMaster ----------------------------------------------------------
177 218
178 VisitedLinkMaster::VisitedLinkMaster(content::BrowserContext* browser_context, 219 VisitedLinkMaster::VisitedLinkMaster(content::BrowserContext* browser_context,
179 VisitedLinkDelegate* delegate, 220 VisitedLinkDelegate* delegate,
180 bool persist_to_disk) 221 bool persist_to_disk)
181 : browser_context_(browser_context), 222 : browser_context_(browser_context),
182 delegate_(delegate), 223 delegate_(delegate),
183 listener_(new VisitedLinkEventListener(this, browser_context)), 224 listener_(new VisitedLinkEventListener(this, browser_context)),
184 persist_to_disk_(persist_to_disk) { 225 persist_to_disk_(persist_to_disk),
226 table_is_loading_from_file_(false),
227 weak_ptr_factory_(this) {
185 InitMembers(); 228 InitMembers();
186 } 229 }
187 230
188 VisitedLinkMaster::VisitedLinkMaster(Listener* listener, 231 VisitedLinkMaster::VisitedLinkMaster(Listener* listener,
189 VisitedLinkDelegate* delegate, 232 VisitedLinkDelegate* delegate,
190 bool persist_to_disk, 233 bool persist_to_disk,
191 bool suppress_rebuild, 234 bool suppress_rebuild,
192 const base::FilePath& filename, 235 const base::FilePath& filename,
193 int32 default_table_size) 236 int32 default_table_size)
194 : browser_context_(NULL), 237 : browser_context_(NULL),
195 delegate_(delegate), 238 delegate_(delegate),
196 persist_to_disk_(persist_to_disk) { 239 persist_to_disk_(persist_to_disk),
240 table_is_loading_from_file_(false),
241 weak_ptr_factory_(this) {
197 listener_.reset(listener); 242 listener_.reset(listener);
198 DCHECK(listener_.get()); 243 DCHECK(listener_.get());
199 InitMembers(); 244 InitMembers();
200 245
201 database_name_override_ = filename; 246 database_name_override_ = filename;
202 table_size_override_ = default_table_size; 247 table_size_override_ = default_table_size;
203 suppress_rebuild_ = suppress_rebuild; 248 suppress_rebuild_ = suppress_rebuild;
204 } 249 }
205 250
206 VisitedLinkMaster::~VisitedLinkMaster() { 251 VisitedLinkMaster::~VisitedLinkMaster() {
207 if (table_builder_.get()) { 252 if (table_builder_.get()) {
208 // Prevent the table builder from calling us back now that we're being 253 // Prevent the table builder from calling us back now that we're being
209 // destroyed. Note that we DON'T delete the object, since the history 254 // destroyed. Note that we DON'T delete the object, since the history
210 // system is still writing into it. When that is complete, the table 255 // system is still writing into it. When that is complete, the table
211 // builder will destroy itself when it finds we are gone. 256 // builder will destroy itself when it finds we are gone.
212 table_builder_->DisownMaster(); 257 table_builder_->DisownMaster();
213 } 258 }
214 FreeURLTable(); 259 FreeURLTable();
215 // FreeURLTable() will schedule closing of the file and deletion of |file_|. 260 // FreeURLTable() will schedule closing of the file and deletion of |file_|.
216 // So nothing should be done here. 261 // So nothing should be done here.
262
263 if (table_is_loading_from_file_ &&
264 (!added_since_load_.empty() || !deleted_since_load_.empty())) {
265 // Delete the database file if it exists because we don't have enough time
266 // to load the table from the database file and now we have inconsistent
267 // state. On the next start table will be rebuilt.
268 base::FilePath filename;
269 GetDatabaseFileName(&filename);
270 PostIOTask(FROM_HERE,
271 base::Bind(IgnoreResult(&base::DeleteFile), filename, false));
272 }
217 } 273 }
218 274
219 void VisitedLinkMaster::InitMembers() { 275 void VisitedLinkMaster::InitMembers() {
220 file_ = NULL; 276 file_ = NULL;
221 shared_memory_ = NULL; 277 shared_memory_ = NULL;
222 shared_memory_serial_ = 0; 278 shared_memory_serial_ = 0;
223 used_items_ = 0; 279 used_items_ = 0;
224 table_size_override_ = 0; 280 table_size_override_ = 0;
225 suppress_rebuild_ = false; 281 suppress_rebuild_ = false;
226 sequence_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken(); 282 sequence_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
227
228 #ifndef NDEBUG
229 posted_asynchronous_operation_ = false;
230 #endif
231 } 283 }
232 284
233 bool VisitedLinkMaster::Init() { 285 bool VisitedLinkMaster::Init() {
234 // We probably shouldn't be loading this from the UI thread, 286 // Create the temporary table. If the table is rebuilt that temporary table
235 // but it does need to happen early on in startup. 287 // will be became the main table.
236 // http://code.google.com/p/chromium/issues/detail?id=24163 288 // The salt must be generated before the table so that it can be copied to
237 base::ThreadRestrictions::ScopedAllowIO allow_io; 289 // the shared memory.
290 GenerateSalt(salt_);
291 if (!CreateURLTable(DefaultTableSize()))
292 return false;
293
294 #ifndef NDEBUG
295 DebugValidate();
296 #endif
238 297
239 if (persist_to_disk_) { 298 if (persist_to_disk_) {
240 if (InitFromFile()) 299 if (InitFromFile())
241 return true; 300 return true;
242 } 301 }
243 return InitFromScratch(suppress_rebuild_); 302 return InitFromScratch(suppress_rebuild_);
244 } 303 }
245 304
246 VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) { 305 VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) {
247 // Extra check that we are not incognito. This should not happen. 306 // Extra check that we are not incognito. This should not happen.
248 // TODO(boliu): Move this check to HistoryService when IsOffTheRecord is 307 // TODO(boliu): Move this check to HistoryService when IsOffTheRecord is
249 // removed from BrowserContext. 308 // removed from BrowserContext.
250 if (browser_context_ && browser_context_->IsOffTheRecord()) { 309 if (browser_context_ && browser_context_->IsOffTheRecord()) {
251 NOTREACHED(); 310 NOTREACHED();
252 return null_hash_; 311 return null_hash_;
253 } 312 }
254 313
255 if (!url.is_valid()) 314 if (!url.is_valid())
256 return null_hash_; // Don't add invalid URLs. 315 return null_hash_; // Don't add invalid URLs.
257 316
258 Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(), 317 Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(),
259 url.spec().size(), 318 url.spec().size(),
260 salt_); 319 salt_);
261 if (table_builder_.get()) { 320 // If the table isn't loaded the table will be rebuilt and after
321 // that accumulated fingerprints will be applied to the table.
322 if (table_builder_.get() || table_is_loading_from_file_) {
262 // If we have a pending delete for this fingerprint, cancel it. 323 // If we have a pending delete for this fingerprint, cancel it.
263 std::set<Fingerprint>::iterator found = 324 deleted_since_rebuild_.erase(fingerprint);
264 deleted_since_rebuild_.find(fingerprint);
265 if (found != deleted_since_rebuild_.end())
266 deleted_since_rebuild_.erase(found);
267 325
268 // A rebuild is in progress, save this addition in the temporary list so 326 // A rebuild or load is in progress, save this addition in the temporary
269 // it can be added once rebuild is complete. 327 // list so it can be added once rebuild is complete.
270 added_since_rebuild_.insert(fingerprint); 328 added_since_rebuild_.insert(fingerprint);
271 } 329 }
272 330
331 if (table_is_loading_from_file_) {
332 // If we have a pending delete for this url, cancel it.
333 deleted_since_load_.erase(url);
334
335 // The loading is in progress, save this addition in the temporary
336 // list so it can be added once the loading is complete.
337 added_since_load_.insert(url);
338 }
339
273 // If the table is "full", we don't add URLs and just drop them on the floor. 340 // If the table is "full", we don't add URLs and just drop them on the floor.
274 // This can happen if we get thousands of new URLs and something causes 341 // This can happen if we get thousands of new URLs and something causes
275 // the table resizing to fail. This check prevents a hang in that case. Note 342 // the table resizing to fail. This check prevents a hang in that case. Note
276 // that this is *not* the resize limit, this is just a sanity check. 343 // that this is *not* the resize limit, this is just a sanity check.
277 if (used_items_ / 8 > table_length_ / 10) 344 if (used_items_ / 8 > table_length_ / 10)
278 return null_hash_; // Table is more than 80% full. 345 return null_hash_; // Table is more than 80% full.
279 346
280 return AddFingerprint(fingerprint, true); 347 return AddFingerprint(fingerprint, true);
281 } 348 }
282 349
283 void VisitedLinkMaster::PostIOTask(const tracked_objects::Location& from_here, 350 void VisitedLinkMaster::PostIOTask(const tracked_objects::Location& from_here,
284 const base::Closure& task) { 351 const base::Closure& task) {
285 DCHECK(persist_to_disk_); 352 DCHECK(persist_to_disk_);
286 BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(sequence_token_, 353 BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(sequence_token_,
287 from_here, task); 354 from_here, task);
288 } 355 }
289 356
290 void VisitedLinkMaster::AddURL(const GURL& url) { 357 void VisitedLinkMaster::AddURL(const GURL& url) {
291 Hash index = TryToAddURL(url); 358 Hash index = TryToAddURL(url);
292 if (!table_builder_.get() && index != null_hash_) { 359 if (!table_builder_.get() &&
360 !table_is_loading_from_file_ &&
361 index != null_hash_) {
293 // Not rebuilding, so we want to keep the file on disk up-to-date. 362 // Not rebuilding, so we want to keep the file on disk up-to-date.
294 if (persist_to_disk_) { 363 if (persist_to_disk_) {
295 WriteUsedItemCountToFile(); 364 WriteUsedItemCountToFile();
296 WriteHashRangeToFile(index, index); 365 WriteHashRangeToFile(index, index);
297 } 366 }
298 ResizeTableIfNecessary(); 367 ResizeTableIfNecessary();
299 } 368 }
300 } 369 }
301 370
302 void VisitedLinkMaster::AddURLs(const std::vector<GURL>& url) { 371 void VisitedLinkMaster::AddURLs(const std::vector<GURL>& urls) {
303 for (std::vector<GURL>::const_iterator i = url.begin(); 372 for (const GURL& url : urls) {
304 i != url.end(); ++i) { 373 Hash index = TryToAddURL(url);
305 Hash index = TryToAddURL(*i); 374 if (!table_builder_.get() &&
306 if (!table_builder_.get() && index != null_hash_) 375 !table_is_loading_from_file_ &&
376 index != null_hash_)
307 ResizeTableIfNecessary(); 377 ResizeTableIfNecessary();
308 } 378 }
309 379
310 // Keeps the file on disk up-to-date. 380 // Keeps the file on disk up-to-date.
311 if (!table_builder_.get() && persist_to_disk_) 381 if (!table_builder_.get() &&
382 !table_is_loading_from_file_ &&
383 persist_to_disk_)
312 WriteFullTable(); 384 WriteFullTable();
313 } 385 }
314 386
315 void VisitedLinkMaster::DeleteAllURLs() { 387 void VisitedLinkMaster::DeleteAllURLs() {
316 // Any pending modifications are invalid. 388 // Any pending modifications are invalid.
317 added_since_rebuild_.clear(); 389 added_since_rebuild_.clear();
318 deleted_since_rebuild_.clear(); 390 deleted_since_rebuild_.clear();
319 391
392 added_since_load_.clear();
393 deleted_since_load_.clear();
394 table_is_loading_from_file_ = false;
395
320 // Clear the hash table. 396 // Clear the hash table.
321 used_items_ = 0; 397 used_items_ = 0;
322 memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint)); 398 memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint));
323 399
324 // Resize it if it is now too empty. Resize may write the new table out for 400 // Resize it if it is now too empty. Resize may write the new table out for
325 // us, otherwise, schedule writing the new table to disk ourselves. 401 // us, otherwise, schedule writing the new table to disk ourselves.
326 if (!ResizeTableIfNecessary() && persist_to_disk_) 402 if (!ResizeTableIfNecessary() && persist_to_disk_)
327 WriteFullTable(); 403 WriteFullTable();
328 404
329 listener_->Reset(); 405 listener_->Reset(false);
330 } 406 }
331 407
332 VisitedLinkDelegate* VisitedLinkMaster::GetDelegate() { 408 VisitedLinkDelegate* VisitedLinkMaster::GetDelegate() {
333 return delegate_; 409 return delegate_;
334 } 410 }
335 411
336 void VisitedLinkMaster::DeleteURLs(URLIterator* urls) { 412 void VisitedLinkMaster::DeleteURLs(URLIterator* urls) {
337 if (!urls->HasNextURL()) 413 if (!urls->HasNextURL())
338 return; 414 return;
339 415
340 listener_->Reset(); 416 listener_->Reset(false);
341 417
342 if (table_builder_.get()) { 418 if (table_builder_.get() || table_is_loading_from_file_) {
343 // A rebuild is in progress, save this deletion in the temporary list so 419 // A rebuild or load is in progress, save this deletion in the temporary
344 // it can be added once rebuild is complete. 420 // list so it can be added once rebuild is complete.
345 while (urls->HasNextURL()) { 421 while (urls->HasNextURL()) {
346 const GURL& url(urls->NextURL()); 422 const GURL& url(urls->NextURL());
347 if (!url.is_valid()) 423 if (!url.is_valid())
348 continue; 424 continue;
349 425
350 Fingerprint fingerprint = 426 Fingerprint fingerprint =
351 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); 427 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_);
352 deleted_since_rebuild_.insert(fingerprint); 428 deleted_since_rebuild_.insert(fingerprint);
353 429
354 // If the URL was just added and now we're deleting it, it may be in the 430 // If the URL was just added and now we're deleting it, it may be in the
355 // list of things added since the last rebuild. Delete it from that list. 431 // list of things added since the last rebuild. Delete it from that list.
356 std::set<Fingerprint>::iterator found = 432 added_since_rebuild_.erase(fingerprint);
357 added_since_rebuild_.find(fingerprint); 433
358 if (found != added_since_rebuild_.end()) 434 if (table_is_loading_from_file_) {
359 added_since_rebuild_.erase(found); 435 deleted_since_load_.insert(url);
436 added_since_load_.erase(url);
437 }
360 438
361 // Delete the URLs from the in-memory table, but don't bother writing 439 // Delete the URLs from the in-memory table, but don't bother writing
362 // to disk since it will be replaced soon. 440 // to disk since it will be replaced soon.
363 DeleteFingerprint(fingerprint, false); 441 DeleteFingerprint(fingerprint, false);
364 } 442 }
365 return; 443 return;
366 } 444 }
367 445
368 // Compute the deleted URLs' fingerprints and delete them 446 // Compute the deleted URLs' fingerprints and delete them
369 std::set<Fingerprint> deleted_fingerprints; 447 std::set<Fingerprint> deleted_fingerprints;
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 605
528 // Write the hash data. 606 // Write the hash data.
529 WriteToFile(file_, kFileHeaderSize, 607 WriteToFile(file_, kFileHeaderSize,
530 hash_table_, table_length_ * sizeof(Fingerprint)); 608 hash_table_, table_length_ * sizeof(Fingerprint));
531 609
532 // The hash table may have shrunk, so make sure this is the end. 610 // The hash table may have shrunk, so make sure this is the end.
533 PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_)); 611 PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_));
534 } 612 }
535 613
536 bool VisitedLinkMaster::InitFromFile() { 614 bool VisitedLinkMaster::InitFromFile() {
537 DCHECK(file_ == NULL); 615 DCHECK_CURRENTLY_ON(BrowserThread::UI);
616
617 DCHECK(file_ == nullptr);
538 DCHECK(persist_to_disk_); 618 DCHECK(persist_to_disk_);
539 619
540 base::FilePath filename; 620 base::FilePath filename;
541 GetDatabaseFileName(&filename); 621 if (!GetDatabaseFileName(&filename))
622 return false;
623
624 table_is_loading_from_file_ = true;
625
626 TableLoadCompleteCallback callback = base::Bind(
627 &VisitedLinkMaster::OnTableLoadComplete, weak_ptr_factory_.GetWeakPtr());
628
629 PostIOTask(FROM_HERE,
630 base::Bind(&VisitedLinkMaster::LoadFromFile, filename, callback));
631
632 return true;
633 }
634
635 // static
636 void VisitedLinkMaster::LoadFromFile(
637 const base::FilePath& filename,
638 const TableLoadCompleteCallback& callback) {
639 scoped_refptr<LoadFromFileResult> load_from_file_result;
640 bool success = LoadApartFromFile(filename, &load_from_file_result);
641
642 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
643 base::Bind(callback, success, load_from_file_result));
644 }
645
646 // static
647 bool VisitedLinkMaster::LoadApartFromFile(
648 const base::FilePath& filename,
649 scoped_refptr<LoadFromFileResult>* load_from_file_result) {
650 DCHECK(load_from_file_result);
651
542 base::ScopedFILE file_closer(base::OpenFile(filename, "rb+")); 652 base::ScopedFILE file_closer(base::OpenFile(filename, "rb+"));
543 if (!file_closer.get()) 653 if (!file_closer.get())
544 return false; 654 return false;
545 655
546 int32 num_entries, used_count; 656 int32 num_entries, used_count;
547 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_)) 657 uint8 salt[LINK_SALT_LENGTH];
658 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt))
548 return false; // Header isn't valid. 659 return false; // Header isn't valid.
549 660
550 // Allocate and read the table. 661 // Allocate and read the table.
551 if (!CreateURLTable(num_entries, false)) 662 scoped_ptr<base::SharedMemory> shared_memory;
663 VisitedLinkCommon::Fingerprint* hash_table;
664 if (!CreateApartURLTable(num_entries, salt, &shared_memory, &hash_table))
552 return false; 665 return false;
553 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, 666
554 hash_table_, num_entries * sizeof(Fingerprint))) { 667 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, hash_table,
555 FreeURLTable(); 668 num_entries * sizeof(Fingerprint))) {
556 return false; 669 return false;
557 } 670 }
558 used_items_ = used_count; 671
672 *load_from_file_result = new LoadFromFileResult(file_closer.Pass(),
673 shared_memory.Pass(),
674 hash_table,
675 num_entries,
676 used_count,
677 salt);
678 return true;
679 }
680
681 void VisitedLinkMaster::OnTableLoadComplete(
682 bool success,
683 scoped_refptr<LoadFromFileResult> load_from_file_result) {
684 DCHECK_CURRENTLY_ON(BrowserThread::UI);
685 DCHECK(persist_to_disk_);
686 DCHECK(!table_builder_.get());
687
688 // When the apart table was loading from the database file the current table
689 // have been cleared.
690 if (!table_is_loading_from_file_)
691 return;
692
693 table_is_loading_from_file_ = false;
694
695 if (!success) {
696 // This temporary sets are used only when table was loaded.
697 added_since_load_.clear();
698 deleted_since_load_.clear();
699
700 // If the table isn't loaded the table will be rebuilt.
701 if (!suppress_rebuild_) {
702 RebuildTableFromDelegate();
703 } else {
704 // When we disallow rebuilds (normally just unit tests), just use the
705 // current empty table.
706 WriteFullTable();
707 }
708 return;
709 }
710
711 // This temprorary sets are needed only to rebuild table.
brettw 2015/12/08 00:54:42 Spelling: temporary
712 added_since_rebuild_.clear();
713 deleted_since_rebuild_.clear();
714
715 DCHECK(load_from_file_result.get());
716
717 // Delete the previous table.
718 DCHECK(shared_memory_);
719 delete shared_memory_;
720 shared_memory_ = nullptr;
721
722 // Assign the open file.
723 DCHECK(!file_);
724 DCHECK(load_from_file_result->file.get());
725 file_ = static_cast<FILE**>(malloc(sizeof(*file_)));
726 *file_ = load_from_file_result->file.release();
727
728 // Assign the loaded table.
729 DCHECK(load_from_file_result->shared_memory.get());
730 DCHECK(load_from_file_result->hash_table);
731 memcpy(salt_, load_from_file_result->salt, LINK_SALT_LENGTH);
732 shared_memory_ = load_from_file_result->shared_memory.release();
733 hash_table_ = load_from_file_result->hash_table;
734 table_length_ = load_from_file_result->num_entries;
735 used_items_ = load_from_file_result->used_count;
559 736
560 #ifndef NDEBUG 737 #ifndef NDEBUG
561 DebugValidate(); 738 DebugValidate();
562 #endif 739 #endif
563 740
564 file_ = static_cast<FILE**>(malloc(sizeof(*file_))); 741 // Send an update notification to all child processes.
565 *file_ = file_closer.release(); 742 listener_->NewTable(shared_memory_);
566 return true; 743
744 if (!added_since_load_.empty() || !deleted_since_load_.empty()) {
745 // Resize the table if the table doesn't have enough capacity.
746 int new_used_items = used_items_ + added_since_load_.size();
747 if (new_used_items >= table_length_)
748 ResizeTable(NewTableSizeForCount(new_used_items));
749
750 // Also add anything that was added while we were asynchronously
751 // loading the table.
752 for (const GURL& url : added_since_load_) {
753 Fingerprint fingerprint =
754 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_);
755 AddFingerprint(fingerprint, false);
756 }
757 added_since_load_.clear();
758
759 // Now handle deletions.
760 for (const GURL& url : deleted_since_load_) {
761 Fingerprint fingerprint =
762 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_);
763 DeleteFingerprint(fingerprint, false);
764 }
765 deleted_since_load_.clear();
766
767 if (persist_to_disk_)
768 WriteFullTable();
769 }
770
771 // All tabs which was loaded when table was being loaded drop their cached
772 // visited link hashes and invalidate their links again.
773 listener_->Reset(true);
567 } 774 }
568 775
569 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { 776 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) {
570 int32 table_size = kDefaultTableSize;
571 if (table_size_override_)
572 table_size = table_size_override_;
573
574 // The salt must be generated before the table so that it can be copied to
575 // the shared memory.
576 GenerateSalt(salt_);
577 if (!CreateURLTable(table_size, true))
578 return false;
579
580 #ifndef NDEBUG
581 DebugValidate();
582 #endif
583
584 if (suppress_rebuild && persist_to_disk_) { 777 if (suppress_rebuild && persist_to_disk_) {
585 // When we disallow rebuilds (normally just unit tests), just use the 778 // When we disallow rebuilds (normally just unit tests), just use the
586 // current empty table. 779 // current empty table.
587 WriteFullTable(); 780 WriteFullTable();
588 return true; 781 return true;
589 } 782 }
590 783
591 // This will build the table from history. On the first run, history will 784 // This will build the table from history. On the first run, history will
592 // be empty, so this will be correct. This will also write the new table 785 // be empty, so this will be correct. This will also write the new table
593 // to disk. We don't want to save explicitly here, since the rebuild may 786 // to disk. We don't want to save explicitly here, since the rebuild may
594 // not complete, leaving us with an empty but valid visited link database. 787 // not complete, leaving us with an empty but valid visited link database.
595 // In the future, we won't know we need to try rebuilding again. 788 // In the future, we won't know we need to try rebuilding again.
596 return RebuildTableFromDelegate(); 789 return RebuildTableFromDelegate();
597 } 790 }
598 791
792 // static
599 bool VisitedLinkMaster::ReadFileHeader(FILE* file, 793 bool VisitedLinkMaster::ReadFileHeader(FILE* file,
600 int32* num_entries, 794 int32* num_entries,
601 int32* used_count, 795 int32* used_count,
602 uint8 salt[LINK_SALT_LENGTH]) { 796 uint8 salt[LINK_SALT_LENGTH]) {
603 DCHECK(persist_to_disk_);
604
605 // Get file size. 797 // Get file size.
606 // Note that there is no need to seek back to the original location in the 798 // Note that there is no need to seek back to the original location in the
607 // file since ReadFromFile() [which is the next call accessing the file] 799 // file since ReadFromFile() [which is the next call accessing the file]
608 // seeks before reading. 800 // seeks before reading.
609 if (fseek(file, 0, SEEK_END) == -1) 801 if (fseek(file, 0, SEEK_END) == -1)
610 return false; 802 return false;
611 size_t file_size = ftell(file); 803 size_t file_size = ftell(file);
612 804
613 if (file_size <= kFileHeaderSize) 805 if (file_size <= kFileHeaderSize)
614 return false; 806 return false;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 if (!browser_context_ || browser_context_->GetPath().empty()) 850 if (!browser_context_ || browser_context_->GetPath().empty())
659 return false; 851 return false;
660 852
661 base::FilePath profile_dir = browser_context_->GetPath(); 853 base::FilePath profile_dir = browser_context_->GetPath();
662 *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links")); 854 *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links"));
663 return true; 855 return true;
664 } 856 }
665 857
666 // Initializes the shared memory structure. The salt should already be filled 858 // Initializes the shared memory structure. The salt should already be filled
667 // in so that it can be written to the shared memory 859 // in so that it can be written to the shared memory
668 bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) { 860 bool VisitedLinkMaster::CreateURLTable(int32 num_entries) {
861 scoped_ptr<base::SharedMemory> shared_memory;
862 VisitedLinkCommon::Fingerprint* hash_table;
863 if (CreateApartURLTable(num_entries, salt_, &shared_memory, &hash_table)) {
864 shared_memory_ = shared_memory.release();
865 hash_table_ = hash_table;
866 table_length_ = num_entries;
867 used_items_ = 0;
868 return true;
869 }
870
871 return false;
872 }
873
874 // static
875 bool VisitedLinkMaster::CreateApartURLTable(
876 int32 num_entries,
877 const uint8 salt[LINK_SALT_LENGTH],
878 scoped_ptr<base::SharedMemory>* shared_memory,
879 VisitedLinkCommon::Fingerprint** hash_table) {
880 DCHECK(salt);
881 DCHECK(shared_memory);
882 DCHECK(hash_table);
883
669 // The table is the size of the table followed by the entries. 884 // The table is the size of the table followed by the entries.
670 uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader); 885 uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader);
671 886
672 // Create the shared memory object. 887 // Create the shared memory object.
673 shared_memory_ = new base::SharedMemory(); 888 scoped_ptr<base::SharedMemory> sh_mem(new base::SharedMemory());
674 if (!shared_memory_) 889 if (!sh_mem)
675 return false; 890 return false;
676 891
677 base::SharedMemoryCreateOptions options; 892 base::SharedMemoryCreateOptions options;
678 options.size = alloc_size; 893 options.size = alloc_size;
679 options.share_read_only = true; 894 options.share_read_only = true;
680 895
681 if (!shared_memory_->Create(options) || !shared_memory_->Map(alloc_size)) { 896 if (!sh_mem->Create(options) || !sh_mem->Map(alloc_size))
682 delete shared_memory_;
683 shared_memory_ = NULL;
684 return false; 897 return false;
685 }
686 898
687 if (init_to_empty) { 899 memset(sh_mem->memory(), 0, alloc_size);
688 memset(shared_memory_->memory(), 0, alloc_size);
689 used_items_ = 0;
690 }
691 table_length_ = num_entries;
692 900
693 // Save the header for other processes to read. 901 // Save the header for other processes to read.
694 SharedHeader* header = static_cast<SharedHeader*>(shared_memory_->memory()); 902 SharedHeader* header = static_cast<SharedHeader*>(sh_mem->memory());
695 header->length = table_length_; 903 header->length = num_entries;
696 memcpy(header->salt, salt_, LINK_SALT_LENGTH); 904 memcpy(header->salt, salt, LINK_SALT_LENGTH);
697 905
698 // Our table pointer is just the data immediately following the size. 906 // Our table pointer is just the data immediately following the size.
699 hash_table_ = reinterpret_cast<Fingerprint*>( 907 *hash_table = reinterpret_cast<Fingerprint*>(
700 static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader)); 908 static_cast<char*>(sh_mem->memory()) + sizeof(SharedHeader));
909
910 *shared_memory = sh_mem.Pass();
701 911
702 return true; 912 return true;
703 } 913 }
704 914
705 bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) { 915 bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) {
706 base::SharedMemory *old_shared_memory = shared_memory_; 916 base::SharedMemory *old_shared_memory = shared_memory_;
707 Fingerprint* old_hash_table = hash_table_; 917 Fingerprint* old_hash_table = hash_table_;
708 int32 old_table_length = table_length_; 918 int32 old_table_length = table_length_;
709 if (!CreateURLTable(num_entries, true)) { 919 if (!CreateURLTable(num_entries)) {
710 // Try to put back the old state. 920 // Try to put back the old state.
711 shared_memory_ = old_shared_memory; 921 shared_memory_ = old_shared_memory;
712 hash_table_ = old_hash_table; 922 hash_table_ = old_hash_table;
713 table_length_ = old_table_length; 923 table_length_ = old_table_length;
714 return false; 924 return false;
715 } 925 }
716 926
717 #ifndef NDEBUG 927 #ifndef NDEBUG
718 DebugValidate(); 928 DebugValidate();
719 #endif 929 #endif
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 999
790 #ifndef NDEBUG 1000 #ifndef NDEBUG
791 DebugValidate(); 1001 DebugValidate();
792 #endif 1002 #endif
793 1003
794 // The new table needs to be written to disk. 1004 // The new table needs to be written to disk.
795 if (persist_to_disk_) 1005 if (persist_to_disk_)
796 WriteFullTable(); 1006 WriteFullTable();
797 } 1007 }
798 1008
1009 uint32 VisitedLinkMaster::DefaultTableSize() const {
1010 if (table_size_override_)
1011 return table_size_override_;
1012
1013 return kDefaultTableSize;
1014 }
1015
799 uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const { 1016 uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const {
800 // These table sizes are selected to be the maximum prime number less than 1017 // These table sizes are selected to be the maximum prime number less than
801 // a "convenient" multiple of 1K. 1018 // a "convenient" multiple of 1K.
802 static const int table_sizes[] = { 1019 static const int table_sizes[] = {
803 16381, // 16K = 16384 <- don't shrink below this table size 1020 16381, // 16K = 16384 <- don't shrink below this table size
804 // (should be == default_table_size) 1021 // (should be == default_table_size)
805 32767, // 32K = 32768 1022 32767, // 32K = 32768
806 65521, // 64K = 65536 1023 65521, // 64K = 65536
807 130051, // 128K = 131072 1024 130051, // 128K = 131072
808 262127, // 256K = 262144 1025 262127, // 256K = 262144
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 // replacement succeeds. 1067 // replacement succeeds.
851 base::SharedMemory* old_shared_memory = shared_memory_; 1068 base::SharedMemory* old_shared_memory = shared_memory_;
852 1069
853 int new_table_size = NewTableSizeForCount( 1070 int new_table_size = NewTableSizeForCount(
854 static_cast<int>(fingerprints.size() + added_since_rebuild_.size())); 1071 static_cast<int>(fingerprints.size() + added_since_rebuild_.size()));
855 if (BeginReplaceURLTable(new_table_size)) { 1072 if (BeginReplaceURLTable(new_table_size)) {
856 // Free the old table. 1073 // Free the old table.
857 delete old_shared_memory; 1074 delete old_shared_memory;
858 1075
859 // Add the stored fingerprints to the hash table. 1076 // Add the stored fingerprints to the hash table.
860 for (size_t i = 0; i < fingerprints.size(); i++) 1077 for (const auto& fingerprint : fingerprints)
861 AddFingerprint(fingerprints[i], false); 1078 AddFingerprint(fingerprint, false);
862 1079
863 // Also add anything that was added while we were asynchronously 1080 // Also add anything that was added while we were asynchronously
864 // generating the new table. 1081 // generating the new table.
865 for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin(); 1082 for (const auto& fingerprint : added_since_rebuild_)
866 i != added_since_rebuild_.end(); ++i) 1083 AddFingerprint(fingerprint, false);
867 AddFingerprint(*i, false);
868 added_since_rebuild_.clear(); 1084 added_since_rebuild_.clear();
869 1085
870 // Now handle deletions. 1086 // Now handle deletions. Do not shrink the table now, we'll shrink it when
871 DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_); 1087 // adding or deleting an url the next time.
1088 for (const auto& fingerprint : deleted_since_rebuild_)
1089 DeleteFingerprint(fingerprint, false);
872 deleted_since_rebuild_.clear(); 1090 deleted_since_rebuild_.clear();
873 1091
874 // Send an update notification to all child processes. 1092 // Send an update notification to all child processes.
875 listener_->NewTable(shared_memory_); 1093 listener_->NewTable(shared_memory_);
1094 // All tabs which was loaded when table was being rebuilt
1095 // invalidate their links again.
1096 listener_->Reset(false);
876 1097
877 if (persist_to_disk_) 1098 if (persist_to_disk_)
878 WriteFullTable(); 1099 WriteFullTable();
879 } 1100 }
880 } 1101 }
881 table_builder_ = NULL; // Will release our reference to the builder. 1102 table_builder_ = NULL; // Will release our reference to the builder.
882 1103
883 // Notify the unit test that the rebuild is complete (will be NULL in prod.) 1104 // Notify the unit test that the rebuild is complete (will be NULL in prod.)
884 if (!rebuild_complete_task_.is_null()) { 1105 if (!rebuild_complete_task_.is_null()) {
885 rebuild_complete_task_.Run(); 1106 rebuild_complete_task_.Run();
886 rebuild_complete_task_.Reset(); 1107 rebuild_complete_task_.Reset();
887 } 1108 }
888 } 1109 }
889 1110
890 void VisitedLinkMaster::WriteToFile(FILE** file, 1111 void VisitedLinkMaster::WriteToFile(FILE** file,
891 off_t offset, 1112 off_t offset,
892 void* data, 1113 void* data,
893 int32 data_size) { 1114 int32 data_size) {
894 DCHECK(persist_to_disk_); 1115 DCHECK(persist_to_disk_);
895 #ifndef NDEBUG 1116 DCHECK(!table_is_loading_from_file_);
896 posted_asynchronous_operation_ = true;
897 #endif
898 PostIOTask(FROM_HERE, 1117 PostIOTask(FROM_HERE,
899 base::Bind(&AsyncWrite, file, offset, 1118 base::Bind(&AsyncWrite, file, offset,
900 std::string(static_cast<const char*>(data), data_size))); 1119 std::string(static_cast<const char*>(data), data_size)));
901 } 1120 }
902 1121
903 void VisitedLinkMaster::WriteUsedItemCountToFile() { 1122 void VisitedLinkMaster::WriteUsedItemCountToFile() {
904 DCHECK(persist_to_disk_); 1123 DCHECK(persist_to_disk_);
905 if (!file_) 1124 if (!file_)
906 return; // See comment on the file_ variable for why this might happen. 1125 return; // See comment on the file_ variable for why this might happen.
907 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); 1126 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_));
(...skipping 14 matching lines...) Expand all
922 WriteToFile(file_, kFileHeaderSize, hash_table_, 1141 WriteToFile(file_, kFileHeaderSize, hash_table_,
923 (last_hash + 1) * sizeof(Fingerprint)); 1142 (last_hash + 1) * sizeof(Fingerprint));
924 } else { 1143 } else {
925 // Normal case, just write the range. 1144 // Normal case, just write the range.
926 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize, 1145 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
927 &hash_table_[first_hash], 1146 &hash_table_[first_hash],
928 (last_hash - first_hash + 1) * sizeof(Fingerprint)); 1147 (last_hash - first_hash + 1) * sizeof(Fingerprint));
929 } 1148 }
930 } 1149 }
931 1150
1151 // static
932 bool VisitedLinkMaster::ReadFromFile(FILE* file, 1152 bool VisitedLinkMaster::ReadFromFile(FILE* file,
933 off_t offset, 1153 off_t offset,
934 void* data, 1154 void* data,
935 size_t data_size) { 1155 size_t data_size) {
936 DCHECK(persist_to_disk_);
937 #ifndef NDEBUG
938 // Since this function is synchronous, we require that no asynchronous
939 // operations could possibly be pending.
940 DCHECK(!posted_asynchronous_operation_);
941 #endif
942
943 if (fseek(file, offset, SEEK_SET) != 0) 1156 if (fseek(file, offset, SEEK_SET) != 0)
944 return false; 1157 return false;
945 1158
946 size_t num_read = fread(data, 1, data_size, file); 1159 size_t num_read = fread(data, 1, data_size, file);
947 return num_read == data_size; 1160 return num_read == data_size;
948 } 1161 }
949 1162
950 // VisitedLinkTableBuilder ---------------------------------------------------- 1163 // VisitedLinkTableBuilder ----------------------------------------------------
951 1164
952 VisitedLinkMaster::TableBuilder::TableBuilder( 1165 VisitedLinkMaster::TableBuilder::TableBuilder(
(...skipping 28 matching lines...) Expand all
981 BrowserThread::UI, FROM_HERE, 1194 BrowserThread::UI, FROM_HERE,
982 base::Bind(&TableBuilder::OnCompleteMainThread, this)); 1195 base::Bind(&TableBuilder::OnCompleteMainThread, this));
983 } 1196 }
984 1197
985 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { 1198 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() {
986 if (master_) 1199 if (master_)
987 master_->OnTableRebuildComplete(success_, fingerprints_); 1200 master_->OnTableRebuildComplete(success_, fingerprints_);
988 } 1201 }
989 1202
990 } // namespace visitedlink 1203 } // namespace visitedlink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698