OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/drive/file_cache.h" | 5 #include "chrome/browser/chromeos/drive/file_cache.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "base/sys_info.h" | 14 #include "base/sys_info.h" |
15 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
16 #include "chrome/browser/chromeos/drive/drive.pb.h" | 16 #include "chrome/browser/chromeos/drive/drive.pb.h" |
17 #include "chrome/browser/chromeos/drive/file_cache_metadata.h" | 17 #include "chrome/browser/chromeos/drive/file_cache_metadata.h" |
18 #include "chrome/browser/chromeos/drive/file_system_util.h" | 18 #include "chrome/browser/chromeos/drive/file_system_util.h" |
| 19 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h" |
19 #include "chrome/browser/google_apis/task_util.h" | 20 #include "chrome/browser/google_apis/task_util.h" |
20 #include "chromeos/chromeos_constants.h" | 21 #include "chromeos/chromeos_constants.h" |
21 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
22 | 23 |
23 using content::BrowserThread; | 24 using content::BrowserThread; |
24 | 25 |
25 namespace drive { | 26 namespace drive { |
26 namespace internal { | 27 namespace internal { |
27 namespace { | 28 namespace { |
28 | 29 |
29 // Name of the cache metadata DB. | |
30 const base::FilePath::CharType* kCacheMetadataDBName = | |
31 FILE_PATH_LITERAL("cache_metadata.db"); | |
32 | |
33 typedef std::map<std::string, FileCacheEntry> CacheMap; | 30 typedef std::map<std::string, FileCacheEntry> CacheMap; |
34 | 31 |
35 // Returns true if |md5| matches the one in |cache_entry| with some | 32 // Returns true if |md5| matches the one in |cache_entry| with some |
36 // exceptions. See the function definition for details. | 33 // exceptions. See the function definition for details. |
37 bool CheckIfMd5Matches(const std::string& md5, | 34 bool CheckIfMd5Matches(const std::string& md5, |
38 const FileCacheEntry& cache_entry) { | 35 const FileCacheEntry& cache_entry) { |
39 if (cache_entry.is_dirty()) { | 36 if (cache_entry.is_dirty()) { |
40 // If the entry is dirty, its MD5 may have been replaced by "local" | 37 // If the entry is dirty, its MD5 may have been replaced by "local" |
41 // during cache initialization, so we don't compare MD5. | 38 // during cache initialization, so we don't compare MD5. |
42 return true; | 39 return true; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback, | 149 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback, |
153 FileCacheEntry* cache_entry, | 150 FileCacheEntry* cache_entry, |
154 bool success) { | 151 bool success) { |
155 DCHECK(cache_entry); | 152 DCHECK(cache_entry); |
156 DCHECK(!callback.is_null()); | 153 DCHECK(!callback.is_null()); |
157 callback.Run(success, *cache_entry); | 154 callback.Run(success, *cache_entry); |
158 } | 155 } |
159 | 156 |
160 } // namespace | 157 } // namespace |
161 | 158 |
162 FileCache::FileCache(const base::FilePath& metadata_directory, | 159 const base::FilePath::CharType FileCache::kOldCacheMetadataDBName[] = |
| 160 FILE_PATH_LITERAL("cache_metadata.db"); |
| 161 |
| 162 FileCache::FileCache(ResourceMetadataStorage* storage, |
163 const base::FilePath& cache_file_directory, | 163 const base::FilePath& cache_file_directory, |
164 base::SequencedTaskRunner* blocking_task_runner, | 164 base::SequencedTaskRunner* blocking_task_runner, |
165 FreeDiskSpaceGetterInterface* free_disk_space_getter) | 165 FreeDiskSpaceGetterInterface* free_disk_space_getter) |
166 : metadata_directory_(metadata_directory), | 166 : cache_file_directory_(cache_file_directory), |
167 cache_file_directory_(cache_file_directory), | |
168 blocking_task_runner_(blocking_task_runner), | 167 blocking_task_runner_(blocking_task_runner), |
| 168 storage_(storage), |
169 free_disk_space_getter_(free_disk_space_getter), | 169 free_disk_space_getter_(free_disk_space_getter), |
170 weak_ptr_factory_(this) { | 170 weak_ptr_factory_(this) { |
171 DCHECK(blocking_task_runner_.get()); | 171 DCHECK(blocking_task_runner_.get()); |
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
173 } | 173 } |
174 | 174 |
175 FileCache::~FileCache() { | 175 FileCache::~FileCache() { |
176 // Must be on the sequenced worker pool, as |metadata_| must be deleted on | 176 // Must be on the sequenced worker pool, as |metadata_| must be deleted on |
177 // the sequenced worker pool. | 177 // the sequenced worker pool. |
178 AssertOnSequencedWorkerPool(); | 178 AssertOnSequencedWorkerPool(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 cache_entry), | 222 cache_entry), |
223 base::Bind( | 223 base::Bind( |
224 &RunGetCacheEntryCallback, callback, base::Owned(cache_entry))); | 224 &RunGetCacheEntryCallback, callback, base::Owned(cache_entry))); |
225 } | 225 } |
226 | 226 |
227 bool FileCache::GetCacheEntry(const std::string& resource_id, | 227 bool FileCache::GetCacheEntry(const std::string& resource_id, |
228 const std::string& md5, | 228 const std::string& md5, |
229 FileCacheEntry* entry) { | 229 FileCacheEntry* entry) { |
230 DCHECK(entry); | 230 DCHECK(entry); |
231 AssertOnSequencedWorkerPool(); | 231 AssertOnSequencedWorkerPool(); |
232 return metadata_->GetCacheEntry(resource_id, entry) && | 232 return storage_->GetCacheEntry(resource_id, entry) && |
233 CheckIfMd5Matches(md5, *entry); | 233 CheckIfMd5Matches(md5, *entry); |
234 } | 234 } |
235 | 235 |
236 void FileCache::IterateOnUIThread( | 236 void FileCache::IterateOnUIThread( |
237 const CacheIterateCallback& iteration_callback, | 237 const CacheIterateCallback& iteration_callback, |
238 const base::Closure& completion_callback) { | 238 const base::Closure& completion_callback) { |
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
240 DCHECK(!iteration_callback.is_null()); | 240 DCHECK(!iteration_callback.is_null()); |
241 DCHECK(!completion_callback.is_null()); | 241 DCHECK(!completion_callback.is_null()); |
242 | 242 |
243 blocking_task_runner_->PostTaskAndReply( | 243 blocking_task_runner_->PostTaskAndReply( |
244 FROM_HERE, | 244 FROM_HERE, |
245 base::Bind(&FileCache::Iterate, | 245 base::Bind(&FileCache::Iterate, |
246 base::Unretained(this), | 246 base::Unretained(this), |
247 google_apis::CreateRelayCallback(iteration_callback)), | 247 google_apis::CreateRelayCallback(iteration_callback)), |
248 completion_callback); | 248 completion_callback); |
249 } | 249 } |
250 | 250 |
251 void FileCache::Iterate(const CacheIterateCallback& iteration_callback) { | 251 void FileCache::Iterate(const CacheIterateCallback& iteration_callback) { |
252 AssertOnSequencedWorkerPool(); | 252 AssertOnSequencedWorkerPool(); |
253 DCHECK(!iteration_callback.is_null()); | 253 DCHECK(!iteration_callback.is_null()); |
254 | 254 |
255 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 255 scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it = |
| 256 storage_->GetCacheEntryIterator(); |
256 for (; !it->IsAtEnd(); it->Advance()) | 257 for (; !it->IsAtEnd(); it->Advance()) |
257 iteration_callback.Run(it->GetKey(), it->GetValue()); | 258 iteration_callback.Run(it->GetID(), it->GetValue()); |
258 DCHECK(!it->HasError()); | 259 DCHECK(!it->HasError()); |
259 } | 260 } |
260 | 261 |
261 void FileCache::FreeDiskSpaceIfNeededForOnUIThread( | 262 void FileCache::FreeDiskSpaceIfNeededForOnUIThread( |
262 int64 num_bytes, | 263 int64 num_bytes, |
263 const InitializeCacheCallback& callback) { | 264 const InitializeCacheCallback& callback) { |
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
265 DCHECK(!callback.is_null()); | 266 DCHECK(!callback.is_null()); |
266 | 267 |
267 base::PostTaskAndReplyWithResult( | 268 base::PostTaskAndReplyWithResult( |
268 blocking_task_runner_.get(), | 269 blocking_task_runner_.get(), |
269 FROM_HERE, | 270 FROM_HERE, |
270 base::Bind(&FileCache::FreeDiskSpaceIfNeededFor, | 271 base::Bind(&FileCache::FreeDiskSpaceIfNeededFor, |
271 base::Unretained(this), | 272 base::Unretained(this), |
272 num_bytes), | 273 num_bytes), |
273 callback); | 274 callback); |
274 } | 275 } |
275 | 276 |
276 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { | 277 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { |
277 AssertOnSequencedWorkerPool(); | 278 AssertOnSequencedWorkerPool(); |
278 | 279 |
279 // Do nothing and return if we have enough space. | 280 // Do nothing and return if we have enough space. |
280 if (HasEnoughSpaceFor(num_bytes, cache_file_directory_)) | 281 if (HasEnoughSpaceFor(num_bytes, cache_file_directory_)) |
281 return true; | 282 return true; |
282 | 283 |
283 // Otherwise, try to free up the disk space. | 284 // Otherwise, try to free up the disk space. |
284 DVLOG(1) << "Freeing up disk space for " << num_bytes; | 285 DVLOG(1) << "Freeing up disk space for " << num_bytes; |
285 | 286 |
286 // Remove all entries unless specially marked. | 287 // Remove all entries unless specially marked. |
287 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 288 scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it = |
| 289 storage_->GetCacheEntryIterator(); |
288 for (; !it->IsAtEnd(); it->Advance()) { | 290 for (; !it->IsAtEnd(); it->Advance()) { |
289 const FileCacheEntry& entry = it->GetValue(); | 291 const FileCacheEntry& entry = it->GetValue(); |
290 if (!entry.is_pinned() && | 292 if (!entry.is_pinned() && |
291 !entry.is_dirty() && | 293 !entry.is_dirty() && |
292 !mounted_files_.count(it->GetKey())) | 294 !mounted_files_.count(it->GetID())) |
293 metadata_->RemoveCacheEntry(it->GetKey()); | 295 storage_->RemoveCacheEntry(it->GetID()); |
294 } | 296 } |
295 DCHECK(!it->HasError()); | 297 DCHECK(!it->HasError()); |
296 | 298 |
297 // Remove all files which have no corresponding cache entries. | 299 // Remove all files which have no corresponding cache entries. |
298 base::FileEnumerator enumerator(cache_file_directory_, | 300 base::FileEnumerator enumerator(cache_file_directory_, |
299 false, // not recursive | 301 false, // not recursive |
300 base::FileEnumerator::FILES); | 302 base::FileEnumerator::FILES); |
301 std::string resource_id; | 303 std::string resource_id; |
302 std::string md5; | 304 std::string md5; |
303 FileCacheEntry entry; | 305 FileCacheEntry entry; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 blocking_task_runner_.get(), | 387 blocking_task_runner_.get(), |
386 FROM_HERE, | 388 FROM_HERE, |
387 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id), | 389 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id), |
388 callback); | 390 callback); |
389 } | 391 } |
390 | 392 |
391 FileError FileCache::Pin(const std::string& resource_id) { | 393 FileError FileCache::Pin(const std::string& resource_id) { |
392 AssertOnSequencedWorkerPool(); | 394 AssertOnSequencedWorkerPool(); |
393 | 395 |
394 FileCacheEntry cache_entry; | 396 FileCacheEntry cache_entry; |
395 metadata_->GetCacheEntry(resource_id, &cache_entry); | 397 storage_->GetCacheEntry(resource_id, &cache_entry); |
396 cache_entry.set_is_pinned(true); | 398 cache_entry.set_is_pinned(true); |
397 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 399 storage_->PutCacheEntry(resource_id, cache_entry); |
398 return FILE_ERROR_OK; | 400 return FILE_ERROR_OK; |
399 } | 401 } |
400 | 402 |
401 void FileCache::UnpinOnUIThread(const std::string& resource_id, | 403 void FileCache::UnpinOnUIThread(const std::string& resource_id, |
402 const FileOperationCallback& callback) { | 404 const FileOperationCallback& callback) { |
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 405 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
404 DCHECK(!callback.is_null()); | 406 DCHECK(!callback.is_null()); |
405 | 407 |
406 base::PostTaskAndReplyWithResult( | 408 base::PostTaskAndReplyWithResult( |
407 blocking_task_runner_.get(), | 409 blocking_task_runner_.get(), |
408 FROM_HERE, | 410 FROM_HERE, |
409 base::Bind(&FileCache::Unpin, base::Unretained(this), resource_id), | 411 base::Bind(&FileCache::Unpin, base::Unretained(this), resource_id), |
410 callback); | 412 callback); |
411 } | 413 } |
412 | 414 |
413 FileError FileCache::Unpin(const std::string& resource_id) { | 415 FileError FileCache::Unpin(const std::string& resource_id) { |
414 AssertOnSequencedWorkerPool(); | 416 AssertOnSequencedWorkerPool(); |
415 | 417 |
416 // Unpinning a file means its entry must exist in cache. | 418 // Unpinning a file means its entry must exist in cache. |
417 FileCacheEntry cache_entry; | 419 FileCacheEntry cache_entry; |
418 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 420 if (!storage_->GetCacheEntry(resource_id, &cache_entry)) |
419 return FILE_ERROR_NOT_FOUND; | 421 return FILE_ERROR_NOT_FOUND; |
420 | 422 |
421 // Now that file operations have completed, update metadata. | 423 // Now that file operations have completed, update metadata. |
422 if (cache_entry.is_present()) { | 424 if (cache_entry.is_present()) { |
423 cache_entry.set_is_pinned(false); | 425 cache_entry.set_is_pinned(false); |
424 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 426 storage_->PutCacheEntry(resource_id, cache_entry); |
425 } else { | 427 } else { |
426 // Remove the existing entry if we are unpinning a non-present file. | 428 // Remove the existing entry if we are unpinning a non-present file. |
427 metadata_->RemoveCacheEntry(resource_id); | 429 storage_->RemoveCacheEntry(resource_id); |
428 } | 430 } |
429 | 431 |
430 // Now it's a chance to free up space if needed. | 432 // Now it's a chance to free up space if needed. |
431 FreeDiskSpaceIfNeededFor(0); | 433 FreeDiskSpaceIfNeededFor(0); |
432 | 434 |
433 return FILE_ERROR_OK; | 435 return FILE_ERROR_OK; |
434 } | 436 } |
435 | 437 |
436 void FileCache::MarkAsMountedOnUIThread( | 438 void FileCache::MarkAsMountedOnUIThread( |
437 const std::string& resource_id, | 439 const std::string& resource_id, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 AssertOnSequencedWorkerPool(); | 486 AssertOnSequencedWorkerPool(); |
485 | 487 |
486 // If file has already been marked dirty in previous instance of chrome, we | 488 // If file has already been marked dirty in previous instance of chrome, we |
487 // would have lost the md5 info during cache initialization, because the file | 489 // would have lost the md5 info during cache initialization, because the file |
488 // would have been renamed to .local extension. | 490 // would have been renamed to .local extension. |
489 // So, search for entry in cache without comparing md5. | 491 // So, search for entry in cache without comparing md5. |
490 | 492 |
491 // Marking a file dirty means its entry and actual file blob must exist in | 493 // Marking a file dirty means its entry and actual file blob must exist in |
492 // cache. | 494 // cache. |
493 FileCacheEntry cache_entry; | 495 FileCacheEntry cache_entry; |
494 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || | 496 if (!storage_->GetCacheEntry(resource_id, &cache_entry) || |
495 !cache_entry.is_present()) { | 497 !cache_entry.is_present()) { |
496 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" | 498 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" |
497 << resource_id | 499 << resource_id |
498 << ", md5=" << md5; | 500 << ", md5=" << md5; |
499 return FILE_ERROR_NOT_FOUND; | 501 return FILE_ERROR_NOT_FOUND; |
500 } | 502 } |
501 | 503 |
502 if (cache_entry.is_dirty()) | 504 if (cache_entry.is_dirty()) |
503 return FILE_ERROR_OK; | 505 return FILE_ERROR_OK; |
504 | 506 |
505 // Get the current path of the file in cache. | 507 // Get the current path of the file in cache. |
506 base::FilePath source_path = GetCacheFilePath(resource_id, md5, | 508 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
507 CACHED_FILE_FROM_SERVER); | 509 CACHED_FILE_FROM_SERVER); |
508 // Determine destination path. | 510 // Determine destination path. |
509 base::FilePath cache_file_path = GetCacheFilePath( | 511 base::FilePath cache_file_path = GetCacheFilePath( |
510 resource_id, md5, CACHED_FILE_LOCALLY_MODIFIED); | 512 resource_id, md5, CACHED_FILE_LOCALLY_MODIFIED); |
511 | 513 |
512 if (!MoveFile(source_path, cache_file_path)) | 514 if (!MoveFile(source_path, cache_file_path)) |
513 return FILE_ERROR_FAILED; | 515 return FILE_ERROR_FAILED; |
514 | 516 |
515 // Now that file operations have completed, update metadata. | 517 // Now that file operations have completed, update metadata. |
516 cache_entry.set_md5(md5); | 518 cache_entry.set_md5(md5); |
517 cache_entry.set_is_dirty(true); | 519 cache_entry.set_is_dirty(true); |
518 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 520 storage_->PutCacheEntry(resource_id, cache_entry); |
519 return FILE_ERROR_OK; | 521 return FILE_ERROR_OK; |
520 } | 522 } |
521 | 523 |
522 FileError FileCache::ClearDirty(const std::string& resource_id, | 524 FileError FileCache::ClearDirty(const std::string& resource_id, |
523 const std::string& md5) { | 525 const std::string& md5) { |
524 AssertOnSequencedWorkerPool(); | 526 AssertOnSequencedWorkerPool(); |
525 | 527 |
526 // |md5| is the new .<md5> extension to rename the file to. | 528 // |md5| is the new .<md5> extension to rename the file to. |
527 // So, search for entry in cache without comparing md5. | 529 // So, search for entry in cache without comparing md5. |
528 FileCacheEntry cache_entry; | 530 FileCacheEntry cache_entry; |
529 | 531 |
530 // Clearing a dirty file means its entry and actual file blob must exist in | 532 // Clearing a dirty file means its entry and actual file blob must exist in |
531 // cache. | 533 // cache. |
532 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || | 534 if (!storage_->GetCacheEntry(resource_id, &cache_entry) || |
533 !cache_entry.is_present()) { | 535 !cache_entry.is_present()) { |
534 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: " | 536 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: " |
535 << "res_id=" << resource_id | 537 << "res_id=" << resource_id |
536 << ", md5=" << md5; | 538 << ", md5=" << md5; |
537 return FILE_ERROR_NOT_FOUND; | 539 return FILE_ERROR_NOT_FOUND; |
538 } | 540 } |
539 | 541 |
540 // If a file is not dirty (it should have been marked dirty via | 542 // If a file is not dirty (it should have been marked dirty via |
541 // MarkDirtyInCache), clearing its dirty state is an invalid operation. | 543 // MarkDirtyInCache), clearing its dirty state is an invalid operation. |
542 if (!cache_entry.is_dirty()) { | 544 if (!cache_entry.is_dirty()) { |
543 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" | 545 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" |
544 << resource_id | 546 << resource_id |
545 << ", md5=" << md5; | 547 << ", md5=" << md5; |
546 return FILE_ERROR_INVALID_OPERATION; | 548 return FILE_ERROR_INVALID_OPERATION; |
547 } | 549 } |
548 | 550 |
549 base::FilePath source_path = GetCacheFilePath(resource_id, md5, | 551 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
550 CACHED_FILE_LOCALLY_MODIFIED); | 552 CACHED_FILE_LOCALLY_MODIFIED); |
551 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, | 553 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, |
552 CACHED_FILE_FROM_SERVER); | 554 CACHED_FILE_FROM_SERVER); |
553 if (!MoveFile(source_path, dest_path)) | 555 if (!MoveFile(source_path, dest_path)) |
554 return FILE_ERROR_FAILED; | 556 return FILE_ERROR_FAILED; |
555 | 557 |
556 // Now that file operations have completed, update metadata. | 558 // Now that file operations have completed, update metadata. |
557 cache_entry.set_md5(md5); | 559 cache_entry.set_md5(md5); |
558 cache_entry.set_is_dirty(false); | 560 cache_entry.set_is_dirty(false); |
559 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 561 storage_->PutCacheEntry(resource_id, cache_entry); |
560 return FILE_ERROR_OK; | 562 return FILE_ERROR_OK; |
561 } | 563 } |
562 | 564 |
563 void FileCache::RemoveOnUIThread(const std::string& resource_id, | 565 void FileCache::RemoveOnUIThread(const std::string& resource_id, |
564 const FileOperationCallback& callback) { | 566 const FileOperationCallback& callback) { |
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
566 DCHECK(!callback.is_null()); | 568 DCHECK(!callback.is_null()); |
567 | 569 |
568 base::PostTaskAndReplyWithResult( | 570 base::PostTaskAndReplyWithResult( |
569 blocking_task_runner_.get(), | 571 blocking_task_runner_.get(), |
570 FROM_HERE, | 572 FROM_HERE, |
571 base::Bind(&FileCache::Remove, base::Unretained(this), resource_id), | 573 base::Bind(&FileCache::Remove, base::Unretained(this), resource_id), |
572 callback); | 574 callback); |
573 } | 575 } |
574 | 576 |
575 FileError FileCache::Remove(const std::string& resource_id) { | 577 FileError FileCache::Remove(const std::string& resource_id) { |
576 AssertOnSequencedWorkerPool(); | 578 AssertOnSequencedWorkerPool(); |
577 | 579 |
578 // MD5 is not passed into RemoveCacheEntry because we would delete all | 580 // MD5 is not passed into RemoveCacheEntry because we would delete all |
579 // cache files corresponding to <resource_id> regardless of the md5. | 581 // cache files corresponding to <resource_id> regardless of the md5. |
580 // So, search for entry in cache without taking md5 into account. | 582 // So, search for entry in cache without taking md5 into account. |
581 FileCacheEntry cache_entry; | 583 FileCacheEntry cache_entry; |
582 | 584 |
583 // If entry doesn't exist, nothing to do. | 585 // If entry doesn't exist, nothing to do. |
584 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 586 if (!storage_->GetCacheEntry(resource_id, &cache_entry)) |
585 return FILE_ERROR_OK; | 587 return FILE_ERROR_OK; |
586 | 588 |
587 // Cannot delete a dirty or mounted file. | 589 // Cannot delete a dirty or mounted file. |
588 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) | 590 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) |
589 return FILE_ERROR_IN_USE; | 591 return FILE_ERROR_IN_USE; |
590 | 592 |
591 // Delete files that match "<resource_id>.*" unless modified locally. | 593 // Delete files that match "<resource_id>.*" unless modified locally. |
592 base::FilePath path_to_delete = GetCacheFilePath(resource_id, util::kWildCard, | 594 base::FilePath path_to_delete = GetCacheFilePath(resource_id, util::kWildCard, |
593 CACHED_FILE_FROM_SERVER); | 595 CACHED_FILE_FROM_SERVER); |
594 base::FilePath path_to_keep = GetCacheFilePath(resource_id, std::string(), | 596 base::FilePath path_to_keep = GetCacheFilePath(resource_id, std::string(), |
595 CACHED_FILE_LOCALLY_MODIFIED); | 597 CACHED_FILE_LOCALLY_MODIFIED); |
596 DeleteFilesSelectively(path_to_delete, path_to_keep); | 598 DeleteFilesSelectively(path_to_delete, path_to_keep); |
597 | 599 |
598 // Now that all file operations have completed, remove from metadata. | 600 // Now that all file operations have completed, remove from metadata. |
599 metadata_->RemoveCacheEntry(resource_id); | 601 storage_->RemoveCacheEntry(resource_id); |
600 | 602 |
601 return FILE_ERROR_OK; | 603 return FILE_ERROR_OK; |
602 } | 604 } |
603 | 605 |
604 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { | 606 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { |
605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
606 DCHECK(!callback.is_null()); | 608 DCHECK(!callback.is_null()); |
607 | 609 |
608 base::PostTaskAndReplyWithResult( | 610 base::PostTaskAndReplyWithResult( |
609 blocking_task_runner_.get(), | 611 blocking_task_runner_.get(), |
610 FROM_HERE, | 612 FROM_HERE, |
611 base::Bind(&FileCache::ClearAll, base::Unretained(this)), | 613 base::Bind(&FileCache::ClearAll, base::Unretained(this)), |
612 callback); | 614 callback); |
613 } | 615 } |
614 | 616 |
615 bool FileCache::Initialize() { | 617 bool FileCache::Initialize() { |
616 AssertOnSequencedWorkerPool(); | 618 AssertOnSequencedWorkerPool(); |
617 | 619 |
618 metadata_.reset(new FileCacheMetadata(blocking_task_runner_.get())); | 620 if (!ImportOldDB(storage_->directory_path().Append( |
619 | 621 kOldCacheMetadataDBName)) && |
620 const base::FilePath db_path = | 622 !storage_->opened_existing_db()) { |
621 metadata_directory_.Append(kCacheMetadataDBName); | 623 CacheMap cache_map; |
622 switch (metadata_->Initialize(db_path)) { | 624 ScanCacheDirectory(cache_file_directory_, &cache_map); |
623 case FileCacheMetadata::INITIALIZE_FAILED: | 625 for (CacheMap::const_iterator it = cache_map.begin(); |
624 return false; | 626 it != cache_map.end(); ++it) { |
625 | 627 storage_->PutCacheEntry(it->first, it->second); |
626 case FileCacheMetadata::INITIALIZE_OPENED: // Do nothing. | |
627 break; | |
628 | |
629 case FileCacheMetadata::INITIALIZE_CREATED: { | |
630 CacheMap cache_map; | |
631 ScanCacheDirectory(cache_file_directory_, &cache_map); | |
632 for (CacheMap::const_iterator it = cache_map.begin(); | |
633 it != cache_map.end(); ++it) { | |
634 metadata_->AddOrUpdateCacheEntry(it->first, it->second); | |
635 } | |
636 break; | |
637 } | 628 } |
638 } | 629 } |
639 return true; | 630 return true; |
640 } | 631 } |
641 | 632 |
642 void FileCache::Destroy() { | 633 void FileCache::Destroy() { |
643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
644 | 635 |
645 // Invalidate the weak pointer. | 636 // Invalidate the weak pointer. |
646 weak_ptr_factory_.InvalidateWeakPtrs(); | 637 weak_ptr_factory_.InvalidateWeakPtrs(); |
(...skipping 21 matching lines...) Expand all Loading... |
668 if (file_operation_type == FILE_OPERATION_COPY) { | 659 if (file_operation_type == FILE_OPERATION_COPY) { |
669 if (!file_util::GetFileSize(source_path, &file_size)) { | 660 if (!file_util::GetFileSize(source_path, &file_size)) { |
670 LOG(WARNING) << "Couldn't get file size for: " << source_path.value(); | 661 LOG(WARNING) << "Couldn't get file size for: " << source_path.value(); |
671 return FILE_ERROR_FAILED; | 662 return FILE_ERROR_FAILED; |
672 } | 663 } |
673 } | 664 } |
674 if (!FreeDiskSpaceIfNeededFor(file_size)) | 665 if (!FreeDiskSpaceIfNeededFor(file_size)) |
675 return FILE_ERROR_NO_SPACE; | 666 return FILE_ERROR_NO_SPACE; |
676 | 667 |
677 FileCacheEntry cache_entry; | 668 FileCacheEntry cache_entry; |
678 metadata_->GetCacheEntry(resource_id, &cache_entry); | 669 storage_->GetCacheEntry(resource_id, &cache_entry); |
679 | 670 |
680 // If file is dirty or mounted, return error. | 671 // If file is dirty or mounted, return error. |
681 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) | 672 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) |
682 return FILE_ERROR_IN_USE; | 673 return FILE_ERROR_IN_USE; |
683 | 674 |
684 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, | 675 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, |
685 CACHED_FILE_FROM_SERVER); | 676 CACHED_FILE_FROM_SERVER); |
686 bool success = false; | 677 bool success = false; |
687 switch (file_operation_type) { | 678 switch (file_operation_type) { |
688 case FILE_OPERATION_MOVE: | 679 case FILE_OPERATION_MOVE: |
(...skipping 26 matching lines...) Expand all Loading... |
715 } | 706 } |
716 | 707 |
717 // Delete files that match |stale_filenames_pattern| except for |dest_path|. | 708 // Delete files that match |stale_filenames_pattern| except for |dest_path|. |
718 DeleteFilesSelectively(stale_filenames_pattern, dest_path); | 709 DeleteFilesSelectively(stale_filenames_pattern, dest_path); |
719 | 710 |
720 if (success) { | 711 if (success) { |
721 // Now that file operations have completed, update metadata. | 712 // Now that file operations have completed, update metadata. |
722 cache_entry.set_md5(md5); | 713 cache_entry.set_md5(md5); |
723 cache_entry.set_is_present(true); | 714 cache_entry.set_is_present(true); |
724 cache_entry.set_is_dirty(false); | 715 cache_entry.set_is_dirty(false); |
725 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 716 storage_->PutCacheEntry(resource_id, cache_entry); |
726 } | 717 } |
727 | 718 |
728 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED; | 719 return success ? FILE_ERROR_OK : FILE_ERROR_FAILED; |
729 } | 720 } |
730 | 721 |
731 FileError FileCache::MarkAsMounted(const std::string& resource_id, | 722 FileError FileCache::MarkAsMounted(const std::string& resource_id, |
732 base::FilePath* cache_file_path) { | 723 base::FilePath* cache_file_path) { |
733 AssertOnSequencedWorkerPool(); | 724 AssertOnSequencedWorkerPool(); |
734 DCHECK(cache_file_path); | 725 DCHECK(cache_file_path); |
735 | 726 |
736 // Get cache entry associated with the resource_id and md5 | 727 // Get cache entry associated with the resource_id and md5 |
737 FileCacheEntry cache_entry; | 728 FileCacheEntry cache_entry; |
738 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 729 if (!storage_->GetCacheEntry(resource_id, &cache_entry)) |
739 return FILE_ERROR_NOT_FOUND; | 730 return FILE_ERROR_NOT_FOUND; |
740 | 731 |
741 if (mounted_files_.count(resource_id)) | 732 if (mounted_files_.count(resource_id)) |
742 return FILE_ERROR_INVALID_OPERATION; | 733 return FILE_ERROR_INVALID_OPERATION; |
743 | 734 |
744 // Ensure the file is readable to cros_disks. See crbug.com/236994. | 735 // Ensure the file is readable to cros_disks. See crbug.com/236994. |
745 base::FilePath path = GetCacheFilePath( | 736 base::FilePath path = GetCacheFilePath( |
746 resource_id, cache_entry.md5(), CACHED_FILE_FROM_SERVER); | 737 resource_id, cache_entry.md5(), CACHED_FILE_FROM_SERVER); |
747 file_util::SetPosixFilePermissions( | 738 file_util::SetPosixFilePermissions( |
748 path, | 739 path, |
(...skipping 27 matching lines...) Expand all Loading... |
776 return FILE_ERROR_INVALID_OPERATION; | 767 return FILE_ERROR_INVALID_OPERATION; |
777 | 768 |
778 mounted_files_.erase(it); | 769 mounted_files_.erase(it); |
779 return FILE_ERROR_OK; | 770 return FILE_ERROR_OK; |
780 } | 771 } |
781 | 772 |
782 bool FileCache::ClearAll() { | 773 bool FileCache::ClearAll() { |
783 AssertOnSequencedWorkerPool(); | 774 AssertOnSequencedWorkerPool(); |
784 | 775 |
785 // Remove entries on the metadata. | 776 // Remove entries on the metadata. |
786 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 777 scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it = |
| 778 storage_->GetCacheEntryIterator(); |
787 for (; !it->IsAtEnd(); it->Advance()) | 779 for (; !it->IsAtEnd(); it->Advance()) |
788 metadata_->RemoveCacheEntry(it->GetKey()); | 780 storage_->RemoveCacheEntry(it->GetID()); |
789 | 781 |
790 if (it->HasError()) | 782 if (it->HasError()) |
791 return false; | 783 return false; |
792 | 784 |
793 // Remove files. | 785 // Remove files. |
794 base::FileEnumerator enumerator(cache_file_directory_, | 786 base::FileEnumerator enumerator(cache_file_directory_, |
795 false, // not recursive | 787 false, // not recursive |
796 base::FileEnumerator::FILES); | 788 base::FileEnumerator::FILES); |
797 for (base::FilePath file = enumerator.Next(); !file.empty(); | 789 for (base::FilePath file = enumerator.Next(); !file.empty(); |
798 file = enumerator.Next()) | 790 file = enumerator.Next()) |
799 file_util::Delete(file, false /* recursive */); | 791 file_util::Delete(file, false /* recursive */); |
800 | 792 |
801 return true; | 793 return true; |
802 } | 794 } |
803 | 795 |
804 bool FileCache::HasEnoughSpaceFor(int64 num_bytes, | 796 bool FileCache::HasEnoughSpaceFor(int64 num_bytes, |
805 const base::FilePath& path) { | 797 const base::FilePath& path) { |
806 int64 free_space = 0; | 798 int64 free_space = 0; |
807 if (free_disk_space_getter_) | 799 if (free_disk_space_getter_) |
808 free_space = free_disk_space_getter_->AmountOfFreeDiskSpace(); | 800 free_space = free_disk_space_getter_->AmountOfFreeDiskSpace(); |
809 else | 801 else |
810 free_space = base::SysInfo::AmountOfFreeDiskSpace(path); | 802 free_space = base::SysInfo::AmountOfFreeDiskSpace(path); |
811 | 803 |
812 // Subtract this as if this portion does not exist. | 804 // Subtract this as if this portion does not exist. |
813 free_space -= kMinFreeSpace; | 805 free_space -= kMinFreeSpace; |
814 return (free_space >= num_bytes); | 806 return (free_space >= num_bytes); |
815 } | 807 } |
816 | 808 |
817 void FileCache::ImportOldDB(const base::FilePath& old_db_path) { | 809 bool FileCache::ImportOldDB(const base::FilePath& old_db_path) { |
818 if (!file_util::PathExists(old_db_path)) // Old DB is not there, do nothing. | 810 if (!file_util::PathExists(old_db_path)) // Old DB is not there, do nothing. |
819 return; | 811 return false; |
820 | 812 |
821 // Copy all entries stored in the old DB. | 813 // Copy all entries stored in the old DB. |
822 FileCacheMetadata old_data(blocking_task_runner_); | 814 bool imported = false; |
823 if (old_data.Initialize(old_db_path)) { | 815 { |
824 scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator(); | 816 FileCacheMetadata old_data(blocking_task_runner_); |
825 for (; !it->IsAtEnd(); it->Advance()) { | 817 if (old_data.Initialize(old_db_path) == |
826 FileCacheEntry entry; | 818 FileCacheMetadata::INITIALIZE_OPENED) { |
827 if (metadata_->GetCacheEntry(it->GetKey(), &entry)) | 819 scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator(); |
828 continue; // Do not overwrite. | 820 for (; !it->IsAtEnd(); it->Advance()) { |
| 821 FileCacheEntry entry; |
| 822 if (storage_->GetCacheEntry(it->GetKey(), &entry)) |
| 823 continue; // Do not overwrite. |
829 | 824 |
830 metadata_->AddOrUpdateCacheEntry(it->GetKey(), it->GetValue()); | 825 storage_->PutCacheEntry(it->GetKey(), it->GetValue()); |
| 826 } |
| 827 imported = true; |
831 } | 828 } |
832 } | 829 } |
833 | 830 |
834 // Delete old DB. | 831 // Delete old DB. |
835 file_util::Delete(old_db_path, true /* recursive */ ); | 832 file_util::Delete(old_db_path, true /* recursive */ ); |
| 833 return imported; |
836 } | 834 } |
837 | 835 |
838 } // namespace internal | 836 } // namespace internal |
839 } // namespace drive | 837 } // namespace drive |
OLD | NEW |