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