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