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 3// found in the LICENSE file. 4 5#include "sync/syncable/on_disk_directory_backing_store.h" 6 7#include "base/logging.h" 8#include "base/stl_util.h" 9#include "base/metrics/histogram.h" 10#include "sync/syncable/syncable-inl.h" 11 12namespace syncer { 13namespace syncable { 14 15namespace { 16 17enum HistogramResultEnum { 18 FIRST_TRY_SUCCESS, 19 SECOND_TRY_SUCCESS, 20 SECOND_TRY_FAILURE, 21 RESULT_COUNT 22}; 23 24} // namespace 25 26OnDiskDirectoryBackingStore::OnDiskDirectoryBackingStore( 27 const std::string& dir_name, const base::FilePath& backing_filepath) 28 : DirectoryBackingStore(dir_name), 29 allow_failure_for_test_(false), 30 backing_filepath_(backing_filepath) { 31 db_->set_exclusive_locking(); 32 db_->set_page_size(4096); 33} 34 35OnDiskDirectoryBackingStore::~OnDiskDirectoryBackingStore() { } 36 37DirOpenResult OnDiskDirectoryBackingStore::TryLoad( 38 Directory::MetahandlesMap* handles_map, 39 JournalIndex* delete_journals, 40 Directory::KernelLoadInfo* kernel_load_info) { 41 DCHECK(CalledOnValidThread()); 42 if (!db_->is_open()) { 43 if (!db_->Open(backing_filepath_)) 44 return FAILED_OPEN_DATABASE; 45 } 46 47 if (!InitializeTables()) 48 return FAILED_OPEN_DATABASE; 49 50 if (!DropDeletedEntries()) 51 return FAILED_DATABASE_CORRUPT; 52 if (!LoadEntries(handles_map)) 53 return FAILED_DATABASE_CORRUPT; 54 if (!LoadDeleteJournals(delete_journals)) 55 return FAILED_DATABASE_CORRUPT; 56 if (!LoadInfo(kernel_load_info)) 57 return FAILED_DATABASE_CORRUPT; 58 if (!VerifyReferenceIntegrity(handles_map)) 59 return FAILED_DATABASE_CORRUPT; 60 61 return OPENED; 62 63} 64 65DirOpenResult OnDiskDirectoryBackingStore::Load( 66 Directory::MetahandlesMap* handles_map, 67 JournalIndex* delete_journals, 68 Directory::KernelLoadInfo* kernel_load_info) { 69 DirOpenResult result = TryLoad(handles_map, delete_journals, 70 kernel_load_info); 71 if (result == OPENED) { 72 UMA_HISTOGRAM_ENUMERATION( 73 "Sync.DirectoryOpenResult", FIRST_TRY_SUCCESS, RESULT_COUNT); 74 return OPENED; 75 } 76 77 ReportFirstTryOpenFailure(); 78 79 // The fallback: delete the current database and return a fresh one. We can 80 // fetch the user's data from the cloud. 81 STLDeleteValues(handles_map); 82 STLDeleteElements(delete_journals); 83 db_.reset(new sql::Connection); 84 // TODO: Manually propagating the default database settings is 85 // brittle. Either have a helper to set these up (or generate a new 86 // connection), or add something like Reset() to sql::Connection. 87 db_->set_exclusive_locking(); 88 db_->set_page_size(4096); 89 db_->set_histogram_tag("SyncDirectory"); 90 base::DeleteFile(backing_filepath_, false); 91 92 result = TryLoad(handles_map, delete_journals, kernel_load_info); 93 if (result == OPENED) { 94 UMA_HISTOGRAM_ENUMERATION( 95 "Sync.DirectoryOpenResult", SECOND_TRY_SUCCESS, RESULT_COUNT); 96 } else { 97 UMA_HISTOGRAM_ENUMERATION( 98 "Sync.DirectoryOpenResult", SECOND_TRY_FAILURE, RESULT_COUNT); 99 } 100 101 return result; 102} 103 104void OnDiskDirectoryBackingStore::ReportFirstTryOpenFailure() { 105 // In debug builds, the last thing we want is to silently clear the database. 106 // It's full of evidence that might help us determine what went wrong. It 107 // might be sqlite's fault, but it could also be a bug in sync. We crash 108 // immediately so a developer can investigate. 109 // 110 // Developers: If you're not interested in debugging this right now, just move 111 // aside the 'Sync Data' directory in your profile. This is similar to what 112 // the code would do if this DCHECK were disabled. 113 NOTREACHED() << "Crashing to preserve corrupt sync database"; 114} 115 116} // namespace syncable 117} // namespace syncer 118