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

Side by Side Diff: chrome/browser/visitedlink_master.cc

Issue 19028: Roll forward 8722,8721 (Closed)
Patch Set: Created 11 years, 10 months 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
« no previous file with comments | « chrome/browser/visitedlink_master.h ('k') | chrome/browser/visitedlink_perftest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include <windows.h> 8 #include <windows.h>
9 #include <io.h>
8 #include <shlobj.h> 10 #include <shlobj.h>
11 #endif // defined(OS_WIN)
12 #include <stdio.h>
13
9 #include <algorithm> 14 #include <algorithm>
10 15
16 #include "base/file_util.h"
11 #include "base/logging.h" 17 #include "base/logging.h"
12 #include "base/message_loop.h" 18 #include "base/message_loop.h"
13 #include "base/path_service.h" 19 #include "base/path_service.h"
20 #include "base/process_util.h"
14 #include "base/rand_util.h" 21 #include "base/rand_util.h"
15 #include "base/stack_container.h" 22 #include "base/stack_container.h"
16 #include "base/string_util.h" 23 #include "base/string_util.h"
24 #include "base/thread.h"
17 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/browser_process.h"
26 #if defined(OS_WIN)
18 #include "chrome/browser/history/history.h" 27 #include "chrome/browser/history/history.h"
19 #include "chrome/browser/profile.h" 28 #include "chrome/browser/profile.h"
29 #else
30 // TODO(port): We should be using history.h & profile.h, remove scaffolding
31 // when those are ported.
32 #include "chrome/common/temp_scaffolding_stubs.h"
33 #endif // !defined(OS_WIN)
34 #if defined(OS_WIN)
20 #include "chrome/common/win_util.h" 35 #include "chrome/common/win_util.h"
36 #endif
37
38 using file_util::ScopedFILE;
39 using file_util::OpenFile;
40 using file_util::TruncateFile;
21 41
22 const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0; 42 const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0;
23 const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4; 43 const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4;
24 const int32 VisitedLinkMaster::kFileHeaderLengthOffset = 8; 44 const int32 VisitedLinkMaster::kFileHeaderLengthOffset = 8;
25 const int32 VisitedLinkMaster::kFileHeaderUsedOffset = 12; 45 const int32 VisitedLinkMaster::kFileHeaderUsedOffset = 12;
26 const int32 VisitedLinkMaster::kFileHeaderSaltOffset = 16; 46 const int32 VisitedLinkMaster::kFileHeaderSaltOffset = 16;
27 47
28 const int32 VisitedLinkMaster::kFileCurrentVersion = 2; 48 const int32 VisitedLinkMaster::kFileCurrentVersion = 2;
29 49
30 // the signature at the beginning of the URL table = "VLnk" (visited links) 50 // the signature at the beginning of the URL table = "VLnk" (visited links)
31 const int32 VisitedLinkMaster::kFileSignature = 0x6b6e4c56; 51 const int32 VisitedLinkMaster::kFileSignature = 0x6b6e4c56;
32 const size_t VisitedLinkMaster::kFileHeaderSize = 52 const size_t VisitedLinkMaster::kFileHeaderSize =
33 kFileHeaderSaltOffset + LINK_SALT_LENGTH; 53 kFileHeaderSaltOffset + LINK_SALT_LENGTH;
34 54
35 // This value should also be the same as the smallest size in the lookup 55 // This value should also be the same as the smallest size in the lookup
36 // table in NewTableSizeForCount (prime number). 56 // table in NewTableSizeForCount (prime number).
37 const unsigned VisitedLinkMaster::kDefaultTableSize = 16381; 57 const unsigned VisitedLinkMaster::kDefaultTableSize = 16381;
38 58
39 const int32 VisitedLinkMaster::kBigDeleteThreshold = 64; 59 const size_t VisitedLinkMaster::kBigDeleteThreshold = 64;
40 60
41 namespace { 61 namespace {
42 62
43 // Fills the given salt structure with some quasi-random values 63 // Fills the given salt structure with some quasi-random values
44 // It is not necessary to generate a cryptographically strong random string, 64 // It is not necessary to generate a cryptographically strong random string,
45 // only that it be reasonably different for different users. 65 // only that it be reasonably different for different users.
46 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) { 66 void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) {
47 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt"; 67 DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt";
48 uint64 randval = base::RandUint64(); 68 uint64 randval = base::RandUint64();
49 memcpy(salt, &randval, 8); 69 memcpy(salt, &randval, 8);
50 } 70 }
71
51 // AsyncWriter ---------------------------------------------------------------- 72 // AsyncWriter ----------------------------------------------------------------
52 73
53 // This task executes on a background thread and executes a write. This 74 // This task executes on a background thread and executes a write. This
54 // prevents us from blocking the UI thread doing I/O. 75 // prevents us from blocking the UI thread doing I/O.
55 class AsyncWriter : public Task { 76 class AsyncWriter : public Task {
56 public: 77 public:
57 AsyncWriter(HANDLE hfile, int32 offset, const void* data, int32 data_len) 78 AsyncWriter(FILE* file, int32 offset, const void* data, size_t data_len)
58 : hfile_(hfile), 79 : file_(file),
59 offset_(offset) { 80 offset_(offset) {
60 data_->resize(data_len); 81 data_->resize(data_len);
61 memcpy(&*data_->begin(), data, data_len); 82 memcpy(&*data_->begin(), data, data_len);
62 } 83 }
63 84
64 virtual void Run() { 85 virtual void Run() {
65 WriteToFile(hfile_, offset_, 86 WriteToFile(file_, offset_,
66 &*data_->begin(), static_cast<int32>(data_->size())); 87 &*data_->begin(), static_cast<int32>(data_->size()));
67 } 88 }
68 89
69 // Exposed as a static so it can be called directly from the Master to 90 // Exposed as a static so it can be called directly from the Master to
70 // reduce the number of platform-specific I/O sites we have. Returns true if 91 // reduce the number of platform-specific I/O sites we have. Returns true if
71 // the write was complete. 92 // the write was complete.
72 static bool WriteToFile(HANDLE hfile, 93 static bool WriteToFile(FILE* file,
73 int32 offset, 94 off_t offset,
74 const void* data, 95 const void* data,
75 int32 data_len) { 96 size_t data_len) {
76 if (SetFilePointer(hfile, offset, NULL, FILE_BEGIN) == 97 if (fseek(file, offset, SEEK_SET) != 0)
77 INVALID_SET_FILE_POINTER)
78 return false; // Don't write to an invalid part of the file. 98 return false; // Don't write to an invalid part of the file.
79 99
80 DWORD num_written; 100 size_t num_written = fwrite(data, 1, data_len, file);
81 return WriteFile(hfile, data, data_len, &num_written, NULL) && 101 return num_written == data_len;
82 (num_written == data_len);
83 } 102 }
84 103
85 private: 104 private:
86 // The data to write and where to write it. 105 // The data to write and where to write it.
87 HANDLE hfile_; 106 FILE* file_;
88 int32 offset_; // Offset from the beginning of the file. 107 int32 offset_; // Offset from the beginning of the file.
89 108
90 // Most writes are just a single fingerprint, so we reserve that much in this 109 // Most writes are just a single fingerprint, so we reserve that much in this
91 // object to avoid mallocs in that case. 110 // object to avoid mallocs in that case.
92 StackVector<char, sizeof(VisitedLinkCommon::Fingerprint)> data_; 111 StackVector<char, sizeof(VisitedLinkCommon::Fingerprint)> data_;
93 112
94 DISALLOW_EVIL_CONSTRUCTORS(AsyncWriter); 113 DISALLOW_EVIL_CONSTRUCTORS(AsyncWriter);
95 }; 114 };
96 115
97 // Used to asynchronously set the end of the file. This must be done on the 116 // Used to asynchronously set the end of the file. This must be done on the
98 // same thread as the writing to keep things synchronized. 117 // same thread as the writing to keep things synchronized.
99 class AsyncSetEndOfFile : public Task { 118 class AsyncSetEndOfFile : public Task {
100 public: 119 public:
101 explicit AsyncSetEndOfFile(HANDLE hfile) : hfile_(hfile) {} 120 explicit AsyncSetEndOfFile(FILE* file) : file_(file) {}
102 121
103 virtual void Run() { 122 virtual void Run() {
104 SetEndOfFile(hfile_); 123 TruncateFile(file_);
105 } 124 }
106 125
107 private: 126 private:
108 HANDLE hfile_; 127 FILE* file_;
109 DISALLOW_EVIL_CONSTRUCTORS(AsyncSetEndOfFile); 128 DISALLOW_EVIL_CONSTRUCTORS(AsyncSetEndOfFile);
110 }; 129 };
111 130
112 // Used to asynchronously close a file. This must be done on the same thread as 131 // Used to asynchronously close a file. This must be done on the same thread as
113 // the writing to keep things synchronized. 132 // the writing to keep things synchronized.
114 class AsyncCloseHandle : public Task { 133 class AsyncCloseHandle : public Task {
115 public: 134 public:
116 explicit AsyncCloseHandle(HANDLE hfile) : hfile_(hfile) {} 135 explicit AsyncCloseHandle(FILE* file) : file_(file) {}
117 136
118 virtual void Run() { 137 virtual void Run() {
119 CloseHandle(hfile_); 138 fclose(file_);
120 } 139 }
121 140
122 private: 141 private:
123 HANDLE hfile_; 142 FILE* file_;
124 DISALLOW_EVIL_CONSTRUCTORS(AsyncCloseHandle); 143 DISALLOW_EVIL_CONSTRUCTORS(AsyncCloseHandle);
125 }; 144 };
126 145
127 } // namespace 146 } // namespace
128 147
129 // TableBuilder --------------------------------------------------------------- 148 // TableBuilder ---------------------------------------------------------------
130 149
131 // How rebuilding from history works 150 // How rebuilding from history works
132 // --------------------------------- 151 // ---------------------------------
133 // 152 //
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread, 206 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread,
188 PostNewTableEvent* poster, 207 PostNewTableEvent* poster,
189 Profile* profile) { 208 Profile* profile) {
190 InitMembers(file_thread, poster, profile); 209 InitMembers(file_thread, poster, profile);
191 } 210 }
192 211
193 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread, 212 VisitedLinkMaster::VisitedLinkMaster(base::Thread* file_thread,
194 PostNewTableEvent* poster, 213 PostNewTableEvent* poster,
195 HistoryService* history_service, 214 HistoryService* history_service,
196 bool suppress_rebuild, 215 bool suppress_rebuild,
197 const std::wstring& filename, 216 const FilePath& filename,
198 int32 default_table_size) { 217 int32 default_table_size) {
199 InitMembers(file_thread, poster, NULL); 218 InitMembers(file_thread, poster, NULL);
200 219
201 database_name_override_.assign(filename); 220 database_name_override_ = filename;
202 table_size_override_ = default_table_size; 221 table_size_override_ = default_table_size;
203 history_service_override_ = history_service; 222 history_service_override_ = history_service;
204 suppress_rebuild_ = suppress_rebuild; 223 suppress_rebuild_ = suppress_rebuild;
205 } 224 }
206 225
207 VisitedLinkMaster::~VisitedLinkMaster() { 226 VisitedLinkMaster::~VisitedLinkMaster() {
208 if (table_builder_.get()) { 227 if (table_builder_.get()) {
209 // Prevent the table builder from calling us back now that we're being 228 // Prevent the table builder from calling us back now that we're being
210 // destroyed. Note that we DON'T delete the object, since the history 229 // destroyed. Note that we DON'T delete the object, since the history
211 // system is still writing into it. When that is complete, the table 230 // system is still writing into it. When that is complete, the table
(...skipping 29 matching lines...) Expand all
241 // The shared memory name should be unique on the system and also needs to 260 // The shared memory name should be unique on the system and also needs to
242 // change when we create a new table. The scheme we use includes the process 261 // change when we create a new table. The scheme we use includes the process
243 // ID, an increasing serial number, and the profile ID. 262 // ID, an increasing serial number, and the profile ID.
244 std::wstring VisitedLinkMaster::GetSharedMemoryName() const { 263 std::wstring VisitedLinkMaster::GetSharedMemoryName() const {
245 // When unit testing, there's no profile, so use an empty ID string. 264 // When unit testing, there's no profile, so use an empty ID string.
246 std::wstring profile_id; 265 std::wstring profile_id;
247 if (profile_) 266 if (profile_)
248 profile_id = profile_->GetID().c_str(); 267 profile_id = profile_->GetID().c_str();
249 268
250 return StringPrintf(L"GVisitedLinks_%lu_%lu_%ls", 269 return StringPrintf(L"GVisitedLinks_%lu_%lu_%ls",
251 GetCurrentProcessId(), shared_memory_serial_, 270 base::GetCurrentProcId(), shared_memory_serial_,
252 profile_id.c_str()); 271 profile_id.c_str());
253 } 272 }
254 273
255 bool VisitedLinkMaster::Init() { 274 bool VisitedLinkMaster::Init() {
256 if (!InitFromFile()) 275 if (!InitFromFile())
257 return InitFromScratch(suppress_rebuild_); 276 return InitFromScratch(suppress_rebuild_);
258 return true; 277 return true;
259 } 278 }
260 279
261 bool VisitedLinkMaster::ShareToProcess(base::ProcessHandle process, 280 bool VisitedLinkMaster::ShareToProcess(base::ProcessHandle process,
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 // since there may be write operations pending on the file I/O thread. 524 // since there may be write operations pending on the file I/O thread.
506 // 525 //
507 // Note that once we start writing, we do not delete on error. This means 526 // Note that once we start writing, we do not delete on error. This means
508 // there can be a partial file, but the short file will be detected next time 527 // there can be a partial file, but the short file will be detected next time
509 // we start, and will be replaced. 528 // we start, and will be replaced.
510 // 529 //
511 // This might possibly get corrupted if we crash in the middle of writing. 530 // This might possibly get corrupted if we crash in the middle of writing.
512 // We should pick up the most common types of these failures when we notice 531 // We should pick up the most common types of these failures when we notice
513 // that the file size is different when we load it back in, and then we will 532 // that the file size is different when we load it back in, and then we will
514 // regenerate the table. 533 // regenerate the table.
515 win_util::ScopedHandle hfile_closer; // Valid only when not open already. 534 ScopedFILE file_closer; // Valid only when not open already.
516 HANDLE hfile; // Always valid. 535 FILE* file; // Always valid.
517 if (file_) { 536 if (file_) {
518 hfile = file_; 537 file = file_;
519 } else { 538 } else {
520 std::wstring filename; 539 FilePath filename;
521 GetDatabaseFileName(&filename); 540 GetDatabaseFileName(&filename);
522 hfile_closer.Set( 541 file_closer.reset(OpenFile(filename, "wb+"));
523 CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, 542 if (!file_closer.get()) {
524 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); 543 DLOG(ERROR) << "Failed to open file " << filename.value();
525 if (!hfile_closer.IsValid())
526 return false; 544 return false;
527 hfile = hfile_closer; 545 }
546 file = file_closer.get();
528 } 547 }
529 548
530 // Write the new header. 549 // Write the new header.
531 int32 header[4]; 550 int32 header[4];
532 header[0] = kFileSignature; 551 header[0] = kFileSignature;
533 header[1] = kFileCurrentVersion; 552 header[1] = kFileCurrentVersion;
534 header[2] = table_length_; 553 header[2] = table_length_;
535 header[3] = used_items_; 554 header[3] = used_items_;
536 WriteToFile(hfile, 0, header, sizeof(header)); 555 WriteToFile(file, 0, header, sizeof(header));
537 WriteToFile(hfile, sizeof(header), salt_, LINK_SALT_LENGTH); 556 WriteToFile(file, sizeof(header), salt_, LINK_SALT_LENGTH);
538 557
539 // Write the hash data. 558 // Write the hash data.
540 WriteToFile(hfile, kFileHeaderSize, 559 WriteToFile(file, kFileHeaderSize,
541 hash_table_, table_length_ * sizeof(Fingerprint)); 560 hash_table_, table_length_ * sizeof(Fingerprint));
542 561
543 // The hash table may have shrunk, so make sure this is the end. 562 // The hash table may have shrunk, so make sure this is the end.
544 if (file_thread_) { 563 if (file_thread_) {
545 AsyncSetEndOfFile* setter = new AsyncSetEndOfFile(hfile); 564 AsyncSetEndOfFile* setter = new AsyncSetEndOfFile(file);
546 file_thread_->PostTask(FROM_HERE, setter); 565 file_thread_->PostTask(FROM_HERE, setter);
547 } else { 566 } else {
548 SetEndOfFile(hfile); 567 TruncateFile(file);
549 } 568 }
550 569
551 // Keep the file open so we can dynamically write changes to it. When the 570 // Keep the file open so we can dynamically write changes to it. When the
552 // file was alrady open, the hfile_closer is NULL, and file_ is already good. 571 // file was already open, the file_closer is NULL, and file_ is already good.
553 if (hfile_closer.IsValid()) 572 if (file_closer.get())
554 file_ = hfile_closer.Take(); 573 file_ = file_closer.release();
555 return true; 574 return true;
556 } 575 }
557 576
558 bool VisitedLinkMaster::InitFromFile() { 577 bool VisitedLinkMaster::InitFromFile() {
559 DCHECK(file_ == NULL); 578 DCHECK(file_ == NULL);
560 579
561 std::wstring filename; 580 FilePath filename;
562 GetDatabaseFileName(&filename); 581 GetDatabaseFileName(&filename);
563 win_util::ScopedHandle hfile( 582 ScopedFILE file_closer(OpenFile(filename, "rb+"));
564 CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, 583 if (!file_closer.get()) {
565 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); 584 DLOG(ERROR) << "Failed to open file " << filename.value();
566 if (!hfile.IsValid())
567 return false; 585 return false;
586 }
568 587
569 int32 num_entries, used_count; 588 int32 num_entries, used_count;
570 if (!ReadFileHeader(hfile, &num_entries, &used_count, salt_)) 589 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_))
571 return false; // Header isn't valid. 590 return false; // Header isn't valid.
572 591
573 // Allocate and read the table. 592 // Allocate and read the table.
574 if (!CreateURLTable(num_entries, false)) 593 if (!CreateURLTable(num_entries, false))
575 return false; 594 return false;
576 if (!ReadFromFile(hfile, kFileHeaderSize, 595 if (!ReadFromFile(file_closer.get(), kFileHeaderSize,
577 hash_table_, num_entries * sizeof(Fingerprint))) { 596 hash_table_, num_entries * sizeof(Fingerprint))) {
578 FreeURLTable(); 597 FreeURLTable();
579 return false; 598 return false;
580 } 599 }
581 used_items_ = used_count; 600 used_items_ = used_count;
582 601
583 file_ = hfile.Take(); 602 file_ = file_closer.release();
584 return true; 603 return true;
585 } 604 }
586 605
587 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { 606 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) {
588 int32 table_size = kDefaultTableSize; 607 int32 table_size = kDefaultTableSize;
589 if (table_size_override_) 608 if (table_size_override_)
590 table_size = table_size_override_; 609 table_size = table_size_override_;
591 610
592 // The salt must be generated before the table so that it can be copied to 611 // The salt must be generated before the table so that it can be copied to
593 // the shared memory. 612 // the shared memory.
594 GenerateSalt(salt_); 613 GenerateSalt(salt_);
595 if (!CreateURLTable(table_size, true)) 614 if (!CreateURLTable(table_size, true))
596 return false; 615 return false;
597 616
598 if (suppress_rebuild) { 617 if (suppress_rebuild) {
599 // When we disallow rebuilds (normally just unit tests), just use the 618 // When we disallow rebuilds (normally just unit tests), just use the
600 // current empty table. 619 // current empty table.
601 return WriteFullTable(); 620 return WriteFullTable();
602 } 621 }
603 622
604 // This will build the table from history. On the first run, history will 623 // This will build the table from history. On the first run, history will
605 // be empty, so this will be correct. This will also write the new table 624 // be empty, so this will be correct. This will also write the new table
606 // to disk. We don't want to save explicitly here, since the rebuild may 625 // to disk. We don't want to save explicitly here, since the rebuild may
607 // not complete, leaving us with an empty but valid visited link database. 626 // not complete, leaving us with an empty but valid visited link database.
608 // In the future, we won't know we need to try rebuilding again. 627 // In the future, we won't know we need to try rebuilding again.
609 return RebuildTableFromHistory(); 628 return RebuildTableFromHistory();
610 } 629 }
611 630
612 bool VisitedLinkMaster::ReadFileHeader(HANDLE hfile, 631 bool VisitedLinkMaster::ReadFileHeader(FILE* file,
613 int32* num_entries, 632 int32* num_entries,
614 int32* used_count, 633 int32* used_count,
615 uint8 salt[LINK_SALT_LENGTH]) { 634 uint8 salt[LINK_SALT_LENGTH]) {
616 int32 file_size = GetFileSize(hfile, NULL); 635 // Get file size.
636 // Note that there is no need to seek back to the original location in the
637 // file since ReadFromFile() [which is the next call accessing the file]
638 // seeks before reading.
639 if (fseek(file, 0, SEEK_END) == -1)
640 return false;
641 size_t file_size = ftell(file);
642
617 if (file_size <= kFileHeaderSize) 643 if (file_size <= kFileHeaderSize)
618 return false; 644 return false;
619 645
620 uint8 header[kFileHeaderSize]; 646 uint8 header[kFileHeaderSize];
621 if (!ReadFromFile(hfile, 0, &header, kFileHeaderSize)) 647 if (!ReadFromFile(file, 0, &header, kFileHeaderSize))
622 return false; 648 return false;
623 649
624 // Verify the signature. 650 // Verify the signature.
625 uint32 signature; 651 int32 signature;
626 memcpy(&signature, &header[kFileHeaderSignatureOffset], sizeof(signature)); 652 memcpy(&signature, &header[kFileHeaderSignatureOffset], sizeof(signature));
627 if (signature != kFileSignature) 653 if (signature != kFileSignature)
628 return false; 654 return false;
629 655
630 // Verify the version is up-to-date. As with other read errors, a version 656 // Verify the version is up-to-date. As with other read errors, a version
631 // mistmatch will trigger a rebuild of the database from history, which will 657 // mistmatch will trigger a rebuild of the database from history, which will
632 // have the effect of migrating the database. 658 // have the effect of migrating the database.
633 int32 version; 659 int32 version;
634 memcpy(&version, &header[kFileHeaderVersionOffset], sizeof(version)); 660 memcpy(&version, &header[kFileHeaderVersionOffset], sizeof(version));
635 if (version != kFileCurrentVersion) 661 if (version != kFileCurrentVersion)
636 return false; // Bad version. 662 return false; // Bad version.
637 663
638 // Read the table size and make sure it matches the file size. 664 // Read the table size and make sure it matches the file size.
639 memcpy(num_entries, &header[kFileHeaderLengthOffset], sizeof(*num_entries)); 665 memcpy(num_entries, &header[kFileHeaderLengthOffset], sizeof(*num_entries));
640 if (*num_entries * sizeof(Fingerprint) + kFileHeaderSize != file_size) 666 if (*num_entries * sizeof(Fingerprint) + kFileHeaderSize != file_size)
641 return false; // Bad size. 667 return false; // Bad size.
642 668
643 // Read the used item count. 669 // Read the used item count.
644 memcpy(used_count, &header[kFileHeaderUsedOffset], sizeof(*used_count)); 670 memcpy(used_count, &header[kFileHeaderUsedOffset], sizeof(*used_count));
645 if (*used_count > *num_entries) 671 if (*used_count > *num_entries)
646 return false; // Bad used item count; 672 return false; // Bad used item count;
647 673
648 // Read the salt. 674 // Read the salt.
649 memcpy(salt, &header[kFileHeaderSaltOffset], LINK_SALT_LENGTH); 675 memcpy(salt, &header[kFileHeaderSaltOffset], LINK_SALT_LENGTH);
650 676
651 // This file looks OK from the header's perspective. 677 // This file looks OK from the header's perspective.
652 return true; 678 return true;
653 } 679 }
654 680
655 bool VisitedLinkMaster::GetDatabaseFileName(std::wstring* filename) { 681 bool VisitedLinkMaster::GetDatabaseFileName(FilePath* filename) {
656 if (!database_name_override_.empty()) { 682 if (!database_name_override_.empty()) {
657 // use this filename, the directory must exist 683 // use this filename, the directory must exist
658 *filename = database_name_override_; 684 *filename = database_name_override_;
659 return true; 685 return true;
660 } 686 }
661 687
662 if (!profile_ || profile_->GetPath().empty()) 688 if (!profile_ || profile_->GetPath().empty())
663 return false; 689 return false;
664 690
665 *filename = profile_->GetPath(); 691 FilePath profile_dir = FilePath::FromWStringHack(profile_->GetPath());
666 filename->append(L"\\Visited Links"); 692 *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links"));
667 return true; 693 return true;
668 } 694 }
669 695
670 // Initializes the shared memory structure. The salt should already be filled 696 // Initializes the shared memory structure. The salt should already be filled
671 // in so that it can be written to the shared memory 697 // in so that it can be written to the shared memory
672 bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) { 698 bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) {
673 // The table is the size of the table followed by the entries. 699 // The table is the size of the table followed by the entries.
674 int32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader); 700 int32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader);
675 701
676 // Create the shared memory object. 702 // Create the shared memory object.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 void VisitedLinkMaster::FreeURLTable() { 754 void VisitedLinkMaster::FreeURLTable() {
729 if (shared_memory_) { 755 if (shared_memory_) {
730 delete shared_memory_; 756 delete shared_memory_;
731 shared_memory_ = NULL; 757 shared_memory_ = NULL;
732 } 758 }
733 if (file_) { 759 if (file_) {
734 if (file_thread_) { 760 if (file_thread_) {
735 AsyncCloseHandle* closer = new AsyncCloseHandle(file_); 761 AsyncCloseHandle* closer = new AsyncCloseHandle(file_);
736 file_thread_->PostTask(FROM_HERE, closer); 762 file_thread_->PostTask(FROM_HERE, closer);
737 } else { 763 } else {
738 CloseHandle(file_); 764 fclose(file_);
739 } 765 }
740 } 766 }
741 } 767 }
742 768
743 bool VisitedLinkMaster::ResizeTableIfNecessary() { 769 bool VisitedLinkMaster::ResizeTableIfNecessary() {
744 DCHECK(table_length_ > 0) << "Must have a table"; 770 DCHECK(table_length_ > 0) << "Must have a table";
745 771
746 // Load limits for good performance/space. We are pretty conservative about 772 // Load limits for good performance/space. We are pretty conservative about
747 // keeping the table not very full. This is because we use linear probing 773 // keeping the table not very full. This is because we use linear probing
748 // which increases the likelihood of clumps of entries which will reduce 774 // which increases the likelihood of clumps of entries which will reduce
749 // performance. 775 // performance.
750 const float max_table_load = 0.5f; // Grow when we're > this full. 776 const float max_table_load = 0.5f; // Grow when we're > this full.
751 const float min_table_load = 0.2f; // Shrink when we're < this full. 777 const float min_table_load = 0.2f; // Shrink when we're < this full.
752 778
753 float load = ComputeTableLoad(); 779 float load = ComputeTableLoad();
754 if (load < max_table_load && 780 if (load < max_table_load &&
755 (table_length_ <= kDefaultTableSize || load > min_table_load)) 781 (table_length_ <= static_cast<float>(kDefaultTableSize) ||
782 load > min_table_load))
756 return false; 783 return false;
757 784
758 // Table needs to grow or shrink. 785 // Table needs to grow or shrink.
759 int new_size = NewTableSizeForCount(used_items_); 786 int new_size = NewTableSizeForCount(used_items_);
760 DCHECK(new_size > used_items_); 787 DCHECK(new_size > used_items_);
761 DCHECK(load <= min_table_load || new_size > table_length_); 788 DCHECK(load <= min_table_load || new_size > table_length_);
762 ResizeTable(new_size); 789 ResizeTable(new_size);
763 return true; 790 return true;
764 } 791 }
765 792
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 2097143, // 2M = 2097152 843 2097143, // 2M = 2097152
817 4194301, // 4M = 4194304 844 4194301, // 4M = 4194304
818 8388571, // 8M = 8388608 845 8388571, // 8M = 8388608
819 16777199, // 16M = 16777216 846 16777199, // 16M = 16777216
820 33554347}; // 32M = 33554432 847 33554347}; // 32M = 33554432
821 848
822 // Try to leave the table 33% full. 849 // Try to leave the table 33% full.
823 int desired = item_count * 3; 850 int desired = item_count * 3;
824 851
825 // Find the closest prime. 852 // Find the closest prime.
826 for (int i = 0; i < arraysize(table_sizes); i ++) { 853 for (size_t i = 0; i < arraysize(table_sizes); i ++) {
827 if (table_sizes[i] > desired) 854 if (table_sizes[i] > desired)
828 return table_sizes[i]; 855 return table_sizes[i];
829 } 856 }
830 857
831 // Growing very big, just approximate a "good" number, not growing as much 858 // Growing very big, just approximate a "good" number, not growing as much
832 // as normal. 859 // as normal.
833 return item_count * 2 - 1; 860 return item_count * 2 - 1;
834 } 861 }
835 862
836 // See the TableBuilder definition in the header file for how this works. 863 // See the TableBuilder definition in the header file for how this works.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 } 928 }
902 table_builder_ = NULL; // Will release our reference to the builder. 929 table_builder_ = NULL; // Will release our reference to the builder.
903 930
904 // Notify the unit test that the rebuild is complete (will be NULL in prod.) 931 // Notify the unit test that the rebuild is complete (will be NULL in prod.)
905 if (rebuild_complete_task_.get()) { 932 if (rebuild_complete_task_.get()) {
906 rebuild_complete_task_->Run(); 933 rebuild_complete_task_->Run();
907 rebuild_complete_task_.reset(NULL); 934 rebuild_complete_task_.reset(NULL);
908 } 935 }
909 } 936 }
910 937
911 void VisitedLinkMaster::WriteToFile(HANDLE hfile, 938 void VisitedLinkMaster::WriteToFile(FILE* file,
912 int32 offset, 939 off_t offset,
913 void* data, 940 void* data,
914 int32 data_size) { 941 int32 data_size) {
915 #ifndef NDEBUG 942 #ifndef NDEBUG
916 posted_asynchronous_operation_ = true; 943 posted_asynchronous_operation_ = true;
917 #endif 944 #endif
918 945
919 if (file_thread_) { 946 if (file_thread_) {
920 // Send the write to the other thread for execution to avoid blocking. 947 // Send the write to the other thread for execution to avoid blocking.
921 AsyncWriter* writer = new AsyncWriter(hfile, offset, data, data_size); 948 AsyncWriter* writer = new AsyncWriter(file, offset, data, data_size);
922 file_thread_->PostTask(FROM_HERE, writer); 949 file_thread_->PostTask(FROM_HERE, writer);
923 } else { 950 } else {
924 // When there is no I/O thread, we are probably running in unit test mode, 951 // When there is no I/O thread, we are probably running in unit test mode,
925 // just do the write synchronously. 952 // just do the write synchronously.
926 AsyncWriter::WriteToFile(hfile, offset, data, data_size); 953 AsyncWriter::WriteToFile(file, offset, data, data_size);
927 } 954 }
928 } 955 }
929 956
930 void VisitedLinkMaster::WriteUsedItemCountToFile() { 957 void VisitedLinkMaster::WriteUsedItemCountToFile() {
931 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); 958 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_));
932 } 959 }
933 960
934 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) { 961 void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) {
935 if (last_hash < first_hash) { 962 if (last_hash < first_hash) {
936 // Handle wraparound at 0. This first write is first_hash->EOF 963 // Handle wraparound at 0. This first write is first_hash->EOF
937 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize, 964 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
938 &hash_table_[first_hash], 965 &hash_table_[first_hash],
939 (table_length_ - first_hash + 1) * sizeof(Fingerprint)); 966 (table_length_ - first_hash + 1) * sizeof(Fingerprint));
940 967
941 // Now do 0->last_lash. 968 // Now do 0->last_lash.
942 WriteToFile(file_, kFileHeaderSize, hash_table_, 969 WriteToFile(file_, kFileHeaderSize, hash_table_,
943 (last_hash + 1) * sizeof(Fingerprint)); 970 (last_hash + 1) * sizeof(Fingerprint));
944 } else { 971 } else {
945 // Normal case, just write the range. 972 // Normal case, just write the range.
946 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize, 973 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
947 &hash_table_[first_hash], 974 &hash_table_[first_hash],
948 (last_hash - first_hash + 1) * sizeof(Fingerprint)); 975 (last_hash - first_hash + 1) * sizeof(Fingerprint));
949 } 976 }
950 } 977 }
951 978
952 bool VisitedLinkMaster::ReadFromFile(HANDLE hfile, 979 bool VisitedLinkMaster::ReadFromFile(FILE* file,
953 int32 offset, 980 off_t offset,
954 void* data, 981 void* data,
955 int32 data_size) { 982 size_t data_size) {
956 #ifndef NDEBUG 983 #ifndef NDEBUG
957 // Since this function is synchronous, we require that no asynchronous 984 // Since this function is synchronous, we require that no asynchronous
958 // operations could possibly be pending. 985 // operations could possibly be pending.
959 DCHECK(!posted_asynchronous_operation_); 986 DCHECK(!posted_asynchronous_operation_);
960 #endif 987 #endif
961 988
962 SetFilePointer(hfile, offset, NULL, FILE_BEGIN); 989 fseek(file, offset, SEEK_SET);
963 990
964 DWORD num_read; 991 size_t num_read = fread(data, 1, data_size, file);
965 return ReadFile(hfile, data, data_size, &num_read, NULL) && 992 return num_read == data_size;
966 num_read == data_size;
967 } 993 }
968 994
969 // VisitedLinkTableBuilder ---------------------------------------------------- 995 // VisitedLinkTableBuilder ----------------------------------------------------
970 996
971 VisitedLinkMaster::TableBuilder::TableBuilder( 997 VisitedLinkMaster::TableBuilder::TableBuilder(
972 VisitedLinkMaster* master, 998 VisitedLinkMaster* master,
973 const uint8 salt[LINK_SALT_LENGTH]) 999 const uint8 salt[LINK_SALT_LENGTH])
974 : master_(master), 1000 : master_(master),
975 success_(true), 1001 main_message_loop_(MessageLoop::current()),
976 main_message_loop_(MessageLoop::current()) { 1002 success_(true) {
977 fingerprints_.reserve(4096); 1003 fingerprints_.reserve(4096);
978 memcpy(salt_, salt, sizeof(salt)); 1004 memcpy(salt_, salt, sizeof(salt));
979 } 1005 }
980 1006
981 // TODO(brettw): Do we want to try to cancel the request if this happens? It 1007 // TODO(brettw): Do we want to try to cancel the request if this happens? It
982 // could delay shutdown if there are a lot of URLs. 1008 // could delay shutdown if there are a lot of URLs.
983 void VisitedLinkMaster::TableBuilder::DisownMaster() { 1009 void VisitedLinkMaster::TableBuilder::DisownMaster() {
984 master_ = NULL; 1010 master_ = NULL;
985 } 1011 }
986 1012
(...skipping 15 matching lines...) Expand all
1002 } 1028 }
1003 1029
1004 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { 1030 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() {
1005 if (master_) 1031 if (master_)
1006 master_->OnTableRebuildComplete(success_, fingerprints_); 1032 master_->OnTableRebuildComplete(success_, fingerprints_);
1007 1033
1008 // WILL (generally) DELETE THIS! This balances the AddRef in 1034 // WILL (generally) DELETE THIS! This balances the AddRef in
1009 // VisitedLinkMaster::RebuildTableFromHistory. 1035 // VisitedLinkMaster::RebuildTableFromHistory.
1010 Release(); 1036 Release();
1011 } 1037 }
OLDNEW
« no previous file with comments | « chrome/browser/visitedlink_master.h ('k') | chrome/browser/visitedlink_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698