metadata_database.h revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright 2013 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_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_ 6#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_ 7 8#include <map> 9#include <set> 10#include <string> 11#include <vector> 12 13#include "base/callback_forward.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/memory/scoped_vector.h" 16#include "base/memory/weak_ptr.h" 17#include "chrome/browser/sync_file_system/drive_backend/tracker_set.h" 18#include "chrome/browser/sync_file_system/sync_callbacks.h" 19#include "chrome/browser/sync_file_system/sync_status_code.h" 20 21namespace base { 22class FilePath; 23class SequencedTaskRunner; 24class SingleThreadTaskRunner; 25} 26 27namespace leveldb { 28class DB; 29class WriteBatch; 30} 31 32namespace google_apis { 33class ChangeResource; 34class FileResource; 35class ResourceEntry; 36} 37 38namespace sync_file_system { 39namespace drive_backend { 40 41class FileDetails; 42class FileMetadata; 43class FileTracker; 44class ServiceMetadata; 45struct DatabaseContents; 46 47// MetadataDatabase holds and maintains a LevelDB instance and its indexes, 48// which holds 1)ServiceMetadata, 2)FileMetadata and 3)FileTracker. 49// 1) ServiceMetadata is a singleton in the database which holds information for 50// the backend. 51// 2) FileMetadata represents a remote-side file and holds latest known 52// metadata of the remote file. 53// 3) FileTracker represents a synced or to-be-synced file and maintains 54// the local-side folder tree. 55// 56// The term "file" includes files, folders and other resources on Drive. 57// 58// FileTrackers form a tree structure on the database, which represents the 59// FileSystem trees of SyncFileSystem. The tree has a FileTracker named 60// sync-root as its root node, and a set of FileTracker named app-root. An 61// app-root represents a remote folder for an installed Chrome App and holds all 62// synced contents for the App. 63// 64// One FileMetadata is created for each tracked remote file, which is identified 65// by FileID. 66// One FileTracker is created for every different {parent tracker, FileID} pair, 67// excluding non-app-root inactive parent trackers. Multiple trackers may be 68// associated to one FileID when the file has multiple parents. Multiple 69// trackers may have the same {parent tracker, title} pair when the associated 70// remote files have the same title. 71// 72// Files have following state: 73// - Unknown file 74// - Has a dirty inactive tracker and empty synced_details. 75// - Is initial state of a tracker, only file_id and parent_tracker_id field 76// are known. 77// - Folder 78// - Is either one of sync-root folder, app-root folder or a regular folder. 79// - Sync-root folder holds app-root folders as its direct children, and 80// holds entire SyncFileSystem files as its descentants. Its tracker 81// should be stored in ServiceMetadata by its tracker_id. 82// - App-root folder holds all files for an application as its descendants. 83// - File 84// - Unsupported file 85// - Represents unsupported files such as hosted documents. Must be 86// inactive. 87// 88// Invariants: 89// - Any tracker in the database must either: 90// - be sync-root, 91// - have an app-root as its parent tracker, or 92// - have an active tracker as its parent. 93// That is, all trackers must be reachable from sync-root via app-root folders 94// and active trackers. 95// 96// - Any active tracker must either: 97// - have |needs_folder_listing| flag and dirty flag, or 98// - have all children at the stored largest change ID. 99// 100// - If multiple trackers have the same parent tracker and same title, they 101// must not have same |file_id|, and at most one of them may be active. 102// - If multiple trackers have the same |file_id|, at most one of them may be 103// active. 104// 105class MetadataDatabase { 106 public: 107 typedef std::map<std::string, FileMetadata*> FileByID; 108 typedef std::map<int64, FileTracker*> TrackerByID; 109 typedef std::map<std::string, TrackerSet> TrackersByFileID; 110 typedef std::map<std::string, TrackerSet> TrackersByTitle; 111 typedef std::map<int64, TrackersByTitle> TrackersByParentAndTitle; 112 typedef std::map<std::string, FileTracker*> TrackerByAppID; 113 typedef std::vector<std::string> FileIDList; 114 115 typedef base::Callback< 116 void(SyncStatusCode status, scoped_ptr<MetadataDatabase> instance)> 117 CreateCallback; 118 119 // The entry point of the MetadataDatabase for production code. 120 static void Create(base::SequencedTaskRunner* task_runner, 121 const base::FilePath& database_path, 122 const CreateCallback& callback); 123 ~MetadataDatabase(); 124 125 int64 GetLargestChangeID() const; 126 int64 GetSyncRootTrackerID() const; 127 bool HasSyncRoot() const; 128 129 // Populates empty database with initial data. 130 // Adds a file metadata and a file tracker for |sync_root_folder|, and adds 131 // file metadata and file trackers for each |app_root_folders|. 132 // Newly added tracker for |sync_root_folder| is active and non-dirty. 133 // Newly added trackers for |app_root_folders| are inactive and non-dirty. 134 // Trackers for |app_root_folders| are not yet registered as app-roots, but 135 // are ready to register. 136 void PopulateInitialData( 137 int64 largest_change_id, 138 const google_apis::FileResource& sync_root_folder, 139 const ScopedVector<google_apis::FileResource>& app_root_folders, 140 const SyncStatusCallback& callback); 141 142 // Registers existing folder as the app-root for |app_id|. The folder 143 // must be an inactive folder that does not yet associated to any App. 144 // This method associates the folder with |app_id| and activates it. 145 void RegisterApp(const std::string& app_id, 146 const std::string& folder_id, 147 const SyncStatusCallback& callback); 148 149 // Inactivates the folder associated to the app to disable |app_id|. 150 // Does nothing if |app_id| is already disabled. 151 void DisableApp(const std::string& app_id, 152 const SyncStatusCallback& callback); 153 154 // Activates the folder associated to |app_id| to enable |app_id|. 155 // Does nothing if |app_id| is already enabled. 156 void EnableApp(const std::string& app_id, 157 const SyncStatusCallback& callback); 158 159 // Unregisters the folder as the app-root for |app_id|. If |app_id| does not 160 // exist, does nothing. The folder is left as an inactive regular folder. 161 // Note that the inactivation drops all descendant files since they are no 162 // longer reachable from sync-root via active folder or app-root. 163 void UnregisterApp(const std::string& app_id, 164 const SyncStatusCallback& callback); 165 166 // Finds the app-root folder for |app_id|. Returns true if exists. 167 // Copies the result to |tracker| if it is non-NULL. 168 bool FindAppRootTracker(const std::string& app_id, 169 FileTracker* tracker) const; 170 171 // Finds the file identified by |file_id|. Returns true if the file is found. 172 // Copies the metadata identified by |file_id| into |file| if exists and 173 // |file| is non-NULL. 174 bool FindFileByFileID(const std::string& file_id, FileMetadata* file) const; 175 176 // Finds the tracker identified by |tracker_id|. Returns true if the tracker 177 // is found. 178 // Copies the tracker identified by |tracker_id| into |tracker| if exists and 179 // |tracker| is non-NULL. 180 bool FindTrackerByTrackerID(int64 tracker_id, FileTracker* tracker) const; 181 182 // Finds the trackers tracking |file_id|. Returns true if the trackers are 183 // found. 184 bool FindTrackersByFileID(const std::string& file_id, 185 TrackerSet* trackers) const; 186 187 // Finds the set of trackers whose parent's tracker ID is |parent_tracker_id|, 188 // and who has |title| as its title in the synced_details. 189 // Copies the tracker set to |trackers| if it is non-NULL. 190 // Returns true if the trackers are found. 191 bool FindTrackersByParentAndTitle( 192 int64 parent_tracker_id, 193 const std::string& title, 194 TrackerSet* trackers) const; 195 196 // Builds the file path for the given tracker. Returns true on success. 197 // |path| can be NULL. 198 // The file path is relative to app-root and have a leading path separator. 199 bool BuildPathForTracker(int64 tracker_id, base::FilePath* path) const; 200 201 // Updates database by |changes|. 202 // Marks each tracker for modified file as dirty and adds new trackers if 203 // needed. 204 void UpdateByChangeList(int64 largest_change_id, 205 ScopedVector<google_apis::ChangeResource> changes, 206 const SyncStatusCallback& callback); 207 208 // Updates database by |resource|. 209 // Marks each tracker for modified file as dirty and adds new trackers if 210 // needed. 211 void UpdateByFileResource(int64 change_id, 212 const google_apis::FileResource& resource, 213 const SyncStatusCallback& callback); 214 215 // Adds |child_file_ids| to |folder_id| as its children. 216 // This method affects the active tracker only. 217 // If the tracker has no further change to sync, unmarks its dirty flag. 218 void PopulateFolderByChildList(const std::string& folder_id, 219 const FileIDList& child_file_ids, 220 const SyncStatusCallback& callback); 221 222 // Updates |synced_details| of the tracker with |updated_details|. 223 void UpdateTracker(int64 tracker_id, 224 const FileDetails& updated_details, 225 const SyncStatusCallback& callback); 226 227 private: 228 friend class ListChangesTaskTest; 229 friend class MetadataDatabaseTest; 230 friend class RegisterAppTaskTest; 231 friend class SyncEngineInitializerTest; 232 233 struct DirtyTrackerComparator { 234 bool operator()(const FileTracker* left, 235 const FileTracker* right) const; 236 }; 237 238 typedef std::set<FileTracker*, DirtyTrackerComparator> DirtyTrackers; 239 240 explicit MetadataDatabase(base::SequencedTaskRunner* task_runner); 241 static void CreateOnTaskRunner(base::SingleThreadTaskRunner* callback_runner, 242 base::SequencedTaskRunner* task_runner, 243 const base::FilePath& database_path, 244 const CreateCallback& callback); 245 static SyncStatusCode CreateForTesting( 246 scoped_ptr<leveldb::DB> db, 247 scoped_ptr<MetadataDatabase>* metadata_database_out); 248 SyncStatusCode InitializeOnTaskRunner(const base::FilePath& database_path); 249 void BuildIndexes(DatabaseContents* contents); 250 251 SyncStatusCode SetLargestChangeIDForTesting(int64 largest_changestamp); 252 253 // Database manipulation methods. 254 void RegisterTrackerAsAppRoot(const std::string& app_id, 255 int64 tracker_id, 256 leveldb::WriteBatch* batch); 257 void MakeTrackerActive(int64 tracker_id, leveldb::WriteBatch* batch); 258 void MakeTrackerInactive(int64 tracker_id, leveldb::WriteBatch* batch); 259 void MakeAppRootDisabled(int64 tracker_id, leveldb::WriteBatch* batch); 260 void MakeAppRootEnabled(int64 tracker_id, leveldb::WriteBatch* batch); 261 262 void UnregisterTrackerAsAppRoot(const std::string& app_id, 263 leveldb::WriteBatch* batch); 264 void RemoveAllDescendantTrackers(int64 root_tracker_id, 265 leveldb::WriteBatch* batch); 266 267 void CreateTrackerForParentAndFileID(const FileTracker& parent_tracker, 268 const std::string& file_id, 269 leveldb::WriteBatch* batch); 270 271 void RemoveTracker(int64 tracker_id, leveldb::WriteBatch* batch); 272 void RemoveTrackerIgnoringSiblings(int64 tracker_id, 273 leveldb::WriteBatch* batch); 274 void RemoveTrackerInternal(int64 tracker_id, 275 leveldb::WriteBatch* batch, 276 bool ignoring_siblings); 277 void MaybeAddTrackersForNewFile(const FileMetadata& file, 278 leveldb::WriteBatch* batch); 279 280 void MarkTrackerSetDirty(TrackerSet* trackers, 281 leveldb::WriteBatch* batch); 282 void MarkTrackersDirtyByFileID(const std::string& file_id, 283 leveldb::WriteBatch* batch); 284 void MarkTrackersDirtyByPath(int64 parent_tracker_id, 285 const std::string& title, 286 leveldb::WriteBatch* batch); 287 288 void EraseTrackerFromFileIDIndex(FileTracker* tracker, 289 leveldb::WriteBatch* batch); 290 void EraseTrackerFromPathIndex(FileTracker* tracker); 291 void EraseFileFromDatabase(const std::string& file_id, 292 leveldb::WriteBatch* batch); 293 294 int64 GetNextTrackerID(leveldb::WriteBatch* batch); 295 296 void RecursiveMarkTrackerAsDirty(int64 root_tracker_id, 297 leveldb::WriteBatch* batch); 298 bool CanActivateTracker(const FileTracker& tracker); 299 bool ShouldKeepDirty(const FileTracker& tracker) const; 300 301 bool HasDisabledAppRoot(const FileTracker& tracker) const; 302 bool HasActiveTrackerForFileID(const std::string& file_id) const; 303 bool HasActiveTrackerForPath(int64 parent_tracker, 304 const std::string& title) const; 305 306 void UpdateTrackerTitle(FileTracker* tracker, 307 const std::string& new_title, 308 leveldb::WriteBatch* batch); 309 310 void WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, 311 const SyncStatusCallback& callback); 312 313 scoped_refptr<base::SequencedTaskRunner> task_runner_; 314 scoped_ptr<leveldb::DB> db_; 315 316 scoped_ptr<ServiceMetadata> service_metadata_; 317 318 FileByID file_by_id_; // Owned. 319 TrackerByID tracker_by_id_; // Owned. 320 321 // Maps FileID to trackers. The active tracker must be unique per FileID. 322 // This must be updated when updating |active| field of a tracker. 323 TrackersByFileID trackers_by_file_id_; // Not owned. 324 325 // Maps AppID to the app-root tracker. 326 // This must be updated when a tracker is registered/unregistered as an 327 // app-root. 328 TrackerByAppID app_root_by_app_id_; // Not owned. 329 330 // Maps |tracker_id| to its children grouped by their |title|. 331 // If the title is unknown for a tracker, treats its title as empty. Empty 332 // titled file must not be active. 333 // The active tracker must be unique per its parent_tracker and its title. 334 // This must be updated when updating |title|, |active| or 335 // |parent_tracker_id|. 336 TrackersByParentAndTitle trackers_by_parent_and_title_; 337 338 // Holds all trackers which marked as dirty. 339 // This must be updated when updating |dirty| field of a tracker. 340 DirtyTrackers dirty_trackers_; // Not owned. 341 342 base::WeakPtrFactory<MetadataDatabase> weak_ptr_factory_; 343 344 DISALLOW_COPY_AND_ASSIGN(MetadataDatabase); 345}; 346 347} // namespace drive_backend 348} // namespace sync_file_system 349 350#endif // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_ 351