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