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 "chrome/browser/history/thumbnail_database.h" | 5 #include "chrome/browser/history/thumbnail_database.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 // want once-only handling? Sqlite.Error.Thumbnail shows | 268 // want once-only handling? Sqlite.Error.Thumbnail shows |
269 // CORRUPT and READONLY as almost 95% of all reports on these | 269 // CORRUPT and READONLY as almost 95% of all reports on these |
270 // channels, so probably easier to just harvest from the field. | 270 // channels, so probably easier to just harvest from the field. |
271 if (rand < kReportsPerMillion) { | 271 if (rand < kReportsPerMillion) { |
272 reported = true; | 272 reported = true; |
273 ReportError(db, extended_error); | 273 ReportError(db, extended_error); |
274 } | 274 } |
275 } | 275 } |
276 } | 276 } |
277 | 277 |
278 // Create v5 schema for recovery code. | |
279 bool InitSchemaV5(sql::Connection* db) { | |
280 // This schema was derived from the strings used when v5 was in | |
281 // force. The [favicons] index and the [icon_mapping] items were | |
282 // copied from the current strings, after verifying that the | |
283 // resulting schema exactly matches the schema created by the | |
284 // original versions of those strings. This allows the linker to | |
285 // share the strings if they match, while preferring correctness of | |
286 // the current versions change. | |
287 | |
288 const char kFaviconsV5[] = | |
289 "CREATE TABLE IF NOT EXISTS favicons(" | |
290 "id INTEGER PRIMARY KEY," | |
291 "url LONGVARCHAR NOT NULL," | |
292 "last_updated INTEGER DEFAULT 0," | |
293 "image_data BLOB," | |
294 "icon_type INTEGER DEFAULT 1," | |
295 "sizes LONGVARCHAR" | |
296 ")"; | |
297 const char kFaviconsIndexV5[] = | |
298 "CREATE INDEX IF NOT EXISTS favicons_url ON favicons(url)"; | |
299 if (!db->Execute(kFaviconsV5) || !db->Execute(kFaviconsIndexV5)) | |
300 return false; | |
301 | |
302 const char kIconMappingV5[] = | |
303 "CREATE TABLE IF NOT EXISTS icon_mapping" | |
304 "(" | |
305 "id INTEGER PRIMARY KEY," | |
306 "page_url LONGVARCHAR NOT NULL," | |
307 "icon_id INTEGER" | |
308 ")"; | |
309 const char kIconMappingUrlIndexV5[] = | |
310 "CREATE INDEX IF NOT EXISTS icon_mapping_page_url_idx" | |
311 " ON icon_mapping(page_url)"; | |
312 const char kIconMappingIdIndexV5[] = | |
313 "CREATE INDEX IF NOT EXISTS icon_mapping_icon_id_idx" | |
314 " ON icon_mapping(icon_id)"; | |
315 if (!db->Execute(kIconMappingV5) || | |
316 !db->Execute(kIconMappingUrlIndexV5) || | |
317 !db->Execute(kIconMappingIdIndexV5)) { | |
318 return false; | |
319 } | |
320 | |
321 return true; | |
322 } | |
323 | |
324 // TODO(shess): Consider InitSchemaV7(). InitSchemaV5() is worthwhile | |
325 // because there appear to be 10s of thousands of marooned v5 | |
326 // databases in the wild. Once recovery reaches stable, the number of | |
327 // corrupt-but-recoverable databases should drop, possibly to the | |
328 // point where it is not worthwhile to maintain previous-version | |
329 // recovery code. | |
330 // TODO(shess): Alternately, think on a way to more cleanly represent | |
331 // versioned schema going forward. | |
332 bool InitTables(sql::Connection* db) { | 278 bool InitTables(sql::Connection* db) { |
333 const char kIconMappingSql[] = | 279 const char kIconMappingSql[] = |
334 "CREATE TABLE IF NOT EXISTS icon_mapping" | 280 "CREATE TABLE IF NOT EXISTS icon_mapping" |
335 "(" | 281 "(" |
336 "id INTEGER PRIMARY KEY," | 282 "id INTEGER PRIMARY KEY," |
337 "page_url LONGVARCHAR NOT NULL," | 283 "page_url LONGVARCHAR NOT NULL," |
338 "icon_id INTEGER" | 284 "icon_id INTEGER" |
339 ")"; | 285 ")"; |
340 if (!db->Execute(kIconMappingSql)) | 286 if (!db->Execute(kIconMappingSql)) |
341 return false; | 287 return false; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 "favicon_bitmaps(icon_id)"; | 335 "favicon_bitmaps(icon_id)"; |
390 if (!db->Execute(kFaviconBitmapsIndexSql)) | 336 if (!db->Execute(kFaviconBitmapsIndexSql)) |
391 return false; | 337 return false; |
392 | 338 |
393 return true; | 339 return true; |
394 } | 340 } |
395 | 341 |
396 enum RecoveryEventType { | 342 enum RecoveryEventType { |
397 RECOVERY_EVENT_RECOVERED = 0, | 343 RECOVERY_EVENT_RECOVERED = 0, |
398 RECOVERY_EVENT_FAILED_SCOPER, | 344 RECOVERY_EVENT_FAILED_SCOPER, |
399 RECOVERY_EVENT_FAILED_META_VERSION_ERROR, // obsolete | 345 RECOVERY_EVENT_FAILED_META_VERSION_ERROR, |
400 RECOVERY_EVENT_FAILED_META_VERSION_NONE, // obsolete | 346 RECOVERY_EVENT_FAILED_META_VERSION_NONE, |
401 RECOVERY_EVENT_FAILED_META_WRONG_VERSION6, // obsolete | 347 RECOVERY_EVENT_FAILED_META_WRONG_VERSION6, // obsolete |
402 RECOVERY_EVENT_FAILED_META_WRONG_VERSION5, // obsolete | 348 RECOVERY_EVENT_FAILED_META_WRONG_VERSION5, |
403 RECOVERY_EVENT_FAILED_META_WRONG_VERSION, | 349 RECOVERY_EVENT_FAILED_META_WRONG_VERSION, |
404 RECOVERY_EVENT_FAILED_RECOVER_META, // obsolete | 350 RECOVERY_EVENT_FAILED_RECOVER_META, |
405 RECOVERY_EVENT_FAILED_META_INSERT, // obsolete | 351 RECOVERY_EVENT_FAILED_META_INSERT, // obsolete |
406 RECOVERY_EVENT_FAILED_INIT, | 352 RECOVERY_EVENT_FAILED_INIT, |
407 RECOVERY_EVENT_FAILED_RECOVER_FAVICONS, // obsolete | 353 RECOVERY_EVENT_FAILED_RECOVER_FAVICONS, |
408 RECOVERY_EVENT_FAILED_FAVICONS_INSERT, // obsolete | 354 RECOVERY_EVENT_FAILED_FAVICONS_INSERT, |
409 RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS, // obsolete | 355 RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS, |
410 RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT, // obsolete | 356 RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT, |
411 RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING, // obsolete | 357 RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING, |
412 RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT, // obsolete | 358 RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT, |
413 RECOVERY_EVENT_RECOVERED_VERSION6, | 359 RECOVERY_EVENT_RECOVERED_VERSION6, |
414 RECOVERY_EVENT_FAILED_META_INIT, | 360 RECOVERY_EVENT_FAILED_META_INIT, |
415 RECOVERY_EVENT_FAILED_META_VERSION, | |
416 RECOVERY_EVENT_DEPRECATED, | |
417 RECOVERY_EVENT_FAILED_V5_INITSCHEMA, | |
418 RECOVERY_EVENT_FAILED_V5_AUTORECOVER_FAVICONS, | |
419 RECOVERY_EVENT_FAILED_V5_AUTORECOVER_ICON_MAPPING, | |
420 RECOVERY_EVENT_RECOVERED_VERSION5, | |
421 RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS, | |
422 RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS, | |
423 RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING, | |
424 | 361 |
425 // Always keep this at the end. | 362 // Always keep this at the end. |
426 RECOVERY_EVENT_MAX, | 363 RECOVERY_EVENT_MAX, |
427 }; | 364 }; |
428 | 365 |
429 void RecordRecoveryEvent(RecoveryEventType recovery_event) { | 366 void RecordRecoveryEvent(RecoveryEventType recovery_event) { |
430 UMA_HISTOGRAM_ENUMERATION("History.FaviconsRecovery", | 367 UMA_HISTOGRAM_ENUMERATION("History.FaviconsRecovery", |
431 recovery_event, RECOVERY_EVENT_MAX); | 368 recovery_event, RECOVERY_EVENT_MAX); |
432 } | 369 } |
433 | 370 |
(...skipping 27 matching lines...) Expand all Loading... |
461 // | 398 // |
462 // Possible responses are unclear. If the failure relates to a | 399 // Possible responses are unclear. If the failure relates to a |
463 // problem somehow specific to the temporary file used to back the | 400 // problem somehow specific to the temporary file used to back the |
464 // database, then an in-memory database could possibly be used. | 401 // database, then an in-memory database could possibly be used. |
465 // This could potentially allow recovering the main database, and | 402 // This could potentially allow recovering the main database, and |
466 // might be simple to implement w/in Begin(). | 403 // might be simple to implement w/in Begin(). |
467 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER); | 404 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER); |
468 return; | 405 return; |
469 } | 406 } |
470 | 407 |
471 // Setup the meta recovery table and fetch the version number from | 408 // Setup the meta recovery table, and check that the version number |
472 // the corrupt database. | 409 // is covered by the recovery code. |
473 int version = 0; | 410 // TODO(shess): sql::Recovery should provide a helper to handle meta. |
474 if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) { | 411 int version = 0; // For reporting which version was recovered. |
475 // TODO(shess): Prior histograms indicate all failures are in | 412 { |
476 // creating the recover virtual table for corrupt.meta. The table | 413 const char kRecoverySql[] = |
477 // may not exist, or the database may be too far gone. Either | 414 "CREATE VIRTUAL TABLE temp.recover_meta USING recover" |
478 // way, unclear how to resolve. | 415 "(" |
479 sql::Recovery::Rollback(recovery.Pass()); | 416 "corrupt.meta," |
480 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION); | 417 "key TEXT NOT NULL," |
481 return; | 418 "value TEXT" // Really? Never int? |
482 } | 419 ")"; |
| 420 if (!recovery->db()->Execute(kRecoverySql)) { |
| 421 // TODO(shess): Failure to create the recover_meta table could |
| 422 // mean that the main database is too corrupt to access, or that |
| 423 // the meta table doesn't exist. |
| 424 sql::Recovery::Rollback(recovery.Pass()); |
| 425 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_RECOVER_META); |
| 426 return; |
| 427 } |
483 | 428 |
484 // Recover v5 database to v5 schema. Next pass through Init() will | 429 { |
485 // migrate to v7. | 430 const char kRecoveryVersionSql[] = |
486 if (version == 5) { | 431 "SELECT value FROM recover_meta WHERE key = 'version'"; |
| 432 sql::Statement recovery_version( |
| 433 recovery->db()->GetUniqueStatement(kRecoveryVersionSql)); |
| 434 if (!recovery_version.Step()) { |
| 435 if (!recovery_version.Succeeded()) { |
| 436 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION_ERROR); |
| 437 // TODO(shess): An error while processing the statement is |
| 438 // probably not recoverable. |
| 439 } else { |
| 440 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION_NONE); |
| 441 // TODO(shess): If a positive version lock cannot be achieved, |
| 442 // the database could still be recovered by optimistically |
| 443 // attempting to copy things. In the limit, the schema found |
| 444 // could be inspected. Less clear is whether optimistic |
| 445 // recovery really makes sense. |
| 446 } |
| 447 recovery_version.Clear(); |
| 448 sql::Recovery::Rollback(recovery.Pass()); |
| 449 return; |
| 450 } |
| 451 version = recovery_version.ColumnInt(0); |
| 452 |
| 453 // Recovery code is generally schema-dependent. Version 7 and |
| 454 // version 6 are very similar, so can be handled together. |
| 455 // Track version 5, to see whether it's worth writing recovery |
| 456 // code for. |
| 457 if (version != 7 && version != 6) { |
| 458 if (version == 5) { |
| 459 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION5); |
| 460 } else { |
| 461 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION); |
| 462 } |
| 463 recovery_version.Clear(); |
| 464 sql::Recovery::Rollback(recovery.Pass()); |
| 465 return; |
| 466 } |
| 467 } |
| 468 |
| 469 // Either version 6 or version 7 recovers to current. |
487 sql::MetaTable recover_meta_table; | 470 sql::MetaTable recover_meta_table; |
488 if (!recover_meta_table.Init(recovery->db(), version, version)) { | 471 if (!recover_meta_table.Init(recovery->db(), kCurrentVersionNumber, |
| 472 kCompatibleVersionNumber)) { |
489 sql::Recovery::Rollback(recovery.Pass()); | 473 sql::Recovery::Rollback(recovery.Pass()); |
490 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT); | 474 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT); |
491 return; | 475 return; |
492 } | 476 } |
493 | |
494 // TODO(shess): These tests are separate for histogram purposes, | |
495 // but once things look stable it can be tightened up. | |
496 if (!InitSchemaV5(recovery->db())) { | |
497 sql::Recovery::Rollback(recovery.Pass()); | |
498 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_V5_INITSCHEMA); | |
499 return; | |
500 } | |
501 | |
502 if (!recovery->AutoRecoverTable("favicons", 0, &favicons_rows_recovered)) { | |
503 sql::Recovery::Rollback(recovery.Pass()); | |
504 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_V5_AUTORECOVER_FAVICONS); | |
505 return; | |
506 } | |
507 | |
508 if (!recovery->AutoRecoverTable("icon_mapping", 0, | |
509 &icon_mapping_rows_recovered)) { | |
510 sql::Recovery::Rollback(recovery.Pass()); | |
511 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_V5_AUTORECOVER_ICON_MAPPING); | |
512 return; | |
513 } | |
514 | |
515 ignore_result(sql::Recovery::Recovered(recovery.Pass())); | |
516 | |
517 // TODO(shess): Could this code be shared with the v6/7 code | |
518 // without requiring too much state to be carried? | |
519 | |
520 // Track the size of the recovered database relative to the size of | |
521 // the input database. The size should almost always be smaller, | |
522 // unless the input database was empty to start with. If the | |
523 // percentage results are very low, something is awry. | |
524 int64 final_size = 0; | |
525 if (original_size > 0 && | |
526 file_util::GetFileSize(db_path, &final_size) && | |
527 final_size > 0) { | |
528 int percentage = static_cast<int>(original_size * 100 / final_size); | |
529 UMA_HISTOGRAM_PERCENTAGE("History.FaviconsRecoveredPercentage", | |
530 std::max(100, percentage)); | |
531 } | |
532 | |
533 // Using 10,000 because these cases mostly care about "none | |
534 // recovered" and "lots recovered". More than 10,000 rows recovered | |
535 // probably means there's something wrong with the profile. | |
536 UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFavicons", | |
537 favicons_rows_recovered); | |
538 UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsIconMapping", | |
539 icon_mapping_rows_recovered); | |
540 | |
541 RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED_VERSION5); | |
542 return; | |
543 } | |
544 | |
545 // This code may be able to fetch versions that the regular | |
546 // deprecation path cannot. | |
547 if (version <= kDeprecatedVersionNumber) { | |
548 sql::Recovery::Unrecoverable(recovery.Pass()); | |
549 RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED); | |
550 return; | |
551 } | |
552 | |
553 // TODO(shess): Earlier versions have been handled or deprecated, | |
554 // later versions should be impossible. Unrecoverable() seems | |
555 // reasonable. | |
556 if (version != 6 && version != 7) { | |
557 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION); | |
558 sql::Recovery::Rollback(recovery.Pass()); | |
559 return; | |
560 } | |
561 | |
562 // Both v6 and v7 recover to current schema version. | |
563 sql::MetaTable recover_meta_table; | |
564 if (!recover_meta_table.Init(recovery->db(), kCurrentVersionNumber, | |
565 kCompatibleVersionNumber)) { | |
566 sql::Recovery::Rollback(recovery.Pass()); | |
567 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT); | |
568 return; | |
569 } | 477 } |
570 | 478 |
571 // Create a fresh version of the database. The recovery code uses | 479 // Create a fresh version of the database. The recovery code uses |
572 // conflict-resolution to handle duplicates, so the indices are | 480 // conflict-resolution to handle duplicates, so the indices are |
573 // necessary. | 481 // necessary. |
574 if (!InitTables(recovery->db()) || !InitIndices(recovery->db())) { | 482 if (!InitTables(recovery->db()) || !InitIndices(recovery->db())) { |
575 // TODO(shess): Unable to create the new schema in the new | 483 // TODO(shess): Unable to create the new schema in the new |
576 // database. The new database should be a temporary file, so | 484 // database. The new database should be a temporary file, so |
577 // being unable to work with it is pretty unclear. | 485 // being unable to work with it is pretty unclear. |
578 // | 486 // |
579 // What are the potential responses, even? The recovery database | 487 // What are the potential responses, even? The recovery database |
580 // could be opened as in-memory. If the temp database had a | 488 // could be opened as in-memory. If the temp database had a |
581 // filesystem problem and the temp filesystem differs from the | 489 // filesystem problem and the temp filesystem differs from the |
582 // main database, then that could fix it. | 490 // main database, then that could fix it. |
583 sql::Recovery::Rollback(recovery.Pass()); | 491 sql::Recovery::Rollback(recovery.Pass()); |
584 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_INIT); | 492 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_INIT); |
585 return; | 493 return; |
586 } | 494 } |
587 | 495 |
588 // [favicons] differs because v6 had an unused [sizes] column which | 496 // Setup favicons table. |
589 // was removed in v7. | 497 { |
590 if (!recovery->AutoRecoverTable("favicons", 1, &favicons_rows_recovered)) { | 498 // Version 6 had the |sizes| column, version 7 removed it. The |
591 sql::Recovery::Rollback(recovery.Pass()); | 499 // recover virtual table treats more columns than expected as an |
592 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS); | 500 // error, but if _fewer_ columns are present, they can be treated |
593 return; | 501 // as NULL. SQLite requires this because ALTER TABLE adds columns |
| 502 // to the schema, but not to the actual table storage. |
| 503 const char kRecoverySql[] = |
| 504 "CREATE VIRTUAL TABLE temp.recover_favicons USING recover" |
| 505 "(" |
| 506 "corrupt.favicons," |
| 507 "id ROWID," |
| 508 "url TEXT NOT NULL," |
| 509 "icon_type INTEGER," |
| 510 "sizes TEXT" |
| 511 ")"; |
| 512 if (!recovery->db()->Execute(kRecoverySql)) { |
| 513 // TODO(shess): Failure to create the recovery table probably |
| 514 // means unrecoverable. |
| 515 sql::Recovery::Rollback(recovery.Pass()); |
| 516 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_RECOVER_FAVICONS); |
| 517 return; |
| 518 } |
| 519 |
| 520 // TODO(shess): Check if the DEFAULT 1 will just cover the |
| 521 // COALESCE(). Either way, the new code has a literal 1 rather |
| 522 // than a NULL, right? |
| 523 const char kCopySql[] = |
| 524 "INSERT OR REPLACE INTO main.favicons " |
| 525 "SELECT id, url, COALESCE(icon_type, 1) FROM recover_favicons"; |
| 526 if (!recovery->db()->Execute(kCopySql)) { |
| 527 // TODO(shess): The recover_favicons table should mask problems |
| 528 // with the source file, so this implies failure to write to the |
| 529 // recovery database. |
| 530 sql::Recovery::Rollback(recovery.Pass()); |
| 531 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_FAVICONS_INSERT); |
| 532 return; |
| 533 } |
| 534 favicons_rows_recovered = recovery->db()->GetLastChangeCount(); |
594 } | 535 } |
595 if (!recovery->AutoRecoverTable("favicon_bitmaps", 0, | 536 |
596 &favicon_bitmaps_rows_recovered)) { | 537 // Setup favicons_bitmaps table. |
597 sql::Recovery::Rollback(recovery.Pass()); | 538 { |
598 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS); | 539 const char kRecoverySql[] = |
599 return; | 540 "CREATE VIRTUAL TABLE temp.recover_favicons_bitmaps USING recover" |
| 541 "(" |
| 542 "corrupt.favicon_bitmaps," |
| 543 "id ROWID," |
| 544 "icon_id INTEGER STRICT NOT NULL," |
| 545 "last_updated INTEGER," |
| 546 "image_data BLOB," |
| 547 "width INTEGER," |
| 548 "height INTEGER" |
| 549 ")"; |
| 550 if (!recovery->db()->Execute(kRecoverySql)) { |
| 551 // TODO(shess): Failure to create the recovery table probably |
| 552 // means unrecoverable. |
| 553 sql::Recovery::Rollback(recovery.Pass()); |
| 554 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS); |
| 555 return; |
| 556 } |
| 557 |
| 558 const char kCopySql[] = |
| 559 "INSERT OR REPLACE INTO main.favicon_bitmaps " |
| 560 "SELECT id, icon_id, COALESCE(last_updated, 0), image_data, " |
| 561 " COALESCE(width, 0), COALESCE(height, 0) " |
| 562 "FROM recover_favicons_bitmaps"; |
| 563 if (!recovery->db()->Execute(kCopySql)) { |
| 564 // TODO(shess): The recover_faviconbitmaps table should mask |
| 565 // problems with the source file, so this implies failure to |
| 566 // write to the recovery database. |
| 567 sql::Recovery::Rollback(recovery.Pass()); |
| 568 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT); |
| 569 return; |
| 570 } |
| 571 favicon_bitmaps_rows_recovered = recovery->db()->GetLastChangeCount(); |
600 } | 572 } |
601 if (!recovery->AutoRecoverTable("icon_mapping", 0, | 573 |
602 &icon_mapping_rows_recovered)) { | 574 // Setup icon_mapping table. |
603 sql::Recovery::Rollback(recovery.Pass()); | 575 { |
604 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING); | 576 const char kRecoverySql[] = |
605 return; | 577 "CREATE VIRTUAL TABLE temp.recover_icon_mapping USING recover" |
| 578 "(" |
| 579 "corrupt.icon_mapping," |
| 580 "id ROWID," |
| 581 "page_url TEXT STRICT NOT NULL," |
| 582 "icon_id INTEGER STRICT" |
| 583 ")"; |
| 584 if (!recovery->db()->Execute(kRecoverySql)) { |
| 585 // TODO(shess): Failure to create the recovery table probably |
| 586 // means unrecoverable. |
| 587 sql::Recovery::Rollback(recovery.Pass()); |
| 588 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING); |
| 589 return; |
| 590 } |
| 591 |
| 592 const char kCopySql[] = |
| 593 "INSERT OR REPLACE INTO main.icon_mapping " |
| 594 "SELECT id, page_url, icon_id FROM recover_icon_mapping"; |
| 595 if (!recovery->db()->Execute(kCopySql)) { |
| 596 // TODO(shess): The recover_icon_mapping table should mask |
| 597 // problems with the source file, so this implies failure to |
| 598 // write to the recovery database. |
| 599 sql::Recovery::Rollback(recovery.Pass()); |
| 600 RecordRecoveryEvent(RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT); |
| 601 return; |
| 602 } |
| 603 icon_mapping_rows_recovered = recovery->db()->GetLastChangeCount(); |
606 } | 604 } |
607 | 605 |
608 // TODO(shess): Is it possible/likely to have broken foreign-key | 606 // TODO(shess): Is it possible/likely to have broken foreign-key |
609 // issues with the tables? | 607 // issues with the tables? |
610 // - icon_mapping.icon_id maps to no favicons.id | 608 // - icon_mapping.icon_id maps to no favicons.id |
611 // - favicon_bitmaps.icon_id maps to no favicons.id | 609 // - favicon_bitmaps.icon_id maps to no favicons.id |
612 // - favicons.id is referenced by no icon_mapping.icon_id | 610 // - favicons.id is referenced by no icon_mapping.icon_id |
613 // - favicons.id is referenced by no favicon_bitmaps.icon_id | 611 // - favicons.id is referenced by no favicon_bitmaps.icon_id |
614 // This step is possibly not worth the effort necessary to develop | 612 // This step is possibly not worth the effort necessary to develop |
615 // and sequence the statements, as it is basically a form of garbage | 613 // and sequence the statements, as it is basically a form of garbage |
(...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1423 meta_table_.SetVersionNumber(7); | 1421 meta_table_.SetVersionNumber(7); |
1424 meta_table_.SetCompatibleVersionNumber(std::min(7, kCompatibleVersionNumber)); | 1422 meta_table_.SetCompatibleVersionNumber(std::min(7, kCompatibleVersionNumber)); |
1425 return true; | 1423 return true; |
1426 } | 1424 } |
1427 | 1425 |
1428 bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() { | 1426 bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() { |
1429 return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons"); | 1427 return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons"); |
1430 } | 1428 } |
1431 | 1429 |
1432 } // namespace history | 1430 } // namespace history |
OLD | NEW |