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_SERVICE_H_
6#define CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_SERVICE_H_
7
8#include <map>
9#include <set>
10#include <string>
11
12#include "base/basictypes.h"
13#include "base/callback.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/weak_ptr.h"
16#include "base/observer_list.h"
17#include "chrome/browser/sync_file_system/local/local_origin_change_observer.h"
18#include "chrome/browser/sync_file_system/remote_change_processor.h"
19#include "chrome/browser/sync_file_system/sync_callbacks.h"
20#include "chrome/browser/sync_file_system/sync_status_code.h"
21
22class GURL;
23class Profile;
24
25namespace storage {
26class FileSystemContext;
27}
28
29namespace leveldb {
30class Env;
31}
32
33namespace storage {
34class ScopedFile;
35}
36
37namespace sync_file_system {
38
39class FileChange;
40class LocalChangeProcessor;
41class LocalFileSyncContext;
42struct LocalFileSyncInfo;
43
44// Maintains local file change tracker and sync status.
45// Owned by SyncFileSystemService (which is a per-profile object).
46class LocalFileSyncService
47    : public RemoteChangeProcessor,
48      public LocalOriginChangeObserver,
49      public base::SupportsWeakPtr<LocalFileSyncService> {
50 public:
51  typedef base::Callback<LocalChangeProcessor*(const GURL& origin)>
52      GetLocalChangeProcessorCallback;
53
54  class Observer {
55   public:
56    Observer() {}
57    virtual ~Observer() {}
58
59    // This is called when there're one or more local changes available.
60    // |pending_changes_hint| indicates the pending queue length to help sync
61    // scheduling but the value may not be accurately reflect the real-time
62    // value.
63    virtual void OnLocalChangeAvailable(int64 pending_changes_hint) = 0;
64
65   private:
66    DISALLOW_COPY_AND_ASSIGN(Observer);
67  };
68
69  typedef base::Callback<void(SyncStatusCode status,
70                              bool has_pending_changes)>
71      HasPendingLocalChangeCallback;
72
73  static scoped_ptr<LocalFileSyncService> Create(Profile* profile);
74  static scoped_ptr<LocalFileSyncService> CreateForTesting(
75      Profile* profile,
76      leveldb::Env* env_override);
77  virtual ~LocalFileSyncService();
78
79  void Shutdown();
80
81  void MaybeInitializeFileSystemContext(
82      const GURL& app_origin,
83      storage::FileSystemContext* file_system_context,
84      const SyncStatusCallback& callback);
85
86  void AddChangeObserver(Observer* observer);
87
88  // Registers |url| to wait until sync is enabled for |url|.
89  // |on_syncable_callback| is to be called when |url| becomes syncable
90  // (i.e. when we have no pending writes and the file is successfully locked
91  // for sync).
92  // Calling this method again while this already has another URL waiting
93  // for sync will overwrite the previously registered URL.
94  void RegisterURLForWaitingSync(const storage::FileSystemURL& url,
95                                 const base::Closure& on_syncable_callback);
96
97  // Synchronize one (or a set of) local change(s) to the remote server
98  // using local_change_processor given by SetLocalChangeProcessor().
99  // |processor| must have same or longer lifetime than this service.
100  // It is invalid to call this method before calling SetLocalChangeProcessor().
101  void ProcessLocalChange(const SyncFileCallback& callback);
102
103  // Sets a local change processor. The value is ignored if
104  // SetLocalChangeProcessorCallback() is called separately.
105  // Either this or SetLocalChangeProcessorCallback() must be called before
106  // any ProcessLocalChange().
107  void SetLocalChangeProcessor(LocalChangeProcessor* local_change_processor);
108
109  // Sets a closure which gets a local change processor for the given origin.
110  // Note that once this is called it overrides the direct processor setting
111  // done by SetLocalChangeProcessor().
112  // Either this or SetLocalChangeProcessor() must be called before any
113  // ProcessLocalChange().
114  //
115  // TODO(kinuko): Remove this method once we stop using multiple backends
116  // (crbug.com/324215), or deprecate the other if we keep doing so.
117  void SetLocalChangeProcessorCallback(
118      const GetLocalChangeProcessorCallback& get_local_change_processor);
119
120  // Returns true via |callback| if the given file |url| has local pending
121  // changes.
122  void HasPendingLocalChanges(const storage::FileSystemURL& url,
123                              const HasPendingLocalChangeCallback& callback);
124
125  void PromoteDemotedChanges(const base::Closure& callback);
126
127  // Returns the metadata of a remote file pointed by |url|.
128  virtual void GetLocalFileMetadata(const storage::FileSystemURL& url,
129                                    const SyncFileMetadataCallback& callback);
130
131  // RemoteChangeProcessor overrides.
132  virtual void PrepareForProcessRemoteChange(
133      const storage::FileSystemURL& url,
134      const PrepareChangeCallback& callback) OVERRIDE;
135  virtual void ApplyRemoteChange(const FileChange& change,
136                                 const base::FilePath& local_path,
137                                 const storage::FileSystemURL& url,
138                                 const SyncStatusCallback& callback) OVERRIDE;
139  virtual void FinalizeRemoteSync(
140      const storage::FileSystemURL& url,
141      bool clear_local_changes,
142      const base::Closure& completion_callback) OVERRIDE;
143  virtual void RecordFakeLocalChange(
144      const storage::FileSystemURL& url,
145      const FileChange& change,
146      const SyncStatusCallback& callback) OVERRIDE;
147
148  // LocalOriginChangeObserver override.
149  virtual void OnChangesAvailableInOrigins(
150      const std::set<GURL>& origins) OVERRIDE;
151
152  // Called when a particular origin (app) is disabled/enabled while
153  // the service is running. This may be called for origins/apps that
154  // are not initialized for the service.
155  void SetOriginEnabled(const GURL& origin, bool enabled);
156
157 private:
158  typedef std::map<GURL, storage::FileSystemContext*> OriginToContext;
159  friend class OriginChangeMapTest;
160
161  class OriginChangeMap {
162   public:
163    typedef std::map<GURL, int64> Map;
164
165    OriginChangeMap();
166    ~OriginChangeMap();
167
168    // Sets |origin| to the next origin to process. (For now we simply apply
169    // round-robin to pick the next origin to avoid starvation.)
170    // Returns false if no origins to process.
171    bool NextOriginToProcess(GURL* origin);
172
173    int64 GetTotalChangeCount() const;
174
175    // Update change_count_map_ for |origin|.
176    void SetOriginChangeCount(const GURL& origin, int64 changes);
177
178    void SetOriginEnabled(const GURL& origin, bool enabled);
179
180   private:
181    // Per-origin changes (cached info, could be stale).
182    Map change_count_map_;
183    Map::iterator next_;
184
185    // Holds a set of disabled (but initialized) origins.
186    std::set<GURL> disabled_origins_;
187  };
188
189  LocalFileSyncService(Profile* profile, leveldb::Env* env_override);
190
191  void DidInitializeFileSystemContext(
192      const GURL& app_origin,
193      storage::FileSystemContext* file_system_context,
194      const SyncStatusCallback& callback,
195      SyncStatusCode status);
196  void DidInitializeForRemoteSync(
197      const storage::FileSystemURL& url,
198      storage::FileSystemContext* file_system_context,
199      const PrepareChangeCallback& callback,
200      SyncStatusCode status);
201
202  // Runs local_sync_callback_ and resets it.
203  void RunLocalSyncCallback(SyncStatusCode status,
204                            const storage::FileSystemURL& url);
205
206  // Callback for ApplyRemoteChange.
207  void DidApplyRemoteChange(
208      const SyncStatusCallback& callback,
209      SyncStatusCode status);
210
211  // Callbacks for ProcessLocalChange.
212  void DidGetFileForLocalSync(SyncStatusCode status,
213                              const LocalFileSyncInfo& sync_file_info,
214                              storage::ScopedFile snapshot);
215  void ProcessNextChangeForURL(storage::ScopedFile snapshot,
216                               const LocalFileSyncInfo& sync_file_info,
217                               const FileChange& last_change,
218                               const FileChangeList& changes,
219                               SyncStatusCode status);
220
221  // A thin wrapper of get_local_change_processor_.
222  LocalChangeProcessor* GetLocalChangeProcessor(
223      const storage::FileSystemURL& url);
224
225  Profile* profile_;
226
227  scoped_refptr<LocalFileSyncContext> sync_context_;
228
229  // Origin to context map. (Assuming that as far as we're in the same
230  // profile single origin wouldn't belong to multiple FileSystemContexts.)
231  OriginToContext origin_to_contexts_;
232
233  // Origins which have pending changes but have not been initialized yet.
234  // (Used only for handling dirty files left in the local tracker database
235  // after a restart.)
236  std::set<GURL> pending_origins_with_changes_;
237
238  OriginChangeMap origin_change_map_;
239
240  // This callback is non-null while a local sync is running (i.e.
241  // ProcessLocalChange has been called and has not been returned yet).
242  SyncFileCallback local_sync_callback_;
243
244  LocalChangeProcessor* local_change_processor_;
245  GetLocalChangeProcessorCallback get_local_change_processor_;
246
247  ObserverList<Observer> change_observers_;
248
249  DISALLOW_COPY_AND_ASSIGN(LocalFileSyncService);
250};
251
252}  // namespace sync_file_system
253
254#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_LOCAL_LOCAL_FILE_SYNC_SERVICE_H_
255