OLD | NEW |
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 "chrome/browser/visitedlink/visitedlink_master.h" | 5 #include "chrome/browser/visitedlink/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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 | 57 |
58 // Fills the given salt structure with some quasi-random values | 58 // Fills the given salt structure with some quasi-random values |
59 // It is not necessary to generate a cryptographically strong random string, | 59 // It is not necessary to generate a cryptographically strong random string, |
60 // only that it be reasonably different for different users. | 60 // only that it be reasonably different for different users. |
61 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { | 61 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { |
62 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt"; | 62 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt"; |
63 uint64 randval = base::RandUint64(); | 63 uint64 randval = base::RandUint64(); |
64 memcpy(salt, &randval, 8); | 64 memcpy(salt, &randval, 8); |
65 } | 65 } |
66 | 66 |
| 67 // Opens file on a background thread to not block UI thread. |
| 68 void AsyncOpen(FILE** file, FilePath filename) { |
| 69 *file = OpenFile(filename, "wb+"); |
| 70 DLOG_IF(ERROR, !(*file)) << "Failed to open file " << filename.value(); |
| 71 } |
| 72 |
67 // Returns true if the write was complete. | 73 // Returns true if the write was complete. |
68 static bool WriteToFile(FILE* file, | 74 static bool WriteToFile(FILE* file, |
69 off_t offset, | 75 off_t offset, |
70 const void* data, | 76 const void* data, |
71 size_t data_len) { | 77 size_t data_len) { |
72 if (fseek(file, offset, SEEK_SET) != 0) | 78 if (fseek(file, offset, SEEK_SET) != 0) |
73 return false; // Don't write to an invalid part of the file. | 79 return false; // Don't write to an invalid part of the file. |
74 | 80 |
75 size_t num_written = fwrite(data, 1, data_len, file); | 81 size_t num_written = fwrite(data, 1, data_len, file); |
76 | 82 |
77 // The write may not make it to the kernel (stdlib may buffer the write) | 83 // The write may not make it to the kernel (stdlib may buffer the write) |
78 // until the next fseek/fclose call. If we crash, it's easy for our used | 84 // until the next fseek/fclose call. If we crash, it's easy for our used |
79 // item count to be out of sync with the number of hashes we write. | 85 // item count to be out of sync with the number of hashes we write. |
80 // Protect against this by calling fflush. | 86 // Protect against this by calling fflush. |
81 int ret = fflush(file); | 87 int ret = fflush(file); |
82 DCHECK_EQ(0, ret); | 88 DCHECK_EQ(0, ret); |
83 return num_written == data_len; | 89 return num_written == data_len; |
84 } | 90 } |
85 | 91 |
86 // This task executes on a background thread and executes a write. This | 92 // This task executes on a background thread and executes a write. This |
87 // prevents us from blocking the UI thread doing I/O. | 93 // prevents us from blocking the UI thread doing I/O. Double pointer to FILE |
88 void AsyncWrite(FILE* file, int32 offset, const std::string& data) { | 94 // is used because file may still not be opened by the time of scheduling |
89 WriteToFile(file, offset, data.data(), data.size()); | 95 // the task for execution. |
| 96 void AsyncWrite(FILE** file, int32 offset, const std::string& data) { |
| 97 WriteToFile(*file, offset, data.data(), data.size()); |
| 98 } |
| 99 |
| 100 // Truncates the file to the current position asynchronously on a background |
| 101 // thread. Double pointer to FILE is used because file may still not be opened |
| 102 // by the time of scheduling the task for execution. |
| 103 void AsyncTruncate(FILE** file) { |
| 104 base::IgnoreResult(TruncateFile(*file)); |
| 105 } |
| 106 |
| 107 // Closes the file on a background thread and releases memory used for storage |
| 108 // of FILE* value. Double pointer to FILE is used because file may still not |
| 109 // be opened by the time of scheduling the task for execution. |
| 110 void AsyncClose(FILE** file) { |
| 111 base::IgnoreResult(fclose(*file)); |
| 112 free(file); |
90 } | 113 } |
91 | 114 |
92 } // namespace | 115 } // namespace |
93 | 116 |
94 // TableBuilder --------------------------------------------------------------- | 117 // TableBuilder --------------------------------------------------------------- |
95 | 118 |
96 // How rebuilding from history works | 119 // How rebuilding from history works |
97 // --------------------------------- | 120 // --------------------------------- |
98 // | 121 // |
99 // We mark that we're rebuilding from history by setting the table_builder_ | 122 // We mark that we're rebuilding from history by setting the table_builder_ |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 | 194 |
172 VisitedLinkMaster::~VisitedLinkMaster() { | 195 VisitedLinkMaster::~VisitedLinkMaster() { |
173 if (table_builder_.get()) { | 196 if (table_builder_.get()) { |
174 // Prevent the table builder from calling us back now that we're being | 197 // Prevent the table builder from calling us back now that we're being |
175 // destroyed. Note that we DON'T delete the object, since the history | 198 // destroyed. Note that we DON'T delete the object, since the history |
176 // system is still writing into it. When that is complete, the table | 199 // system is still writing into it. When that is complete, the table |
177 // builder will destroy itself when it finds we are gone. | 200 // builder will destroy itself when it finds we are gone. |
178 table_builder_->DisownMaster(); | 201 table_builder_->DisownMaster(); |
179 } | 202 } |
180 FreeURLTable(); | 203 FreeURLTable(); |
| 204 // FreeURLTable() will schedule closing of the file and deletion of |file_|. |
| 205 // So nothing should be done here. |
181 } | 206 } |
182 | 207 |
183 void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) { | 208 void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) { |
184 DCHECK(listener); | 209 DCHECK(listener); |
185 | 210 |
186 listener_ = listener; | 211 listener_ = listener; |
187 file_ = NULL; | 212 file_ = NULL; |
188 shared_memory_ = NULL; | 213 shared_memory_ = NULL; |
189 shared_memory_serial_ = 0; | 214 shared_memory_serial_ = 0; |
190 used_items_ = 0; | 215 used_items_ = 0; |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 AddFingerprint(shuffled_fingerprints[i], false); | 473 AddFingerprint(shuffled_fingerprints[i], false); |
449 } | 474 } |
450 | 475 |
451 // Write the affected range to disk [deleted_hash, end_range]. | 476 // Write the affected range to disk [deleted_hash, end_range]. |
452 if (update_file) | 477 if (update_file) |
453 WriteHashRangeToFile(deleted_hash, end_range); | 478 WriteHashRangeToFile(deleted_hash, end_range); |
454 | 479 |
455 return true; | 480 return true; |
456 } | 481 } |
457 | 482 |
458 bool VisitedLinkMaster::WriteFullTable() { | 483 void VisitedLinkMaster::WriteFullTable() { |
459 // This function can get called when the file is open, for example, when we | 484 // This function can get called when the file is open, for example, when we |
460 // resize the table. We must handle this case and not try to reopen the file, | 485 // resize the table. We must handle this case and not try to reopen the file, |
461 // since there may be write operations pending on the file I/O thread. | 486 // since there may be write operations pending on the file I/O thread. |
462 // | 487 // |
463 // Note that once we start writing, we do not delete on error. This means | 488 // Note that once we start writing, we do not delete on error. This means |
464 // there can be a partial file, but the short file will be detected next time | 489 // there can be a partial file, but the short file will be detected next time |
465 // we start, and will be replaced. | 490 // we start, and will be replaced. |
466 // | 491 // |
467 // This might possibly get corrupted if we crash in the middle of writing. | 492 // This might possibly get corrupted if we crash in the middle of writing. |
468 // We should pick up the most common types of these failures when we notice | 493 // We should pick up the most common types of these failures when we notice |
469 // that the file size is different when we load it back in, and then we will | 494 // that the file size is different when we load it back in, and then we will |
470 // regenerate the table. | 495 // regenerate the table. |
471 if (!file_) { | 496 if (!file_) { |
| 497 file_ = static_cast<FILE**>(calloc(1, sizeof(*file_))); |
472 FilePath filename; | 498 FilePath filename; |
473 GetDatabaseFileName(&filename); | 499 GetDatabaseFileName(&filename); |
474 file_ = OpenFile(filename, "wb+"); | 500 PostIOTask(FROM_HERE, base::Bind(&AsyncOpen, file_, filename)); |
475 if (!file_) { | |
476 DLOG(ERROR) << "Failed to open file " << filename.value(); | |
477 return false; | |
478 } | |
479 } | 501 } |
480 | 502 |
481 // Write the new header. | 503 // Write the new header. |
482 int32 header[4]; | 504 int32 header[4]; |
483 header[0] = kFileSignature; | 505 header[0] = kFileSignature; |
484 header[1] = kFileCurrentVersion; | 506 header[1] = kFileCurrentVersion; |
485 header[2] = table_length_; | 507 header[2] = table_length_; |
486 header[3] = used_items_; | 508 header[3] = used_items_; |
487 WriteToFile(file_, 0, header, sizeof(header)); | 509 WriteToFile(file_, 0, header, sizeof(header)); |
488 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); | 510 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); |
489 | 511 |
490 // Write the hash data. | 512 // Write the hash data. |
491 WriteToFile(file_, kFileHeaderSize, | 513 WriteToFile(file_, kFileHeaderSize, |
492 hash_table_, table_length_ * sizeof(Fingerprint)); | 514 hash_table_, table_length_ * sizeof(Fingerprint)); |
493 | 515 |
494 // The hash table may have shrunk, so make sure this is the end. | 516 // The hash table may have shrunk, so make sure this is the end. |
495 PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&TruncateFile), file_)); | 517 PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_)); |
496 return true; | |
497 } | 518 } |
498 | 519 |
499 bool VisitedLinkMaster::InitFromFile() { | 520 bool VisitedLinkMaster::InitFromFile() { |
500 DCHECK(file_ == NULL); | 521 DCHECK(file_ == NULL); |
501 | 522 |
502 FilePath filename; | 523 FilePath filename; |
503 GetDatabaseFileName(&filename); | 524 GetDatabaseFileName(&filename); |
504 ScopedFILE file_closer(OpenFile(filename, "rb+")); | 525 ScopedFILE file_closer(OpenFile(filename, "rb+")); |
505 if (!file_closer.get()) | 526 if (!file_closer.get()) |
506 return false; | 527 return false; |
507 | 528 |
508 int32 num_entries, used_count; | 529 int32 num_entries, used_count; |
509 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_)) | 530 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_)) |
510 return false; // Header isn't valid. | 531 return false; // Header isn't valid. |
511 | 532 |
512 // Allocate and read the table. | 533 // Allocate and read the table. |
513 if (!CreateURLTable(num_entries, false)) | 534 if (!CreateURLTable(num_entries, false)) |
514 return false; | 535 return false; |
515 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, | 536 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, |
516 hash_table_, num_entries * sizeof(Fingerprint))) { | 537 hash_table_, num_entries * sizeof(Fingerprint))) { |
517 FreeURLTable(); | 538 FreeURLTable(); |
518 return false; | 539 return false; |
519 } | 540 } |
520 used_items_ = used_count; | 541 used_items_ = used_count; |
521 | 542 |
522 #ifndef NDEBUG | 543 #ifndef NDEBUG |
523 DebugValidate(); | 544 DebugValidate(); |
524 #endif | 545 #endif |
525 | 546 |
526 file_ = file_closer.release(); | 547 file_ = static_cast<FILE**>(malloc(sizeof(*file_))); |
| 548 *file_ = file_closer.release(); |
527 return true; | 549 return true; |
528 } | 550 } |
529 | 551 |
530 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { | 552 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { |
531 int32 table_size = kDefaultTableSize; | 553 int32 table_size = kDefaultTableSize; |
532 if (table_size_override_) | 554 if (table_size_override_) |
533 table_size = table_size_override_; | 555 table_size = table_size_override_; |
534 | 556 |
535 // The salt must be generated before the table so that it can be copied to | 557 // The salt must be generated before the table so that it can be copied to |
536 // the shared memory. | 558 // the shared memory. |
537 GenerateSalt(salt_); | 559 GenerateSalt(salt_); |
538 if (!CreateURLTable(table_size, true)) | 560 if (!CreateURLTable(table_size, true)) |
539 return false; | 561 return false; |
540 | 562 |
541 #ifndef NDEBUG | 563 #ifndef NDEBUG |
542 DebugValidate(); | 564 DebugValidate(); |
543 #endif | 565 #endif |
544 | 566 |
545 if (suppress_rebuild) { | 567 if (suppress_rebuild) { |
546 // When we disallow rebuilds (normally just unit tests), just use the | 568 // When we disallow rebuilds (normally just unit tests), just use the |
547 // current empty table. | 569 // current empty table. |
548 return WriteFullTable(); | 570 WriteFullTable(); |
| 571 return true; |
549 } | 572 } |
550 | 573 |
551 // This will build the table from history. On the first run, history will | 574 // This will build the table from history. On the first run, history will |
552 // be empty, so this will be correct. This will also write the new table | 575 // be empty, so this will be correct. This will also write the new table |
553 // to disk. We don't want to save explicitly here, since the rebuild may | 576 // to disk. We don't want to save explicitly here, since the rebuild may |
554 // not complete, leaving us with an empty but valid visited link database. | 577 // not complete, leaving us with an empty but valid visited link database. |
555 // In the future, we won't know we need to try rebuilding again. | 578 // In the future, we won't know we need to try rebuilding again. |
556 return RebuildTableFromHistory(); | 579 return RebuildTableFromHistory(); |
557 } | 580 } |
558 | 581 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 return true; | 698 return true; |
676 } | 699 } |
677 | 700 |
678 void VisitedLinkMaster::FreeURLTable() { | 701 void VisitedLinkMaster::FreeURLTable() { |
679 if (shared_memory_) { | 702 if (shared_memory_) { |
680 delete shared_memory_; | 703 delete shared_memory_; |
681 shared_memory_ = NULL; | 704 shared_memory_ = NULL; |
682 } | 705 } |
683 if (!file_) | 706 if (!file_) |
684 return; | 707 return; |
685 PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&fclose), file_)); | 708 PostIOTask(FROM_HERE, base::Bind(&AsyncClose, file_)); |
| 709 // AsyncClose() will close the file and free the memory pointed by |file_|. |
| 710 file_ = NULL; |
686 } | 711 } |
687 | 712 |
688 bool VisitedLinkMaster::ResizeTableIfNecessary() { | 713 bool VisitedLinkMaster::ResizeTableIfNecessary() { |
689 DCHECK(table_length_ > 0) << "Must have a table"; | 714 DCHECK(table_length_ > 0) << "Must have a table"; |
690 | 715 |
691 // Load limits for good performance/space. We are pretty conservative about | 716 // Load limits for good performance/space. We are pretty conservative about |
692 // keeping the table not very full. This is because we use linear probing | 717 // keeping the table not very full. This is because we use linear probing |
693 // which increases the likelihood of clumps of entries which will reduce | 718 // which increases the likelihood of clumps of entries which will reduce |
694 // performance. | 719 // performance. |
695 const float max_table_load = 0.5f; // Grow when we're > this full. | 720 const float max_table_load = 0.5f; // Grow when we're > this full. |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
830 for (size_t i = 0; i < fingerprints.size(); i++) | 855 for (size_t i = 0; i < fingerprints.size(); i++) |
831 AddFingerprint(fingerprints[i], false); | 856 AddFingerprint(fingerprints[i], false); |
832 | 857 |
833 // Also add anything that was added while we were asynchronously | 858 // Also add anything that was added while we were asynchronously |
834 // generating the new table. | 859 // generating the new table. |
835 for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin(); | 860 for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin(); |
836 i != added_since_rebuild_.end(); ++i) | 861 i != added_since_rebuild_.end(); ++i) |
837 AddFingerprint(*i, false); | 862 AddFingerprint(*i, false); |
838 added_since_rebuild_.clear(); | 863 added_since_rebuild_.clear(); |
839 | 864 |
840 // We shouldn't be writing the table from the main thread! | |
841 // http://code.google.com/p/chromium/issues/detail?id=24163 | |
842 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
843 | |
844 // Now handle deletions. | 865 // Now handle deletions. |
845 DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_); | 866 DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_); |
846 deleted_since_rebuild_.clear(); | 867 deleted_since_rebuild_.clear(); |
847 | 868 |
848 // Send an update notification to all child processes. | 869 // Send an update notification to all child processes. |
849 listener_->NewTable(shared_memory_); | 870 listener_->NewTable(shared_memory_); |
850 | 871 |
851 WriteFullTable(); | 872 WriteFullTable(); |
852 } | 873 } |
853 } | 874 } |
854 table_builder_ = NULL; // Will release our reference to the builder. | 875 table_builder_ = NULL; // Will release our reference to the builder. |
855 | 876 |
856 // Notify the unit test that the rebuild is complete (will be NULL in prod.) | 877 // Notify the unit test that the rebuild is complete (will be NULL in prod.) |
857 if (!rebuild_complete_task_.is_null()) { | 878 if (!rebuild_complete_task_.is_null()) { |
858 rebuild_complete_task_.Run(); | 879 rebuild_complete_task_.Run(); |
859 rebuild_complete_task_.Reset(); | 880 rebuild_complete_task_.Reset(); |
860 } | 881 } |
861 } | 882 } |
862 | 883 |
863 void VisitedLinkMaster::WriteToFile(FILE* file, | 884 void VisitedLinkMaster::WriteToFile(FILE** file, |
864 off_t offset, | 885 off_t offset, |
865 void* data, | 886 void* data, |
866 int32 data_size) { | 887 int32 data_size) { |
867 #ifndef NDEBUG | 888 #ifndef NDEBUG |
868 posted_asynchronous_operation_ = true; | 889 posted_asynchronous_operation_ = true; |
869 #endif | 890 #endif |
870 PostIOTask(FROM_HERE, | 891 PostIOTask(FROM_HERE, |
871 base::Bind(&AsyncWrite, file, offset, | 892 base::Bind(&AsyncWrite, file, offset, |
872 std::string(static_cast<const char*>(data), data_size))); | 893 std::string(static_cast<const char*>(data), data_size))); |
873 } | 894 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 } | 972 } |
952 | 973 |
953 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { | 974 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { |
954 if (master_) | 975 if (master_) |
955 master_->OnTableRebuildComplete(success_, fingerprints_); | 976 master_->OnTableRebuildComplete(success_, fingerprints_); |
956 | 977 |
957 // WILL (generally) DELETE THIS! This balances the AddRef in | 978 // WILL (generally) DELETE THIS! This balances the AddRef in |
958 // VisitedLinkMaster::RebuildTableFromHistory. | 979 // VisitedLinkMaster::RebuildTableFromHistory. |
959 Release(); | 980 Release(); |
960 } | 981 } |
OLD | NEW |