15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_cache_metadata.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sequenced_task_runner.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/drive/drive.pb.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system_util.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace drive { 18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace internal { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum DBOpenStatus { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_SUCCESS, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_FAILURE_CORRUPTION, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_FAILURE_OTHER, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_FAILURE_UNRECOVERABLE, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_MAX_VALUE, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileCacheMetadata::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it) 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : it_(it.Pass()) { 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(it_); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) it_->SeekToFirst(); 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AdvanceInternal(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileCacheMetadata::Iterator::~Iterator() { 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileCacheMetadata::Iterator::IsAtEnd() const { 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return !it_->Valid(); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::string FileCacheMetadata::Iterator::GetKey() const { 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!IsAtEnd()); 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return it_->key().ToString(); 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const FileCacheEntry& FileCacheMetadata::Iterator::GetValue() const { 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!IsAtEnd()); 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return entry_; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FileCacheMetadata::Iterator::Advance() { 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!IsAtEnd()); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) it_->Next(); 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AdvanceInternal(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileCacheMetadata::Iterator::HasError() const { 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return !it_->status().ok(); 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FileCacheMetadata::Iterator::AdvanceInternal() { 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (; it_->Valid(); it_->Next()) { 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Skip unparsable broken entries. 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // TODO(hashimoto): Broken entries should be cleaned up at some point. 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (entry_.ParseFromArray(it_->value().data(), it_->value().size())) 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileCacheMetadata::FileCacheMetadata( 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SequencedTaskRunner* blocking_task_runner) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : blocking_task_runner_(blocking_task_runner) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileCacheMetadata::~FileCacheMetadata() { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileCacheMetadata::InitializeResult FileCacheMetadata::Initialize( 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::FilePath& db_path) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool created = !base::PathExists(db_path); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::DB* level_db = NULL; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::Options options; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options.create_if_missing = true; 1036bda25ffe15103e73b1811c624157f45962839deTorne (Richard Coles) options.max_open_files = 64; // Use minimum. 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) leveldb::Status db_status = leveldb::DB::Open(options, db_path.AsUTF8Unsafe(), 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &level_db); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the db and scan the physical cache. This will fix a corrupt db, but 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // perhaps not other causes of failed DB::Open. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DBOpenStatus uma_status = DB_OPEN_SUCCESS; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!db_status.ok()) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Cache db failed to open: " << db_status.ToString(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uma_status = db_status.IsCorruption() ? 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DB_OPEN_FAILURE_CORRUPTION : DB_OPEN_FAILURE_OTHER; 1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const bool deleted = base::DeleteFile(db_path, true); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(deleted); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db_status = leveldb::DB::Open(options, db_path.value(), &level_db); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!db_status.ok()) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Still failed to open: " << db_status.ToString(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Drive.CacheDBOpenStatus", 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_FAILURE_UNRECOVERABLE, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DB_OPEN_MAX_VALUE); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return INITIALIZE_FAILED; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) created = true; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Drive.CacheDBOpenStatus", uma_status, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DB_OPEN_MAX_VALUE); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(level_db); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) level_db_.reset(level_db); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return created ? INITIALIZE_CREATED : INITIALIZE_OPENED; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FileCacheMetadata::AddOrUpdateCacheEntry( 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& resource_id, 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const FileCacheEntry& cache_entry) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "AddOrUpdateCacheEntry, resource_id=" << resource_id; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool ok = cache_entry.SerializeToString(&serialized); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ok) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) level_db_->Put(leveldb::WriteOptions(), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::Slice(resource_id), 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::Slice(serialized)); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void FileCacheMetadata::RemoveCacheEntry(const std::string& resource_id) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "RemoveCacheEntry, resource_id=" << resource_id; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) level_db_->Delete(leveldb::WriteOptions(), leveldb::Slice(resource_id)); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileCacheMetadata::GetCacheEntry(const std::string& resource_id, 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FileCacheEntry* entry) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(entry); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized; 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const leveldb::Status status = level_db_->Get( 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) leveldb::ReadOptions(), 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::Slice(resource_id), &serialized); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status.ok()) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Can't find " << resource_id << " in cache db"; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!entry->ParseFromString(serialized)) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to parse " << serialized; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<FileCacheMetadata::Iterator> FileCacheMetadata::GetIterator() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertOnSequencedWorkerPool(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator( 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) leveldb::ReadOptions())); 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return make_scoped_ptr(new Iterator(iter.Pass())); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FileCacheMetadata::AssertOnSequencedWorkerPool() { 1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(!blocking_task_runner_.get() || 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blocking_task_runner_->RunsTasksOnCurrentThread()); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} // namespace internal 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace drive 192