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 |