Chromium Code Reviews| 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 // Name of the cache metadata DB. |
| 30 const base::FilePath::CharType* kCacheMetadataDBName = | 31 const base::FilePath::CharType kCacheMetadataDBName[] = |
| 31 FILE_PATH_LITERAL("cache_metadata.db"); | 32 FILE_PATH_LITERAL("cache_metadata.db"); |
| 32 | 33 |
| 33 typedef std::map<std::string, FileCacheEntry> CacheMap; | 34 typedef std::map<std::string, FileCacheEntry> CacheMap; |
| 34 | 35 |
| 35 // Returns true if |md5| matches the one in |cache_entry| with some | 36 // Returns true if |md5| matches the one in |cache_entry| with some |
| 36 // exceptions. See the function definition for details. | 37 // exceptions. See the function definition for details. |
| 37 bool CheckIfMd5Matches(const std::string& md5, | 38 bool CheckIfMd5Matches(const std::string& md5, |
| 38 const FileCacheEntry& cache_entry) { | 39 const FileCacheEntry& cache_entry) { |
| 39 if (cache_entry.is_dirty()) { | 40 if (cache_entry.is_dirty()) { |
| 40 // If the entry is dirty, its MD5 may have been replaced by "local" | 41 // If the entry is dirty, its MD5 may have been replaced by "local" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback, | 153 void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback, |
| 153 FileCacheEntry* cache_entry, | 154 FileCacheEntry* cache_entry, |
| 154 bool success) { | 155 bool success) { |
| 155 DCHECK(cache_entry); | 156 DCHECK(cache_entry); |
| 156 DCHECK(!callback.is_null()); | 157 DCHECK(!callback.is_null()); |
| 157 callback.Run(success, *cache_entry); | 158 callback.Run(success, *cache_entry); |
| 158 } | 159 } |
| 159 | 160 |
| 160 } // namespace | 161 } // namespace |
| 161 | 162 |
| 162 FileCache::FileCache(const base::FilePath& metadata_directory, | 163 FileCache::FileCache(ResourceMetadataStorage* storage, |
| 163 const base::FilePath& cache_file_directory, | 164 const base::FilePath& cache_file_directory, |
| 164 base::SequencedTaskRunner* blocking_task_runner, | 165 base::SequencedTaskRunner* blocking_task_runner, |
| 165 FreeDiskSpaceGetterInterface* free_disk_space_getter) | 166 FreeDiskSpaceGetterInterface* free_disk_space_getter) |
| 166 : metadata_directory_(metadata_directory), | 167 : cache_file_directory_(cache_file_directory), |
| 167 cache_file_directory_(cache_file_directory), | |
| 168 blocking_task_runner_(blocking_task_runner), | 168 blocking_task_runner_(blocking_task_runner), |
| 169 storage_(storage), | |
| 169 free_disk_space_getter_(free_disk_space_getter), | 170 free_disk_space_getter_(free_disk_space_getter), |
| 170 weak_ptr_factory_(this) { | 171 weak_ptr_factory_(this) { |
| 171 DCHECK(blocking_task_runner_.get()); | 172 DCHECK(blocking_task_runner_.get()); |
| 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 173 } | 174 } |
| 174 | 175 |
| 175 FileCache::~FileCache() { | 176 FileCache::~FileCache() { |
| 176 // Must be on the sequenced worker pool, as |metadata_| must be deleted on | 177 // Must be on the sequenced worker pool, as |metadata_| must be deleted on |
| 177 // the sequenced worker pool. | 178 // the sequenced worker pool. |
| 178 AssertOnSequencedWorkerPool(); | 179 AssertOnSequencedWorkerPool(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 cache_entry), | 223 cache_entry), |
| 223 base::Bind( | 224 base::Bind( |
| 224 &RunGetCacheEntryCallback, callback, base::Owned(cache_entry))); | 225 &RunGetCacheEntryCallback, callback, base::Owned(cache_entry))); |
| 225 } | 226 } |
| 226 | 227 |
| 227 bool FileCache::GetCacheEntry(const std::string& resource_id, | 228 bool FileCache::GetCacheEntry(const std::string& resource_id, |
| 228 const std::string& md5, | 229 const std::string& md5, |
| 229 FileCacheEntry* entry) { | 230 FileCacheEntry* entry) { |
| 230 DCHECK(entry); | 231 DCHECK(entry); |
| 231 AssertOnSequencedWorkerPool(); | 232 AssertOnSequencedWorkerPool(); |
| 232 return metadata_->GetCacheEntry(resource_id, entry) && | 233 return storage_->GetCacheEntry(resource_id, entry) && |
| 233 CheckIfMd5Matches(md5, *entry); | 234 CheckIfMd5Matches(md5, *entry); |
| 234 } | 235 } |
| 235 | 236 |
| 236 void FileCache::IterateOnUIThread( | 237 void FileCache::IterateOnUIThread( |
| 237 const CacheIterateCallback& iteration_callback, | 238 const CacheIterateCallback& iteration_callback, |
| 238 const base::Closure& completion_callback) { | 239 const base::Closure& completion_callback) { |
| 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 240 DCHECK(!iteration_callback.is_null()); | 241 DCHECK(!iteration_callback.is_null()); |
| 241 DCHECK(!completion_callback.is_null()); | 242 DCHECK(!completion_callback.is_null()); |
| 242 | 243 |
| 243 blocking_task_runner_->PostTaskAndReply( | 244 blocking_task_runner_->PostTaskAndReply( |
| 244 FROM_HERE, | 245 FROM_HERE, |
| 245 base::Bind(&FileCache::Iterate, | 246 base::Bind(&FileCache::Iterate, |
| 246 base::Unretained(this), | 247 base::Unretained(this), |
| 247 google_apis::CreateRelayCallback(iteration_callback)), | 248 google_apis::CreateRelayCallback(iteration_callback)), |
| 248 completion_callback); | 249 completion_callback); |
| 249 } | 250 } |
| 250 | 251 |
| 251 void FileCache::Iterate(const CacheIterateCallback& iteration_callback) { | 252 void FileCache::Iterate(const CacheIterateCallback& iteration_callback) { |
| 252 AssertOnSequencedWorkerPool(); | 253 AssertOnSequencedWorkerPool(); |
| 253 DCHECK(!iteration_callback.is_null()); | 254 DCHECK(!iteration_callback.is_null()); |
| 254 | 255 |
| 255 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 256 scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it = |
| 257 storage_->GetCacheEntryIterator(); | |
| 256 for (; !it->IsAtEnd(); it->Advance()) | 258 for (; !it->IsAtEnd(); it->Advance()) |
| 257 iteration_callback.Run(it->GetKey(), it->GetValue()); | 259 iteration_callback.Run(it->GetID(), it->GetValue()); |
| 258 DCHECK(!it->HasError()); | 260 DCHECK(!it->HasError()); |
| 259 } | 261 } |
| 260 | 262 |
| 261 void FileCache::FreeDiskSpaceIfNeededForOnUIThread( | 263 void FileCache::FreeDiskSpaceIfNeededForOnUIThread( |
| 262 int64 num_bytes, | 264 int64 num_bytes, |
| 263 const InitializeCacheCallback& callback) { | 265 const InitializeCacheCallback& callback) { |
| 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 265 DCHECK(!callback.is_null()); | 267 DCHECK(!callback.is_null()); |
| 266 | 268 |
| 267 base::PostTaskAndReplyWithResult( | 269 base::PostTaskAndReplyWithResult( |
| 268 blocking_task_runner_.get(), | 270 blocking_task_runner_.get(), |
| 269 FROM_HERE, | 271 FROM_HERE, |
| 270 base::Bind(&FileCache::FreeDiskSpaceIfNeededFor, | 272 base::Bind(&FileCache::FreeDiskSpaceIfNeededFor, |
| 271 base::Unretained(this), | 273 base::Unretained(this), |
| 272 num_bytes), | 274 num_bytes), |
| 273 callback); | 275 callback); |
| 274 } | 276 } |
| 275 | 277 |
| 276 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { | 278 bool FileCache::FreeDiskSpaceIfNeededFor(int64 num_bytes) { |
| 277 AssertOnSequencedWorkerPool(); | 279 AssertOnSequencedWorkerPool(); |
| 278 | 280 |
| 279 // Do nothing and return if we have enough space. | 281 // Do nothing and return if we have enough space. |
| 280 if (HasEnoughSpaceFor(num_bytes, cache_file_directory_)) | 282 if (HasEnoughSpaceFor(num_bytes, cache_file_directory_)) |
| 281 return true; | 283 return true; |
| 282 | 284 |
| 283 // Otherwise, try to free up the disk space. | 285 // Otherwise, try to free up the disk space. |
| 284 DVLOG(1) << "Freeing up disk space for " << num_bytes; | 286 DVLOG(1) << "Freeing up disk space for " << num_bytes; |
| 285 | 287 |
| 286 // Remove all entries unless specially marked. | 288 // Remove all entries unless specially marked. |
| 287 scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator(); | 289 scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it = |
| 290 storage_->GetCacheEntryIterator(); | |
| 288 for (; !it->IsAtEnd(); it->Advance()) { | 291 for (; !it->IsAtEnd(); it->Advance()) { |
| 289 const FileCacheEntry& entry = it->GetValue(); | 292 const FileCacheEntry& entry = it->GetValue(); |
| 290 if (!entry.is_pinned() && | 293 if (!entry.is_pinned() && |
| 291 !entry.is_dirty() && | 294 !entry.is_dirty() && |
| 292 !mounted_files_.count(it->GetKey())) | 295 !mounted_files_.count(it->GetID())) |
| 293 metadata_->RemoveCacheEntry(it->GetKey()); | 296 storage_->RemoveCacheEntry(it->GetID()); |
| 294 } | 297 } |
| 295 DCHECK(!it->HasError()); | 298 DCHECK(!it->HasError()); |
| 296 | 299 |
| 297 // Remove all files which have no corresponding cache entries. | 300 // Remove all files which have no corresponding cache entries. |
| 298 base::FileEnumerator enumerator(cache_file_directory_, | 301 base::FileEnumerator enumerator(cache_file_directory_, |
| 299 false, // not recursive | 302 false, // not recursive |
| 300 base::FileEnumerator::FILES); | 303 base::FileEnumerator::FILES); |
| 301 std::string resource_id; | 304 std::string resource_id; |
| 302 std::string md5; | 305 std::string md5; |
| 303 FileCacheEntry entry; | 306 FileCacheEntry entry; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 blocking_task_runner_.get(), | 388 blocking_task_runner_.get(), |
| 386 FROM_HERE, | 389 FROM_HERE, |
| 387 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id), | 390 base::Bind(&FileCache::Pin, base::Unretained(this), resource_id), |
| 388 callback); | 391 callback); |
| 389 } | 392 } |
| 390 | 393 |
| 391 FileError FileCache::Pin(const std::string& resource_id) { | 394 FileError FileCache::Pin(const std::string& resource_id) { |
| 392 AssertOnSequencedWorkerPool(); | 395 AssertOnSequencedWorkerPool(); |
| 393 | 396 |
| 394 FileCacheEntry cache_entry; | 397 FileCacheEntry cache_entry; |
| 395 metadata_->GetCacheEntry(resource_id, &cache_entry); | 398 storage_->GetCacheEntry(resource_id, &cache_entry); |
| 396 cache_entry.set_is_pinned(true); | 399 cache_entry.set_is_pinned(true); |
| 397 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 400 storage_->PutCacheEntry(resource_id, cache_entry); |
| 398 return FILE_ERROR_OK; | 401 return FILE_ERROR_OK; |
| 399 } | 402 } |
| 400 | 403 |
| 401 void FileCache::UnpinOnUIThread(const std::string& resource_id, | 404 void FileCache::UnpinOnUIThread(const std::string& resource_id, |
| 402 const FileOperationCallback& callback) { | 405 const FileOperationCallback& callback) { |
| 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 404 DCHECK(!callback.is_null()); | 407 DCHECK(!callback.is_null()); |
| 405 | 408 |
| 406 base::PostTaskAndReplyWithResult( | 409 base::PostTaskAndReplyWithResult( |
| 407 blocking_task_runner_.get(), | 410 blocking_task_runner_.get(), |
| 408 FROM_HERE, | 411 FROM_HERE, |
| 409 base::Bind(&FileCache::Unpin, base::Unretained(this), resource_id), | 412 base::Bind(&FileCache::Unpin, base::Unretained(this), resource_id), |
| 410 callback); | 413 callback); |
| 411 } | 414 } |
| 412 | 415 |
| 413 FileError FileCache::Unpin(const std::string& resource_id) { | 416 FileError FileCache::Unpin(const std::string& resource_id) { |
| 414 AssertOnSequencedWorkerPool(); | 417 AssertOnSequencedWorkerPool(); |
| 415 | 418 |
| 416 // Unpinning a file means its entry must exist in cache. | 419 // Unpinning a file means its entry must exist in cache. |
| 417 FileCacheEntry cache_entry; | 420 FileCacheEntry cache_entry; |
| 418 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 421 if (!storage_->GetCacheEntry(resource_id, &cache_entry)) |
| 419 return FILE_ERROR_NOT_FOUND; | 422 return FILE_ERROR_NOT_FOUND; |
| 420 | 423 |
| 421 // Now that file operations have completed, update metadata. | 424 // Now that file operations have completed, update metadata. |
| 422 if (cache_entry.is_present()) { | 425 if (cache_entry.is_present()) { |
| 423 cache_entry.set_is_pinned(false); | 426 cache_entry.set_is_pinned(false); |
| 424 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 427 storage_->PutCacheEntry(resource_id, cache_entry); |
| 425 } else { | 428 } else { |
| 426 // Remove the existing entry if we are unpinning a non-present file. | 429 // Remove the existing entry if we are unpinning a non-present file. |
| 427 metadata_->RemoveCacheEntry(resource_id); | 430 storage_->RemoveCacheEntry(resource_id); |
| 428 } | 431 } |
| 429 | 432 |
| 430 // Now it's a chance to free up space if needed. | 433 // Now it's a chance to free up space if needed. |
| 431 FreeDiskSpaceIfNeededFor(0); | 434 FreeDiskSpaceIfNeededFor(0); |
| 432 | 435 |
| 433 return FILE_ERROR_OK; | 436 return FILE_ERROR_OK; |
| 434 } | 437 } |
| 435 | 438 |
| 436 void FileCache::MarkAsMountedOnUIThread( | 439 void FileCache::MarkAsMountedOnUIThread( |
| 437 const std::string& resource_id, | 440 const std::string& resource_id, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 AssertOnSequencedWorkerPool(); | 487 AssertOnSequencedWorkerPool(); |
| 485 | 488 |
| 486 // If file has already been marked dirty in previous instance of chrome, we | 489 // 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 | 490 // would have lost the md5 info during cache initialization, because the file |
| 488 // would have been renamed to .local extension. | 491 // would have been renamed to .local extension. |
| 489 // So, search for entry in cache without comparing md5. | 492 // So, search for entry in cache without comparing md5. |
| 490 | 493 |
| 491 // Marking a file dirty means its entry and actual file blob must exist in | 494 // Marking a file dirty means its entry and actual file blob must exist in |
| 492 // cache. | 495 // cache. |
| 493 FileCacheEntry cache_entry; | 496 FileCacheEntry cache_entry; |
| 494 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || | 497 if (!storage_->GetCacheEntry(resource_id, &cache_entry) || |
| 495 !cache_entry.is_present()) { | 498 !cache_entry.is_present()) { |
| 496 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" | 499 LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id=" |
| 497 << resource_id | 500 << resource_id |
| 498 << ", md5=" << md5; | 501 << ", md5=" << md5; |
| 499 return FILE_ERROR_NOT_FOUND; | 502 return FILE_ERROR_NOT_FOUND; |
| 500 } | 503 } |
| 501 | 504 |
| 502 if (cache_entry.is_dirty()) | 505 if (cache_entry.is_dirty()) |
| 503 return FILE_ERROR_OK; | 506 return FILE_ERROR_OK; |
| 504 | 507 |
| 505 // Get the current path of the file in cache. | 508 // Get the current path of the file in cache. |
| 506 base::FilePath source_path = GetCacheFilePath(resource_id, md5, | 509 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
| 507 CACHED_FILE_FROM_SERVER); | 510 CACHED_FILE_FROM_SERVER); |
| 508 // Determine destination path. | 511 // Determine destination path. |
| 509 base::FilePath cache_file_path = GetCacheFilePath( | 512 base::FilePath cache_file_path = GetCacheFilePath( |
| 510 resource_id, md5, CACHED_FILE_LOCALLY_MODIFIED); | 513 resource_id, md5, CACHED_FILE_LOCALLY_MODIFIED); |
| 511 | 514 |
| 512 if (!MoveFile(source_path, cache_file_path)) | 515 if (!MoveFile(source_path, cache_file_path)) |
| 513 return FILE_ERROR_FAILED; | 516 return FILE_ERROR_FAILED; |
| 514 | 517 |
| 515 // Now that file operations have completed, update metadata. | 518 // Now that file operations have completed, update metadata. |
| 516 cache_entry.set_md5(md5); | 519 cache_entry.set_md5(md5); |
| 517 cache_entry.set_is_dirty(true); | 520 cache_entry.set_is_dirty(true); |
| 518 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 521 storage_->PutCacheEntry(resource_id, cache_entry); |
| 519 return FILE_ERROR_OK; | 522 return FILE_ERROR_OK; |
| 520 } | 523 } |
| 521 | 524 |
| 522 FileError FileCache::ClearDirty(const std::string& resource_id, | 525 FileError FileCache::ClearDirty(const std::string& resource_id, |
| 523 const std::string& md5) { | 526 const std::string& md5) { |
| 524 AssertOnSequencedWorkerPool(); | 527 AssertOnSequencedWorkerPool(); |
| 525 | 528 |
| 526 // |md5| is the new .<md5> extension to rename the file to. | 529 // |md5| is the new .<md5> extension to rename the file to. |
| 527 // So, search for entry in cache without comparing md5. | 530 // So, search for entry in cache without comparing md5. |
| 528 FileCacheEntry cache_entry; | 531 FileCacheEntry cache_entry; |
| 529 | 532 |
| 530 // Clearing a dirty file means its entry and actual file blob must exist in | 533 // Clearing a dirty file means its entry and actual file blob must exist in |
| 531 // cache. | 534 // cache. |
| 532 if (!metadata_->GetCacheEntry(resource_id, &cache_entry) || | 535 if (!storage_->GetCacheEntry(resource_id, &cache_entry) || |
| 533 !cache_entry.is_present()) { | 536 !cache_entry.is_present()) { |
| 534 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: " | 537 LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: " |
| 535 << "res_id=" << resource_id | 538 << "res_id=" << resource_id |
| 536 << ", md5=" << md5; | 539 << ", md5=" << md5; |
| 537 return FILE_ERROR_NOT_FOUND; | 540 return FILE_ERROR_NOT_FOUND; |
| 538 } | 541 } |
| 539 | 542 |
| 540 // If a file is not dirty (it should have been marked dirty via | 543 // If a file is not dirty (it should have been marked dirty via |
| 541 // MarkDirtyInCache), clearing its dirty state is an invalid operation. | 544 // MarkDirtyInCache), clearing its dirty state is an invalid operation. |
| 542 if (!cache_entry.is_dirty()) { | 545 if (!cache_entry.is_dirty()) { |
| 543 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" | 546 LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id=" |
| 544 << resource_id | 547 << resource_id |
| 545 << ", md5=" << md5; | 548 << ", md5=" << md5; |
| 546 return FILE_ERROR_INVALID_OPERATION; | 549 return FILE_ERROR_INVALID_OPERATION; |
| 547 } | 550 } |
| 548 | 551 |
| 549 base::FilePath source_path = GetCacheFilePath(resource_id, md5, | 552 base::FilePath source_path = GetCacheFilePath(resource_id, md5, |
| 550 CACHED_FILE_LOCALLY_MODIFIED); | 553 CACHED_FILE_LOCALLY_MODIFIED); |
| 551 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, | 554 base::FilePath dest_path = GetCacheFilePath(resource_id, md5, |
| 552 CACHED_FILE_FROM_SERVER); | 555 CACHED_FILE_FROM_SERVER); |
| 553 if (!MoveFile(source_path, dest_path)) | 556 if (!MoveFile(source_path, dest_path)) |
| 554 return FILE_ERROR_FAILED; | 557 return FILE_ERROR_FAILED; |
| 555 | 558 |
| 556 // Now that file operations have completed, update metadata. | 559 // Now that file operations have completed, update metadata. |
| 557 cache_entry.set_md5(md5); | 560 cache_entry.set_md5(md5); |
| 558 cache_entry.set_is_dirty(false); | 561 cache_entry.set_is_dirty(false); |
| 559 metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry); | 562 storage_->PutCacheEntry(resource_id, cache_entry); |
| 560 return FILE_ERROR_OK; | 563 return FILE_ERROR_OK; |
| 561 } | 564 } |
| 562 | 565 |
| 563 void FileCache::RemoveOnUIThread(const std::string& resource_id, | 566 void FileCache::RemoveOnUIThread(const std::string& resource_id, |
| 564 const FileOperationCallback& callback) { | 567 const FileOperationCallback& callback) { |
| 565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 566 DCHECK(!callback.is_null()); | 569 DCHECK(!callback.is_null()); |
| 567 | 570 |
| 568 base::PostTaskAndReplyWithResult( | 571 base::PostTaskAndReplyWithResult( |
| 569 blocking_task_runner_.get(), | 572 blocking_task_runner_.get(), |
| 570 FROM_HERE, | 573 FROM_HERE, |
| 571 base::Bind(&FileCache::Remove, base::Unretained(this), resource_id), | 574 base::Bind(&FileCache::Remove, base::Unretained(this), resource_id), |
| 572 callback); | 575 callback); |
| 573 } | 576 } |
| 574 | 577 |
| 575 FileError FileCache::Remove(const std::string& resource_id) { | 578 FileError FileCache::Remove(const std::string& resource_id) { |
| 576 AssertOnSequencedWorkerPool(); | 579 AssertOnSequencedWorkerPool(); |
| 577 | 580 |
| 578 // MD5 is not passed into RemoveCacheEntry because we would delete all | 581 // MD5 is not passed into RemoveCacheEntry because we would delete all |
| 579 // cache files corresponding to <resource_id> regardless of the md5. | 582 // cache files corresponding to <resource_id> regardless of the md5. |
| 580 // So, search for entry in cache without taking md5 into account. | 583 // So, search for entry in cache without taking md5 into account. |
| 581 FileCacheEntry cache_entry; | 584 FileCacheEntry cache_entry; |
| 582 | 585 |
| 583 // If entry doesn't exist, nothing to do. | 586 // If entry doesn't exist, nothing to do. |
| 584 if (!metadata_->GetCacheEntry(resource_id, &cache_entry)) | 587 if (!storage_->GetCacheEntry(resource_id, &cache_entry)) |
| 585 return FILE_ERROR_OK; | 588 return FILE_ERROR_OK; |
| 586 | 589 |
| 587 // Cannot delete a dirty or mounted file. | 590 // Cannot delete a dirty or mounted file. |
| 588 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) | 591 if (cache_entry.is_dirty() || mounted_files_.count(resource_id)) |
| 589 return FILE_ERROR_IN_USE; | 592 return FILE_ERROR_IN_USE; |
| 590 | 593 |
| 591 // Delete files that match "<resource_id>.*" unless modified locally. | 594 // Delete files that match "<resource_id>.*" unless modified locally. |
| 592 base::FilePath path_to_delete = GetCacheFilePath(resource_id, util::kWildCard, | 595 base::FilePath path_to_delete = GetCacheFilePath(resource_id, util::kWildCard, |
| 593 CACHED_FILE_FROM_SERVER); | 596 CACHED_FILE_FROM_SERVER); |
| 594 base::FilePath path_to_keep = GetCacheFilePath(resource_id, std::string(), | 597 base::FilePath path_to_keep = GetCacheFilePath(resource_id, std::string(), |
| 595 CACHED_FILE_LOCALLY_MODIFIED); | 598 CACHED_FILE_LOCALLY_MODIFIED); |
| 596 DeleteFilesSelectively(path_to_delete, path_to_keep); | 599 DeleteFilesSelectively(path_to_delete, path_to_keep); |
| 597 | 600 |
| 598 // Now that all file operations have completed, remove from metadata. | 601 // Now that all file operations have completed, remove from metadata. |
| 599 metadata_->RemoveCacheEntry(resource_id); | 602 storage_->RemoveCacheEntry(resource_id); |
| 600 | 603 |
| 601 return FILE_ERROR_OK; | 604 return FILE_ERROR_OK; |
| 602 } | 605 } |
| 603 | 606 |
| 604 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { | 607 void FileCache::ClearAllOnUIThread(const InitializeCacheCallback& callback) { |
| 605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 606 DCHECK(!callback.is_null()); | 609 DCHECK(!callback.is_null()); |
| 607 | 610 |
| 608 base::PostTaskAndReplyWithResult( | 611 base::PostTaskAndReplyWithResult( |
| 609 blocking_task_runner_.get(), | 612 blocking_task_runner_.get(), |
| 610 FROM_HERE, | 613 FROM_HERE, |
| 611 base::Bind(&FileCache::ClearAll, base::Unretained(this)), | 614 base::Bind(&FileCache::ClearAll, base::Unretained(this)), |
| 612 callback); | 615 callback); |
| 613 } | 616 } |
| 614 | 617 |
| 615 bool FileCache::Initialize() { | 618 bool FileCache::Initialize() { |
| 616 AssertOnSequencedWorkerPool(); | 619 AssertOnSequencedWorkerPool(); |
| 617 | 620 |
| 618 metadata_.reset(new FileCacheMetadata(blocking_task_runner_.get())); | 621 if (!ImportOldDB(storage_->directory_path().Append(kCacheMetadataDBName)) && |
| 619 | 622 !storage_->opened_existing_db()) { |
| 620 const base::FilePath db_path = | 623 CacheMap cache_map; |
| 621 metadata_directory_.Append(kCacheMetadataDBName); | 624 ScanCacheDirectory(cache_file_directory_, &cache_map); |
| 622 switch (metadata_->Initialize(db_path)) { | 625 for (CacheMap::const_iterator it = cache_map.begin(); |
| 623 case FileCacheMetadata::INITIALIZE_FAILED: | 626 it != cache_map.end(); ++it) { |
| 624 return false; | 627 storage_->PutCacheEntry(it->first, it->second); |
| 625 | |
| 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 FileCacheMetadata old_data(blocking_task_runner_); |
| 823 if (old_data.Initialize(old_db_path)) { | 815 if (old_data.Initialize(old_db_path)) { |
| 824 scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator(); | 816 scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator(); |
| 825 for (; !it->IsAtEnd(); it->Advance()) { | 817 for (; !it->IsAtEnd(); it->Advance()) { |
| 826 FileCacheEntry entry; | 818 FileCacheEntry entry; |
| 827 if (metadata_->GetCacheEntry(it->GetKey(), &entry)) | 819 if (storage_->GetCacheEntry(it->GetKey(), &entry)) |
| 828 continue; // Do not overwrite. | 820 continue; // Do not overwrite. |
| 829 | 821 |
| 830 metadata_->AddOrUpdateCacheEntry(it->GetKey(), it->GetValue()); | 822 storage_->PutCacheEntry(it->GetKey(), it->GetValue()); |
| 831 } | 823 } |
| 832 } | 824 } |
|
kinaba
2013/06/21 07:32:50
When old_data.Initialize() failed, shouldn't we re
hashimoto
2013/06/21 08:23:41
Amazingly good catch.
Done as you suggested.
| |
| 833 | 825 |
| 834 // Delete old DB. | 826 // Delete old DB. |
| 835 file_util::Delete(old_db_path, true /* recursive */ ); | 827 file_util::Delete(old_db_path, true /* recursive */ ); |
| 828 return true; | |
| 836 } | 829 } |
| 837 | 830 |
| 838 } // namespace internal | 831 } // namespace internal |
| 839 } // namespace drive | 832 } // namespace drive |
| OLD | NEW |