OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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_master.h" | 5 #include "chrome/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> |
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 #if defined(OS_WIN) | 16 #if defined(OS_WIN) |
17 #include "app/win_util.h" | 17 #include "app/win_util.h" |
18 #endif | 18 #endif |
19 #include "base/file_util.h" | 19 #include "base/file_util.h" |
20 #include "base/logging.h" | 20 #include "base/logging.h" |
21 #include "base/message_loop.h" | 21 #include "base/message_loop.h" |
22 #include "base/path_service.h" | 22 #include "base/path_service.h" |
23 #include "base/process_util.h" | 23 #include "base/process_util.h" |
24 #include "base/rand_util.h" | 24 #include "base/rand_util.h" |
25 #include "base/stack_container.h" | 25 #include "base/stack_container.h" |
26 #include "base/string_util.h" | 26 #include "base/string_util.h" |
27 #include "base/thread.h" | |
28 #include "chrome/browser/browser_process.h" | 27 #include "chrome/browser/browser_process.h" |
29 #include "chrome/browser/history/history.h" | 28 #include "chrome/browser/history/history.h" |
30 #include "chrome/browser/profile.h" | 29 #include "chrome/browser/profile.h" |
31 | 30 |
32 using file_util::ScopedFILE; | 31 using file_util::ScopedFILE; |
33 using file_util::OpenFile; | 32 using file_util::OpenFile; |
34 using file_util::TruncateFile; | 33 using file_util::TruncateFile; |
35 | 34 |
36 const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0; | 35 const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0; |
37 const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4; | 36 const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 virtual void OnComplete(bool succeed); | 182 virtual void OnComplete(bool succeed); |
184 | 183 |
185 private: | 184 private: |
186 // OnComplete mashals to this function on the main thread to do the | 185 // OnComplete mashals to this function on the main thread to do the |
187 // notification. | 186 // notification. |
188 void OnCompleteMainThread(); | 187 void OnCompleteMainThread(); |
189 | 188 |
190 // Owner of this object. MAY ONLY BE ACCESSED ON THE MAIN THREAD! | 189 // Owner of this object. MAY ONLY BE ACCESSED ON THE MAIN THREAD! |
191 VisitedLinkMaster* master_; | 190 VisitedLinkMaster* master_; |
192 | 191 |
193 // The thread the visited link master is on where we will notify it. | |
194 MessageLoop* main_message_loop_; | |
195 | |
196 // Indicates whether the operation has failed or not. | 192 // Indicates whether the operation has failed or not. |
197 bool success_; | 193 bool success_; |
198 | 194 |
199 // Salt for this new table. | 195 // Salt for this new table. |
200 uint8 salt_[LINK_SALT_LENGTH]; | 196 uint8 salt_[LINK_SALT_LENGTH]; |
201 | 197 |
202 // Stores the fingerprints we computed on the background thread. | 198 // Stores the fingerprints we computed on the background thread. |
203 VisitedLinkCommon::Fingerprints fingerprints_; | 199 VisitedLinkCommon::Fingerprints fingerprints_; |
204 }; | 200 }; |
205 | 201 |
206 // VisitedLinkMaster ---------------------------------------------------------- | 202 // VisitedLinkMaster ---------------------------------------------------------- |
207 | 203 |
208 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread, | 204 VisitedLinkMaster::VisitedLinkMaster(Listener* listener, |
209 Listener* listener, | |
210 Profile* profile) { | 205 Profile* profile) { |
211 InitMembers(file_thread, listener, profile); | 206 InitMembers(listener, profile); |
212 } | 207 } |
213 | 208 |
214 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread, | 209 VisitedLinkMaster::VisitedLinkMaster(Listener* listener, |
215 Listener* listener, | |
216 HistoryService* history_service, | 210 HistoryService* history_service, |
217 bool suppress_rebuild, | 211 bool suppress_rebuild, |
218 const FilePath& filename, | 212 const FilePath& filename, |
219 int32 default_table_size) { | 213 int32 default_table_size) { |
220 InitMembers(file_thread, listener, NULL); | 214 InitMembers(listener, NULL); |
221 | 215 |
222 database_name_override_ = filename; | 216 database_name_override_ = filename; |
223 table_size_override_ = default_table_size; | 217 table_size_override_ = default_table_size; |
224 history_service_override_ = history_service; | 218 history_service_override_ = history_service; |
225 suppress_rebuild_ = suppress_rebuild; | 219 suppress_rebuild_ = suppress_rebuild; |
226 } | 220 } |
227 | 221 |
228 VisitedLinkMaster::~VisitedLinkMaster() { | 222 VisitedLinkMaster::~VisitedLinkMaster() { |
229 if (table_builder_.get()) { | 223 if (table_builder_.get()) { |
230 // Prevent the table builder from calling us back now that we're being | 224 // Prevent the table builder from calling us back now that we're being |
231 // destroyed. Note that we DON'T delete the object, since the history | 225 // destroyed. Note that we DON'T delete the object, since the history |
232 // system is still writing into it. When that is complete, the table | 226 // system is still writing into it. When that is complete, the table |
233 // builder will destroy itself when it finds we are gone. | 227 // builder will destroy itself when it finds we are gone. |
234 table_builder_->DisownMaster(); | 228 table_builder_->DisownMaster(); |
235 } | 229 } |
236 FreeURLTable(); | 230 FreeURLTable(); |
237 } | 231 } |
238 | 232 |
239 void VisitedLinkMaster::InitMembers(base::Thread* file_thread, | 233 void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) { |
240 Listener* listener, | |
241 Profile* profile) { | |
242 DCHECK(listener); | 234 DCHECK(listener); |
243 | 235 |
244 if (file_thread) | |
245 file_thread_ = file_thread->message_loop(); | |
246 else | |
247 file_thread_ = NULL; | |
248 | |
249 listener_ = listener; | 236 listener_ = listener; |
250 file_ = NULL; | 237 file_ = NULL; |
251 shared_memory_ = NULL; | 238 shared_memory_ = NULL; |
252 shared_memory_serial_ = 0; | 239 shared_memory_serial_ = 0; |
253 used_items_ = 0; | 240 used_items_ = 0; |
254 table_size_override_ = 0; | 241 table_size_override_ = 0; |
255 history_service_override_ = NULL; | 242 history_service_override_ = NULL; |
256 suppress_rebuild_ = false; | 243 suppress_rebuild_ = false; |
257 profile_ = profile; | 244 profile_ = profile; |
258 | 245 |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 header[2] = table_length_; | 533 header[2] = table_length_; |
547 header[3] = used_items_; | 534 header[3] = used_items_; |
548 WriteToFile(file_, 0, header, sizeof(header)); | 535 WriteToFile(file_, 0, header, sizeof(header)); |
549 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); | 536 WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH); |
550 | 537 |
551 // Write the hash data. | 538 // Write the hash data. |
552 WriteToFile(file_, kFileHeaderSize, | 539 WriteToFile(file_, kFileHeaderSize, |
553 hash_table_, table_length_ * sizeof(Fingerprint)); | 540 hash_table_, table_length_ * sizeof(Fingerprint)); |
554 | 541 |
555 // The hash table may have shrunk, so make sure this is the end. | 542 // The hash table may have shrunk, so make sure this is the end. |
556 if (file_thread_) { | 543 ChromeThread::PostTask( |
557 AsyncSetEndOfFile* setter = new AsyncSetEndOfFile(file_); | 544 ChromeThread::FILE, FROM_HERE, new AsyncSetEndOfFile(file_)); |
558 file_thread_->PostTask(FROM_HERE, setter); | |
559 } else { | |
560 TruncateFile(file_); | |
561 } | |
562 | |
563 return true; | 545 return true; |
564 } | 546 } |
565 | 547 |
566 bool VisitedLinkMaster::InitFromFile() { | 548 bool VisitedLinkMaster::InitFromFile() { |
567 DCHECK(file_ == NULL); | 549 DCHECK(file_ == NULL); |
568 | 550 |
569 FilePath filename; | 551 FilePath filename; |
570 GetDatabaseFileName(&filename); | 552 GetDatabaseFileName(&filename); |
571 ScopedFILE file_closer(OpenFile(filename, "rb+")); | 553 ScopedFILE file_closer(OpenFile(filename, "rb+")); |
572 if (!file_closer.get()) | 554 if (!file_closer.get()) |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
747 #endif | 729 #endif |
748 | 730 |
749 return true; | 731 return true; |
750 } | 732 } |
751 | 733 |
752 void VisitedLinkMaster::FreeURLTable() { | 734 void VisitedLinkMaster::FreeURLTable() { |
753 if (shared_memory_) { | 735 if (shared_memory_) { |
754 delete shared_memory_; | 736 delete shared_memory_; |
755 shared_memory_ = NULL; | 737 shared_memory_ = NULL; |
756 } | 738 } |
757 if (file_) { | 739 if (!file_) |
758 if (file_thread_) { | 740 return; |
759 AsyncCloseHandle* closer = new AsyncCloseHandle(file_); | 741 |
760 file_thread_->PostTask(FROM_HERE, closer); | 742 ChromeThread::PostTask( |
761 } else { | 743 ChromeThread::FILE, FROM_HERE, new AsyncCloseHandle(file_)); |
762 fclose(file_); | |
763 } | |
764 } | |
765 } | 744 } |
766 | 745 |
767 bool VisitedLinkMaster::ResizeTableIfNecessary() { | 746 bool VisitedLinkMaster::ResizeTableIfNecessary() { |
768 DCHECK(table_length_ > 0) << "Must have a table"; | 747 DCHECK(table_length_ > 0) << "Must have a table"; |
769 | 748 |
770 // Load limits for good performance/space. We are pretty conservative about | 749 // Load limits for good performance/space. We are pretty conservative about |
771 // keeping the table not very full. This is because we use linear probing | 750 // keeping the table not very full. This is because we use linear probing |
772 // which increases the likelihood of clumps of entries which will reduce | 751 // which increases the likelihood of clumps of entries which will reduce |
773 // performance. | 752 // performance. |
774 const float max_table_load = 0.5f; // Grow when we're > this full. | 753 const float max_table_load = 0.5f; // Grow when we're > this full. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 } | 913 } |
935 | 914 |
936 void VisitedLinkMaster::WriteToFile(FILE* file, | 915 void VisitedLinkMaster::WriteToFile(FILE* file, |
937 off_t offset, | 916 off_t offset, |
938 void* data, | 917 void* data, |
939 int32 data_size) { | 918 int32 data_size) { |
940 #ifndef NDEBUG | 919 #ifndef NDEBUG |
941 posted_asynchronous_operation_ = true; | 920 posted_asynchronous_operation_ = true; |
942 #endif | 921 #endif |
943 | 922 |
944 if (file_thread_) { | 923 ChromeThread::PostTask( |
945 // Send the write to the other thread for execution to avoid blocking. | 924 ChromeThread::FILE, FROM_HERE, |
946 AsyncWriter* writer = new AsyncWriter(file, offset, data, data_size); | 925 new AsyncWriter(file, offset, data, data_size)); |
947 file_thread_->PostTask(FROM_HERE, writer); | |
948 } else { | |
949 // When there is no I/O thread, we are probably running in unit test mode, | |
950 // just do the write synchronously. | |
951 AsyncWriter::WriteToFile(file, offset, data, data_size); | |
952 } | |
953 } | 926 } |
954 | 927 |
955 void VisitedLinkMaster::WriteUsedItemCountToFile() { | 928 void VisitedLinkMaster::WriteUsedItemCountToFile() { |
956 if (!file_) | 929 if (!file_) |
957 return; // See comment on the file_ variable for why this might happen. | 930 return; // See comment on the file_ variable for why this might happen. |
958 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); | 931 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); |
959 } | 932 } |
960 | 933 |
961 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { | 934 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { |
962 if (!file_) | 935 if (!file_) |
(...skipping 30 matching lines...) Expand all Loading... |
993 size_t num_read = fread(data, 1, data_size, file); | 966 size_t num_read = fread(data, 1, data_size, file); |
994 return num_read == data_size; | 967 return num_read == data_size; |
995 } | 968 } |
996 | 969 |
997 // VisitedLinkTableBuilder ---------------------------------------------------- | 970 // VisitedLinkTableBuilder ---------------------------------------------------- |
998 | 971 |
999 VisitedLinkMaster::TableBuilder::TableBuilder( | 972 VisitedLinkMaster::TableBuilder::TableBuilder( |
1000 VisitedLinkMaster* master, | 973 VisitedLinkMaster* master, |
1001 const uint8 salt[LINK_SALT_LENGTH]) | 974 const uint8 salt[LINK_SALT_LENGTH]) |
1002 : master_(master), | 975 : master_(master), |
1003 main_message_loop_(MessageLoop::current()), | |
1004 success_(true) { | 976 success_(true) { |
1005 fingerprints_.reserve(4096); | 977 fingerprints_.reserve(4096); |
1006 memcpy(salt_, salt, sizeof(salt)); | 978 memcpy(salt_, salt, sizeof(salt)); |
1007 } | 979 } |
1008 | 980 |
1009 // TODO(brettw): Do we want to try to cancel the request if this happens? It | 981 // TODO(brettw): Do we want to try to cancel the request if this happens? It |
1010 // could delay shutdown if there are a lot of URLs. | 982 // could delay shutdown if there are a lot of URLs. |
1011 void VisitedLinkMaster::TableBuilder::DisownMaster() { | 983 void VisitedLinkMaster::TableBuilder::DisownMaster() { |
1012 master_ = NULL; | 984 master_ = NULL; |
1013 } | 985 } |
1014 | 986 |
1015 void VisitedLinkMaster::TableBuilder::OnURL(const GURL& url) { | 987 void VisitedLinkMaster::TableBuilder::OnURL(const GURL& url) { |
1016 if (!url.is_empty()) { | 988 if (!url.is_empty()) { |
1017 fingerprints_.push_back(VisitedLinkMaster::ComputeURLFingerprint( | 989 fingerprints_.push_back(VisitedLinkMaster::ComputeURLFingerprint( |
1018 url.spec().data(), url.spec().length(), salt_)); | 990 url.spec().data(), url.spec().length(), salt_)); |
1019 } | 991 } |
1020 } | 992 } |
1021 | 993 |
1022 void VisitedLinkMaster::TableBuilder::OnComplete(bool success) { | 994 void VisitedLinkMaster::TableBuilder::OnComplete(bool success) { |
1023 success_ = success; | 995 success_ = success; |
1024 DLOG_IF(WARNING, !success) << "Unable to rebuild visited links"; | 996 DLOG_IF(WARNING, !success) << "Unable to rebuild visited links"; |
1025 | 997 |
1026 // Marshal to the main thread to notify the VisitedLinkMaster that the | 998 // Marshal to the main thread to notify the VisitedLinkMaster that the |
1027 // rebuild is complete. | 999 // rebuild is complete. |
1028 main_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | 1000 ChromeThread::PostTask( |
1029 &TableBuilder::OnCompleteMainThread)); | 1001 ChromeThread::UI, FROM_HERE, |
| 1002 NewRunnableMethod(this, &TableBuilder::OnCompleteMainThread)); |
1030 } | 1003 } |
1031 | 1004 |
1032 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { | 1005 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { |
1033 if (master_) | 1006 if (master_) |
1034 master_->OnTableRebuildComplete(success_, fingerprints_); | 1007 master_->OnTableRebuildComplete(success_, fingerprints_); |
1035 | 1008 |
1036 // WILL (generally) DELETE THIS! This balances the AddRef in | 1009 // WILL (generally) DELETE THIS! This balances the AddRef in |
1037 // VisitedLinkMaster::RebuildTableFromHistory. | 1010 // VisitedLinkMaster::RebuildTableFromHistory. |
1038 Release(); | 1011 Release(); |
1039 } | 1012 } |
OLD | NEW |