blob: 90d59cd22f777e40a4ae38d3b4bbe7d14af1684c [file] [log] [blame]
[email protected]3653146a2012-05-29 13:41:471// Copyright (c) 2012 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_CHROMEOS_GDATA_GDATA_CACHE_H_
6#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_CACHE_H_
7#pragma once
8
9#include <map>
10#include <string>
11
[email protected]32a7fc852012-06-08 17:25:5012#include "base/file_path.h"
[email protected]3653146a2012-05-29 13:41:4713#include "base/memory/scoped_ptr.h"
[email protected]73f9c742012-06-15 07:37:1314#include "base/memory/weak_ptr.h"
15#include "base/observer_list.h"
[email protected]a321b9632012-06-14 03:29:1716#include "base/platform_file.h"
[email protected]fcc92a52012-06-08 22:54:1617#include "base/threading/sequenced_worker_pool.h"
[email protected]3653146a2012-05-29 13:41:4718
[email protected]01ba15f72012-06-09 00:41:0519class Profile;
20
[email protected]3653146a2012-05-29 13:41:4721namespace gdata {
22
[email protected]ca5f6da2012-06-18 12:54:5923class GDataCacheMetadata;
24
[email protected]7986b8d2012-06-14 15:05:1425// Callback for SetMountedStateOnUIThread.
26typedef base::Callback<void(base::PlatformFileError error,
27 const FilePath& file_path)> SetMountedStateCallback;
28
[email protected]73f9c742012-06-15 07:37:1329// Callback for completion of cache operation.
30typedef base::Callback<void(base::PlatformFileError error,
31 const std::string& resource_id,
32 const std::string& md5)> CacheOperationCallback;
33
[email protected]c960d222012-06-15 10:03:5034// Callback for GetFileFromCache.
35typedef base::Callback<void(base::PlatformFileError error,
36 const std::string& resource_id,
37 const std::string& md5,
38 const FilePath& cache_file_path)>
39 GetFileFromCacheCallback;
40
[email protected]6b70c7b2012-06-14 03:10:4341// GDataCache is used to maintain cache states of GDataFileSystem.
42//
43// All non-static public member functions, unless mentioned otherwise (see
44// GetCacheFilePath() for example), should be called from the sequenced
[email protected]73f9c742012-06-15 07:37:1345// worker pool with the sequence token set by CreateGDataCacheOnUIThread(). This
[email protected]6b70c7b2012-06-14 03:10:4346// threading model is enforced by AssertOnSequencedWorkerPool().
[email protected]73f9c742012-06-15 07:37:1347//
48// TODO(hashimoto): Change threading model of this class to make public methods
49// being called on UI thread unless mentioned otherwise. crbug.com/132926
[email protected]3653146a2012-05-29 13:41:4750class GDataCache {
51 public:
52 // Enum defining GCache subdirectory location.
[email protected]6b70c7b2012-06-14 03:10:4353 // This indexes into |GDataCache::cache_paths_| vector.
[email protected]3653146a2012-05-29 13:41:4754 enum CacheSubDirectoryType {
55 CACHE_TYPE_META = 0, // Downloaded feeds.
56 CACHE_TYPE_PINNED, // Symlinks to files in persistent dir that are
57 // pinned, or to /dev/null for non-existent
58 // files.
59 CACHE_TYPE_OUTGOING, // Symlinks to files in persistent or tmp dir to
60 // be uploaded.
61 CACHE_TYPE_PERSISTENT, // Files that are pinned or modified locally,
62 // not evictable, hopefully.
63 CACHE_TYPE_TMP, // Files that don't meet criteria to be in
64 // persistent dir, and hence evictable.
65 CACHE_TYPE_TMP_DOWNLOADS, // Downloaded files.
66 CACHE_TYPE_TMP_DOCUMENTS, // Temporary JSON files for hosted documents.
67 NUM_CACHE_TYPES, // This must be at the end.
68 };
69
70 // This is used as a bitmask for the cache state.
71 enum CacheState {
72 CACHE_STATE_NONE = 0x0,
73 CACHE_STATE_PINNED = 0x1 << 0,
74 CACHE_STATE_PRESENT = 0x1 << 1,
75 CACHE_STATE_DIRTY = 0x1 << 2,
76 CACHE_STATE_MOUNTED = 0x1 << 3,
77 };
78
[email protected]32a7fc852012-06-08 17:25:5079 // Enum defining origin of a cached file.
80 enum CachedFileOrigin {
81 CACHED_FILE_FROM_SERVER = 0,
82 CACHED_FILE_LOCALLY_MODIFIED,
83 CACHED_FILE_MOUNTED,
84 };
85
[email protected]a321b9632012-06-14 03:29:1786 // Enum defining type of file operation e.g. copy or move, etc.
87 enum FileOperationType {
88 FILE_OPERATION_MOVE = 0,
89 FILE_OPERATION_COPY,
90 };
[email protected]32a7fc852012-06-08 17:25:5091
[email protected]73f9c742012-06-15 07:37:1392 // Used to notify events. All events are notified on UI thread.
93 class Observer {
94 public:
95 // Triggered when the cache has been initialized.
96 virtual void OnCacheInitialized() {}
97
98 // Triggered when a file has been pinned successfully.
99 virtual void OnCachePinned(const std::string& resource_id,
100 const std::string& md5) {}
101
102 // Triggered when a file has been unpinned successfully.
103 virtual void OnCacheUnpinned(const std::string& resource_id,
104 const std::string& md5) {}
105
[email protected]d7664c22012-06-18 19:35:49106 // Triggered when a dirty file has been committed (saved) successfully.
107 virtual void OnCacheCommitted(const std::string& resource_id) {}
108
[email protected]73f9c742012-06-15 07:37:13109 protected:
110 virtual ~Observer() {}
111 };
112
[email protected]3653146a2012-05-29 13:41:47113 // Structure to store information of an existing cache file.
114 struct CacheEntry {
[email protected]1ecd66312012-06-14 05:26:59115 CacheEntry() : sub_dir_type(CACHE_TYPE_META),
116 cache_state(0) {}
117
[email protected]3653146a2012-05-29 13:41:47118 CacheEntry(const std::string& md5,
[email protected]a321b9632012-06-14 03:29:17119 CacheSubDirectoryType sub_dir_type,
120 int cache_state)
[email protected]3653146a2012-05-29 13:41:47121 : md5(md5),
122 sub_dir_type(sub_dir_type),
123 cache_state(cache_state) {
124 }
125
126 bool IsPresent() const { return IsCachePresent(cache_state); }
127 bool IsPinned() const { return IsCachePinned(cache_state); }
128 bool IsDirty() const { return IsCacheDirty(cache_state); }
129 bool IsMounted() const { return IsCacheMounted(cache_state); }
130
131 // For debugging purposes.
132 std::string ToString() const;
133
134 std::string md5;
135 CacheSubDirectoryType sub_dir_type;
136 int cache_state;
137 };
138
139 static bool IsCachePresent(int cache_state) {
140 return cache_state & CACHE_STATE_PRESENT;
141 }
142 static bool IsCachePinned(int cache_state) {
143 return cache_state & CACHE_STATE_PINNED;
144 }
145 static bool IsCacheDirty(int cache_state) {
146 return cache_state & CACHE_STATE_DIRTY;
147 }
148 static bool IsCacheMounted(int cache_state) {
149 return cache_state & CACHE_STATE_MOUNTED;
150 }
151 static int SetCachePresent(int cache_state) {
152 return cache_state |= CACHE_STATE_PRESENT;
153 }
154 static int SetCachePinned(int cache_state) {
155 return cache_state |= CACHE_STATE_PINNED;
156 }
157 static int SetCacheDirty(int cache_state) {
158 return cache_state |= CACHE_STATE_DIRTY;
159 }
160 static int SetCacheMounted(int cache_state) {
161 return cache_state |= CACHE_STATE_MOUNTED;
162 }
163 static int ClearCachePresent(int cache_state) {
164 return cache_state &= ~CACHE_STATE_PRESENT;
165 }
166 static int ClearCachePinned(int cache_state) {
167 return cache_state &= ~CACHE_STATE_PINNED;
168 }
169 static int ClearCacheDirty(int cache_state) {
170 return cache_state &= ~CACHE_STATE_DIRTY;
171 }
172 static int ClearCacheMounted(int cache_state) {
173 return cache_state &= ~CACHE_STATE_MOUNTED;
174 }
175
[email protected]32a7fc852012-06-08 17:25:50176 // Returns the sub-directory under gdata cache directory for the given sub
177 // directory type. Example: <user_profile_dir>/GCache/v1/tmp
[email protected]6b70c7b2012-06-14 03:10:43178 //
179 // Can be called on any thread.
[email protected]32a7fc852012-06-08 17:25:50180 FilePath GetCacheDirectoryPath(CacheSubDirectoryType sub_dir_type) const;
181
182 // Returns absolute path of the file if it were cached or to be cached.
[email protected]6b70c7b2012-06-14 03:10:43183 //
184 // Can be called on any thread.
[email protected]32a7fc852012-06-08 17:25:50185 FilePath GetCacheFilePath(const std::string& resource_id,
186 const std::string& md5,
187 CacheSubDirectoryType sub_dir_type,
188 CachedFileOrigin file_orign) const;
189
[email protected]01ba15f72012-06-09 00:41:05190 // Returns true if the given path is under gdata cache directory, i.e.
191 // <user_profile_dir>/GCache/v1
[email protected]6b70c7b2012-06-14 03:10:43192 //
193 // Can be called on any thread.
[email protected]01ba15f72012-06-09 00:41:05194 bool IsUnderGDataCacheDirectory(const FilePath& path) const;
195
[email protected]73f9c742012-06-15 07:37:13196 // Adds observer.
197 // Must be called on UI thread.
198 void AddObserver(Observer* observer);
199
200 // Removes observer.
201 // Must be called on UI thread.
202 void RemoveObserver(Observer* observer);
203
[email protected]a321b9632012-06-14 03:29:17204 // Frees up disk space to store the given number of bytes, while keeping
205 // kMinFreSpace bytes on the disk, if needed. |has_enough_space| is
206 // updated to indicate if we have enough space.
207 void FreeDiskSpaceIfNeededFor(int64 num_bytes,
208 bool* has_enough_space);
209
210 // Checks if file corresponding to |resource_id| and |md5| exists in cache.
[email protected]c960d222012-06-15 10:03:50211 void GetFileOnUIThread(const std::string& resource_id,
212 const std::string& md5,
213 const GetFileFromCacheCallback& callback);
[email protected]a321b9632012-06-14 03:29:17214
215 // Modifies cache state, which involves the following:
216 // - moves or copies (per |file_operation_type|) |source_path|
217 // to |dest_path| in the cache dir
218 // - if necessary, creates symlink
219 // - deletes stale cached versions of |resource_id| in
220 // |dest_path|'s directory.
[email protected]73f9c742012-06-15 07:37:13221 void StoreOnUIThread(const std::string& resource_id,
222 const std::string& md5,
223 const FilePath& source_path,
224 FileOperationType file_operation_type,
225 const CacheOperationCallback& callback);
[email protected]a321b9632012-06-14 03:29:17226
227 // Modifies cache state, which involves the following:
228 // - moves |source_path| to |dest_path| in persistent dir if
229 // file is not dirty
230 // - creates symlink in pinned dir that references downloaded or locally
231 // modified file
[email protected]73f9c742012-06-15 07:37:13232 void PinOnUIThread(const std::string& resource_id,
233 const std::string& md5,
234 const CacheOperationCallback& callback);
[email protected]a321b9632012-06-14 03:29:17235
236 // Modifies cache state, which involves the following:
237 // - moves |source_path| to |dest_path| in tmp dir if file is not dirty
238 // - deletes symlink from pinned dir
[email protected]73f9c742012-06-15 07:37:13239 void UnpinOnUIThread(const std::string& resource_id,
240 const std::string& md5,
241 const CacheOperationCallback& callback);
[email protected]7986b8d2012-06-14 15:05:14242
[email protected]a321b9632012-06-14 03:29:17243 // Modifies cache state, which involves the following:
244 // - moves |source_path| to |dest_path|, where
245 // if we're mounting: |source_path| is the unmounted path and has .<md5>
246 // extension, and |dest_path| is the mounted path in persistent dir
247 // and has .<md5>.mounted extension;
248 // if we're unmounting: the opposite is true for the two paths, i.e.
249 // |dest_path| is the mounted path and |source_path| the unmounted path.
[email protected]73f9c742012-06-15 07:37:13250 void SetMountedStateOnUIThread(const FilePath& file_path,
251 bool to_mount,
252 const SetMountedStateCallback& callback);
[email protected]a321b9632012-06-14 03:29:17253
254 // Modifies cache state, which involves the following:
255 // - moves |source_path| to |dest_path| in persistent dir, where
256 // |source_path| has .<md5> extension and |dest_path| has .local extension
257 // - if file is pinned, updates symlink in pinned dir to reference dirty file
[email protected]c960d222012-06-15 10:03:50258 void MarkDirtyOnUIThread(const std::string& resource_id,
259 const std::string& md5,
260 const GetFileFromCacheCallback& callback);
[email protected]a321b9632012-06-14 03:29:17261
262 // Modifies cache state, i.e. creates symlink in outgoing
263 // dir to reference dirty file in persistent dir.
[email protected]73f9c742012-06-15 07:37:13264 void CommitDirtyOnUIThread(const std::string& resource_id,
265 const std::string& md5,
266 const CacheOperationCallback& callback);
[email protected]a321b9632012-06-14 03:29:17267
268 // Modifies cache state, which involves the following:
269 // - moves |source_path| to |dest_path| in persistent dir if
270 // file is pinned or tmp dir otherwise, where |source_path| has .local
271 // extension and |dest_path| has .<md5> extension
272 // - deletes symlink in outgoing dir
273 // - if file is pinned, updates symlink in pinned dir to reference
274 // |dest_path|
[email protected]73f9c742012-06-15 07:37:13275 void ClearDirtyOnUIThread(const std::string& resource_id,
276 const std::string& md5,
277 const CacheOperationCallback& callback);
[email protected]a321b9632012-06-14 03:29:17278
279 // Does the following:
280 // - remove all delete stale cache versions corresponding to |resource_id| in
281 // persistent, tmp and pinned directories
282 // - remove entry corresponding to |resource_id| from cache map.
[email protected]73f9c742012-06-15 07:37:13283 void RemoveOnUIThread(const std::string& resource_id,
284 const CacheOperationCallback& callback);
[email protected]a321b9632012-06-14 03:29:17285
[email protected]73f9c742012-06-15 07:37:13286 // Utility method to call Initialize on UI thread.
287 void RequestInitializeOnUIThread();
288
[email protected]3653146a2012-05-29 13:41:47289 // Returns the cache entry for file corresponding to |resource_id| and |md5|
290 // if entry exists in cache map. Otherwise, returns NULL.
291 // |md5| can be empty if only matching |resource_id| is desired, which may
292 // happen when looking for pinned entries where symlinks' filenames have no
293 // extension and hence no md5.
[email protected]ca5f6da2012-06-18 12:54:59294 scoped_ptr<CacheEntry> GetCacheEntry(const std::string& resource_id,
295 const std::string& md5);
[email protected]3653146a2012-05-29 13:41:47296
297 // Factory methods for GDataCache.
[email protected]fcc92a52012-06-08 22:54:16298 // |pool| and |sequence_token| are used to assert that the functions are
299 // called on the right sequenced worker pool with the right sequence token.
300 //
301 // For testing, the thread assertion can be disabled by passing NULL and
302 // the default value of SequenceToken.
[email protected]73f9c742012-06-15 07:37:13303 static GDataCache* CreateGDataCacheOnUIThread(
[email protected]fcc92a52012-06-08 22:54:16304 const FilePath& cache_root_path,
305 base::SequencedWorkerPool* pool,
306 const base::SequencedWorkerPool::SequenceToken& sequence_token);
[email protected]3653146a2012-05-29 13:41:47307
[email protected]73f9c742012-06-15 07:37:13308 // Deletes the cache.
309 void DestroyOnUIThread();
310
[email protected]01ba15f72012-06-09 00:41:05311 // Gets the cache root path (i.e. <user_profile_dir>/GCache/v1) from the
312 // profile.
313 // TODO(satorux): Write a unit test for this.
314 static FilePath GetCacheRootPath(Profile* profile);
315
[email protected]ca5f6da2012-06-18 12:54:59316 private:
[email protected]fcc92a52012-06-08 22:54:16317 GDataCache(
318 const FilePath& cache_root_path,
319 base::SequencedWorkerPool* pool_,
320 const base::SequencedWorkerPool::SequenceToken& sequence_token);
[email protected]73f9c742012-06-15 07:37:13321 virtual ~GDataCache();
[email protected]fcc92a52012-06-08 22:54:16322
323 // Checks whether the current thread is on the right sequenced worker pool
324 // with the right sequence ID. If not, DCHECK will fail.
325 void AssertOnSequencedWorkerPool();
[email protected]3653146a2012-05-29 13:41:47326
[email protected]ca5f6da2012-06-18 12:54:59327 // Initializes the cache.
328 void Initialize();
[email protected]73f9c742012-06-15 07:37:13329
330 // Deletes the cache.
331 void Destroy();
332
[email protected]c960d222012-06-15 10:03:50333 // Used to implement GetFileOnUIThread.
334 void GetFile(const std::string& resource_id,
335 const std::string& md5,
336 base::PlatformFileError* error,
337 FilePath* cache_file_path);
338
[email protected]73f9c742012-06-15 07:37:13339 // Used to implement StoreOnUIThread.
340 void Store(const std::string& resource_id,
341 const std::string& md5,
342 const FilePath& source_path,
343 FileOperationType file_operation_type,
344 base::PlatformFileError* error);
345
346 // Used to implement PinOnUIThread.
347 void Pin(const std::string& resource_id,
348 const std::string& md5,
349 FileOperationType file_operation_type,
350 base::PlatformFileError* error);
351
352 // Used to implement UnpinOnUIThread.
353 void Unpin(const std::string& resource_id,
354 const std::string& md5,
355 FileOperationType file_operation_type,
356 base::PlatformFileError* error);
357
358 // Used to implement SetMountedStateOnUIThread.
359 void SetMountedState(const FilePath& file_path,
360 bool to_mount,
361 base::PlatformFileError* error,
362 FilePath* cache_file_path);
363
[email protected]c960d222012-06-15 10:03:50364 // Used to implement MarkDirtyOnUIThread.
365 void MarkDirty(const std::string& resource_id,
366 const std::string& md5,
367 FileOperationType file_operation_type,
368 base::PlatformFileError* error,
369 FilePath* cache_file_path);
370
[email protected]73f9c742012-06-15 07:37:13371 // Used to implement CommitDirtyOnUIThread.
372 void CommitDirty(const std::string& resource_id,
373 const std::string& md5,
374 FileOperationType file_operation_type,
375 base::PlatformFileError* error);
376
377 // Used to implement ClearDirtyOnUIThread.
378 void ClearDirty(const std::string& resource_id,
379 const std::string& md5,
380 FileOperationType file_operation_type,
381 base::PlatformFileError* error);
382
383 // Used to implement RemoveOnUIThread.
384 void Remove(const std::string& resource_id,
385 base::PlatformFileError* error);
386
387 // Notifies the observers when cache is initialized.
388 void OnInitialized();
389
390 // Runs callback and notifies the observers when file is pinned.
391 void OnPinned(base::PlatformFileError* error,
392 const std::string& resource_id,
393 const std::string& md5,
394 const CacheOperationCallback& callback);
395
396 // Runs callback and notifies the observers when file is unpinned.
397 void OnUnpinned(base::PlatformFileError* error,
398 const std::string& resource_id,
399 const std::string& md5,
400 const CacheOperationCallback& callback);
401
[email protected]d7664c22012-06-18 19:35:49402 // Runs callback and notifies the observers when file is committed.
403 void OnCommitDirty(base::PlatformFileError* error,
404 const std::string& resource_id,
405 const std::string& md5,
406 const CacheOperationCallback& callback);
407
[email protected]01ba15f72012-06-09 00:41:05408 // The root directory of the cache (i.e. <user_profile_dir>/GCache/v1).
409 const FilePath cache_root_path_;
[email protected]32a7fc852012-06-08 17:25:50410 // Paths for all subdirectories of GCache, one for each
411 // GDataCache::CacheSubDirectoryType enum.
[email protected]6b70c7b2012-06-14 03:10:43412 const std::vector<FilePath> cache_paths_;
[email protected]fcc92a52012-06-08 22:54:16413 base::SequencedWorkerPool* pool_;
414 const base::SequencedWorkerPool::SequenceToken sequence_token_;
[email protected]32a7fc852012-06-08 17:25:50415
[email protected]ca5f6da2012-06-18 12:54:59416 // The cache state data. This member must be access only on the blocking pool.
417 scoped_ptr<GDataCacheMetadata> metadata_;
418
[email protected]73f9c742012-06-15 07:37:13419 // WeakPtrFactory and WeakPtr bound to the UI thread.
420 base::WeakPtrFactory<GDataCache> ui_weak_ptr_factory_;
421 base::WeakPtr<GDataCache> ui_weak_ptr_;
422
423 // List of observers, this member must be accessed on UI thread.
424 ObserverList<Observer> observers_;
425
[email protected]3653146a2012-05-29 13:41:47426 DISALLOW_COPY_AND_ASSIGN(GDataCache);
427};
428
[email protected]a321b9632012-06-14 03:29:17429
430// The minimum free space to keep. GDataFileSystem::GetFileByPath() returns
431// base::PLATFORM_FILE_ERROR_NO_SPACE if the available space is smaller than
432// this value.
433//
434// Copied from cryptohome/homedirs.h.
435// TODO(satorux): Share the constant.
436const int64 kMinFreeSpace = 512 * 1LL << 20;
437
438// Interface class used for getting the free disk space. Only for testing.
439class FreeDiskSpaceGetterInterface {
440 public:
441 virtual ~FreeDiskSpaceGetterInterface() {}
442 virtual int64 AmountOfFreeDiskSpace() const = 0;
443};
444
445// Sets the free disk space getter for testing.
446// The existing getter is deleted.
447void SetFreeDiskSpaceGetterForTesting(
448 FreeDiskSpaceGetterInterface* getter);
449
[email protected]3653146a2012-05-29 13:41:47450} // namespace gdata
451
452#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_CACHE_H_