Chromium Code Reviews| 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 "components/visitedlink/browser/visitedlink_master.h" | 5 #include "components/visitedlink/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> |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // of FILE* value. Double pointer to FILE is used because file may still not | 109 // of FILE* value. Double pointer to FILE is used because file may still not |
| 110 // be opened by the time of scheduling the task for execution. | 110 // be opened by the time of scheduling the task for execution. |
| 111 void AsyncClose(FILE** file) { | 111 void AsyncClose(FILE** file) { |
| 112 if (*file) | 112 if (*file) |
| 113 base::IgnoreResult(fclose(*file)); | 113 base::IgnoreResult(fclose(*file)); |
| 114 free(file); | 114 free(file); |
| 115 } | 115 } |
| 116 | 116 |
| 117 } // namespace | 117 } // namespace |
| 118 | 118 |
| 119 struct VisitedLinkMaster::LoadFromFileResult | |
| 120 : public base::RefCountedThreadSafe<LoadFromFileResult> { | |
| 121 LoadFromFileResult(base::ScopedFILE file, | |
| 122 scoped_ptr<base::SharedMemory> shared_memory, | |
| 123 Fingerprint* hash_table, | |
| 124 int32 num_entries, | |
| 125 int32 used_count, | |
| 126 uint8 salt[LINK_SALT_LENGTH]); | |
| 127 | |
| 128 base::ScopedFILE file; | |
| 129 scoped_ptr<base::SharedMemory> shared_memory; | |
| 130 Fingerprint* hash_table; | |
| 131 int32 num_entries; | |
| 132 int32 used_count; | |
| 133 uint8 salt[LINK_SALT_LENGTH]; | |
| 134 | |
| 135 private: | |
| 136 friend class base::RefCountedThreadSafe<LoadFromFileResult>; | |
| 137 virtual ~LoadFromFileResult(); | |
| 138 | |
| 139 DISALLOW_COPY_AND_ASSIGN(LoadFromFileResult); | |
| 140 }; | |
| 141 | |
| 142 VisitedLinkMaster::LoadFromFileResult::LoadFromFileResult( | |
| 143 base::ScopedFILE file, | |
| 144 scoped_ptr<base::SharedMemory> shared_memory, | |
| 145 Fingerprint* hash_table, | |
| 146 int32 num_entries, | |
| 147 int32 used_count, | |
| 148 uint8 salt[LINK_SALT_LENGTH]) | |
| 149 : file(file.Pass()), | |
| 150 shared_memory(shared_memory.Pass()), | |
| 151 hash_table(hash_table), | |
| 152 num_entries(num_entries), | |
| 153 used_count(used_count) { | |
| 154 memcpy(this->salt, salt, LINK_SALT_LENGTH); | |
| 155 } | |
| 156 | |
| 157 VisitedLinkMaster::LoadFromFileResult::~LoadFromFileResult() { | |
| 158 } | |
| 159 | |
| 119 // TableBuilder --------------------------------------------------------------- | 160 // TableBuilder --------------------------------------------------------------- |
| 120 | 161 |
| 121 // How rebuilding from history works | 162 // How rebuilding from history works |
| 122 // --------------------------------- | 163 // --------------------------------- |
| 123 // | 164 // |
| 124 // We mark that we're rebuilding from history by setting the table_builder_ | 165 // We mark that we're rebuilding from history by setting the table_builder_ |
| 125 // member in VisitedLinkMaster to the TableBuilder we create. This builder | 166 // member in VisitedLinkMaster to the TableBuilder we create. This builder |
| 126 // will be called on the history thread by the history system for every URL | 167 // will be called on the history thread by the history system for every URL |
| 127 // in the database. | 168 // in the database. |
| 128 // | 169 // |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 }; | 215 }; |
| 175 | 216 |
| 176 // VisitedLinkMaster ---------------------------------------------------------- | 217 // VisitedLinkMaster ---------------------------------------------------------- |
| 177 | 218 |
| 178 VisitedLinkMaster::VisitedLinkMaster(content::BrowserContext* browser_context, | 219 VisitedLinkMaster::VisitedLinkMaster(content::BrowserContext* browser_context, |
| 179 VisitedLinkDelegate* delegate, | 220 VisitedLinkDelegate* delegate, |
| 180 bool persist_to_disk) | 221 bool persist_to_disk) |
| 181 : browser_context_(browser_context), | 222 : browser_context_(browser_context), |
| 182 delegate_(delegate), | 223 delegate_(delegate), |
| 183 listener_(new VisitedLinkEventListener(this, browser_context)), | 224 listener_(new VisitedLinkEventListener(this, browser_context)), |
| 184 persist_to_disk_(persist_to_disk) { | 225 persist_to_disk_(persist_to_disk), |
| 226 table_is_loading_from_file_(false), | |
| 227 weak_ptr_factory_(this) { | |
| 185 InitMembers(); | 228 InitMembers(); |
| 186 } | 229 } |
| 187 | 230 |
| 188 VisitedLinkMaster::VisitedLinkMaster(Listener* listener, | 231 VisitedLinkMaster::VisitedLinkMaster(Listener* listener, |
| 189 VisitedLinkDelegate* delegate, | 232 VisitedLinkDelegate* delegate, |
| 190 bool persist_to_disk, | 233 bool persist_to_disk, |
| 191 bool suppress_rebuild, | 234 bool suppress_rebuild, |
| 192 const base::FilePath& filename, | 235 const base::FilePath& filename, |
| 193 int32 default_table_size) | 236 int32 default_table_size) |
| 194 : browser_context_(NULL), | 237 : browser_context_(NULL), |
| 195 delegate_(delegate), | 238 delegate_(delegate), |
| 196 persist_to_disk_(persist_to_disk) { | 239 persist_to_disk_(persist_to_disk), |
| 240 table_is_loading_from_file_(false), | |
| 241 weak_ptr_factory_(this) { | |
| 197 listener_.reset(listener); | 242 listener_.reset(listener); |
| 198 DCHECK(listener_.get()); | 243 DCHECK(listener_.get()); |
| 199 InitMembers(); | 244 InitMembers(); |
| 200 | 245 |
| 201 database_name_override_ = filename; | 246 database_name_override_ = filename; |
| 202 table_size_override_ = default_table_size; | 247 table_size_override_ = default_table_size; |
| 203 suppress_rebuild_ = suppress_rebuild; | 248 suppress_rebuild_ = suppress_rebuild; |
| 204 } | 249 } |
| 205 | 250 |
| 206 VisitedLinkMaster::~VisitedLinkMaster() { | 251 VisitedLinkMaster::~VisitedLinkMaster() { |
| 207 if (table_builder_.get()) { | 252 if (table_builder_.get()) { |
| 208 // Prevent the table builder from calling us back now that we're being | 253 // Prevent the table builder from calling us back now that we're being |
| 209 // destroyed. Note that we DON'T delete the object, since the history | 254 // destroyed. Note that we DON'T delete the object, since the history |
| 210 // system is still writing into it. When that is complete, the table | 255 // system is still writing into it. When that is complete, the table |
| 211 // builder will destroy itself when it finds we are gone. | 256 // builder will destroy itself when it finds we are gone. |
| 212 table_builder_->DisownMaster(); | 257 table_builder_->DisownMaster(); |
| 213 } | 258 } |
| 214 FreeURLTable(); | 259 FreeURLTable(); |
| 215 // FreeURLTable() will schedule closing of the file and deletion of |file_|. | 260 // FreeURLTable() will schedule closing of the file and deletion of |file_|. |
| 216 // So nothing should be done here. | 261 // So nothing should be done here. |
| 262 | |
| 263 if (table_is_loading_from_file_ && | |
| 264 (!added_since_load_.empty() || !deleted_since_load_.empty())) { | |
| 265 // Delete the database file if it exists because we don't have enough time | |
| 266 // to load the table from the database file and now we have inconsistent | |
| 267 // state. On the next start table will be rebuilt. | |
| 268 base::FilePath filename; | |
| 269 GetDatabaseFileName(&filename); | |
| 270 PostIOTask(FROM_HERE, | |
| 271 base::Bind(IgnoreResult(&base::DeleteFile), filename, false)); | |
| 272 } | |
| 217 } | 273 } |
| 218 | 274 |
| 219 void VisitedLinkMaster::InitMembers() { | 275 void VisitedLinkMaster::InitMembers() { |
| 220 file_ = NULL; | 276 file_ = NULL; |
| 221 shared_memory_ = NULL; | 277 shared_memory_ = NULL; |
| 222 shared_memory_serial_ = 0; | 278 shared_memory_serial_ = 0; |
| 223 used_items_ = 0; | 279 used_items_ = 0; |
| 224 table_size_override_ = 0; | 280 table_size_override_ = 0; |
| 225 suppress_rebuild_ = false; | 281 suppress_rebuild_ = false; |
| 226 sequence_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken(); | 282 sequence_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken(); |
| 227 | |
| 228 #ifndef NDEBUG | |
| 229 posted_asynchronous_operation_ = false; | |
| 230 #endif | |
| 231 } | 283 } |
| 232 | 284 |
| 233 bool VisitedLinkMaster::Init() { | 285 bool VisitedLinkMaster::Init() { |
| 234 // We probably shouldn't be loading this from the UI thread, | 286 // Create the temporary table. If the table is rebuilt that temporary table |
| 235 // but it does need to happen early on in startup. | 287 // will be became the main table. |
| 236 // http://code.google.com/p/chromium/issues/detail?id=24163 | 288 // The salt must be generated before the table so that it can be copied to |
| 237 base::ThreadRestrictions::ScopedAllowIO allow_io; | 289 // the shared memory. |
| 290 GenerateSalt(salt_); | |
| 291 if (!CreateURLTable(DefaultTableSize())) | |
| 292 return false; | |
| 293 | |
| 294 #ifndef NDEBUG | |
| 295 DebugValidate(); | |
| 296 #endif | |
| 238 | 297 |
| 239 if (persist_to_disk_) { | 298 if (persist_to_disk_) { |
| 240 if (InitFromFile()) | 299 if (InitFromFile()) |
| 241 return true; | 300 return true; |
| 242 } | 301 } |
| 243 return InitFromScratch(suppress_rebuild_); | 302 return InitFromScratch(suppress_rebuild_); |
| 244 } | 303 } |
| 245 | 304 |
| 246 VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) { | 305 VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) { |
| 247 // Extra check that we are not incognito. This should not happen. | 306 // Extra check that we are not incognito. This should not happen. |
| 248 // TODO(boliu): Move this check to HistoryService when IsOffTheRecord is | 307 // TODO(boliu): Move this check to HistoryService when IsOffTheRecord is |
| 249 // removed from BrowserContext. | 308 // removed from BrowserContext. |
| 250 if (browser_context_ && browser_context_->IsOffTheRecord()) { | 309 if (browser_context_ && browser_context_->IsOffTheRecord()) { |
| 251 NOTREACHED(); | 310 NOTREACHED(); |
| 252 return null_hash_; | 311 return null_hash_; |
| 253 } | 312 } |
| 254 | 313 |
| 255 if (!url.is_valid()) | 314 if (!url.is_valid()) |
| 256 return null_hash_; // Don't add invalid URLs. | 315 return null_hash_; // Don't add invalid URLs. |
| 257 | 316 |
| 258 Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(), | 317 Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(), |
| 259 url.spec().size(), | 318 url.spec().size(), |
| 260 salt_); | 319 salt_); |
| 261 if (table_builder_.get()) { | 320 // If the table isn't loaded the table will be rebuilt and after |
| 321 // that accumulated fingerprints will be applied to the table. | |
| 322 if (table_builder_.get() || table_is_loading_from_file_) { | |
| 262 // If we have a pending delete for this fingerprint, cancel it. | 323 // If we have a pending delete for this fingerprint, cancel it. |
| 263 std::set<Fingerprint>::iterator found = | 324 deleted_since_rebuild_.erase(fingerprint); |
| 264 deleted_since_rebuild_.find(fingerprint); | |
| 265 if (found != deleted_since_rebuild_.end()) | |
| 266 deleted_since_rebuild_.erase(found); | |
| 267 | 325 |
| 268 // A rebuild is in progress, save this addition in the temporary list so | 326 // A rebuild or load is in progress, save this addition in the temporary |
| 269 // it can be added once rebuild is complete. | 327 // list so it can be added once rebuild is complete. |
| 270 added_since_rebuild_.insert(fingerprint); | 328 added_since_rebuild_.insert(fingerprint); |
| 271 } | 329 } |
| 272 | 330 |
| 331 if (table_is_loading_from_file_) { | |
| 332 // If we have a pending delete for this url, cancel it. | |
| 333 deleted_since_load_.erase(url); | |
| 334 | |
| 335 // The loading is in progress, save this addition in the temporary | |
| 336 // list so it can be added once the loading is complete. | |
| 337 added_since_load_.insert(url); | |
| 338 } | |
| 339 | |
| 273 // If the table is "full", we don't add URLs and just drop them on the floor. | 340 // If the table is "full", we don't add URLs and just drop them on the floor. |
| 274 // This can happen if we get thousands of new URLs and something causes | 341 // This can happen if we get thousands of new URLs and something causes |
| 275 // the table resizing to fail. This check prevents a hang in that case. Note | 342 // the table resizing to fail. This check prevents a hang in that case. Note |
| 276 // that this is *not* the resize limit, this is just a sanity check. | 343 // that this is *not* the resize limit, this is just a sanity check. |
| 277 if (used_items_ / 8 > table_length_ / 10) | 344 if (used_items_ / 8 > table_length_ / 10) |
| 278 return null_hash_; // Table is more than 80% full. | 345 return null_hash_; // Table is more than 80% full. |
| 279 | 346 |
| 280 return AddFingerprint(fingerprint, true); | 347 return AddFingerprint(fingerprint, true); |
| 281 } | 348 } |
| 282 | 349 |
| 283 void VisitedLinkMaster::PostIOTask(const tracked_objects::Location& from_here, | 350 void VisitedLinkMaster::PostIOTask(const tracked_objects::Location& from_here, |
| 284 const base::Closure& task) { | 351 const base::Closure& task) { |
| 285 DCHECK(persist_to_disk_); | 352 DCHECK(persist_to_disk_); |
| 286 BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(sequence_token_, | 353 BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(sequence_token_, |
| 287 from_here, task); | 354 from_here, task); |
| 288 } | 355 } |
| 289 | 356 |
| 290 void VisitedLinkMaster::AddURL(const GURL& url) { | 357 void VisitedLinkMaster::AddURL(const GURL& url) { |
| 291 Hash index = TryToAddURL(url); | 358 Hash index = TryToAddURL(url); |
| 292 if (!table_builder_.get() && index != null_hash_) { | 359 if (!table_builder_.get() && |
| 360 !table_is_loading_from_file_ && | |
| 361 index != null_hash_) { | |
| 293 // Not rebuilding, so we want to keep the file on disk up-to-date. | 362 // Not rebuilding, so we want to keep the file on disk up-to-date. |
| 294 if (persist_to_disk_) { | 363 if (persist_to_disk_) { |
| 295 WriteUsedItemCountToFile(); | 364 WriteUsedItemCountToFile(); |
| 296 WriteHashRangeToFile(index, index); | 365 WriteHashRangeToFile(index, index); |
| 297 } | 366 } |
| 298 ResizeTableIfNecessary(); | 367 ResizeTableIfNecessary(); |
| 299 } | 368 } |
| 300 } | 369 } |
| 301 | 370 |
| 302 void VisitedLinkMaster::AddURLs(const std::vector<GURL>& url) { | 371 void VisitedLinkMaster::AddURLs(const std::vector<GURL>& urls) { |
| 303 for (std::vector<GURL>::const_iterator i = url.begin(); | 372 for (const GURL& url : urls) { |
| 304 i != url.end(); ++i) { | 373 Hash index = TryToAddURL(url); |
| 305 Hash index = TryToAddURL(*i); | 374 if (!table_builder_.get() && |
| 306 if (!table_builder_.get() && index != null_hash_) | 375 !table_is_loading_from_file_ && |
| 376 index != null_hash_) | |
| 307 ResizeTableIfNecessary(); | 377 ResizeTableIfNecessary(); |
| 308 } | 378 } |
| 309 | 379 |
| 310 // Keeps the file on disk up-to-date. | 380 // Keeps the file on disk up-to-date. |
| 311 if (!table_builder_.get() && persist_to_disk_) | 381 if (!table_builder_.get() && |
| 382 !table_is_loading_from_file_ && | |
| 383 persist_to_disk_) | |
| 312 WriteFullTable(); | 384 WriteFullTable(); |
| 313 } | 385 } |
| 314 | 386 |
| 315 void VisitedLinkMaster::DeleteAllURLs() { | 387 void VisitedLinkMaster::DeleteAllURLs() { |
| 316 // Any pending modifications are invalid. | 388 // Any pending modifications are invalid. |
| 317 added_since_rebuild_.clear(); | 389 added_since_rebuild_.clear(); |
| 318 deleted_since_rebuild_.clear(); | 390 deleted_since_rebuild_.clear(); |
| 319 | 391 |
| 392 added_since_load_.clear(); | |
| 393 deleted_since_load_.clear(); | |
| 394 table_is_loading_from_file_ = false; | |
| 395 | |
| 320 // Clear the hash table. | 396 // Clear the hash table. |
| 321 used_items_ = 0; | 397 used_items_ = 0; |
| 322 memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint)); | 398 memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint)); |
| 323 | 399 |
| 324 // Resize it if it is now too empty. Resize may write the new table out for | 400 // Resize it if it is now too empty. Resize may write the new table out for |
| 325 // us, otherwise, schedule writing the new table to disk ourselves. | 401 // us, otherwise, schedule writing the new table to disk ourselves. |
| 326 if (!ResizeTableIfNecessary() && persist_to_disk_) | 402 if (!ResizeTableIfNecessary() && persist_to_disk_) |
| 327 WriteFullTable(); | 403 WriteFullTable(); |
| 328 | 404 |
| 329 listener_->Reset(); | 405 listener_->Reset(false); |
| 330 } | 406 } |
| 331 | 407 |
| 332 VisitedLinkDelegate* VisitedLinkMaster::GetDelegate() { | 408 VisitedLinkDelegate* VisitedLinkMaster::GetDelegate() { |
| 333 return delegate_; | 409 return delegate_; |
| 334 } | 410 } |
| 335 | 411 |
| 336 void VisitedLinkMaster::DeleteURLs(URLIterator* urls) { | 412 void VisitedLinkMaster::DeleteURLs(URLIterator* urls) { |
| 337 if (!urls->HasNextURL()) | 413 if (!urls->HasNextURL()) |
| 338 return; | 414 return; |
| 339 | 415 |
| 340 listener_->Reset(); | 416 listener_->Reset(false); |
| 341 | 417 |
| 342 if (table_builder_.get()) { | 418 if (table_builder_.get() || table_is_loading_from_file_) { |
| 343 // A rebuild is in progress, save this deletion in the temporary list so | 419 // A rebuild or load is in progress, save this deletion in the temporary |
| 344 // it can be added once rebuild is complete. | 420 // list so it can be added once rebuild is complete. |
| 345 while (urls->HasNextURL()) { | 421 while (urls->HasNextURL()) { |
| 346 const GURL& url(urls->NextURL()); | 422 const GURL& url(urls->NextURL()); |
| 347 if (!url.is_valid()) | 423 if (!url.is_valid()) |
| 348 continue; | 424 continue; |
| 349 | 425 |
| 350 Fingerprint fingerprint = | 426 Fingerprint fingerprint = |
| 351 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); | 427 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); |
| 352 deleted_since_rebuild_.insert(fingerprint); | 428 deleted_since_rebuild_.insert(fingerprint); |
| 353 | 429 |
| 354 // If the URL was just added and now we're deleting it, it may be in the | 430 // If the URL was just added and now we're deleting it, it may be in the |
| 355 // list of things added since the last rebuild. Delete it from that list. | 431 // list of things added since the last rebuild. Delete it from that list. |
| 356 std::set<Fingerprint>::iterator found = | 432 added_since_rebuild_.erase(fingerprint); |
| 357 added_since_rebuild_.find(fingerprint); | 433 |
| 358 if (found != added_since_rebuild_.end()) | 434 if (table_is_loading_from_file_) { |
| 359 added_since_rebuild_.erase(found); | 435 deleted_since_load_.insert(url); |
| 436 added_since_load_.erase(url); | |
| 437 } | |
| 360 | 438 |
| 361 // Delete the URLs from the in-memory table, but don't bother writing | 439 // Delete the URLs from the in-memory table, but don't bother writing |
| 362 // to disk since it will be replaced soon. | 440 // to disk since it will be replaced soon. |
| 363 DeleteFingerprint(fingerprint, false); | 441 DeleteFingerprint(fingerprint, false); |
| 364 } | 442 } |
| 365 return; | 443 return; |
| 366 } | 444 } |
| 367 | 445 |
| 368 // Compute the deleted URLs' fingerprints and delete them | 446 // Compute the deleted URLs' fingerprints and delete them |
| 369 std::set<Fingerprint> deleted_fingerprints; | 447 std::set<Fingerprint> deleted_fingerprints; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 | 605 |
| 528 // Write the hash data. | 606 // Write the hash data. |
| 529 WriteToFile(file_, kFileHeaderSize, | 607 WriteToFile(file_, kFileHeaderSize, |
| 530 hash_table_, table_length_ * sizeof(Fingerprint)); | 608 hash_table_, table_length_ * sizeof(Fingerprint)); |
| 531 | 609 |
| 532 // The hash table may have shrunk, so make sure this is the end. | 610 // The hash table may have shrunk, so make sure this is the end. |
| 533 PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_)); | 611 PostIOTask(FROM_HERE, base::Bind(&AsyncTruncate, file_)); |
| 534 } | 612 } |
| 535 | 613 |
| 536 bool VisitedLinkMaster::InitFromFile() { | 614 bool VisitedLinkMaster::InitFromFile() { |
| 537 DCHECK(file_ == NULL); | 615 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 616 | |
| 617 DCHECK(file_ == nullptr); | |
| 538 DCHECK(persist_to_disk_); | 618 DCHECK(persist_to_disk_); |
| 539 | 619 |
| 540 base::FilePath filename; | 620 base::FilePath filename; |
| 541 GetDatabaseFileName(&filename); | 621 if (!GetDatabaseFileName(&filename)) |
| 622 return false; | |
| 623 | |
| 624 table_is_loading_from_file_ = true; | |
| 625 | |
| 626 TableLoadCompleteCallback callback = base::Bind( | |
| 627 &VisitedLinkMaster::OnTableLoadComplete, weak_ptr_factory_.GetWeakPtr()); | |
| 628 | |
| 629 PostIOTask(FROM_HERE, | |
| 630 base::Bind(&VisitedLinkMaster::LoadFromFile, filename, callback)); | |
| 631 | |
| 632 return true; | |
| 633 } | |
| 634 | |
| 635 // static | |
| 636 void VisitedLinkMaster::LoadFromFile( | |
| 637 const base::FilePath& filename, | |
| 638 const TableLoadCompleteCallback& callback) { | |
| 639 scoped_refptr<LoadFromFileResult> load_from_file_result; | |
| 640 bool success = LoadApartFromFile(filename, &load_from_file_result); | |
| 641 | |
| 642 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 643 base::Bind(callback, success, load_from_file_result)); | |
| 644 } | |
| 645 | |
| 646 // static | |
| 647 bool VisitedLinkMaster::LoadApartFromFile( | |
| 648 const base::FilePath& filename, | |
| 649 scoped_refptr<LoadFromFileResult>* load_from_file_result) { | |
| 650 DCHECK(load_from_file_result); | |
| 651 | |
| 542 base::ScopedFILE file_closer(base::OpenFile(filename, "rb+")); | 652 base::ScopedFILE file_closer(base::OpenFile(filename, "rb+")); |
| 543 if (!file_closer.get()) | 653 if (!file_closer.get()) |
| 544 return false; | 654 return false; |
| 545 | 655 |
| 546 int32 num_entries, used_count; | 656 int32 num_entries, used_count; |
| 547 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_)) | 657 uint8 salt[LINK_SALT_LENGTH]; |
| 658 if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt)) | |
| 548 return false; // Header isn't valid. | 659 return false; // Header isn't valid. |
| 549 | 660 |
| 550 // Allocate and read the table. | 661 // Allocate and read the table. |
| 551 if (!CreateURLTable(num_entries, false)) | 662 scoped_ptr<base::SharedMemory> shared_memory; |
| 663 VisitedLinkCommon::Fingerprint* hash_table; | |
| 664 if (!CreateApartURLTable(num_entries, salt, &shared_memory, &hash_table)) | |
| 552 return false; | 665 return false; |
| 553 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, | 666 |
| 554 hash_table_, num_entries * sizeof(Fingerprint))) { | 667 if (!ReadFromFile(file_closer.get(), kFileHeaderSize, hash_table, |
| 555 FreeURLTable(); | 668 num_entries * sizeof(Fingerprint))) { |
| 556 return false; | 669 return false; |
| 557 } | 670 } |
| 558 used_items_ = used_count; | 671 |
| 672 *load_from_file_result = new LoadFromFileResult(file_closer.Pass(), | |
| 673 shared_memory.Pass(), | |
| 674 hash_table, | |
| 675 num_entries, | |
| 676 used_count, | |
| 677 salt); | |
| 678 return true; | |
| 679 } | |
| 680 | |
| 681 void VisitedLinkMaster::OnTableLoadComplete( | |
| 682 bool success, | |
| 683 scoped_refptr<LoadFromFileResult> load_from_file_result) { | |
| 684 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 685 DCHECK(persist_to_disk_); | |
| 686 DCHECK(!table_builder_.get()); | |
| 687 | |
| 688 // When the apart table was loading from the database file the current table | |
| 689 // have been cleared. | |
| 690 if (!table_is_loading_from_file_) | |
| 691 return; | |
| 692 | |
| 693 table_is_loading_from_file_ = false; | |
| 694 | |
| 695 if (!success) { | |
| 696 // This temporary sets are used only when table was loaded. | |
| 697 added_since_load_.clear(); | |
| 698 deleted_since_load_.clear(); | |
| 699 | |
| 700 // If the table isn't loaded the table will be rebuilt. | |
| 701 if (!suppress_rebuild_) { | |
| 702 RebuildTableFromDelegate(); | |
| 703 } else { | |
| 704 // When we disallow rebuilds (normally just unit tests), just use the | |
| 705 // current empty table. | |
| 706 WriteFullTable(); | |
| 707 } | |
| 708 return; | |
| 709 } | |
| 710 | |
| 711 // This temprorary sets are needed only to rebuild table. | |
|
brettw
2015/12/08 00:54:42
Spelling: temporary
| |
| 712 added_since_rebuild_.clear(); | |
| 713 deleted_since_rebuild_.clear(); | |
| 714 | |
| 715 DCHECK(load_from_file_result.get()); | |
| 716 | |
| 717 // Delete the previous table. | |
| 718 DCHECK(shared_memory_); | |
| 719 delete shared_memory_; | |
| 720 shared_memory_ = nullptr; | |
| 721 | |
| 722 // Assign the open file. | |
| 723 DCHECK(!file_); | |
| 724 DCHECK(load_from_file_result->file.get()); | |
| 725 file_ = static_cast<FILE**>(malloc(sizeof(*file_))); | |
| 726 *file_ = load_from_file_result->file.release(); | |
| 727 | |
| 728 // Assign the loaded table. | |
| 729 DCHECK(load_from_file_result->shared_memory.get()); | |
| 730 DCHECK(load_from_file_result->hash_table); | |
| 731 memcpy(salt_, load_from_file_result->salt, LINK_SALT_LENGTH); | |
| 732 shared_memory_ = load_from_file_result->shared_memory.release(); | |
| 733 hash_table_ = load_from_file_result->hash_table; | |
| 734 table_length_ = load_from_file_result->num_entries; | |
| 735 used_items_ = load_from_file_result->used_count; | |
| 559 | 736 |
| 560 #ifndef NDEBUG | 737 #ifndef NDEBUG |
| 561 DebugValidate(); | 738 DebugValidate(); |
| 562 #endif | 739 #endif |
| 563 | 740 |
| 564 file_ = static_cast<FILE**>(malloc(sizeof(*file_))); | 741 // Send an update notification to all child processes. |
| 565 *file_ = file_closer.release(); | 742 listener_->NewTable(shared_memory_); |
| 566 return true; | 743 |
| 744 if (!added_since_load_.empty() || !deleted_since_load_.empty()) { | |
| 745 // Resize the table if the table doesn't have enough capacity. | |
| 746 int new_used_items = used_items_ + added_since_load_.size(); | |
| 747 if (new_used_items >= table_length_) | |
| 748 ResizeTable(NewTableSizeForCount(new_used_items)); | |
| 749 | |
| 750 // Also add anything that was added while we were asynchronously | |
| 751 // loading the table. | |
| 752 for (const GURL& url : added_since_load_) { | |
| 753 Fingerprint fingerprint = | |
| 754 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); | |
| 755 AddFingerprint(fingerprint, false); | |
| 756 } | |
| 757 added_since_load_.clear(); | |
| 758 | |
| 759 // Now handle deletions. | |
| 760 for (const GURL& url : deleted_since_load_) { | |
| 761 Fingerprint fingerprint = | |
| 762 ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); | |
| 763 DeleteFingerprint(fingerprint, false); | |
| 764 } | |
| 765 deleted_since_load_.clear(); | |
| 766 | |
| 767 if (persist_to_disk_) | |
| 768 WriteFullTable(); | |
| 769 } | |
| 770 | |
| 771 // All tabs which was loaded when table was being loaded drop their cached | |
| 772 // visited link hashes and invalidate their links again. | |
| 773 listener_->Reset(true); | |
| 567 } | 774 } |
| 568 | 775 |
| 569 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { | 776 bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) { |
| 570 int32 table_size = kDefaultTableSize; | |
| 571 if (table_size_override_) | |
| 572 table_size = table_size_override_; | |
| 573 | |
| 574 // The salt must be generated before the table so that it can be copied to | |
| 575 // the shared memory. | |
| 576 GenerateSalt(salt_); | |
| 577 if (!CreateURLTable(table_size, true)) | |
| 578 return false; | |
| 579 | |
| 580 #ifndef NDEBUG | |
| 581 DebugValidate(); | |
| 582 #endif | |
| 583 | |
| 584 if (suppress_rebuild && persist_to_disk_) { | 777 if (suppress_rebuild && persist_to_disk_) { |
| 585 // When we disallow rebuilds (normally just unit tests), just use the | 778 // When we disallow rebuilds (normally just unit tests), just use the |
| 586 // current empty table. | 779 // current empty table. |
| 587 WriteFullTable(); | 780 WriteFullTable(); |
| 588 return true; | 781 return true; |
| 589 } | 782 } |
| 590 | 783 |
| 591 // This will build the table from history. On the first run, history will | 784 // This will build the table from history. On the first run, history will |
| 592 // be empty, so this will be correct. This will also write the new table | 785 // be empty, so this will be correct. This will also write the new table |
| 593 // to disk. We don't want to save explicitly here, since the rebuild may | 786 // to disk. We don't want to save explicitly here, since the rebuild may |
| 594 // not complete, leaving us with an empty but valid visited link database. | 787 // not complete, leaving us with an empty but valid visited link database. |
| 595 // In the future, we won't know we need to try rebuilding again. | 788 // In the future, we won't know we need to try rebuilding again. |
| 596 return RebuildTableFromDelegate(); | 789 return RebuildTableFromDelegate(); |
| 597 } | 790 } |
| 598 | 791 |
| 792 // static | |
| 599 bool VisitedLinkMaster::ReadFileHeader(FILE* file, | 793 bool VisitedLinkMaster::ReadFileHeader(FILE* file, |
| 600 int32* num_entries, | 794 int32* num_entries, |
| 601 int32* used_count, | 795 int32* used_count, |
| 602 uint8 salt[LINK_SALT_LENGTH]) { | 796 uint8 salt[LINK_SALT_LENGTH]) { |
| 603 DCHECK(persist_to_disk_); | |
| 604 | |
| 605 // Get file size. | 797 // Get file size. |
| 606 // Note that there is no need to seek back to the original location in the | 798 // Note that there is no need to seek back to the original location in the |
| 607 // file since ReadFromFile() [which is the next call accessing the file] | 799 // file since ReadFromFile() [which is the next call accessing the file] |
| 608 // seeks before reading. | 800 // seeks before reading. |
| 609 if (fseek(file, 0, SEEK_END) == -1) | 801 if (fseek(file, 0, SEEK_END) == -1) |
| 610 return false; | 802 return false; |
| 611 size_t file_size = ftell(file); | 803 size_t file_size = ftell(file); |
| 612 | 804 |
| 613 if (file_size <= kFileHeaderSize) | 805 if (file_size <= kFileHeaderSize) |
| 614 return false; | 806 return false; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 if (!browser_context_ || browser_context_->GetPath().empty()) | 850 if (!browser_context_ || browser_context_->GetPath().empty()) |
| 659 return false; | 851 return false; |
| 660 | 852 |
| 661 base::FilePath profile_dir = browser_context_->GetPath(); | 853 base::FilePath profile_dir = browser_context_->GetPath(); |
| 662 *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links")); | 854 *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links")); |
| 663 return true; | 855 return true; |
| 664 } | 856 } |
| 665 | 857 |
| 666 // Initializes the shared memory structure. The salt should already be filled | 858 // Initializes the shared memory structure. The salt should already be filled |
| 667 // in so that it can be written to the shared memory | 859 // in so that it can be written to the shared memory |
| 668 bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) { | 860 bool VisitedLinkMaster::CreateURLTable(int32 num_entries) { |
| 861 scoped_ptr<base::SharedMemory> shared_memory; | |
| 862 VisitedLinkCommon::Fingerprint* hash_table; | |
| 863 if (CreateApartURLTable(num_entries, salt_, &shared_memory, &hash_table)) { | |
| 864 shared_memory_ = shared_memory.release(); | |
| 865 hash_table_ = hash_table; | |
| 866 table_length_ = num_entries; | |
| 867 used_items_ = 0; | |
| 868 return true; | |
| 869 } | |
| 870 | |
| 871 return false; | |
| 872 } | |
| 873 | |
| 874 // static | |
| 875 bool VisitedLinkMaster::CreateApartURLTable( | |
| 876 int32 num_entries, | |
| 877 const uint8 salt[LINK_SALT_LENGTH], | |
| 878 scoped_ptr<base::SharedMemory>* shared_memory, | |
| 879 VisitedLinkCommon::Fingerprint** hash_table) { | |
| 880 DCHECK(salt); | |
| 881 DCHECK(shared_memory); | |
| 882 DCHECK(hash_table); | |
| 883 | |
| 669 // The table is the size of the table followed by the entries. | 884 // The table is the size of the table followed by the entries. |
| 670 uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader); | 885 uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader); |
| 671 | 886 |
| 672 // Create the shared memory object. | 887 // Create the shared memory object. |
| 673 shared_memory_ = new base::SharedMemory(); | 888 scoped_ptr<base::SharedMemory> sh_mem(new base::SharedMemory()); |
| 674 if (!shared_memory_) | 889 if (!sh_mem) |
| 675 return false; | 890 return false; |
| 676 | 891 |
| 677 base::SharedMemoryCreateOptions options; | 892 base::SharedMemoryCreateOptions options; |
| 678 options.size = alloc_size; | 893 options.size = alloc_size; |
| 679 options.share_read_only = true; | 894 options.share_read_only = true; |
| 680 | 895 |
| 681 if (!shared_memory_->Create(options) || !shared_memory_->Map(alloc_size)) { | 896 if (!sh_mem->Create(options) || !sh_mem->Map(alloc_size)) |
| 682 delete shared_memory_; | |
| 683 shared_memory_ = NULL; | |
| 684 return false; | 897 return false; |
| 685 } | |
| 686 | 898 |
| 687 if (init_to_empty) { | 899 memset(sh_mem->memory(), 0, alloc_size); |
| 688 memset(shared_memory_->memory(), 0, alloc_size); | |
| 689 used_items_ = 0; | |
| 690 } | |
| 691 table_length_ = num_entries; | |
| 692 | 900 |
| 693 // Save the header for other processes to read. | 901 // Save the header for other processes to read. |
| 694 SharedHeader* header = static_cast<SharedHeader*>(shared_memory_->memory()); | 902 SharedHeader* header = static_cast<SharedHeader*>(sh_mem->memory()); |
| 695 header->length = table_length_; | 903 header->length = num_entries; |
| 696 memcpy(header->salt, salt_, LINK_SALT_LENGTH); | 904 memcpy(header->salt, salt, LINK_SALT_LENGTH); |
| 697 | 905 |
| 698 // Our table pointer is just the data immediately following the size. | 906 // Our table pointer is just the data immediately following the size. |
| 699 hash_table_ = reinterpret_cast<Fingerprint*>( | 907 *hash_table = reinterpret_cast<Fingerprint*>( |
| 700 static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader)); | 908 static_cast<char*>(sh_mem->memory()) + sizeof(SharedHeader)); |
| 909 | |
| 910 *shared_memory = sh_mem.Pass(); | |
| 701 | 911 |
| 702 return true; | 912 return true; |
| 703 } | 913 } |
| 704 | 914 |
| 705 bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) { | 915 bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) { |
| 706 base::SharedMemory *old_shared_memory = shared_memory_; | 916 base::SharedMemory *old_shared_memory = shared_memory_; |
| 707 Fingerprint* old_hash_table = hash_table_; | 917 Fingerprint* old_hash_table = hash_table_; |
| 708 int32 old_table_length = table_length_; | 918 int32 old_table_length = table_length_; |
| 709 if (!CreateURLTable(num_entries, true)) { | 919 if (!CreateURLTable(num_entries)) { |
| 710 // Try to put back the old state. | 920 // Try to put back the old state. |
| 711 shared_memory_ = old_shared_memory; | 921 shared_memory_ = old_shared_memory; |
| 712 hash_table_ = old_hash_table; | 922 hash_table_ = old_hash_table; |
| 713 table_length_ = old_table_length; | 923 table_length_ = old_table_length; |
| 714 return false; | 924 return false; |
| 715 } | 925 } |
| 716 | 926 |
| 717 #ifndef NDEBUG | 927 #ifndef NDEBUG |
| 718 DebugValidate(); | 928 DebugValidate(); |
| 719 #endif | 929 #endif |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 | 999 |
| 790 #ifndef NDEBUG | 1000 #ifndef NDEBUG |
| 791 DebugValidate(); | 1001 DebugValidate(); |
| 792 #endif | 1002 #endif |
| 793 | 1003 |
| 794 // The new table needs to be written to disk. | 1004 // The new table needs to be written to disk. |
| 795 if (persist_to_disk_) | 1005 if (persist_to_disk_) |
| 796 WriteFullTable(); | 1006 WriteFullTable(); |
| 797 } | 1007 } |
| 798 | 1008 |
| 1009 uint32 VisitedLinkMaster::DefaultTableSize() const { | |
| 1010 if (table_size_override_) | |
| 1011 return table_size_override_; | |
| 1012 | |
| 1013 return kDefaultTableSize; | |
| 1014 } | |
| 1015 | |
| 799 uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const { | 1016 uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const { |
| 800 // These table sizes are selected to be the maximum prime number less than | 1017 // These table sizes are selected to be the maximum prime number less than |
| 801 // a "convenient" multiple of 1K. | 1018 // a "convenient" multiple of 1K. |
| 802 static const int table_sizes[] = { | 1019 static const int table_sizes[] = { |
| 803 16381, // 16K = 16384 <- don't shrink below this table size | 1020 16381, // 16K = 16384 <- don't shrink below this table size |
| 804 // (should be == default_table_size) | 1021 // (should be == default_table_size) |
| 805 32767, // 32K = 32768 | 1022 32767, // 32K = 32768 |
| 806 65521, // 64K = 65536 | 1023 65521, // 64K = 65536 |
| 807 130051, // 128K = 131072 | 1024 130051, // 128K = 131072 |
| 808 262127, // 256K = 262144 | 1025 262127, // 256K = 262144 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 850 // replacement succeeds. | 1067 // replacement succeeds. |
| 851 base::SharedMemory* old_shared_memory = shared_memory_; | 1068 base::SharedMemory* old_shared_memory = shared_memory_; |
| 852 | 1069 |
| 853 int new_table_size = NewTableSizeForCount( | 1070 int new_table_size = NewTableSizeForCount( |
| 854 static_cast<int>(fingerprints.size() + added_since_rebuild_.size())); | 1071 static_cast<int>(fingerprints.size() + added_since_rebuild_.size())); |
| 855 if (BeginReplaceURLTable(new_table_size)) { | 1072 if (BeginReplaceURLTable(new_table_size)) { |
| 856 // Free the old table. | 1073 // Free the old table. |
| 857 delete old_shared_memory; | 1074 delete old_shared_memory; |
| 858 | 1075 |
| 859 // Add the stored fingerprints to the hash table. | 1076 // Add the stored fingerprints to the hash table. |
| 860 for (size_t i = 0; i < fingerprints.size(); i++) | 1077 for (const auto& fingerprint : fingerprints) |
| 861 AddFingerprint(fingerprints[i], false); | 1078 AddFingerprint(fingerprint, false); |
| 862 | 1079 |
| 863 // Also add anything that was added while we were asynchronously | 1080 // Also add anything that was added while we were asynchronously |
| 864 // generating the new table. | 1081 // generating the new table. |
| 865 for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin(); | 1082 for (const auto& fingerprint : added_since_rebuild_) |
| 866 i != added_since_rebuild_.end(); ++i) | 1083 AddFingerprint(fingerprint, false); |
| 867 AddFingerprint(*i, false); | |
| 868 added_since_rebuild_.clear(); | 1084 added_since_rebuild_.clear(); |
| 869 | 1085 |
| 870 // Now handle deletions. | 1086 // Now handle deletions. Do not shrink the table now, we'll shrink it when |
| 871 DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_); | 1087 // adding or deleting an url the next time. |
| 1088 for (const auto& fingerprint : deleted_since_rebuild_) | |
| 1089 DeleteFingerprint(fingerprint, false); | |
| 872 deleted_since_rebuild_.clear(); | 1090 deleted_since_rebuild_.clear(); |
| 873 | 1091 |
| 874 // Send an update notification to all child processes. | 1092 // Send an update notification to all child processes. |
| 875 listener_->NewTable(shared_memory_); | 1093 listener_->NewTable(shared_memory_); |
| 1094 // All tabs which was loaded when table was being rebuilt | |
| 1095 // invalidate their links again. | |
| 1096 listener_->Reset(false); | |
| 876 | 1097 |
| 877 if (persist_to_disk_) | 1098 if (persist_to_disk_) |
| 878 WriteFullTable(); | 1099 WriteFullTable(); |
| 879 } | 1100 } |
| 880 } | 1101 } |
| 881 table_builder_ = NULL; // Will release our reference to the builder. | 1102 table_builder_ = NULL; // Will release our reference to the builder. |
| 882 | 1103 |
| 883 // Notify the unit test that the rebuild is complete (will be NULL in prod.) | 1104 // Notify the unit test that the rebuild is complete (will be NULL in prod.) |
| 884 if (!rebuild_complete_task_.is_null()) { | 1105 if (!rebuild_complete_task_.is_null()) { |
| 885 rebuild_complete_task_.Run(); | 1106 rebuild_complete_task_.Run(); |
| 886 rebuild_complete_task_.Reset(); | 1107 rebuild_complete_task_.Reset(); |
| 887 } | 1108 } |
| 888 } | 1109 } |
| 889 | 1110 |
| 890 void VisitedLinkMaster::WriteToFile(FILE** file, | 1111 void VisitedLinkMaster::WriteToFile(FILE** file, |
| 891 off_t offset, | 1112 off_t offset, |
| 892 void* data, | 1113 void* data, |
| 893 int32 data_size) { | 1114 int32 data_size) { |
| 894 DCHECK(persist_to_disk_); | 1115 DCHECK(persist_to_disk_); |
| 895 #ifndef NDEBUG | 1116 DCHECK(!table_is_loading_from_file_); |
| 896 posted_asynchronous_operation_ = true; | |
| 897 #endif | |
| 898 PostIOTask(FROM_HERE, | 1117 PostIOTask(FROM_HERE, |
| 899 base::Bind(&AsyncWrite, file, offset, | 1118 base::Bind(&AsyncWrite, file, offset, |
| 900 std::string(static_cast<const char*>(data), data_size))); | 1119 std::string(static_cast<const char*>(data), data_size))); |
| 901 } | 1120 } |
| 902 | 1121 |
| 903 void VisitedLinkMaster::WriteUsedItemCountToFile() { | 1122 void VisitedLinkMaster::WriteUsedItemCountToFile() { |
| 904 DCHECK(persist_to_disk_); | 1123 DCHECK(persist_to_disk_); |
| 905 if (!file_) | 1124 if (!file_) |
| 906 return; // See comment on the file_ variable for why this might happen. | 1125 return; // See comment on the file_ variable for why this might happen. |
| 907 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); | 1126 WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_)); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 922 WriteToFile(file_, kFileHeaderSize, hash_table_, | 1141 WriteToFile(file_, kFileHeaderSize, hash_table_, |
| 923 (last_hash + 1) * sizeof(Fingerprint)); | 1142 (last_hash + 1) * sizeof(Fingerprint)); |
| 924 } else { | 1143 } else { |
| 925 // Normal case, just write the range. | 1144 // Normal case, just write the range. |
| 926 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize, | 1145 WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize, |
| 927 &hash_table_[first_hash], | 1146 &hash_table_[first_hash], |
| 928 (last_hash - first_hash + 1) * sizeof(Fingerprint)); | 1147 (last_hash - first_hash + 1) * sizeof(Fingerprint)); |
| 929 } | 1148 } |
| 930 } | 1149 } |
| 931 | 1150 |
| 1151 // static | |
| 932 bool VisitedLinkMaster::ReadFromFile(FILE* file, | 1152 bool VisitedLinkMaster::ReadFromFile(FILE* file, |
| 933 off_t offset, | 1153 off_t offset, |
| 934 void* data, | 1154 void* data, |
| 935 size_t data_size) { | 1155 size_t data_size) { |
| 936 DCHECK(persist_to_disk_); | |
| 937 #ifndef NDEBUG | |
| 938 // Since this function is synchronous, we require that no asynchronous | |
| 939 // operations could possibly be pending. | |
| 940 DCHECK(!posted_asynchronous_operation_); | |
| 941 #endif | |
| 942 | |
| 943 if (fseek(file, offset, SEEK_SET) != 0) | 1156 if (fseek(file, offset, SEEK_SET) != 0) |
| 944 return false; | 1157 return false; |
| 945 | 1158 |
| 946 size_t num_read = fread(data, 1, data_size, file); | 1159 size_t num_read = fread(data, 1, data_size, file); |
| 947 return num_read == data_size; | 1160 return num_read == data_size; |
| 948 } | 1161 } |
| 949 | 1162 |
| 950 // VisitedLinkTableBuilder ---------------------------------------------------- | 1163 // VisitedLinkTableBuilder ---------------------------------------------------- |
| 951 | 1164 |
| 952 VisitedLinkMaster::TableBuilder::TableBuilder( | 1165 VisitedLinkMaster::TableBuilder::TableBuilder( |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 981 BrowserThread::UI, FROM_HERE, | 1194 BrowserThread::UI, FROM_HERE, |
| 982 base::Bind(&TableBuilder::OnCompleteMainThread, this)); | 1195 base::Bind(&TableBuilder::OnCompleteMainThread, this)); |
| 983 } | 1196 } |
| 984 | 1197 |
| 985 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { | 1198 void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() { |
| 986 if (master_) | 1199 if (master_) |
| 987 master_->OnTableRebuildComplete(success_, fingerprints_); | 1200 master_->OnTableRebuildComplete(success_, fingerprints_); |
| 988 } | 1201 } |
| 989 | 1202 |
| 990 } // namespace visitedlink | 1203 } // namespace visitedlink |
| OLD | NEW |