Home | History | Annotate | Download | only in syncable
      1 // Copyright (c) 2010 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 #ifndef CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_BACKING_STORE_H_
      6 #define CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_BACKING_STORE_H_
      7 #pragma once
      8 
      9 #include <string>
     10 
     11 #include "base/file_path.h"
     12 #include "base/gtest_prod_util.h"
     13 #include "chrome/browser/sync/syncable/dir_open_result.h"
     14 #include "chrome/browser/sync/syncable/model_type.h"
     15 #include "chrome/browser/sync/syncable/syncable.h"
     16 
     17 extern "C" {
     18 struct sqlite3;
     19 struct sqlite3_stmt;
     20 }
     21 
     22 class SQLStatement;
     23 
     24 namespace sync_pb {
     25 class EntitySpecifics;
     26 }
     27 
     28 namespace syncable {
     29 
     30 struct ColumnSpec;
     31 typedef Directory::MetahandlesIndex MetahandlesIndex;
     32 
     33 // Provides sqlite3-based persistence for a syncable::Directory object. You can
     34 // load all the persisted data to prime a syncable::Directory on startup by
     35 // invoking Load.  The only other thing you (or more correctly, a Directory)
     36 // can do here is save any changes that have occurred since calling Load, which
     37 // can be done periodically as often as desired*
     38 //
     39 // * If you only ever use a DirectoryBackingStore (DBS) from a single thread
     40 // then you can stop reading now. This is implemented using sqlite3, which
     41 // requires that each thread accesses a DB via a handle (sqlite3*) opened by
     42 // sqlite_open for that thread and only that thread.  To avoid complicated TLS
     43 // logic to swap handles in-and-out as different threads try to get a hold of a
     44 // DBS, the DBS does two things:
     45 // 1.  Uses a separate handle for Load()ing which is closed as soon as loading
     46 //     finishes, and
     47 // 2.  Requires that SaveChanges *only* be called from a single thread, and that
     48 //     thread *must* be the thread that owns / is responsible for destroying
     49 //     the DBS.
     50 // This way, any thread may open a Directory (which today can be either the
     51 // AuthWatcherThread or SyncCoreThread) and Load its DBS.  The first time
     52 // SaveChanges is called a new sqlite3 handle is created, and it will get closed
     53 // when the DBS is destroyed, which is the reason for the requirement that the
     54 // thread that "uses" the DBS is the thread that destroys it.
     55 class DirectoryBackingStore {
     56  public:
     57   DirectoryBackingStore(const std::string& dir_name,
     58                         const FilePath& backing_filepath);
     59 
     60   virtual ~DirectoryBackingStore();
     61 
     62   // Loads and drops all currently persisted meta entries into |entry_bucket|
     63   // and loads appropriate persisted kernel info into |info_bucket|.
     64   // NOTE: On success (return value of OPENED), the buckets are populated with
     65   // newly allocated items, meaning ownership is bestowed upon the caller.
     66   DirOpenResult Load(MetahandlesIndex* entry_bucket,
     67                      Directory::KernelLoadInfo* kernel_load_info);
     68 
     69   // Updates the on-disk store with the input |snapshot| as a database
     70   // transaction.  Does NOT open any syncable transactions as this would cause
     71   // opening transactions elsewhere to block on synchronous I/O.
     72   // DO NOT CALL THIS FROM MORE THAN ONE THREAD EVER.  Also, whichever thread
     73   // calls SaveChanges *must* be the thread that owns/destroys |this|.
     74   virtual bool SaveChanges(const Directory::SaveChangesSnapshot& snapshot);
     75 
     76  private:
     77   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion67To68);
     78   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion68To69);
     79   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion69To70);
     80   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion70To71);
     81   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion71To72);
     82   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion72To73);
     83   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion73To74);
     84   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion74To75);
     85   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, ModelTypeIds);
     86   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, Corruption);
     87   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, DeleteEntries);
     88   FRIEND_TEST_ALL_PREFIXES(MigrationTest, ToCurrentVersion);
     89   friend class MigrationTest;
     90 
     91   // General Directory initialization and load helpers.
     92   DirOpenResult InitializeTables();
     93   // Returns an sqlite return code, usually SQLITE_DONE.
     94   int CreateTables();
     95 
     96   // Create 'share_info' or 'temp_share_info' depending on value of
     97   // is_temporary. Returns an sqlite
     98   // return code, SQLITE_DONE on success.
     99   int CreateShareInfoTable(bool is_temporary);
    100 
    101   int CreateShareInfoTableVersion71(bool is_temporary);
    102   // Create 'metas' or 'temp_metas' depending on value of is_temporary.
    103   // Returns an sqlite return code, SQLITE_DONE on success.
    104   int CreateMetasTable(bool is_temporary);
    105   // Returns an sqlite return code, SQLITE_DONE on success.
    106   int CreateModelsTable();
    107   int CreateV71ModelsTable();
    108 
    109   // We don't need to load any synced and applied deleted entries, we can
    110   // in fact just purge them forever on startup.
    111   bool DropDeletedEntries();
    112   // Drops a table if it exists, harmless if the table did not already exist.
    113   int SafeDropTable(const char* table_name);
    114 
    115   // Load helpers for entries and attributes.
    116   bool LoadEntries(MetahandlesIndex* entry_bucket);
    117   bool LoadInfo(Directory::KernelLoadInfo* info);
    118 
    119   // Save/update helpers for entries.  Return false if sqlite commit fails.
    120   bool SaveEntryToDB(const EntryKernel& entry);
    121   bool SaveNewEntryToDB(const EntryKernel& entry);
    122   bool UpdateEntryToDB(const EntryKernel& entry);
    123 
    124   // Creates a new sqlite3 handle to the backing database. Sets sqlite operation
    125   // timeout preferences and registers our overridden sqlite3 operators for
    126   // said handle.  Returns true on success, false if the sqlite open operation
    127   // did not succeed.
    128   bool OpenAndConfigureHandleHelper(sqlite3** handle) const;
    129   // Initialize and destroy load_dbhandle_.  Broken out for testing.
    130   bool BeginLoad();
    131   void EndLoad();
    132   DirOpenResult DoLoad(MetahandlesIndex* entry_bucket,
    133       Directory::KernelLoadInfo* kernel_load_info);
    134 
    135   // Close save_dbhandle_.  Broken out for testing.
    136   void EndSave();
    137 
    138   // Removes each entry whose metahandle is in |handles| from the database.
    139   // Does synchronous I/O.  Returns false on error.
    140   bool DeleteEntries(const MetahandleSet& handles);
    141 
    142   // Lazy creation of save_dbhandle_ for use by SaveChanges code path.
    143   sqlite3* LazyGetSaveHandle();
    144 
    145   // Drop all tables in preparation for reinitialization.
    146   void DropAllTables();
    147 
    148   // Serialization helpers for syncable::ModelType.  These convert between
    149   // the ModelType enum and the values we persist in the database to identify
    150   // a model.  We persist a default instance of the specifics protobuf as the
    151   // ID, rather than the enum value.
    152   static ModelType ModelIdToModelTypeEnum(const void* data, int length);
    153   static std::string ModelTypeEnumToModelId(ModelType model_type);
    154 
    155   // Runs an integrity check on the current database.  If the
    156   // integrity check fails, false is returned and error is populated
    157   // with an error message.
    158   bool CheckIntegrity(sqlite3* handle, std::string* error) const;
    159 
    160   // Migration utilities.
    161   bool AddColumn(const ColumnSpec* column);
    162   bool RefreshColumns();
    163   bool SetVersion(int version);
    164   int GetVersion();
    165   bool MigrateToSpecifics(const char* old_columns,
    166                           const char* specifics_column,
    167                           void(*handler_function) (
    168                               SQLStatement* old_value_query,
    169                               int old_value_column,
    170                               sync_pb::EntitySpecifics* mutable_new_value));
    171 
    172   // Individual version migrations.
    173   bool MigrateVersion67To68();
    174   bool MigrateVersion68To69();
    175   bool MigrateVersion69To70();
    176   bool MigrateVersion70To71();
    177   bool MigrateVersion71To72();
    178   bool MigrateVersion72To73();
    179   bool MigrateVersion73To74();
    180   bool MigrateVersion74To75();
    181 
    182   // The handle to our sqlite on-disk store for initialization and loading, and
    183   // for saving changes periodically via SaveChanges, respectively.
    184   // TODO(timsteele): We should only have one handle here.  The reason we need
    185   // two at the moment is because the DB can be opened by either the AuthWatcher
    186   // or SyncCore threads, but SaveChanges is always called by the latter.  We
    187   // need to change initialization so the DB is only accessed from one thread.
    188   sqlite3* load_dbhandle_;
    189   sqlite3* save_dbhandle_;
    190 
    191   std::string dir_name_;
    192   FilePath backing_filepath_;
    193 
    194   // Set to true if migration left some old columns around that need to be
    195   // discarded.
    196   bool needs_column_refresh_;
    197 
    198   DISALLOW_COPY_AND_ASSIGN(DirectoryBackingStore);
    199 };
    200 
    201 }  // namespace syncable
    202 
    203 #endif  // CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_BACKING_STORE_H_
    204