| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_ |
| #define CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_ |
| |
| #include <deque> |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/callback.h" |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/sync_file_system/local/local_file_sync_status.h" |
| #include "chrome/browser/sync_file_system/sync_callbacks.h" |
| #include "chrome/browser/sync_file_system/sync_status_code.h" |
| #include "url/gurl.h" |
| |
| namespace base { |
| class SingleThreadTaskRunner; |
| } |
| |
| namespace storage { |
| class FileSystemContext; |
| class FileSystemURL; |
| } |
| |
| namespace leveldb { |
| class Env; |
| } |
| |
| namespace storage { |
| class ScopedFile; |
| } |
| |
| namespace sync_file_system { |
| |
| class FileChange; |
| class LocalFileChangeTracker; |
| struct LocalFileSyncInfo; |
| class LocalOriginChangeObserver; |
| class RootDeleteHelper; |
| class SyncableFileOperationRunner; |
| |
| // This class works as a bridge between LocalFileSyncService (which is a |
| // per-profile object) and FileSystemContext's (which is a per-storage-partition |
| // object and may exist multiple in a profile). |
| // An instance of this class is shared by FileSystemContexts and outlives |
| // LocalFileSyncService. |
| class LocalFileSyncContext |
| : public base::RefCountedThreadSafe<LocalFileSyncContext>, |
| public LocalFileSyncStatus::Observer { |
| public: |
| enum SyncMode { |
| SYNC_EXCLUSIVE, |
| SYNC_SNAPSHOT, |
| }; |
| |
| typedef base::Callback<void(SyncStatusCode status, |
| const LocalFileSyncInfo& sync_file_info, |
| storage::ScopedFile snapshot)> |
| LocalFileSyncInfoCallback; |
| |
| typedef base::Callback<void(SyncStatusCode status, |
| bool has_pending_changes)> |
| HasPendingLocalChangeCallback; |
| |
| LocalFileSyncContext(const base::FilePath& base_path, |
| leveldb::Env* env_override, |
| base::SingleThreadTaskRunner* ui_task_runner, |
| base::SingleThreadTaskRunner* io_task_runner); |
| |
| // Initializes |file_system_context| for syncable file operations |
| // and registers the it into the internal map. |
| // Calling this multiple times for the same file_system_context is valid. |
| // This method must be called on UI thread. |
| void MaybeInitializeFileSystemContext( |
| const GURL& source_url, |
| storage::FileSystemContext* file_system_context, |
| const SyncStatusCallback& callback); |
| |
| // Called when the corresponding LocalFileSyncService exits. |
| // This method must be called on UI thread. |
| void ShutdownOnUIThread(); |
| |
| // Picks a file for next local sync and returns it after disabling writes |
| // for the file. |
| // This method must be called on UI thread. |
| void GetFileForLocalSync(storage::FileSystemContext* file_system_context, |
| const LocalFileSyncInfoCallback& callback); |
| |
| // TODO(kinuko): Make this private. |
| // Clears all pending local changes for |url|. |done_callback| is called |
| // when the changes are cleared. |
| // This method must be called on UI thread. |
| void ClearChangesForURL(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| const base::Closure& done_callback); |
| |
| // Finalizes SnapshotSync, which must have been started by |
| // PrepareForSync with SYNC_SNAPSHOT. |
| // Updates the on-disk dirty flag for |url| in the tracker DB. |
| // This will clear the dirty flag if |sync_finish_status| is SYNC_STATUS_OK |
| // or SYNC_STATUS_HAS_CONFLICT. |
| // |done_callback| is called when the changes are committed. |
| void FinalizeSnapshotSync(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| SyncStatusCode sync_finish_status, |
| const base::Closure& done_callback); |
| |
| // Finalizes ExclusiveSync, which must have been started by |
| // PrepareForSync with SYNC_EXCLUSIVE. |
| void FinalizeExclusiveSync(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| bool clear_local_changes, |
| const base::Closure& done_callback); |
| |
| // Prepares for sync |url| by disabling writes on |url|. |
| // If the target |url| is being written and cannot start sync it |
| // returns SYNC_STATUS_WRITING status code via |callback|. |
| // Otherwise returns the current change sets made on |url|. |
| // |
| // If |sync_mode| is SYNC_EXCLUSIVE this leaves the target file locked. |
| // If |sync_mode| is SYNC_SNAPSHOT this creates a snapshot (if the |
| // target file is not deleted) and unlocks the file before returning. |
| // |
| // For SYNC_EXCLUSIVE, caller must call FinalizeExclusiveSync() to finalize |
| // sync and unlock the file. |
| // For SYNC_SNAPSHOT, caller must call FinalizeSnapshotSync() to finalize |
| // sync to reset the mirrored change status and decrement writing count. |
| // |
| // This method must be called on UI thread. |
| void PrepareForSync(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| SyncMode sync_mode, |
| const LocalFileSyncInfoCallback& callback); |
| |
| // Registers |url| to wait until sync is enabled for |url|. |
| // |on_syncable_callback| is to be called when |url| becomes syncable |
| // (i.e. when we have no pending writes and the file is successfully locked |
| // for sync). |
| // |
| // Calling this method again while this already has another URL waiting |
| // for sync will overwrite the previously registered URL. |
| // |
| // This method must be called on UI thread. |
| void RegisterURLForWaitingSync(const storage::FileSystemURL& url, |
| const base::Closure& on_syncable_callback); |
| |
| // Applies a remote change. |
| // This method must be called on UI thread. |
| void ApplyRemoteChange(storage::FileSystemContext* file_system_context, |
| const FileChange& change, |
| const base::FilePath& local_path, |
| const storage::FileSystemURL& url, |
| const SyncStatusCallback& callback); |
| |
| // Records a fake local change in the local change tracker. |
| void RecordFakeLocalChange(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| const FileChange& change, |
| const SyncStatusCallback& callback); |
| |
| // This must be called on UI thread. |
| void GetFileMetadata(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| const SyncFileMetadataCallback& callback); |
| |
| // Returns true via |callback| if the given file |url| has local pending |
| // changes. |
| void HasPendingLocalChanges(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| const HasPendingLocalChangeCallback& callback); |
| |
| void PromoteDemotedChanges(const GURL& origin, |
| storage::FileSystemContext* file_system_context, |
| const base::Closure& callback); |
| void UpdateChangesForOrigin(const GURL& origin, |
| const base::Closure& callback); |
| |
| // They must be called on UI thread. |
| void AddOriginChangeObserver(LocalOriginChangeObserver* observer); |
| void RemoveOriginChangeObserver(LocalOriginChangeObserver* observer); |
| |
| // OperationRunner is accessible only on IO thread. |
| base::WeakPtr<SyncableFileOperationRunner> operation_runner() const; |
| |
| // SyncContext is accessible only on IO thread. |
| LocalFileSyncStatus* sync_status() const; |
| |
| // For testing; override the duration to notify changes from the |
| // default value. |
| void set_mock_notify_changes_duration_in_sec(int duration) { |
| mock_notify_changes_duration_in_sec_ = duration; |
| } |
| |
| protected: |
| // LocalFileSyncStatus::Observer overrides. They are called on IO thread. |
| void OnSyncEnabled(const storage::FileSystemURL& url) override; |
| void OnWriteEnabled(const storage::FileSystemURL& url) override; |
| |
| private: |
| typedef base::Callback<void(base::File::Error result)> StatusCallback; |
| typedef std::deque<SyncStatusCallback> StatusCallbackQueue; |
| typedef std::deque<storage::FileSystemURL> FileSystemURLQueue; |
| friend class base::RefCountedThreadSafe<LocalFileSyncContext>; |
| friend class CannedSyncableFileSystem; |
| |
| ~LocalFileSyncContext() override; |
| |
| void ShutdownOnIOThread(); |
| |
| // Starts a timer to eventually call NotifyAvailableChangesOnIOThread. |
| // The caller is expected to update origins_with_pending_changes_ before |
| // calling this. |
| void ScheduleNotifyChangesUpdatedOnIOThread(const base::Closure& callback); |
| |
| // Called by the internal timer on IO thread to notify changes to UI thread. |
| void NotifyAvailableChangesOnIOThread(); |
| |
| // Called from NotifyAvailableChangesOnIOThread. |
| void NotifyAvailableChanges(const std::set<GURL>& origins, |
| const std::vector<base::Closure>& callbacks); |
| |
| // Helper routines for MaybeInitializeFileSystemContext. |
| void InitializeFileSystemContextOnIOThread( |
| const GURL& source_url, |
| storage::FileSystemContext* file_system_context, |
| const GURL& /* root */, |
| const std::string& /* name */, |
| base::File::Error error); |
| SyncStatusCode InitializeChangeTrackerOnFileThread( |
| scoped_ptr<LocalFileChangeTracker>* tracker_ptr, |
| storage::FileSystemContext* file_system_context, |
| std::set<GURL>* origins_with_changes); |
| void DidInitializeChangeTrackerOnIOThread( |
| scoped_ptr<LocalFileChangeTracker>* tracker_ptr, |
| const GURL& source_url, |
| storage::FileSystemContext* file_system_context, |
| std::set<GURL>* origins_with_changes, |
| SyncStatusCode status); |
| void DidInitialize(const GURL& source_url, |
| storage::FileSystemContext* file_system_context, |
| SyncStatusCode status); |
| |
| // Helper routines for GetFileForLocalSync. |
| scoped_ptr<FileSystemURLQueue> GetNextURLsForSyncOnFileThread( |
| storage::FileSystemContext* file_system_context); |
| void TryPrepareForLocalSync(storage::FileSystemContext* file_system_context, |
| const LocalFileSyncInfoCallback& callback, |
| scoped_ptr<FileSystemURLQueue> urls); |
| void DidTryPrepareForLocalSync( |
| storage::FileSystemContext* file_system_context, |
| scoped_ptr<FileSystemURLQueue> remaining_urls, |
| const LocalFileSyncInfoCallback& callback, |
| SyncStatusCode status, |
| const LocalFileSyncInfo& sync_file_info, |
| storage::ScopedFile snapshot); |
| void PromoteDemotedChangesForURL( |
| storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url); |
| void PromoteDemotedChangesForURLs( |
| storage::FileSystemContext* file_system_context, |
| scoped_ptr<FileSystemURLQueue> url); |
| |
| // Callback routine for PrepareForSync and GetFileForLocalSync. |
| void DidGetWritingStatusForSync( |
| storage::FileSystemContext* file_system_context, |
| SyncStatusCode status, |
| const storage::FileSystemURL& url, |
| SyncMode sync_mode, |
| const LocalFileSyncInfoCallback& callback); |
| |
| // Helper routine for sync/writing flag handling. |
| // |
| // If |for_snapshot_sync| is true, this increments the writing counter |
| // for |url| (after clearing syncing flag), so that other sync activities |
| // won't step in while snapshot sync is ongoing. |
| // In this case FinalizeSnapshotSyncOnIOThread must be called after the |
| // snapshot sync is finished to decrement the writing counter. |
| void ClearSyncFlagOnIOThread(const storage::FileSystemURL& url, |
| bool for_snapshot_sync); |
| void FinalizeSnapshotSyncOnIOThread(const storage::FileSystemURL& url); |
| |
| void HandleRemoteDelete(storage::FileSystemContext* file_system_context, |
| const storage::FileSystemURL& url, |
| const SyncStatusCallback& callback); |
| void HandleRemoteAddOrUpdate(storage::FileSystemContext* file_system_context, |
| const FileChange& change, |
| const base::FilePath& local_path, |
| const storage::FileSystemURL& url, |
| const SyncStatusCallback& callback); |
| void DidRemoveExistingEntryForRemoteAddOrUpdate( |
| storage::FileSystemContext* file_system_context, |
| const FileChange& change, |
| const base::FilePath& local_path, |
| const storage::FileSystemURL& url, |
| const SyncStatusCallback& callback, |
| base::File::Error error); |
| |
| // Callback routine for ApplyRemoteChange. |
| void DidApplyRemoteChange(const storage::FileSystemURL& url, |
| const SyncStatusCallback& callback_on_ui, |
| base::File::Error file_error); |
| |
| void DidGetFileMetadata( |
| const SyncFileMetadataCallback& callback, |
| base::File::Error file_error, |
| const base::File::Info& file_info); |
| |
| base::TimeDelta NotifyChangesDuration(); |
| |
| void DidCreateDirectoryForCopyIn( |
| storage::FileSystemContext* file_system_context, |
| const base::FilePath& local_file_path, |
| const storage::FileSystemURL& dest_url, |
| const StatusCallback& callback, |
| base::File::Error error); |
| |
| const base::FilePath local_base_path_; |
| leveldb::Env* env_override_; |
| |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| |
| // Indicates if the sync service is shutdown. |
| bool shutdown_on_ui_; // Updated and referred only on UI thread. |
| bool shutdown_on_io_; // Updated and referred only on IO thread. |
| |
| // OperationRunner. This must be accessed only on IO thread. |
| scoped_ptr<SyncableFileOperationRunner> operation_runner_; |
| |
| // Keeps track of writing/syncing status. |
| // This must be accessed only on IO thread. |
| scoped_ptr<LocalFileSyncStatus> sync_status_; |
| |
| // Pointers to file system contexts that have been initialized for |
| // synchronization (i.e. that own this instance). |
| // This must be accessed only on UI thread. |
| std::set<storage::FileSystemContext*> file_system_contexts_; |
| |
| // Accessed only on UI thread. |
| std::map<storage::FileSystemContext*, StatusCallbackQueue> |
| pending_initialize_callbacks_; |
| |
| // A URL and associated callback waiting for sync is enabled. |
| // Accessed only on IO thread. |
| storage::FileSystemURL url_waiting_sync_on_io_; |
| base::Closure url_syncable_callback_; |
| |
| // Used only on IO thread for available changes notifications. |
| base::Time last_notified_changes_; |
| scoped_ptr<base::OneShotTimer<LocalFileSyncContext> > timer_on_io_; |
| std::vector<base::Closure> pending_completion_callbacks_; |
| std::set<GURL> origins_with_pending_changes_; |
| |
| // Populated while root directory deletion is being handled for |
| // ApplyRemoteChange(). Modified only on IO thread. |
| scoped_ptr<RootDeleteHelper> root_delete_helper_; |
| |
| ObserverList<LocalOriginChangeObserver> origin_change_observers_; |
| |
| int mock_notify_changes_duration_in_sec_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LocalFileSyncContext); |
| }; |
| |
| } // namespace sync_file_system |
| |
| #endif // CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_CONTEXT_H_ |