| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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> |
| 11 #endif // defined(OS_WIN) | 11 #endif // defined(OS_WIN) |
| 12 #include <stdio.h> | 12 #include <stdio.h> |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 | 15 |
| 16 #include "base/bind.h" | 16 #include "base/bind.h" |
| 17 #include "base/bind_helpers.h" |
| 17 #include "base/file_util.h" | 18 #include "base/file_util.h" |
| 18 #include "base/logging.h" | 19 #include "base/logging.h" |
| 19 #include "base/message_loop.h" | 20 #include "base/message_loop.h" |
| 20 #include "base/path_service.h" | 21 #include "base/path_service.h" |
| 21 #include "base/process_util.h" | 22 #include "base/process_util.h" |
| 22 #include "base/rand_util.h" | 23 #include "base/rand_util.h" |
| 23 #include "base/stack_container.h" | 24 #include "base/stack_container.h" |
| 24 #include "base/string_util.h" | 25 #include "base/string_util.h" |
| 25 #include "base/threading/thread_restrictions.h" | 26 #include "base/threading/thread_restrictions.h" |
| 26 #include "chrome/browser/history/history.h" | 27 #include "chrome/browser/history/history.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 55 | 56 |
| 56 // Fills the given salt structure with some quasi-random values | 57 // Fills the given salt structure with some quasi-random values |
| 57 // It is not necessary to generate a cryptographically strong random string, | 58 // It is not necessary to generate a cryptographically strong random string, |
| 58 // only that it be reasonably different for different users. | 59 // only that it be reasonably different for different users. |
| 59 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { | 60 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { |
| 60 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt"; | 61 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt"; |
| 61 uint64 randval = base::RandUint64(); | 62 uint64 randval = base::RandUint64(); |
| 62 memcpy(salt, &randval, 8); | 63 memcpy(salt, &randval, 8); |
| 63 } | 64 } |
| 64 | 65 |
| 65 // AsyncWriter ---------------------------------------------------------------- | 66 // Returns true if the write was complete. |
| 67 static bool WriteToFile(FILE* file, |
| 68 off_t offset, |
| 69 const void* data, |
| 70 size_t data_len) { |
| 71 if (fseek(file, offset, SEEK_SET) != 0) |
| 72 return false; // Don't write to an invalid part of the file. |
| 73 |
| 74 size_t num_written = fwrite(data, 1, data_len, file); |
| 75 |
| 76 // The write may not make it to the kernel (stdlib may buffer the write) |
| 77 // until the next fseek/fclose call. If we crash, it's easy for our used |
| 78 // item count to be out of sync with the number of hashes we write. |
| 79 // Protect against this by calling fflush. |
| 80 int ret = fflush(file); |
| 81 DCHECK_EQ(0, ret); |
| 82 return num_written == data_len; |
| 83 } |
| 66 | 84 |
| 67 // This task executes on a background thread and executes a write. This | 85 // This task executes on a background thread and executes a write. This |
| 68 // prevents us from blocking the UI thread doing I/O. | 86 // prevents us from blocking the UI thread doing I/O. |
| 69 class AsyncWriter : public Task { | 87 void AsyncWrite(FILE* file, int32 offset, const std::string& data) { |
| 70 public: | 88 WriteToFile(file, offset, data.data(), data.size()); |
| 71 AsyncWriter(FILE* file, int32 offset, const void* data, size_t data_len) | 89 } |
| 72 : file_(file), | |
| 73 offset_(offset) { | |
| 74 data_->resize(data_len); | |
| 75 memcpy(&*data_->begin(), data, data_len); | |
| 76 } | |
| 77 | |
| 78 virtual void Run() { | |
| 79 WriteToFile(file_, offset_, | |
| 80 &*data_->begin(), static_cast<int32>(data_->size())); | |
| 81 } | |
| 82 | |
| 83 // Exposed as a static so it can be called directly from the Master to | |
| 84 // reduce the number of platform-specific I/O sites we have. Returns true if | |
| 85 // the write was complete. | |
| 86 static bool WriteToFile(FILE* file, | |
| 87 off_t offset, | |
| 88 const void* data, | |
| 89 size_t data_len) { | |
| 90 if (fseek(file, offset, SEEK_SET) != 0) | |
| 91 return false; // Don't write to an invalid part of the file. | |
| 92 | |
| 93 size_t num_written = fwrite(data, 1, data_len, file); | |
| 94 | |
| 95 // The write may not make it to the kernel (stdlib may buffer the write) | |
| 96 // until the next fseek/fclose call. If we crash, it's easy for our used | |
| 97 // item count to be out of sync with the number of hashes we write. | |
| 98 // Protect against this by calling fflush. | |
| 99 int ret = fflush(file); | |
| 100 DCHECK_EQ(0, ret); | |
| 101 return num_written == data_len; | |
| 102 } | |
| 103 | |
| 104 private: | |
| 105 // The data to write and where to write it. | |
| 106 FILE* file_; | |
| 107 int32 offset_; // Offset from the beginning of the file. | |
| 108 | |
| 109 // Most writes are just a single fingerprint, so we reserve that much in this | |
| 110 // object to avoid mallocs in that case. | |
| 111 StackVector<char, sizeof(VisitedLinkCommon::Fingerprint)> data_; | |
| 112 | |
| 113 DISALLOW_COPY_AND_ASSIGN(AsyncWriter); | |
| 114 }; | |
| 115 | |
| 116 // Used to asynchronously set the end of the file. This must be done on the | |
| 117 // same thread as the writing to keep things synchronized. | |
| 118 class AsyncSetEndOfFile : public Task { | |
| 119 public: | |
| 120 explicit AsyncSetEndOfFile(FILE* file) : file_(file) {} | |
| 121 | |
| 122 virtual void Run() { | |
| 123 TruncateFile(file_); | |
| 124 } | |
| 125 | |
| 126 private: | |
| 127 FILE* file_; | |
| 128 DISALLOW_COPY_AND_ASSIGN(AsyncSetEndOfFile); | |
| 129 }; | |
| 130 | |
| 131 // Used to asynchronously close a file. This must be done on the same thread as | |
| 132 // the writing to keep things synchronized. | |
| 133 class AsyncCloseHandle : public Task { | |
| 134 public: | |
| 135 explicit AsyncCloseHandle(FILE* file) : file_(file) {} | |
| 136 | |
| 137 virtual void Run() { | |
| 138 fclose(file_); | |
| 139 } | |
| 140 | |
| 141 private: | |
| 142 FILE* file_; | |
| 143 DISALLOW_COPY_AND_ASSIGN(AsyncCloseHandle); | |
| 144 }; | |
| 145 | 90 |
| 146 } // namespace | 91 } // namespace |
| 147 | 92 |
| 148 // TableBuilder --------------------------------------------------------------- | 93 // TableBuilder --------------------------------------------------------------- |
| 149 | 94 |
| 150 // How rebuilding from history works | 95 // How rebuilding from history works |
| 151 // --------------------------------- | 96 // --------------------------------- |
| 152 // | 97 // |
| 153 // We mark that we're rebuilding from history by setting the table_builder_ | 98 // We mark that we're rebuilding from history by setting the table_builder_ |
| 154 // member in VisitedLinkMaster to the TableBuilder we create. This builder | 99 // member in VisitedLinkMaster to the TableBuilder we create. This builder |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 header[3] = used_items_; | 474 header[3] = used_items_; |
| 530 WriteToFile(file_, 0, header, sizeof(header)); | 475 WriteToFile(file_, 0, header, sizeof(header)); |
| 531 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); | 476 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); |
| 532 | 477 |
| 533 // Write the hash data. | 478 // Write the hash data. |
| 534 WriteToFile(file_, kFileHeaderSize, | 479 WriteToFile(file_, kFileHeaderSize, |
| 535 hash_table_, table_length_ * sizeof(Fingerprint)); | 480 hash_table_, table_length_ * sizeof(Fingerprint)); |
| 536 | 481 |
| 537 // The hash table may have shrunk, so make sure this is the end. | 482 // The hash table may have shrunk, so make sure this is the end. |
| 538 BrowserThread::PostTask( | 483 BrowserThread::PostTask( |
| 539 BrowserThread::FILE, FROM_HERE, new AsyncSetEndOfFile(file_)); | 484 BrowserThread::FILE, |
| 485 FROM_HERE, |
| 486 base::Bind(base::IgnoreResult(&TruncateFile), file_)); |
| 540 return true; | 487 return true; |
| 541 } | 488 } |
| 542 | 489 |
| 543 bool VisitedLinkMaster::InitFromFile() { | 490 bool VisitedLinkMaster::InitFromFile() { |
| 544 DCHECK(file_ == NULL); | 491 DCHECK(file_ == NULL); |
| 545 | 492 |
| 546 FilePath filename; | 493 FilePath filename; |
| 547 GetDatabaseFileName(&filename); | 494 GetDatabaseFileName(&filename); |
| 548 ScopedFILE file_closer(OpenFile(filename, "rb+")); | 495 ScopedFILE file_closer(OpenFile(filename, "rb+")); |
| 549 if (!file_closer.get()) | 496 if (!file_closer.get()) |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 | 668 |
| 722 void VisitedLinkMaster::FreeURLTable() { | 669 void VisitedLinkMaster::FreeURLTable() { |
| 723 if (shared_memory_) { | 670 if (shared_memory_) { |
| 724 delete shared_memory_; | 671 delete shared_memory_; |
| 725 shared_memory_ = NULL; | 672 shared_memory_ = NULL; |
| 726 } | 673 } |
| 727 if (!file_) | 674 if (!file_) |
| 728 return; | 675 return; |
| 729 | 676 |
| 730 BrowserThread::PostTask( | 677 BrowserThread::PostTask( |
| 731 BrowserThread::FILE, FROM_HERE, new AsyncCloseHandle(file_)); | 678 BrowserThread::FILE, |
| 679 FROM_HERE, |
| 680 base::Bind(base::IgnoreResult(&fclose), file_)); |
| 732 } | 681 } |
| 733 | 682 |
| 734 bool VisitedLinkMaster::ResizeTableIfNecessary() { | 683 bool VisitedLinkMaster::ResizeTableIfNecessary() { |
| 735 DCHECK(table_length_ > 0) << "Must have a table"; | 684 DCHECK(table_length_ > 0) << "Must have a table"; |
| 736 | 685 |
| 737 // Load limits for good performance/space. We are pretty conservative about | 686 // Load limits for good performance/space. We are pretty conservative about |
| 738 // keeping the table not very full. This is because we use linear probing | 687 // keeping the table not very full. This is because we use linear probing |
| 739 // which increases the likelihood of clumps of entries which will reduce | 688 // which increases the likelihood of clumps of entries which will reduce |
| 740 // performance. | 689 // performance. |
| 741 const float max_table_load = 0.5f; // Grow when we're > this full. | 690 const float max_table_load = 0.5f; // Grow when we're > this full. |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 void VisitedLinkMaster::WriteToFile(FILE* file, | 856 void VisitedLinkMaster::WriteToFile(FILE* file, |
| 908 off_t offset, | 857 off_t offset, |
| 909 void* data, | 858 void* data, |
| 910 int32 data_size) { | 859 int32 data_size) { |
| 911 #ifndef NDEBUG | 860 #ifndef NDEBUG |
| 912 posted_asynchronous_operation_ = true; | 861 posted_asynchronous_operation_ = true; |
| 913 #endif | 862 #endif |
| 914 | 863 |
| 915 BrowserThread::PostTask( | 864 BrowserThread::PostTask( |
| 916 BrowserThread::FILE, FROM_HERE, | 865 BrowserThread::FILE, FROM_HERE, |
| 917 new AsyncWriter(file, offset, data, data_size)); | 866 base::Bind(&AsyncWrite, file, offset, |
| 867 std::string(static_cast<const char*>(data), data_size))); |
| 918 } | 868 } |
| 919 | 869 |
| 920 void VisitedLinkMaster::WriteUsedItemCountToFile() { | 870 void VisitedLinkMaster::WriteUsedItemCountToFile() { |
| 921 if (!file_) | 871 if (!file_) |
| 922 return; // See comment on the file_ variable for why this might happen. | 872 return; // See comment on the file_ variable for why this might happen. |
| 923 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); | 873 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); |
| 924 } | 874 } |
| 925 | 875 |
| 926 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { | 876 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { |
| 927 if (!file_) | 877 if (!file_) |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 996 } | 946 } |
| 997 | 947 |
| 998 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { | 948 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { |
| 999 if (master_) | 949 if (master_) |
| 1000 master_->OnTableRebuildComplete(success_, fingerprints_); | 950 master_->OnTableRebuildComplete(success_, fingerprints_); |
| 1001 | 951 |
| 1002 // WILL (generally) DELETE THIS! This balances the AddRef in | 952 // WILL (generally) DELETE THIS! This balances the AddRef in |
| 1003 // VisitedLinkMaster::RebuildTableFromHistory. | 953 // VisitedLinkMaster::RebuildTableFromHistory. |
| 1004 Release(); | 954 Release(); |
| 1005 } | 955 } |
| OLD | NEW |