Home | History | Annotate | Download | only in syncable
      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 
     12 namespace syncer {
     13 namespace syncable {
     14 
     15 namespace {
     16 
     17 enum HistogramResultEnum {
     18   FIRST_TRY_SUCCESS,
     19   SECOND_TRY_SUCCESS,
     20   SECOND_TRY_FAILURE,
     21   RESULT_COUNT
     22 };
     23 
     24 }  // namespace
     25 
     26 OnDiskDirectoryBackingStore::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 
     35 OnDiskDirectoryBackingStore::~OnDiskDirectoryBackingStore() { }
     36 
     37 DirOpenResult 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 
     65 DirOpenResult 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 
    104 void 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