metadata_database.h revision ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16
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
20namespace base {
21class FilePath;
22class SequencedTaskRunner;
23class SingleThreadTaskRunner;
24}
25
26namespace leveldb {
27class DB;
28class WriteBatch;
29}
30
31namespace google_apis {
32class ChangeResource;
33class FileResource;
34class ResourceEntry;
35}
36
37namespace sync_file_system {
38namespace drive_backend {
39
40class FileMetadata;
41class FileTracker;
42class ServiceMetadata;
43struct 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//
103class 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