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