1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h"
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/location.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/sequenced_task_runner.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/drive.pb.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace drive {
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace internal {
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Enum to describe DB initialization status.
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)enum DBInitStatus {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_SUCCESS,
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_NOT_FOUND,
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_CORRUPTION,
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_IO_ERROR,
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_FAILED,
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_INCOMPATIBLE,
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_BROKEN,
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DB_INIT_MAX_VALUE,
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::FilePath::CharType kResourceMapDBName[] =
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FILE_PATH_LITERAL("resource_metadata_resource_map.db");
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::FilePath::CharType kChildMapDBName[] =
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FILE_PATH_LITERAL("resource_metadata_child_map.db");
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Meant to be a character which never happen to be in real resource IDs.
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kDBKeyDelimeter = '\0';
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// String used as a suffix of a key for a cache entry.
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst char kCacheEntryKeySuffix[] = "CACHE";
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns a string to be used as the key for the header.
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string GetHeaderDBKey() {
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string key;
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  key.push_back(kDBKeyDelimeter);
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  key.append("HEADER");
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return key;
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true if |key| is a key for a child entry.
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool IsChildEntryKey(const leveldb::Slice& key) {
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return !key.empty() && key[key.size() - 1] == kDBKeyDelimeter;
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Returns a string to be used as a key for a cache entry.
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string GetCacheEntryKey(const std::string& resource_id) {
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string key(resource_id);
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  key.push_back(kDBKeyDelimeter);
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  key.append(kCacheEntryKeySuffix);
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return key;
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Returns true if |key| is a key for a cache entry.
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool IsCacheEntryKey(const leveldb::Slice& key) {
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // A cache entry key should end with |kDBKeyDelimeter + kCacheEntryKeySuffix|.
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const leveldb::Slice expected_suffix(kCacheEntryKeySuffix,
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       arraysize(kCacheEntryKeySuffix) - 1);
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (key.size() < 1 + expected_suffix.size() ||
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      key[key.size() - expected_suffix.size() - 1] != kDBKeyDelimeter)
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const leveldb::Slice key_substring(
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      key.data() + key.size() - expected_suffix.size(), expected_suffix.size());
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return key_substring.compare(expected_suffix) == 0;
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Converts leveldb::Status to DBInitStatus.
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)DBInitStatus LevelDBStatusToDBInitStatus(const leveldb::Status status) {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status.ok())
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return DB_INIT_SUCCESS;
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status.IsNotFound())
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return DB_INIT_NOT_FOUND;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status.IsCorruption())
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return DB_INIT_CORRUPTION;
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status.IsIOError())
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return DB_INIT_IO_ERROR;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DB_INIT_FAILED;
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)ResourceMetadataStorage::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it)
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  : it_(it.Pass()) {
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(it_);
100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Skip the header entry.
102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Note: The header entry comes before all other entries because its key
103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // starts with kDBKeyDelimeter. (i.e. '\0')
104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  it_->Seek(leveldb::Slice(GetHeaderDBKey()));
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  Advance();
107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)ResourceMetadataStorage::Iterator::~Iterator() {
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool ResourceMetadataStorage::Iterator::IsAtEnd() const {
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return !it_->Valid();
116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const ResourceEntry& ResourceMetadataStorage::Iterator::Get() const {
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!IsAtEnd());
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return entry_;
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
12458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochbool ResourceMetadataStorage::Iterator::GetCacheEntry(
12558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    FileCacheEntry* cache_entry) {
12658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  base::ThreadRestrictions::AssertIOAllowed();
12758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(!IsAtEnd());
12858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
12958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // Try to seek to the cache entry.
13058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  std::string current_key = it_->key().ToString();
13158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  std::string cache_entry_key = GetCacheEntryKey(current_key);
13258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  it_->Seek(leveldb::Slice(cache_entry_key));
13358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
13458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  bool success = it_->Valid() &&
13558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      it_->key().compare(cache_entry_key) == 0 &&
13658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      cache_entry->ParseFromArray(it_->value().data(), it_->value().size());
13758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
13858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // Seek back to the original position.
13958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  it_->Seek(leveldb::Slice(current_key));
14058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(!IsAtEnd());
14158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK_EQ(current_key, it_->key().ToString());
14258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
14358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return success;
14458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
14558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void ResourceMetadataStorage::Iterator::Advance() {
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!IsAtEnd());
149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (it_->Next() ; it_->Valid(); it_->Next()) {
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!IsChildEntryKey(it_->key()) &&
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        !IsCacheEntryKey(it_->key()) &&
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        entry_.ParseFromArray(it_->value().data(), it_->value().size()))
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      break;
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool ResourceMetadataStorage::Iterator::HasError() const {
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return !it_->status().ok();
161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::CacheEntryIterator::CacheEntryIterator(
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_ptr<leveldb::Iterator> it) : it_(it.Pass()) {
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(it_);
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  it_->SeekToFirst();
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AdvanceInternal();
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::CacheEntryIterator::~CacheEntryIterator() {
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::CacheEntryIterator::IsAtEnd() const {
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return !it_->Valid();
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst std::string& ResourceMetadataStorage::CacheEntryIterator::GetID() const {
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!IsAtEnd());
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return resource_id_;
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst FileCacheEntry&
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::CacheEntryIterator::GetValue() const {
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!IsAtEnd());
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return entry_;
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ResourceMetadataStorage::CacheEntryIterator::Advance() {
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!IsAtEnd());
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  it_->Next();
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AdvanceInternal();
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::CacheEntryIterator::HasError() const {
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return !it_->status().ok();
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ResourceMetadataStorage::CacheEntryIterator::AdvanceInternal() {
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (; it_->Valid(); it_->Next()) {
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Skip unparsable broken entries.
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // TODO(hashimoto): Broken entries should be cleaned up at some point.
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (IsCacheEntryKey(it_->key()) &&
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        entry_.ParseFromArray(it_->value().data(), it_->value().size())) {
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const size_t kSuffixLength = arraysize(kCacheEntryKeySuffix) - 1;
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const int id_length = it_->key().size() - 1 - kSuffixLength;
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      resource_id_.assign(it_->key().data(), id_length);
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::ResourceMetadataStorage(
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::FilePath& directory_path,
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::SequencedTaskRunner* blocking_task_runner)
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : directory_path_(directory_path),
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      opened_existing_db_(false),
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      blocking_task_runner_(blocking_task_runner) {
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ResourceMetadataStorage::Destroy() {
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  blocking_task_runner_->PostTask(
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FROM_HERE,
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(&ResourceMetadataStorage::DestroyOnBlockingPool,
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Unretained(this)));
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::Initialize() {
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove unused child map DB.
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::FilePath child_map_path = directory_path_.Append(kChildMapDBName);
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::DeleteFile(child_map_path, true /* recursive */);
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  resource_map_.reset();
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::FilePath resource_map_path =
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directory_path_.Append(kResourceMapDBName);
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Try to open the existing DB.
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  leveldb::DB* db = NULL;
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  leveldb::Options options;
2526bda25ffe15103e73b1811c624157f45962839deTorne (Richard Coles)  options.max_open_files = 64;  // Use minimum.
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  options.create_if_missing = false;
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DBInitStatus open_existing_result = DB_INIT_NOT_FOUND;
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(resource_map_path)) {
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    leveldb::Status status =
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    open_existing_result = LevelDBStatusToDBInitStatus(status);
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (open_existing_result == DB_INIT_SUCCESS) {
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_map_.reset(db);
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Check the validity of existing DB.
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ResourceMetadataHeader header;
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!GetHeader(&header) || header.version() != kDBVersion) {
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      open_existing_result = DB_INIT_INCOMPATIBLE;
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(INFO) << "Reject incompatible DB.";
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (!CheckValidity()) {
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      open_existing_result = DB_INIT_BROKEN;
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(ERROR) << "Reject invalid DB.";
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (open_existing_result == DB_INIT_SUCCESS)
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      opened_existing_db_ = true;
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      resource_map_.reset();
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBOpenExistingResult",
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            open_existing_result,
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            DB_INIT_MAX_VALUE);
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DBInitStatus init_result = DB_INIT_SUCCESS;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Failed to open the existing DB, create new DB.
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!resource_map_) {
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_map_.reset();
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Clean up the destination.
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const bool kRecursive = true;
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(resource_map_path, kRecursive);
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Create DB.
2966bda25ffe15103e73b1811c624157f45962839deTorne (Richard Coles)    options.max_open_files = 64;  // Use minimum.
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    options.create_if_missing = true;
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    leveldb::Status status =
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (status.ok()) {
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      resource_map_.reset(db);
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Set up header.
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceMetadataHeader header;
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      header.set_version(kDBVersion);
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!PutHeader(header)) {
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        init_result = DB_INIT_FAILED;
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        resource_map_.reset();
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(ERROR) << "Failed to create resource map DB: " << status.ToString();
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      init_result = LevelDBStatusToDBInitStatus(status);
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBInitResult",
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            init_result,
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            DB_INIT_MAX_VALUE);
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return resource_map_;
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::SetLargestChangestamp(
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 largest_changestamp) {
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResourceMetadataHeader header;
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!GetHeader(&header)) {
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Failed to get the header.";
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  header.set_largest_changestamp(largest_changestamp);
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return PutHeader(header);
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int64 ResourceMetadataStorage::GetLargestChangestamp() {
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResourceMetadataHeader header;
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!GetHeader(&header)) {
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Failed to get the header.";
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0;
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return header.largest_changestamp();
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::PutEntry(const ResourceEntry& entry) {
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!entry.resource_id().empty());
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string serialized_entry;
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry.SerializeToString(&serialized_entry)) {
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Failed to serialize the entry: " << entry.resource_id();
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  leveldb::WriteBatch batch;
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove from the old parent.
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ResourceEntry old_entry;
3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (GetEntry(entry.resource_id(), &old_entry) &&
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      !old_entry.parent_resource_id().empty()) {
3627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    batch.Delete(GetChildEntryKey(old_entry.parent_resource_id(),
3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                  old_entry.base_name()));
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add to the new parent.
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry.parent_resource_id().empty()) {
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    batch.Put(GetChildEntryKey(entry.parent_resource_id(), entry.base_name()),
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              entry.resource_id());
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Put the entry itself.
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  batch.Put(entry.resource_id(), serialized_entry);
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                      &batch);
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return status.ok();
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool ResourceMetadataStorage::GetEntry(const std::string& resource_id,
3817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                       ResourceEntry* out_entry) {
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!resource_id.empty());
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string serialized_entry;
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const leveldb::Status status = resource_map_->Get(leveldb::ReadOptions(),
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                    leveldb::Slice(resource_id),
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                    &serialized_entry);
3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return status.ok() && out_entry->ParseFromString(serialized_entry);
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::RemoveEntry(const std::string& resource_id) {
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!resource_id.empty());
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ResourceEntry entry;
3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!GetEntry(resource_id, &entry))
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  leveldb::WriteBatch batch;
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove from the parent.
4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!entry.parent_resource_id().empty()) {
4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    batch.Delete(GetChildEntryKey(entry.parent_resource_id(),
4057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                  entry.base_name()));
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove the entry itself.
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  batch.Delete(resource_id);
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                      &batch);
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return status.ok();
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
415b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)scoped_ptr<ResourceMetadataStorage::Iterator>
416b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)ResourceMetadataStorage::GetIterator() {
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> it(
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      resource_map_->NewIterator(leveldb::ReadOptions()));
421b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return make_scoped_ptr(new Iterator(it.Pass()));
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string ResourceMetadataStorage::GetChild(
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& child_name) {
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string child_resource_id;
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  resource_map_->Get(
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::ReadOptions(),
432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::Slice(GetChildEntryKey(parent_resource_id, child_name)),
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &child_resource_id);
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return child_resource_id;
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ResourceMetadataStorage::GetChildren(const std::string& parent_resource_id,
438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                          std::vector<std::string>* children) {
439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Iterate over all entries with keys starting with |parent_resource_id|.
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> it(
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      resource_map_->NewIterator(leveldb::ReadOptions()));
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (it->Seek(parent_resource_id);
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       it->Valid() && it->key().starts_with(leveldb::Slice(parent_resource_id));
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       it->Next()) {
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (IsChildEntryKey(it->key()))
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      children->push_back(it->value().ToString());
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(it->status().ok());
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::PutCacheEntry(const std::string& resource_id,
454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            const FileCacheEntry& entry) {
455eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!resource_id.empty());
457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string serialized_entry;
459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!entry.SerializeToString(&serialized_entry)) {
460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(ERROR) << "Failed to serialize the entry.";
461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const leveldb::Status status = resource_map_->Put(
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::WriteOptions(),
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::Slice(GetCacheEntryKey(resource_id)),
467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::Slice(serialized_entry));
468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return status.ok();
469eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::GetCacheEntry(const std::string& resource_id,
472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            FileCacheEntry* out_entry) {
473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!resource_id.empty());
475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string serialized_entry;
477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const leveldb::Status status = resource_map_->Get(
478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::ReadOptions(),
479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::Slice(GetCacheEntryKey(resource_id)),
480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &serialized_entry);
481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return status.ok() && out_entry->ParseFromString(serialized_entry);
482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::RemoveCacheEntry(const std::string& resource_id) {
485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!resource_id.empty());
487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const leveldb::Status status = resource_map_->Delete(
489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::WriteOptions(),
490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb::Slice(GetCacheEntryKey(resource_id)));
491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return status.ok();
492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<ResourceMetadataStorage::CacheEntryIterator>
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::GetCacheEntryIterator() {
496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<leveldb::Iterator> it(
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      resource_map_->NewIterator(leveldb::ReadOptions()));
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return make_scoped_ptr(new CacheEntryIterator(it.Pass()));
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochResourceMetadataStorage::~ResourceMetadataStorage() {
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ResourceMetadataStorage::DestroyOnBlockingPool() {
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delete this;
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string ResourceMetadataStorage::GetChildEntryKey(
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& child_name) {
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string key = parent_resource_id;
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  key.push_back(kDBKeyDelimeter);
517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  key.append(child_name);
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  key.push_back(kDBKeyDelimeter);
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return key;
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::PutHeader(
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ResourceMetadataHeader& header) {
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string serialized_header;
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!header.SerializeToString(&serialized_header)) {
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Failed to serialize the header";
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const leveldb::Status status = resource_map_->Put(
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::WriteOptions(),
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::Slice(GetHeaderDBKey()),
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::Slice(serialized_header));
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return status.ok();
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceMetadataStorage::GetHeader(ResourceMetadataHeader* header) {
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string serialized_header;
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const leveldb::Status status = resource_map_->Get(
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::ReadOptions(),
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::Slice(GetHeaderDBKey()),
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &serialized_header);
547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return status.ok() && header->ParseFromString(serialized_header);
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResourceMetadataStorage::CheckValidity() {
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Perform read with checksums verification enalbed.
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  leveldb::ReadOptions options;
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  options.verify_checksums = true;
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> it(resource_map_->NewIterator(options));
558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  it->SeekToFirst();
559c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
560eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // DB is organized like this:
561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //
562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // <key>                          : <value>
563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "\0HEADER"                     : ResourceMetadataHeader
564eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of A|"                    : ResourceEntry for entry A.
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of A|\0CACHE"             : FileCacheEntry for entry A.
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of A|\0|child name 1|\0"  : ID of the 1st child entry of entry A.
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of A|\0|child name 2|\0"  : ID of the 2nd child entry of entry A.
568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // ...
569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of A|\0|child name n|\0"  : ID of the nth child entry of entry A.
570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of B|"                    : ResourceEntry for entry B.
571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "|ID of B|\0CACHE"             : FileCacheEntry for entry B.
572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // ...
573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check the header.
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ResourceMetadataHeader header;
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!it->Valid() ||
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      it->key() != GetHeaderDBKey() ||  // Header entry must come first.
578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !header.ParseFromArray(it->value().data(), it->value().size()) ||
579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      header.version() != kDBVersion) {
580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Invalid header detected. version = " << header.version();
581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
584a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Check all entries.
585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t num_entries_with_parent = 0;
586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t num_child_entries = 0;
587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ResourceEntry entry;
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string serialized_parent_entry;
589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string child_resource_id;
590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (it->Next(); it->Valid(); it->Next()) {
591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Count child entries.
592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (IsChildEntryKey(it->key())) {
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_child_entries;
594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Ignore cache entries.
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (IsCacheEntryKey(it->key()))
599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Check if stored data is broken.
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!entry.ParseFromArray(it->value().data(), it->value().size()) ||
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        entry.resource_id() != it->key()) {
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DLOG(ERROR) << "Broken entry detected";
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!entry.parent_resource_id().empty()) {
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Check if the parent entry is stored.
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      leveldb::Status status = resource_map_->Get(
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          options,
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          leveldb::Slice(entry.parent_resource_id()),
613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &serialized_parent_entry);
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!status.ok()) {
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DLOG(ERROR) << "Can't get parent entry. status = " << status.ToString();
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Check if parent-child relationship is stored correctly.
620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      status = resource_map_->Get(
621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          options,
622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          leveldb::Slice(GetChildEntryKey(entry.parent_resource_id(),
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          entry.base_name())),
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &child_resource_id);
625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!status.ok() || child_resource_id != entry.resource_id()) {
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DLOG(ERROR) << "Child map is broken. status = " << status.ToString();
627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_entries_with_parent;
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!it->status().ok() || num_child_entries != num_entries_with_parent) {
633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(ERROR) << "Error during checking resource map. status = "
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                << it->status().ToString();
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace internal
641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace drive
642