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