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_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_
6#define CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_
7
8#include <deque>
9#include <map>
10#include <set>
11#include <string>
12
13#include "base/basictypes.h"
14#include "base/callback.h"
15#include "base/files/file.h"
16#include "base/files/file_path.h"
17#include "base/logging.h"
18#include "base/memory/ref_counted.h"
19#include "base/memory/scoped_ptr.h"
20#include "base/memory/weak_ptr.h"
21#include "base/observer_list.h"
22#include "base/timer/timer.h"
23#include "chrome/browser/sync_file_system/local/local_file_sync_status.h"
24#include "chrome/browser/sync_file_system/sync_callbacks.h"
25#include "chrome/browser/sync_file_system/sync_status_code.h"
26#include "url/gurl.h"
27
28namespace base {
29class SingleThreadTaskRunner;
30}
31
32namespace storage {
33class FileSystemContext;
34class FileSystemURL;
35}
36
37namespace leveldb {
38class Env;
39}
40
41namespace storage {
42class ScopedFile;
43}
44
45namespace sync_file_system {
46
47class FileChange;
48class LocalFileChangeTracker;
49struct LocalFileSyncInfo;
50class LocalOriginChangeObserver;
51class RootDeleteHelper;
52class SyncableFileOperationRunner;
53
54// This class works as a bridge between LocalFileSyncService (which is a
55// per-profile object) and FileSystemContext's (which is a per-storage-partition
56// object and may exist multiple in a profile).
57// An instance of this class is shared by FileSystemContexts and outlives
58// LocalFileSyncService.
59class LocalFileSyncContext
60    : public base::RefCountedThreadSafe<LocalFileSyncContext>,
61      public LocalFileSyncStatus::Observer {
62 public:
63  enum SyncMode {
64    SYNC_EXCLUSIVE,
65    SYNC_SNAPSHOT,
66  };
67
68  typedef base::Callback<void(SyncStatusCode status,
69                              const LocalFileSyncInfo& sync_file_info,
70                              storage::ScopedFile snapshot)>
71      LocalFileSyncInfoCallback;
72
73  typedef base::Callback<void(SyncStatusCode status,
74                              bool has_pending_changes)>
75      HasPendingLocalChangeCallback;
76
77  LocalFileSyncContext(const base::FilePath& base_path,
78                       leveldb::Env* env_override,
79                       base::SingleThreadTaskRunner* ui_task_runner,
80                       base::SingleThreadTaskRunner* io_task_runner);
81
82  // Initializes |file_system_context| for syncable file operations
83  // and registers the it into the internal map.
84  // Calling this multiple times for the same file_system_context is valid.
85  // This method must be called on UI thread.
86  void MaybeInitializeFileSystemContext(
87      const GURL& source_url,
88      storage::FileSystemContext* file_system_context,
89      const SyncStatusCallback& callback);
90
91  // Called when the corresponding LocalFileSyncService exits.
92  // This method must be called on UI thread.
93  void ShutdownOnUIThread();
94
95  // Picks a file for next local sync and returns it after disabling writes
96  // for the file.
97  // This method must be called on UI thread.
98  void GetFileForLocalSync(storage::FileSystemContext* file_system_context,
99                           const LocalFileSyncInfoCallback& callback);
100
101  // TODO(kinuko): Make this private.
102  // Clears all pending local changes for |url|. |done_callback| is called
103  // when the changes are cleared.
104  // This method must be called on UI thread.
105  void ClearChangesForURL(storage::FileSystemContext* file_system_context,
106                          const storage::FileSystemURL& url,
107                          const base::Closure& done_callback);
108
109  // Finalizes SnapshotSync, which must have been started by
110  // PrepareForSync with SYNC_SNAPSHOT.
111  // Updates the on-disk dirty flag for |url| in the tracker DB.
112  // This will clear the dirty flag if |sync_finish_status| is SYNC_STATUS_OK
113  // or SYNC_STATUS_HAS_CONFLICT.
114  // |done_callback| is called when the changes are committed.
115  void FinalizeSnapshotSync(storage::FileSystemContext* file_system_context,
116                            const storage::FileSystemURL& url,
117                            SyncStatusCode sync_finish_status,
118                            const base::Closure& done_callback);
119
120  // Finalizes ExclusiveSync, which must have been started by
121  // PrepareForSync with SYNC_EXCLUSIVE.
122  void FinalizeExclusiveSync(storage::FileSystemContext* file_system_context,
123                             const storage::FileSystemURL& url,
124                             bool clear_local_changes,
125                             const base::Closure& done_callback);
126
127  // Prepares for sync |url| by disabling writes on |url|.
128  // If the target |url| is being written and cannot start sync it
129  // returns SYNC_STATUS_WRITING status code via |callback|.
130  // Otherwise returns the current change sets made on |url|.
131  //
132  // If |sync_mode| is SYNC_EXCLUSIVE this leaves the target file locked.
133  // If |sync_mode| is SYNC_SNAPSHOT this creates a snapshot (if the
134  // target file is not deleted) and unlocks the file before returning.
135  //
136  // For SYNC_EXCLUSIVE, caller must call FinalizeExclusiveSync() to finalize
137  // sync and unlock the file.
138  // For SYNC_SNAPSHOT, caller must call FinalizeSnapshotSync() to finalize
139  // sync to reset the mirrored change status and decrement writing count.
140  //
141  // This method must be called on UI thread.
142  void PrepareForSync(storage::FileSystemContext* file_system_context,
143                      const storage::FileSystemURL& url,
144                      SyncMode sync_mode,
145                      const LocalFileSyncInfoCallback& callback);
146
147  // Registers |url| to wait until sync is enabled for |url|.
148  // |on_syncable_callback| is to be called when |url| becomes syncable
149  // (i.e. when we have no pending writes and the file is successfully locked
150  // for sync).
151  //
152  // Calling this method again while this already has another URL waiting
153  // for sync will overwrite the previously registered URL.
154  //
155  // This method must be called on UI thread.
156  void RegisterURLForWaitingSync(const storage::FileSystemURL& url,
157                                 const base::Closure& on_syncable_callback);
158
159  // Applies a remote change.
160  // This method must be called on UI thread.
161  void ApplyRemoteChange(storage::FileSystemContext* file_system_context,
162                         const FileChange& change,
163                         const base::FilePath& local_path,
164                         const storage::FileSystemURL& url,
165                         const SyncStatusCallback& callback);
166
167  // Records a fake local change in the local change tracker.
168  void RecordFakeLocalChange(storage::FileSystemContext* file_system_context,
169                             const storage::FileSystemURL& url,
170                             const FileChange& change,
171                             const SyncStatusCallback& callback);
172
173  // This must be called on UI thread.
174  void GetFileMetadata(storage::FileSystemContext* file_system_context,
175                       const storage::FileSystemURL& url,
176                       const SyncFileMetadataCallback& callback);
177
178  // Returns true via |callback| if the given file |url| has local pending
179  // changes.
180  void HasPendingLocalChanges(storage::FileSystemContext* file_system_context,
181                              const storage::FileSystemURL& url,
182                              const HasPendingLocalChangeCallback& callback);
183
184  void PromoteDemotedChanges(const GURL& origin,
185                             storage::FileSystemContext* file_system_context,
186                             const base::Closure& callback);
187  void UpdateChangesForOrigin(const GURL& origin,
188                              const base::Closure& callback);
189
190  // They must be called on UI thread.
191  void AddOriginChangeObserver(LocalOriginChangeObserver* observer);
192  void RemoveOriginChangeObserver(LocalOriginChangeObserver* observer);
193
194  // OperationRunner is accessible only on IO thread.
195  base::WeakPtr<SyncableFileOperationRunner> operation_runner() const;
196
197  // SyncContext is accessible only on IO thread.
198  LocalFileSyncStatus* sync_status() const;
199
200  // For testing; override the duration to notify changes from the
201  // default value.
202  void set_mock_notify_changes_duration_in_sec(int duration) {
203    mock_notify_changes_duration_in_sec_ = duration;
204  }
205
206 protected:
207  // LocalFileSyncStatus::Observer overrides. They are called on IO thread.
208  virtual void OnSyncEnabled(const storage::FileSystemURL& url) OVERRIDE;
209  virtual void OnWriteEnabled(const storage::FileSystemURL& url) OVERRIDE;
210
211 private:
212  typedef base::Callback<void(base::File::Error result)> StatusCallback;
213  typedef std::deque<SyncStatusCallback> StatusCallbackQueue;
214  typedef std::deque<storage::FileSystemURL> FileSystemURLQueue;
215  friend class base::RefCountedThreadSafe<LocalFileSyncContext>;
216  friend class CannedSyncableFileSystem;
217
218  virtual ~LocalFileSyncContext();
219
220  void ShutdownOnIOThread();
221
222  // Starts a timer to eventually call NotifyAvailableChangesOnIOThread.
223  // The caller is expected to update origins_with_pending_changes_ before
224  // calling this.
225  void ScheduleNotifyChangesUpdatedOnIOThread(const base::Closure& callback);
226
227  // Called by the internal timer on IO thread to notify changes to UI thread.
228  void NotifyAvailableChangesOnIOThread(const base::Closure& callback);
229
230  // Called from NotifyAvailableChangesOnIOThread.
231  void NotifyAvailableChanges(const std::set<GURL>& origins,
232                              const base::Closure& callback);
233
234  // Helper routines for MaybeInitializeFileSystemContext.
235  void InitializeFileSystemContextOnIOThread(
236      const GURL& source_url,
237      storage::FileSystemContext* file_system_context,
238      const GURL& /* root */,
239      const std::string& /* name */,
240      base::File::Error error);
241  SyncStatusCode InitializeChangeTrackerOnFileThread(
242      scoped_ptr<LocalFileChangeTracker>* tracker_ptr,
243      storage::FileSystemContext* file_system_context,
244      std::set<GURL>* origins_with_changes);
245  void DidInitializeChangeTrackerOnIOThread(
246      scoped_ptr<LocalFileChangeTracker>* tracker_ptr,
247      const GURL& source_url,
248      storage::FileSystemContext* file_system_context,
249      std::set<GURL>* origins_with_changes,
250      SyncStatusCode status);
251  void DidInitialize(const GURL& source_url,
252                     storage::FileSystemContext* file_system_context,
253                     SyncStatusCode status);
254
255  // Helper routines for GetFileForLocalSync.
256  scoped_ptr<FileSystemURLQueue> GetNextURLsForSyncOnFileThread(
257      storage::FileSystemContext* file_system_context);
258  void TryPrepareForLocalSync(storage::FileSystemContext* file_system_context,
259                              const LocalFileSyncInfoCallback& callback,
260                              scoped_ptr<FileSystemURLQueue> urls);
261  void DidTryPrepareForLocalSync(
262      storage::FileSystemContext* file_system_context,
263      scoped_ptr<FileSystemURLQueue> remaining_urls,
264      const LocalFileSyncInfoCallback& callback,
265      SyncStatusCode status,
266      const LocalFileSyncInfo& sync_file_info,
267      storage::ScopedFile snapshot);
268  void PromoteDemotedChangesForURL(
269      storage::FileSystemContext* file_system_context,
270      const storage::FileSystemURL& url);
271  void PromoteDemotedChangesForURLs(
272      storage::FileSystemContext* file_system_context,
273      scoped_ptr<FileSystemURLQueue> url);
274
275  // Callback routine for PrepareForSync and GetFileForLocalSync.
276  void DidGetWritingStatusForSync(
277      storage::FileSystemContext* file_system_context,
278      SyncStatusCode status,
279      const storage::FileSystemURL& url,
280      SyncMode sync_mode,
281      const LocalFileSyncInfoCallback& callback);
282
283  // Helper routine for sync/writing flag handling.
284  //
285  // If |for_snapshot_sync| is true, this increments the writing counter
286  // for |url| (after clearing syncing flag), so that other sync activities
287  // won't step in while snapshot sync is ongoing.
288  // In this case FinalizeSnapshotSyncOnIOThread must be called after the
289  // snapshot sync is finished to decrement the writing counter.
290  void ClearSyncFlagOnIOThread(const storage::FileSystemURL& url,
291                               bool for_snapshot_sync);
292  void FinalizeSnapshotSyncOnIOThread(const storage::FileSystemURL& url);
293
294  void HandleRemoteDelete(storage::FileSystemContext* file_system_context,
295                          const storage::FileSystemURL& url,
296                          const SyncStatusCallback& callback);
297  void HandleRemoteAddOrUpdate(storage::FileSystemContext* file_system_context,
298                               const FileChange& change,
299                               const base::FilePath& local_path,
300                               const storage::FileSystemURL& url,
301                               const SyncStatusCallback& callback);
302  void DidRemoveExistingEntryForRemoteAddOrUpdate(
303      storage::FileSystemContext* file_system_context,
304      const FileChange& change,
305      const base::FilePath& local_path,
306      const storage::FileSystemURL& url,
307      const SyncStatusCallback& callback,
308      base::File::Error error);
309
310  // Callback routine for ApplyRemoteChange.
311  void DidApplyRemoteChange(const storage::FileSystemURL& url,
312                            const SyncStatusCallback& callback_on_ui,
313                            base::File::Error file_error);
314
315  void DidGetFileMetadata(
316      const SyncFileMetadataCallback& callback,
317      base::File::Error file_error,
318      const base::File::Info& file_info);
319
320  base::TimeDelta NotifyChangesDuration();
321
322  void DidCreateDirectoryForCopyIn(
323      storage::FileSystemContext* file_system_context,
324      const base::FilePath& local_file_path,
325      const storage::FileSystemURL& dest_url,
326      const StatusCallback& callback,
327      base::File::Error error);
328
329  const base::FilePath local_base_path_;
330  leveldb::Env* env_override_;
331
332  scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
333  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
334
335  // Indicates if the sync service is shutdown.
336  bool shutdown_on_ui_;  // Updated and referred only on UI thread.
337  bool shutdown_on_io_;  // Updated and referred only on IO thread.
338
339  // OperationRunner. This must be accessed only on IO thread.
340  scoped_ptr<SyncableFileOperationRunner> operation_runner_;
341
342  // Keeps track of writing/syncing status.
343  // This must be accessed only on IO thread.
344  scoped_ptr<LocalFileSyncStatus> sync_status_;
345
346  // Pointers to file system contexts that have been initialized for
347  // synchronization (i.e. that own this instance).
348  // This must be accessed only on UI thread.
349  std::set<storage::FileSystemContext*> file_system_contexts_;
350
351  // Accessed only on UI thread.
352  std::map<storage::FileSystemContext*, StatusCallbackQueue>
353      pending_initialize_callbacks_;
354
355  // A URL and associated callback waiting for sync is enabled.
356  // Accessed only on IO thread.
357  storage::FileSystemURL url_waiting_sync_on_io_;
358  base::Closure url_syncable_callback_;
359
360  // Used only on IO thread for available changes notifications.
361  base::Time last_notified_changes_;
362  scoped_ptr<base::OneShotTimer<LocalFileSyncContext> > timer_on_io_;
363  std::set<GURL> origins_with_pending_changes_;
364
365  // Populated while root directory deletion is being handled for
366  // ApplyRemoteChange(). Modified only on IO thread.
367  scoped_ptr<RootDeleteHelper> root_delete_helper_;
368
369  ObserverList<LocalOriginChangeObserver> origin_change_observers_;
370
371  int mock_notify_changes_duration_in_sec_;
372
373  DISALLOW_COPY_AND_ASSIGN(LocalFileSyncContext);
374};
375
376}  // namespace sync_file_system
377
378#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_
379