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

Side by Side Diff: chrome/browser/safe_browsing/safe_browsing_store_file.cc

Issue 8349018: Safe-browsing SBAddPrefix from vector to deque. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Tweak some naming. Created 9 years, 2 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h" 5 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
6 6
7 #include "base/md5.h" 7 #include "base/md5.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 9
10 namespace { 10 namespace {
(...skipping 30 matching lines...) Expand all
41 // Although fseek takes negative values, for this case, we only want 41 // Although fseek takes negative values, for this case, we only want
42 // to skip forward. 42 // to skip forward.
43 DCHECK(static_cast<long>(bytes) >= 0); 43 DCHECK(static_cast<long>(bytes) >= 0);
44 if (static_cast<long>(bytes) < 0) 44 if (static_cast<long>(bytes) < 0)
45 return false; 45 return false;
46 int rv = fseek(fp, static_cast<long>(bytes), SEEK_CUR); 46 int rv = fseek(fp, static_cast<long>(bytes), SEEK_CUR);
47 DCHECK_EQ(rv, 0); 47 DCHECK_EQ(rv, 0);
48 return rv == 0; 48 return rv == 0;
49 } 49 }
50 50
51 // Read an array of |nmemb| items from |fp| into |ptr|, and fold the 51 // Read from |fp| into |item|, and fold the input data into the
52 // input data into the checksum in |context|, if non-NULL. Return 52 // checksum in |context|, if non-NULL. Return true on success.
53 // true on success.
54 template <class T> 53 template <class T>
55 bool ReadArray(T* ptr, size_t nmemb, FILE* fp, base::MD5Context* context) { 54 bool ReadItem(T* item, FILE* fp, base::MD5Context* context) {
56 const size_t ret = fread(ptr, sizeof(T), nmemb, fp); 55 const size_t ret = fread(item, sizeof(T), 1, fp);
57 if (ret != nmemb) 56 if (ret != 1)
58 return false; 57 return false;
59 58
60 if (context) { 59 if (context) {
61 base::MD5Update(context, 60 base::MD5Update(context,
62 base::StringPiece(reinterpret_cast<char*>(ptr), 61 base::StringPiece(reinterpret_cast<char*>(item),
63 sizeof(T) * nmemb)); 62 sizeof(T)));
64 } 63 }
65 return true; 64 return true;
66 } 65 }
67 66
68 // Write an array of |nmemb| items from |ptr| to |fp|, and fold the 67 // Write |item| to |fp|, and fold the output data into the checksum in
69 // output data into the checksum in |context|, if non-NULL. Return 68 // |context|, if non-NULL. Return true on success.
70 // true on success.
71 template <class T> 69 template <class T>
72 bool WriteArray(const T* ptr, size_t nmemb, FILE* fp, 70 bool WriteItem(const T& item, FILE* fp, base::MD5Context* context) {
73 base::MD5Context* context) { 71 const size_t ret = fwrite(&item, sizeof(T), 1, fp);
74 const size_t ret = fwrite(ptr, sizeof(T), nmemb, fp); 72 if (ret != 1)
75 if (ret != nmemb)
76 return false; 73 return false;
77 74
78 if (context) { 75 if (context) {
79 base::MD5Update(context, 76 base::MD5Update(context,
80 base::StringPiece(reinterpret_cast<const char*>(ptr), 77 base::StringPiece(reinterpret_cast<const char*>(&item),
81 sizeof(T) * nmemb)); 78 sizeof(T)));
82 } 79 }
83 80
84 return true; 81 return true;
85 } 82 }
86 83
87 // Expand |values| to fit |count| new items, read those items from 84 // Read |count| items into |values| from |fp|, and fold them into the
88 // |fp| and fold them into the checksum in |context|. Returns true on 85 // checksum in |context|. Returns true on success.
89 // success. 86 template <typename CT>
90 template <class T> 87 bool ReadToContainer(CT* values, size_t count, FILE* fp,
91 bool ReadToVector(std::vector<T>* values, size_t count, FILE* fp, 88 base::MD5Context* context) {
92 base::MD5Context* context) {
93 // Pointers into an empty vector may not be valid.
94 if (!count) 89 if (!count)
95 return true; 90 return true;
96 91
97 // Grab the size for purposes of finding where to read to. The 92 for (size_t i = 0; i < count; ++i) {
98 // resize could invalidate any iterator captured here. 93 typename CT::value_type value;
99 const size_t original_size = values->size(); 94 if (!ReadItem(&value, fp, context))
100 values->resize(original_size + count); 95 return false;
101 96
102 // Sayeth Herb Sutter: Vectors are guaranteed to be contiguous. So 97 // push_back() is more obvious, but coded this way std::set can
103 // get a pointer to where to read the data to. 98 // also be read.
104 T* ptr = &((*values)[original_size]); 99 values->insert(values->end(), value);
105 if (!ReadArray(ptr, count, fp, context)) {
106 values->resize(original_size);
107 return false;
108 } 100 }
109 101
110 return true; 102 return true;
111 } 103 }
112 104
113 // Write all of |values| to |fp|, and fold the data into the checksum 105 // Write all of |values| to |fp|, and fold the data into the checksum
114 // in |context|, if non-NULL. Returns true on succsess. 106 // in |context|, if non-NULL. Returns true on succsess.
115 template <class T> 107 template <typename CT>
116 bool WriteVector(const std::vector<T>& values, FILE* fp, 108 bool WriteContainer(const CT& values, FILE* fp,
117 base::MD5Context* context) { 109 base::MD5Context* context) {
118 // Pointers into empty vectors may not be valid.
119 if (values.empty()) 110 if (values.empty())
120 return true; 111 return true;
121 112
122 // Sayeth Herb Sutter: Vectors are guaranteed to be contiguous. So 113 for (typename CT::const_iterator iter = values.begin();
123 // get a pointer to where to write from. 114 iter != values.end(); ++iter) {
124 const T* ptr = &(values[0]); 115 if (!WriteItem(*iter, fp, context))
125 return WriteArray(ptr, values.size(), fp, context); 116 return false;
126 } 117 }
127
128 // Read an array of |count| integers and add them to |values|.
129 // Returns true on success.
130 bool ReadToChunkSet(std::set<int32>* values, size_t count, FILE* fp,
131 base::MD5Context* context) {
132 if (!count)
133 return true;
134
135 std::vector<int32> flat_values;
136 if (!ReadToVector(&flat_values, count, fp, context))
137 return false;
138
139 values->insert(flat_values.begin(), flat_values.end());
140 return true; 118 return true;
141 } 119 }
142 120
143 // Write the contents of |values| as an array of integers. Returns
144 // true on success.
145 bool WriteChunkSet(const std::set<int32>& values, FILE* fp,
146 base::MD5Context* context) {
147 if (values.empty())
148 return true;
149
150 const std::vector<int32> flat_values(values.begin(), values.end());
151 return WriteVector(flat_values, fp, context);
152 }
153
154 // Delete the chunks in |deleted| from |chunks|. 121 // Delete the chunks in |deleted| from |chunks|.
155 void DeleteChunksFromSet(const base::hash_set<int32>& deleted, 122 void DeleteChunksFromSet(const base::hash_set<int32>& deleted,
156 std::set<int32>* chunks) { 123 std::set<int32>* chunks) {
157 for (std::set<int32>::iterator iter = chunks->begin(); 124 for (std::set<int32>::iterator iter = chunks->begin();
158 iter != chunks->end();) { 125 iter != chunks->end();) {
159 std::set<int32>::iterator prev = iter++; 126 std::set<int32>::iterator prev = iter++;
160 if (deleted.count(*prev) > 0) 127 if (deleted.count(*prev) > 0)
161 chunks->erase(prev); 128 chunks->erase(prev);
162 } 129 }
163 } 130 }
(...skipping 20 matching lines...) Expand all
184 151
185 return true; 152 return true;
186 } 153 }
187 154
188 // This a helper function that reads header to |header|. Returns true if the 155 // This a helper function that reads header to |header|. Returns true if the
189 // magic number is correct and santiy check passes. 156 // magic number is correct and santiy check passes.
190 bool ReadAndVerifyHeader(const FilePath& filename, 157 bool ReadAndVerifyHeader(const FilePath& filename,
191 FILE* fp, 158 FILE* fp,
192 FileHeader* header, 159 FileHeader* header,
193 base::MD5Context* context) { 160 base::MD5Context* context) {
194 if (!ReadArray(header, 1, fp, context)) 161 if (!ReadItem(header, fp, context))
195 return false; 162 return false;
196 if (header->magic != kFileMagic || header->version != kFileVersion) 163 if (header->magic != kFileMagic || header->version != kFileVersion)
197 return false; 164 return false;
198 if (!FileHeaderSanityCheck(filename, *header)) 165 if (!FileHeaderSanityCheck(filename, *header))
199 return false; 166 return false;
200 return true; 167 return true;
201 } 168 }
202 169
203 } // namespace 170 } // namespace
204 171
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 253
287 bool SafeBrowsingStoreFile::BeginChunk() { 254 bool SafeBrowsingStoreFile::BeginChunk() {
288 return ClearChunkBuffers(); 255 return ClearChunkBuffers();
289 } 256 }
290 257
291 bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) { 258 bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
292 add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix)); 259 add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix));
293 return true; 260 return true;
294 } 261 }
295 262
296 bool SafeBrowsingStoreFile::GetAddPrefixes( 263 bool SafeBrowsingStoreFile::GetAddPrefixes(SBAddPrefixes* add_prefixes) {
297 std::vector<SBAddPrefix>* add_prefixes) {
298 add_prefixes->clear(); 264 add_prefixes->clear();
299 265
300 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb")); 266 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb"));
301 if (file.get() == NULL) return false; 267 if (file.get() == NULL) return false;
302 268
303 FileHeader header; 269 FileHeader header;
304 if (!ReadAndVerifyHeader(filename_, file.get(), &header, NULL)) 270 if (!ReadAndVerifyHeader(filename_, file.get(), &header, NULL))
305 return OnCorruptDatabase(); 271 return OnCorruptDatabase();
306 272
307 size_t add_prefix_offset = header.add_chunk_count * sizeof(int32) + 273 size_t add_prefix_offset = header.add_chunk_count * sizeof(int32) +
308 header.sub_chunk_count * sizeof(int32); 274 header.sub_chunk_count * sizeof(int32);
309 if (!FileSkip(add_prefix_offset, file.get())) 275 if (!FileSkip(add_prefix_offset, file.get()))
310 return false; 276 return false;
311 277
312 if (!ReadToVector(add_prefixes, header.add_prefix_count, file.get(), NULL)) 278 if (!ReadToContainer(add_prefixes, header.add_prefix_count, file.get(), NULL))
313 return false; 279 return false;
314 280
315 return true; 281 return true;
316 } 282 }
317 283
318 bool SafeBrowsingStoreFile::GetAddFullHashes( 284 bool SafeBrowsingStoreFile::GetAddFullHashes(
319 std::vector<SBAddFullHash>* add_full_hashes) { 285 std::vector<SBAddFullHash>* add_full_hashes) {
320 add_full_hashes->clear(); 286 add_full_hashes->clear();
321 287
322 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb")); 288 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb"));
323 if (file.get() == NULL) return false; 289 if (file.get() == NULL) return false;
324 290
325 FileHeader header; 291 FileHeader header;
326 if (!ReadAndVerifyHeader(filename_, file.get(), &header, NULL)) 292 if (!ReadAndVerifyHeader(filename_, file.get(), &header, NULL))
327 return OnCorruptDatabase(); 293 return OnCorruptDatabase();
328 294
329 size_t offset = 295 size_t offset =
330 header.add_chunk_count * sizeof(int32) + 296 header.add_chunk_count * sizeof(int32) +
331 header.sub_chunk_count * sizeof(int32) + 297 header.sub_chunk_count * sizeof(int32) +
332 header.add_prefix_count * sizeof(SBAddPrefix) + 298 header.add_prefix_count * sizeof(SBAddPrefix) +
333 header.sub_prefix_count * sizeof(SBSubPrefix); 299 header.sub_prefix_count * sizeof(SBSubPrefix);
334 if (!FileSkip(offset, file.get())) 300 if (!FileSkip(offset, file.get()))
335 return false; 301 return false;
336 302
337 return ReadToVector(add_full_hashes, 303 return ReadToContainer(add_full_hashes,
338 header.add_hash_count, 304 header.add_hash_count,
339 file.get(), 305 file.get(),
340 NULL); 306 NULL);
341 } 307 }
342 308
343 bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id, 309 bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id,
344 base::Time receive_time, 310 base::Time receive_time,
345 const SBFullHash& full_hash) { 311 const SBFullHash& full_hash) {
346 add_hashes_.push_back(SBAddFullHash(chunk_id, receive_time, full_hash)); 312 add_hashes_.push_back(SBAddFullHash(chunk_id, receive_time, full_hash));
347 return true; 313 return true;
348 } 314 }
349 315
350 bool SafeBrowsingStoreFile::WriteSubPrefix(int32 chunk_id, 316 bool SafeBrowsingStoreFile::WriteSubPrefix(int32 chunk_id,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 // Structures should all be clear unless something bad happened. 352 // Structures should all be clear unless something bad happened.
387 DCHECK(add_chunks_cache_.empty()); 353 DCHECK(add_chunks_cache_.empty());
388 DCHECK(sub_chunks_cache_.empty()); 354 DCHECK(sub_chunks_cache_.empty());
389 DCHECK(add_del_cache_.empty()); 355 DCHECK(add_del_cache_.empty());
390 DCHECK(sub_del_cache_.empty()); 356 DCHECK(sub_del_cache_.empty());
391 DCHECK(add_prefixes_.empty()); 357 DCHECK(add_prefixes_.empty());
392 DCHECK(sub_prefixes_.empty()); 358 DCHECK(sub_prefixes_.empty());
393 DCHECK(add_hashes_.empty()); 359 DCHECK(add_hashes_.empty());
394 DCHECK(sub_hashes_.empty()); 360 DCHECK(sub_hashes_.empty());
395 DCHECK_EQ(chunks_written_, 0); 361 DCHECK_EQ(chunks_written_, 0);
396 add_prefixes_added_ = 0;
397 362
398 // Since the following code will already hit the profile looking for 363 // Since the following code will already hit the profile looking for
399 // database files, this is a reasonable to time delete any old 364 // database files, this is a reasonable to time delete any old
400 // files. 365 // files.
401 CheckForOriginalAndDelete(filename_); 366 CheckForOriginalAndDelete(filename_);
402 367
403 corruption_seen_ = false; 368 corruption_seen_ = false;
404 369
405 const FilePath new_filename = TemporaryFileForFilename(filename_); 370 const FilePath new_filename = TemporaryFileForFilename(filename_);
406 file_util::ScopedFILE new_file(file_util::OpenFile(new_filename, "wb+")); 371 file_util::ScopedFILE new_file(file_util::OpenFile(new_filename, "wb+"));
407 if (new_file.get() == NULL) 372 if (new_file.get() == NULL)
408 return false; 373 return false;
409 374
410 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb")); 375 file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb"));
411 empty_ = (file.get() == NULL); 376 empty_ = (file.get() == NULL);
412 if (empty_) { 377 if (empty_) {
413 // If the file exists but cannot be opened, try to delete it (not 378 // If the file exists but cannot be opened, try to delete it (not
414 // deleting directly, the bloom filter needs to be deleted, too). 379 // deleting directly, the bloom filter needs to be deleted, too).
415 if (file_util::PathExists(filename_)) 380 if (file_util::PathExists(filename_))
416 return OnCorruptDatabase(); 381 return OnCorruptDatabase();
417 382
418 new_file_.swap(new_file); 383 new_file_.swap(new_file);
419 return true; 384 return true;
420 } 385 }
421 386
422 FileHeader header; 387 FileHeader header;
423 if (!ReadArray(&header, 1, file.get(), NULL)) 388 if (!ReadItem(&header, file.get(), NULL))
424 return OnCorruptDatabase(); 389 return OnCorruptDatabase();
425 390
426 if (header.magic != kFileMagic || header.version != kFileVersion) { 391 if (header.magic != kFileMagic || header.version != kFileVersion) {
427 if (!strcmp(reinterpret_cast<char*>(&header.magic), "SQLite format 3")) { 392 if (!strcmp(reinterpret_cast<char*>(&header.magic), "SQLite format 3")) {
428 RecordFormatEvent(FORMAT_EVENT_FOUND_SQLITE); 393 RecordFormatEvent(FORMAT_EVENT_FOUND_SQLITE);
429 } else { 394 } else {
430 RecordFormatEvent(FORMAT_EVENT_FOUND_UNKNOWN); 395 RecordFormatEvent(FORMAT_EVENT_FOUND_UNKNOWN);
431 } 396 }
432 397
433 // Close the file so that it can be deleted. 398 // Close the file so that it can be deleted.
434 file.reset(); 399 file.reset();
435 400
436 return OnCorruptDatabase(); 401 return OnCorruptDatabase();
437 } 402 }
438 403
439 // TODO(shess): Under POSIX it is possible that this could size a 404 // TODO(shess): Under POSIX it is possible that this could size a
440 // file different from the file which was opened. 405 // file different from the file which was opened.
441 if (!FileHeaderSanityCheck(filename_, header)) 406 if (!FileHeaderSanityCheck(filename_, header))
442 return OnCorruptDatabase(); 407 return OnCorruptDatabase();
443 408
444 // Pull in the chunks-seen data for purposes of implementing 409 // Pull in the chunks-seen data for purposes of implementing
445 // |GetAddChunks()| and |GetSubChunks()|. This data is sent up to 410 // |GetAddChunks()| and |GetSubChunks()|. This data is sent up to
446 // the server at the beginning of an update. 411 // the server at the beginning of an update.
447 if (!ReadToChunkSet(&add_chunks_cache_, header.add_chunk_count, 412 if (!ReadToContainer(&add_chunks_cache_, header.add_chunk_count,
448 file.get(), NULL) || 413 file.get(), NULL) ||
449 !ReadToChunkSet(&sub_chunks_cache_, header.sub_chunk_count, 414 !ReadToContainer(&sub_chunks_cache_, header.sub_chunk_count,
450 file.get(), NULL)) 415 file.get(), NULL))
451 return OnCorruptDatabase(); 416 return OnCorruptDatabase();
452 417
453 file_.swap(file); 418 file_.swap(file);
454 new_file_.swap(new_file); 419 new_file_.swap(new_file);
455 return true; 420 return true;
456 } 421 }
457 422
458 bool SafeBrowsingStoreFile::FinishChunk() { 423 bool SafeBrowsingStoreFile::FinishChunk() {
459 if (!add_prefixes_.size() && !sub_prefixes_.size() && 424 if (!add_prefixes_.size() && !sub_prefixes_.size() &&
460 !add_hashes_.size() && !sub_hashes_.size()) 425 !add_hashes_.size() && !sub_hashes_.size())
461 return true; 426 return true;
462 427
463 ChunkHeader header; 428 ChunkHeader header;
464 header.add_prefix_count = add_prefixes_.size(); 429 header.add_prefix_count = add_prefixes_.size();
465 header.sub_prefix_count = sub_prefixes_.size(); 430 header.sub_prefix_count = sub_prefixes_.size();
466 header.add_hash_count = add_hashes_.size(); 431 header.add_hash_count = add_hashes_.size();
467 header.sub_hash_count = sub_hashes_.size(); 432 header.sub_hash_count = sub_hashes_.size();
468 if (!WriteArray(&header, 1, new_file_.get(), NULL)) 433 if (!WriteItem(header, new_file_.get(), NULL))
469 return false; 434 return false;
470 435
471 if (!WriteVector(add_prefixes_, new_file_.get(), NULL) || 436 if (!WriteContainer(add_prefixes_, new_file_.get(), NULL) ||
472 !WriteVector(sub_prefixes_, new_file_.get(), NULL) || 437 !WriteContainer(sub_prefixes_, new_file_.get(), NULL) ||
473 !WriteVector(add_hashes_, new_file_.get(), NULL) || 438 !WriteContainer(add_hashes_, new_file_.get(), NULL) ||
474 !WriteVector(sub_hashes_, new_file_.get(), NULL)) 439 !WriteContainer(sub_hashes_, new_file_.get(), NULL))
475 return false; 440 return false;
476 441
477 ++chunks_written_; 442 ++chunks_written_;
478 add_prefixes_added_ += add_prefixes_.size();
479 443
480 // Clear everything to save memory. 444 // Clear everything to save memory.
481 return ClearChunkBuffers(); 445 return ClearChunkBuffers();
482 } 446 }
483 447
484 bool SafeBrowsingStoreFile::DoUpdate( 448 bool SafeBrowsingStoreFile::DoUpdate(
485 const std::vector<SBAddFullHash>& pending_adds, 449 const std::vector<SBAddFullHash>& pending_adds,
486 const std::set<SBPrefix>& prefix_misses, 450 const std::set<SBPrefix>& prefix_misses,
487 std::vector<SBAddPrefix>* add_prefixes_result, 451 SBAddPrefixes* add_prefixes_result,
488 std::vector<SBAddFullHash>* add_full_hashes_result) { 452 std::vector<SBAddFullHash>* add_full_hashes_result) {
489 DCHECK(file_.get() || empty_); 453 DCHECK(file_.get() || empty_);
490 DCHECK(new_file_.get()); 454 DCHECK(new_file_.get());
491 CHECK(add_prefixes_result); 455 CHECK(add_prefixes_result);
492 CHECK(add_full_hashes_result); 456 CHECK(add_full_hashes_result);
493 457
494 std::vector<SBAddPrefix> add_prefixes; 458 SBAddPrefixes add_prefixes;
495 std::vector<SBSubPrefix> sub_prefixes; 459 std::vector<SBSubPrefix> sub_prefixes;
496 std::vector<SBAddFullHash> add_full_hashes; 460 std::vector<SBAddFullHash> add_full_hashes;
497 std::vector<SBSubFullHash> sub_full_hashes; 461 std::vector<SBSubFullHash> sub_full_hashes;
498 462
499 // Read original data into the vectors. 463 // Read original data into the vectors.
500 if (!empty_) { 464 if (!empty_) {
501 DCHECK(file_.get()); 465 DCHECK(file_.get());
502 466
503 if (!FileRewind(file_.get())) 467 if (!FileRewind(file_.get()))
504 return OnCorruptDatabase(); 468 return OnCorruptDatabase();
505 469
506 base::MD5Context context; 470 base::MD5Context context;
507 base::MD5Init(&context); 471 base::MD5Init(&context);
508 472
509 // Read the file header and make sure it looks right. 473 // Read the file header and make sure it looks right.
510 FileHeader header; 474 FileHeader header;
511 if (!ReadAndVerifyHeader(filename_, file_.get(), &header, &context)) 475 if (!ReadAndVerifyHeader(filename_, file_.get(), &header, &context))
512 return OnCorruptDatabase(); 476 return OnCorruptDatabase();
513 477
514 // Re-read the chunks-seen data to get to the later data in the 478 // Re-read the chunks-seen data to get to the later data in the
515 // file and calculate the checksum. No new elements should be 479 // file and calculate the checksum. No new elements should be
516 // added to the sets. 480 // added to the sets.
517 if (!ReadToChunkSet(&add_chunks_cache_, header.add_chunk_count, 481 if (!ReadToContainer(&add_chunks_cache_, header.add_chunk_count,
518 file_.get(), &context) || 482 file_.get(), &context) ||
519 !ReadToChunkSet(&sub_chunks_cache_, header.sub_chunk_count, 483 !ReadToContainer(&sub_chunks_cache_, header.sub_chunk_count,
520 file_.get(), &context)) 484 file_.get(), &context))
521 return OnCorruptDatabase(); 485 return OnCorruptDatabase();
522 486
523 add_prefixes.reserve(header.add_prefix_count + add_prefixes_added_); 487 if (!ReadToContainer(&add_prefixes, header.add_prefix_count,
524 488 file_.get(), &context) ||
525 if (!ReadToVector(&add_prefixes, header.add_prefix_count, 489 !ReadToContainer(&sub_prefixes, header.sub_prefix_count,
526 file_.get(), &context) || 490 file_.get(), &context) ||
527 !ReadToVector(&sub_prefixes, header.sub_prefix_count, 491 !ReadToContainer(&add_full_hashes, header.add_hash_count,
528 file_.get(), &context) || 492 file_.get(), &context) ||
529 !ReadToVector(&add_full_hashes, header.add_hash_count, 493 !ReadToContainer(&sub_full_hashes, header.sub_hash_count,
530 file_.get(), &context) || 494 file_.get(), &context))
531 !ReadToVector(&sub_full_hashes, header.sub_hash_count,
532 file_.get(), &context))
533 return OnCorruptDatabase(); 495 return OnCorruptDatabase();
534 496
535 // Calculate the digest to this point. 497 // Calculate the digest to this point.
536 base::MD5Digest calculated_digest; 498 base::MD5Digest calculated_digest;
537 base::MD5Final(&calculated_digest, &context); 499 base::MD5Final(&calculated_digest, &context);
538 500
539 // Read the stored checksum and verify it. 501 // Read the stored checksum and verify it.
540 base::MD5Digest file_digest; 502 base::MD5Digest file_digest;
541 if (!ReadArray(&file_digest, 1, file_.get(), NULL)) 503 if (!ReadItem(&file_digest, file_.get(), NULL))
542 return OnCorruptDatabase(); 504 return OnCorruptDatabase();
543 505
544 if (0 != memcmp(&file_digest, &calculated_digest, sizeof(file_digest))) 506 if (0 != memcmp(&file_digest, &calculated_digest, sizeof(file_digest)))
545 return OnCorruptDatabase(); 507 return OnCorruptDatabase();
546 508
547 // Close the file so we can later rename over it. 509 // Close the file so we can later rename over it.
548 file_.reset(); 510 file_.reset();
549 } else {
550 add_prefixes.reserve(add_prefixes_added_);
551 } 511 }
552 DCHECK(!file_.get()); 512 DCHECK(!file_.get());
553 513
554 // Rewind the temporary storage. 514 // Rewind the temporary storage.
555 if (!FileRewind(new_file_.get())) 515 if (!FileRewind(new_file_.get()))
556 return false; 516 return false;
557 517
558 // Get chunk file's size for validating counts. 518 // Get chunk file's size for validating counts.
559 int64 size = 0; 519 int64 size = 0;
560 if (!file_util::GetFileSize(TemporaryFileForFilename(filename_), &size)) 520 if (!file_util::GetFileSize(TemporaryFileForFilename(filename_), &size))
561 return OnCorruptDatabase(); 521 return OnCorruptDatabase();
562 522
563 // Track update size to answer questions at http://crbug.com/72216 . 523 // Track update size to answer questions at http://crbug.com/72216 .
564 // Log small updates as 1k so that the 0 (underflow) bucket can be 524 // Log small updates as 1k so that the 0 (underflow) bucket can be
565 // used for "empty" in SafeBrowsingDatabase. 525 // used for "empty" in SafeBrowsingDatabase.
566 UMA_HISTOGRAM_COUNTS("SB2.DatabaseUpdateKilobytes", 526 UMA_HISTOGRAM_COUNTS("SB2.DatabaseUpdateKilobytes",
567 std::max(static_cast<int>(size / 1024), 1)); 527 std::max(static_cast<int>(size / 1024), 1));
568 528
569 // TODO(shess): For SB2.AddPrefixesReallocs histogram.
570 int add_prefixes_reallocs = 0;
571
572 // Append the accumulated chunks onto the vectors read from |file_|. 529 // Append the accumulated chunks onto the vectors read from |file_|.
573 for (int i = 0; i < chunks_written_; ++i) { 530 for (int i = 0; i < chunks_written_; ++i) {
574 ChunkHeader header; 531 ChunkHeader header;
575 532
576 int64 ofs = ftell(new_file_.get()); 533 int64 ofs = ftell(new_file_.get());
577 if (ofs == -1) 534 if (ofs == -1)
578 return false; 535 return false;
579 536
580 if (!ReadArray(&header, 1, new_file_.get(), NULL)) 537 if (!ReadItem(&header, new_file_.get(), NULL))
581 return false; 538 return false;
582 539
583 // As a safety measure, make sure that the header describes a sane 540 // As a safety measure, make sure that the header describes a sane
584 // chunk, given the remaining file size. 541 // chunk, given the remaining file size.
585 int64 expected_size = ofs + sizeof(ChunkHeader); 542 int64 expected_size = ofs + sizeof(ChunkHeader);
586 expected_size += header.add_prefix_count * sizeof(SBAddPrefix); 543 expected_size += header.add_prefix_count * sizeof(SBAddPrefix);
587 expected_size += header.sub_prefix_count * sizeof(SBSubPrefix); 544 expected_size += header.sub_prefix_count * sizeof(SBSubPrefix);
588 expected_size += header.add_hash_count * sizeof(SBAddFullHash); 545 expected_size += header.add_hash_count * sizeof(SBAddFullHash);
589 expected_size += header.sub_hash_count * sizeof(SBSubFullHash); 546 expected_size += header.sub_hash_count * sizeof(SBSubFullHash);
590 if (expected_size > size) 547 if (expected_size > size)
591 return false; 548 return false;
592 549
593 // TODO(shess): For SB2.AddPrefixesReallocs histogram.
594 SBAddPrefix* add_prefixes_old_start =
595 (add_prefixes.size() ? &add_prefixes[0] : NULL);
596
597 // TODO(shess): If the vectors were kept sorted, then this code 550 // TODO(shess): If the vectors were kept sorted, then this code
598 // could use std::inplace_merge() to merge everything together in 551 // could use std::inplace_merge() to merge everything together in
599 // sorted order. That might still be slower than just sorting at 552 // sorted order. That might still be slower than just sorting at
600 // the end if there were a large number of chunks. In that case 553 // the end if there were a large number of chunks. In that case
601 // some sort of recursive binary merge might be in order (merge 554 // some sort of recursive binary merge might be in order (merge
602 // chunks pairwise, merge those chunks pairwise, and so on, then 555 // chunks pairwise, merge those chunks pairwise, and so on, then
603 // merge the result with the main list). 556 // merge the result with the main list).
604 if (!ReadToVector(&add_prefixes, header.add_prefix_count, 557 if (!ReadToContainer(&add_prefixes, header.add_prefix_count,
605 new_file_.get(), NULL) || 558 new_file_.get(), NULL) ||
606 !ReadToVector(&sub_prefixes, header.sub_prefix_count, 559 !ReadToContainer(&sub_prefixes, header.sub_prefix_count,
607 new_file_.get(), NULL) || 560 new_file_.get(), NULL) ||
608 !ReadToVector(&add_full_hashes, header.add_hash_count, 561 !ReadToContainer(&add_full_hashes, header.add_hash_count,
609 new_file_.get(), NULL) || 562 new_file_.get(), NULL) ||
610 !ReadToVector(&sub_full_hashes, header.sub_hash_count, 563 !ReadToContainer(&sub_full_hashes, header.sub_hash_count,
611 new_file_.get(), NULL)) 564 new_file_.get(), NULL))
612 return false; 565 return false;
613
614 // Determine if the vector data moved to a new location. This
615 // won't track cases where the malloc library was able to expand
616 // the storage in place, but those cases shouldn't cause memory
617 // fragmentation anyhow.
618 SBAddPrefix* add_prefixes_new_start =
619 (add_prefixes.size() ? &add_prefixes[0] : NULL);
620 if (add_prefixes_old_start != add_prefixes_new_start)
621 ++add_prefixes_reallocs;
622 } 566 }
623 567
624 // Track the number of times this number of re-allocations occurred.
625 UMA_HISTOGRAM_COUNTS_100("SB2.AddPrefixesReallocs", add_prefixes_reallocs);
626
627 // Append items from |pending_adds|. 568 // Append items from |pending_adds|.
628 add_full_hashes.insert(add_full_hashes.end(), 569 add_full_hashes.insert(add_full_hashes.end(),
629 pending_adds.begin(), pending_adds.end()); 570 pending_adds.begin(), pending_adds.end());
630 571
631 // Check how often a prefix was checked which wasn't in the 572 // Check how often a prefix was checked which wasn't in the
632 // database. 573 // database.
633 SBCheckPrefixMisses(add_prefixes, prefix_misses); 574 SBCheckPrefixMisses(add_prefixes, prefix_misses);
634 575
635 // Knock the subs from the adds and process deleted chunks. 576 // Knock the subs from the adds and process deleted chunks.
636 SBProcessSubs(&add_prefixes, &sub_prefixes, 577 SBProcessSubs(&add_prefixes, &sub_prefixes,
(...skipping 14 matching lines...) Expand all
651 // Write a file header. 592 // Write a file header.
652 FileHeader header; 593 FileHeader header;
653 header.magic = kFileMagic; 594 header.magic = kFileMagic;
654 header.version = kFileVersion; 595 header.version = kFileVersion;
655 header.add_chunk_count = add_chunks_cache_.size(); 596 header.add_chunk_count = add_chunks_cache_.size();
656 header.sub_chunk_count = sub_chunks_cache_.size(); 597 header.sub_chunk_count = sub_chunks_cache_.size();
657 header.add_prefix_count = add_prefixes.size(); 598 header.add_prefix_count = add_prefixes.size();
658 header.sub_prefix_count = sub_prefixes.size(); 599 header.sub_prefix_count = sub_prefixes.size();
659 header.add_hash_count = add_full_hashes.size(); 600 header.add_hash_count = add_full_hashes.size();
660 header.sub_hash_count = sub_full_hashes.size(); 601 header.sub_hash_count = sub_full_hashes.size();
661 if (!WriteArray(&header, 1, new_file_.get(), &context)) 602 if (!WriteItem(header, new_file_.get(), &context))
662 return false; 603 return false;
663 604
664 // Write all the chunk data. 605 // Write all the chunk data.
665 if (!WriteChunkSet(add_chunks_cache_, new_file_.get(), &context) || 606 if (!WriteContainer(add_chunks_cache_, new_file_.get(), &context) ||
666 !WriteChunkSet(sub_chunks_cache_, new_file_.get(), &context) || 607 !WriteContainer(sub_chunks_cache_, new_file_.get(), &context) ||
667 !WriteVector(add_prefixes, new_file_.get(), &context) || 608 !WriteContainer(add_prefixes, new_file_.get(), &context) ||
668 !WriteVector(sub_prefixes, new_file_.get(), &context) || 609 !WriteContainer(sub_prefixes, new_file_.get(), &context) ||
669 !WriteVector(add_full_hashes, new_file_.get(), &context) || 610 !WriteContainer(add_full_hashes, new_file_.get(), &context) ||
670 !WriteVector(sub_full_hashes, new_file_.get(), &context)) 611 !WriteContainer(sub_full_hashes, new_file_.get(), &context))
671 return false; 612 return false;
672 613
673 // Write the checksum at the end. 614 // Write the checksum at the end.
674 base::MD5Digest digest; 615 base::MD5Digest digest;
675 base::MD5Final(&digest, &context); 616 base::MD5Final(&digest, &context);
676 if (!WriteArray(&digest, 1, new_file_.get(), NULL)) 617 if (!WriteItem(digest, new_file_.get(), NULL))
677 return false; 618 return false;
678 619
679 // Trim any excess left over from the temporary chunk data. 620 // Trim any excess left over from the temporary chunk data.
680 if (!file_util::TruncateFile(new_file_.get())) 621 if (!file_util::TruncateFile(new_file_.get()))
681 return false; 622 return false;
682 623
683 // Close the file handle and swizzle the file into place. 624 // Close the file handle and swizzle the file into place.
684 new_file_.reset(); 625 new_file_.reset();
685 if (!file_util::Delete(filename_, false) && 626 if (!file_util::Delete(filename_, false) &&
686 file_util::PathExists(filename_)) 627 file_util::PathExists(filename_))
(...skipping 10 matching lines...) Expand all
697 // Pass the resulting data off to the caller. 638 // Pass the resulting data off to the caller.
698 add_prefixes_result->swap(add_prefixes); 639 add_prefixes_result->swap(add_prefixes);
699 add_full_hashes_result->swap(add_full_hashes); 640 add_full_hashes_result->swap(add_full_hashes);
700 641
701 return true; 642 return true;
702 } 643 }
703 644
704 bool SafeBrowsingStoreFile::FinishUpdate( 645 bool SafeBrowsingStoreFile::FinishUpdate(
705 const std::vector<SBAddFullHash>& pending_adds, 646 const std::vector<SBAddFullHash>& pending_adds,
706 const std::set<SBPrefix>& prefix_misses, 647 const std::set<SBPrefix>& prefix_misses,
707 std::vector<SBAddPrefix>* add_prefixes_result, 648 SBAddPrefixes* add_prefixes_result,
708 std::vector<SBAddFullHash>* add_full_hashes_result) { 649 std::vector<SBAddFullHash>* add_full_hashes_result) {
709 DCHECK(add_prefixes_result); 650 DCHECK(add_prefixes_result);
710 DCHECK(add_full_hashes_result); 651 DCHECK(add_full_hashes_result);
711 652
712 bool ret = DoUpdate(pending_adds, prefix_misses, 653 bool ret = DoUpdate(pending_adds, prefix_misses,
713 add_prefixes_result, add_full_hashes_result); 654 add_prefixes_result, add_full_hashes_result);
714 655
715 if (!ret) { 656 if (!ret) {
716 CancelUpdate(); 657 CancelUpdate();
717 return false; 658 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end()); 694 out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end());
754 } 695 }
755 696
756 void SafeBrowsingStoreFile::DeleteAddChunk(int32 chunk_id) { 697 void SafeBrowsingStoreFile::DeleteAddChunk(int32 chunk_id) {
757 add_del_cache_.insert(chunk_id); 698 add_del_cache_.insert(chunk_id);
758 } 699 }
759 700
760 void SafeBrowsingStoreFile::DeleteSubChunk(int32 chunk_id) { 701 void SafeBrowsingStoreFile::DeleteSubChunk(int32 chunk_id) {
761 sub_del_cache_.insert(chunk_id); 702 sub_del_cache_.insert(chunk_id);
762 } 703 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698