Commit 19af5d3e authored by achuith@chromium.org's avatar achuith@chromium.org

GDataDB support with leveldb.

* Define GDataDB interface with methods to Put, Get and Delete. Also define a path-based iterator.
* GDataLevelDB implements GDataDB using leveldb. 
* Add methods SerializeToString and FromProtoString to serialize GDataEntry to strings and vice versa.
* GDataDBTests test Put, Get, Delete for files and directories.
* Iterator tests in GDataDBTests.
* GDataDBFactory class to create GDataLevelDB instance.
* Update deps to allow leveldatabase.

TODO:
* There is no integration with GDataRootDirectory/GDataFileSystem yet.

BUG=chromium-os:29232
TEST=unittests pass.
Review URL: https://chromiumcodereview.appspot.com/10210012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133833 0039d316-1c4b-4281-b951-d872f2087c98
parent 8074250d
include_rules = [
"+leveldb"
]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_H_
#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_H_
#pragma once
#include <string>
#include "base/memory/scoped_ptr.h"
class FilePath;
namespace gdata {
class GDataEntry;
class GDataDBIter;
// GData Database interface class.
class GDataDB {
public:
enum Status {
DB_OK = 0,
DB_KEY_NOT_FOUND, // Key not found.
DB_CORRUPTION, // Database file corrupt.
DB_IO_ERROR, // File I/O error.
DB_INTERNAL_ERROR,
};
virtual ~GDataDB() {}
// Puts |entry| to the database.
virtual Status Put(const GDataEntry& entry) = 0;
// Deletes a database entry with key |resource_id| or |path| respectively.
virtual Status DeleteByResourceId(const std::string& resource_id) = 0;
virtual Status DeleteByPath(const FilePath& path) = 0;
// Fetches a GDataEntry* by key |resource_id| or |path| respectively.
virtual Status GetByResourceId(const std::string& resource_id,
scoped_ptr<GDataEntry>* entry) = 0;
virtual Status GetByPath(const FilePath& path,
scoped_ptr<GDataEntry>* entry) = 0;
// Creates an iterator to fetch all GDataEntry's under |path|.
// Will not return NULL.
virtual scoped_ptr<GDataDBIter> CreateIterator(const FilePath& path) = 0;
protected:
GDataDB() {}
};
// GData Database Iterator interface class.
class GDataDBIter {
public:
virtual ~GDataDBIter() {}
// Fetches the next |entry| in the iteration sequence. Returns false when
// there are no more entries.
virtual bool GetNext(std::string* path, scoped_ptr<GDataEntry>* entry) = 0;
protected:
GDataDBIter() {}
};
} // namespace gdata
#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/gdata/gdata_db_factory.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "chrome/browser/chromeos/gdata/gdata_leveldb.h"
namespace gdata {
namespace db_factory {
scoped_ptr<GDataDB> CreateGDataDB(const FilePath& db_path) {
DVLOG(1) << "CreateGDataDB " << db_path.value();
GDataLevelDB* level_db = new GDataLevelDB();
level_db->Init(db_path);
return scoped_ptr<GDataDB>(level_db);
}
} // namespace db_factory
} // namespace gdata
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_FACTORY_H_
#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_FACTORY_H_
#pragma once
#include "base/memory/scoped_ptr.h"
class FilePath;
namespace gdata {
class GDataDB;
namespace db_factory {
// Factory method to create an instance of GDataDB.
scoped_ptr<GDataDB> CreateGDataDB(const FilePath& db_path);
} // namespace db_factory
} // namespace gdata
#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_DB_FACTORY_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/gdata/gdata_db.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/chromeos/gdata/gdata_db_factory.h"
#include "chrome/browser/chromeos/gdata/gdata_files.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "chrome/test/base/testing_profile.h"
namespace gdata {
namespace {
class GDataDBTest : public testing::Test {
public:
GDataDBTest() {
}
virtual ~GDataDBTest() {
}
protected:
// testing::Test implementation.
virtual void SetUp() OVERRIDE;
// Tests GDataDB::GetPath and GDataDB::ResourceId, ensuring that an entry
// matching |source| does not exist.
void TestGetNotFound(const GDataEntry& source);
// Tests GDataDB::GetPath and GDataDB::ResourceId, ensuring that an entry
// matching |source| exists.
void TestGetFound(const GDataEntry& source);
// Initialize the database with the following entries:
// dir1
// dir2
// dir1/dir3
// dir1/file4
// dir1/file5
// dir2/file6
// dir2/file7
// dir2/file8
// dir1/dir3/file9
// dir1/dir3/file10
void InitDB();
// Helper functions to add a directory/file, incrementing index.
GDataDirectory* AddDirectory(GDataDirectory* parent, int sequence_id);
GDataFile* AddFile(GDataDirectory* parent, int sequence_id);
// Tests GDataDB::NewIterator and GDataDBIter::GetNext.
// Creates an iterator with start at |parent|, and iterates comparing with
// expected |filenames|.
void TestIter(const std::string& parent,
const char* file_paths[],
size_t file_paths_size);
scoped_ptr<TestingProfile> profile_;
scoped_ptr<GDataDB> gdata_db_;
GDataRootDirectory root_;
};
void GDataDBTest::SetUp() {
profile_.reset(new TestingProfile());
gdata_db_ = db_factory::CreateGDataDB(
profile_->GetPath().Append("testdb"));
}
void GDataDBTest::TestGetNotFound(const GDataEntry& source) {
scoped_ptr<GDataEntry> entry;
GDataDB::Status status = gdata_db_->GetByPath(source.GetFilePath(), &entry);
EXPECT_EQ(GDataDB::DB_KEY_NOT_FOUND, status);
EXPECT_FALSE(entry.get());
status = gdata_db_->GetByResourceId(source.resource_id(), &entry);
EXPECT_EQ(GDataDB::DB_KEY_NOT_FOUND, status);
EXPECT_FALSE(entry.get());
}
void GDataDBTest::TestGetFound(const GDataEntry& source) {
scoped_ptr<GDataEntry> entry;
GDataDB::Status status = gdata_db_->GetByPath(source.GetFilePath(), &entry);
EXPECT_EQ(GDataDB::DB_OK, status);
ASSERT_TRUE(entry.get());
EXPECT_EQ(source.file_name(), entry->file_name());
EXPECT_EQ(source.resource_id(), entry->resource_id());
EXPECT_EQ(source.content_url(), entry->content_url());
entry.reset();
status = gdata_db_->GetByResourceId(source.resource_id(), &entry);
EXPECT_EQ(GDataDB::DB_OK, status);
ASSERT_TRUE(entry.get());
EXPECT_EQ(source.file_name(), entry->file_name());
EXPECT_EQ(source.resource_id(), entry->resource_id());
EXPECT_EQ(source.content_url(), entry->content_url());
}
void GDataDBTest::InitDB() {
int sequence_id = 1;
GDataDirectory* dir1 = AddDirectory(NULL, sequence_id++);
GDataDirectory* dir2 = AddDirectory(NULL, sequence_id++);
GDataDirectory* dir3 = AddDirectory(dir1, sequence_id++);
AddFile(dir1, sequence_id++);
AddFile(dir1, sequence_id++);
AddFile(dir2, sequence_id++);
AddFile(dir2, sequence_id++);
AddFile(dir2, sequence_id++);
AddFile(dir3, sequence_id++);
AddFile(dir3, sequence_id++);
}
GDataDirectory* GDataDBTest::AddDirectory(GDataDirectory* parent,
int sequence_id) {
GDataDirectory* dir = new GDataDirectory(parent ? parent : &root_, &root_);
const std::string dir_name = "dir" + base::IntToString(sequence_id);
const std::string resource_id = std::string("dir_resource_id:") +
dir_name;
dir->set_file_name(dir_name);
dir->set_resource_id(resource_id);
GDataDB::Status status = gdata_db_->Put(*dir);
EXPECT_EQ(GDataDB::DB_OK, status);
DVLOG(1) << "AddDirectory " << dir->GetFilePath().value()
<< ", " << resource_id;
return dir;
}
GDataFile* GDataDBTest::AddFile(GDataDirectory* parent,
int sequence_id) {
GDataFile* file = new GDataFile(parent, &root_);
const std::string file_name = "file" + base::IntToString(sequence_id);
const std::string resource_id = std::string("file_resource_id:") +
file_name;
file->set_file_name(file_name);
file->set_resource_id(resource_id);
GDataDB::Status status = gdata_db_->Put(*file);
EXPECT_EQ(GDataDB::DB_OK, status);
DVLOG(1) << "AddFile " << file->GetFilePath().value()
<< ", " << resource_id;
return file;
}
void GDataDBTest::TestIter(const std::string& parent,
const char* file_paths[],
size_t file_paths_size) {
scoped_ptr<GDataDBIter> iter = gdata_db_->CreateIterator(
FilePath::FromUTF8Unsafe(parent));
for (size_t i = 0; ; ++i) {
scoped_ptr<GDataEntry> entry;
std::string path;
if (!iter->GetNext(&path, &entry)) {
EXPECT_EQ(i, file_paths_size);
break;
}
ASSERT_LT(i, file_paths_size);
// TODO(achuith): Also test entry->GetFilePath().
EXPECT_EQ(FilePath(file_paths[i]).BaseName().value(), entry->file_name());
EXPECT_EQ(file_paths[i], path);
DVLOG(1) << "Iter " << path;
}
}
} // namespace
TEST_F(GDataDBTest, PutTest) {
GDataDirectory* dir = new GDataDirectory(&root_, &root_);
dir->set_file_name("dir");
dir->set_resource_id("dir_resource_id");
dir->set_content_url(GURL("http://content/dir"));
dir->set_upload_url(GURL("http://upload/dir"));
TestGetNotFound(*dir);
GDataDB::Status status = gdata_db_->Put(*dir);
EXPECT_EQ(GDataDB::DB_OK, status);
TestGetFound(*dir);
scoped_ptr<GDataEntry> entry;
gdata_db_->GetByPath(dir->GetFilePath(), &entry);
EXPECT_EQ(dir->upload_url(), entry->AsGDataDirectory()->upload_url());
EXPECT_TRUE(entry->AsGDataDirectory()->file_info().is_directory);
status = gdata_db_->DeleteByPath(dir->GetFilePath());
EXPECT_EQ(GDataDB::DB_OK, status);
TestGetNotFound(*dir);
GDataFile* file = new GDataFile(dir, &root_);
file->set_file_name("file1");
file->set_resource_id("file1_resource_id");
file->set_content_url(GURL("http://content/dir1/file1"));
file->set_file_md5("file1_md5");
TestGetNotFound(*file);
status = gdata_db_->Put(*file);
EXPECT_EQ(GDataDB::DB_OK, status);
TestGetFound(*file);
gdata_db_->GetByPath(file->GetFilePath(), &entry);
EXPECT_EQ(file->file_md5(), entry->AsGDataFile()->file_md5());
EXPECT_FALSE(entry->AsGDataFile()->file_info().is_directory);
status = gdata_db_->DeleteByPath(file->GetFilePath());
EXPECT_EQ(GDataDB::DB_OK, status);
TestGetNotFound(*file);
}
TEST_F(GDataDBTest, IterTest) {
InitDB();
const char* dir1_children[] = {
"dir1",
"dir1/dir3",
"dir1/dir3/file10",
"dir1/dir3/file9",
"dir1/file4",
"dir1/file5",
};
TestIter("dir1", dir1_children, arraysize(dir1_children));
const char* dir2_children[] = {
"dir2",
"dir2/file6",
"dir2/file7",
"dir2/file8",
};
TestIter("dir2", dir2_children, arraysize(dir2_children));
const char* dir3_children[] = {
"dir1/dir3",
"dir1/dir3/file10",
"dir1/dir3/file9",
};
TestIter("dir1/dir3", dir3_children, arraysize(dir3_children));
const char* file10[] = {
"dir1/dir3/file10",
};
TestIter(file10[0], file10, arraysize(file10));
const char* all_entries[] = {
"dir1",
"dir1/dir3",
"dir1/dir3/file10",
"dir1/dir3/file9",
"dir1/file4",
"dir1/file5",
"dir2",
"dir2/file6",
"dir2/file7",
"dir2/file8",
};
TestIter("", all_entries, arraysize(all_entries));
TestIter("dir4", NULL, 0);
}
} // namespace gdata
...@@ -78,10 +78,20 @@ GDataRootDirectory* GDataEntry::AsGDataRootDirectory() { ...@@ -78,10 +78,20 @@ GDataRootDirectory* GDataEntry::AsGDataRootDirectory() {
return NULL; return NULL;
} }
FilePath GDataEntry::GetFilePath() { const GDataFile* GDataEntry::AsGDataFileConst() const {
// cast away const and call the non-const version. This is safe.
return const_cast<GDataEntry*>(this)->AsGDataFile();
}
const GDataDirectory* GDataEntry::AsGDataDirectoryConst() const {
// cast away const and call the non-const version. This is safe.
return const_cast<GDataEntry*>(this)->AsGDataDirectory();
}
FilePath GDataEntry::GetFilePath() const {
FilePath path; FilePath path;
std::vector<FilePath::StringType> parts; std::vector<FilePath::StringType> parts;
for (GDataEntry* entry = this; entry != NULL; entry = entry->parent()) for (const GDataEntry* entry = this; entry != NULL; entry = entry->parent_)
parts.push_back(entry->file_name()); parts.push_back(entry->file_name());
// Paste paths parts back together in reverse order from upward tree // Paste paths parts back together in reverse order from upward tree
...@@ -133,6 +143,7 @@ GDataFile::GDataFile(GDataDirectory* parent, GDataRootDirectory* root) ...@@ -133,6 +143,7 @@ GDataFile::GDataFile(GDataDirectory* parent, GDataRootDirectory* root)
: GDataEntry(parent, root), : GDataEntry(parent, root),
kind_(gdata::DocumentEntry::UNKNOWN), kind_(gdata::DocumentEntry::UNKNOWN),
is_hosted_document_(false) { is_hosted_document_(false) {
file_info_.is_directory = false;
} }
GDataFile::~GDataFile() { GDataFile::~GDataFile() {
...@@ -581,6 +592,7 @@ void GDataEntry::ToProto(GDataEntryProto* proto) const { ...@@ -581,6 +592,7 @@ void GDataEntry::ToProto(GDataEntryProto* proto) const {
} }
void GDataFile::FromProto(const GDataFileProto& proto) { void GDataFile::FromProto(const GDataFileProto& proto) {
DCHECK(!proto.gdata_entry().file_info().is_directory());
GDataEntry::FromProto(proto.gdata_entry()); GDataEntry::FromProto(proto.gdata_entry());
kind_ = DocumentEntry::EntryKind(proto.kind()); kind_ = DocumentEntry::EntryKind(proto.kind());
thumbnail_url_ = GURL(proto.thumbnail_url()); thumbnail_url_ = GURL(proto.thumbnail_url());
...@@ -595,6 +607,7 @@ void GDataFile::FromProto(const GDataFileProto& proto) { ...@@ -595,6 +607,7 @@ void GDataFile::FromProto(const GDataFileProto& proto) {
void GDataFile::ToProto(GDataFileProto* proto) const { void GDataFile::ToProto(GDataFileProto* proto) const {
GDataEntry::ToProto(proto->mutable_gdata_entry()); GDataEntry::ToProto(proto->mutable_gdata_entry());
DCHECK(!proto->gdata_entry().file_info().is_directory());
proto->set_kind(kind_); proto->set_kind(kind_);
proto->set_thumbnail_url(thumbnail_url_.spec()); proto->set_thumbnail_url(thumbnail_url_.spec());
proto->set_alternate_url(alternate_url_.spec()); proto->set_alternate_url(alternate_url_.spec());
...@@ -607,6 +620,7 @@ void GDataFile::ToProto(GDataFileProto* proto) const { ...@@ -607,6 +620,7 @@ void GDataFile::ToProto(GDataFileProto* proto) const {
} }
void GDataDirectory::FromProto(const GDataDirectoryProto& proto) { void GDataDirectory::FromProto(const GDataDirectoryProto& proto) {
DCHECK(proto.gdata_entry().file_info().is_directory());
GDataEntry::FromProto(proto.gdata_entry()); GDataEntry::FromProto(proto.gdata_entry());
refresh_time_ = base::Time::FromInternalValue(proto.refresh_time()); refresh_time_ = base::Time::FromInternalValue(proto.refresh_time());
start_feed_url_ = GURL(proto.start_feed_url()); start_feed_url_ = GURL(proto.start_feed_url());
...@@ -627,6 +641,7 @@ void GDataDirectory::FromProto(const GDataDirectoryProto& proto) { ...@@ -627,6 +641,7 @@ void GDataDirectory::FromProto(const GDataDirectoryProto& proto) {
void GDataDirectory::ToProto(GDataDirectoryProto* proto) const { void GDataDirectory::ToProto(GDataDirectoryProto* proto) const {
GDataEntry::ToProto(proto->mutable_gdata_entry()); GDataEntry::ToProto(proto->mutable_gdata_entry());
DCHECK(proto->gdata_entry().file_info().is_directory());
proto->set_refresh_time(refresh_time_.ToInternalValue()); proto->set_refresh_time(refresh_time_.ToInternalValue());
proto->set_start_feed_url(start_feed_url_.spec()); proto->set_start_feed_url(start_feed_url_.spec());
proto->set_next_feed_url(next_feed_url_.spec()); proto->set_next_feed_url(next_feed_url_.spec());
...@@ -654,18 +669,61 @@ void GDataRootDirectory::ToProto(GDataRootDirectoryProto* proto) const { ...@@ -654,18 +669,61 @@ void GDataRootDirectory::ToProto(GDataRootDirectoryProto* proto) const {
proto->set_largest_changestamp(largest_changestamp_); proto->set_largest_changestamp(largest_changestamp_);
} }
void GDataRootDirectory::SerializeToString(std::string* proto_string) const { void GDataEntry::SerializeToString(std::string* serialized_proto) const {
const GDataFile* file = AsGDataFileConst();
const GDataDirectory* dir = AsGDataDirectoryConst();
if (file) {
scoped_ptr<GDataFileProto> proto(new GDataFileProto());
file->ToProto(proto.get());
const bool ok = proto->SerializeToString(serialized_proto);
DCHECK(ok);
} else if (dir) {
scoped_ptr<GDataDirectoryProto> proto(new GDataDirectoryProto());
dir->ToProto(proto.get());
const bool ok = proto->SerializeToString(serialized_proto);
DCHECK(ok);
}
}
// static
scoped_ptr<GDataEntry> GDataEntry::FromProtoString(
const std::string& serialized_proto) {
// First try to parse as GDataDirectoryProto. Note that this can succeed for
// a serialized_proto that's really a GDataFileProto - we have to check
// is_directory to be sure.
scoped_ptr<GDataDirectoryProto> dir_proto(new GDataDirectoryProto());
bool ok = dir_proto->ParseFromString(serialized_proto);
if (ok && dir_proto->gdata_entry().file_info().is_directory()) {
GDataDirectory* dir = new GDataDirectory(NULL, NULL);
dir->FromProto(*dir_proto);
return scoped_ptr<GDataEntry>(dir);
}
scoped_ptr<GDataFileProto> file_proto(new GDataFileProto());
ok = file_proto->ParseFromString(serialized_proto);
if (ok) {
DCHECK(!file_proto->gdata_entry().file_info().is_directory());
GDataFile* file = new GDataFile(NULL, NULL);
file->FromProto(*file_proto);
return scoped_ptr<GDataEntry>(file);
}
return scoped_ptr<GDataEntry>(NULL);
}
void GDataRootDirectory::SerializeToString(
std::string* serialized_proto) const {
scoped_ptr<GDataRootDirectoryProto> proto( scoped_ptr<GDataRootDirectoryProto> proto(
new GDataRootDirectoryProto()); new GDataRootDirectoryProto());
ToProto(proto.get()); ToProto(proto.get());
const bool ok = proto->SerializeToString(proto_string); const bool ok = proto->SerializeToString(serialized_proto);
DCHECK(ok); DCHECK(ok);
} }
bool GDataRootDirectory::ParseFromString(const std::string& proto_string) { bool GDataRootDirectory::ParseFromString(const std::string& serialized_proto) {
scoped_ptr<GDataRootDirectoryProto> proto( scoped_ptr<GDataRootDirectoryProto> proto(
new GDataRootDirectoryProto()); new GDataRootDirectoryProto());
bool ok = proto->ParseFromString(proto_string); bool ok = proto->ParseFromString(serialized_proto);
if (ok) { if (ok) {
FromProto(*proto.get()); FromProto(*proto.get());
set_origin(FROM_CACHE); set_origin(FROM_CACHE);
......
...@@ -59,15 +59,27 @@ class GDataEntry { ...@@ -59,15 +59,27 @@ class GDataEntry {
public: public:
explicit GDataEntry(GDataDirectory* parent, GDataRootDirectory* root); explicit GDataEntry(GDataDirectory* parent, GDataRootDirectory* root);
virtual ~GDataEntry(); virtual ~GDataEntry();
virtual GDataFile* AsGDataFile(); virtual GDataFile* AsGDataFile();
virtual GDataDirectory* AsGDataDirectory(); virtual GDataDirectory* AsGDataDirectory();
virtual GDataRootDirectory* AsGDataRootDirectory(); virtual GDataRootDirectory* AsGDataRootDirectory();
// const versions of AsGDataFile and AsGDataDirectory.
const GDataFile* AsGDataFileConst() const;
const GDataDirectory* AsGDataDirectoryConst() const;
// Converts DocumentEntry into GDataEntry. // Converts DocumentEntry into GDataEntry.
static GDataEntry* FromDocumentEntry(GDataDirectory* parent, static GDataEntry* FromDocumentEntry(GDataDirectory* parent,
DocumentEntry* doc, DocumentEntry* doc,
GDataRootDirectory* root); GDataRootDirectory* root);
// Serialize/Parse to/from string via proto classes.
// TODO(achuith): Correctly set up parent_ and root_ links in
// FromProtoString.
void SerializeToString(std::string* serialized_proto) const;
static scoped_ptr<GDataEntry> FromProtoString(
const std::string& serialized_proto);
// Convert to/from proto. // Convert to/from proto.
void FromProto(const GDataEntryProto& proto); void FromProto(const GDataEntryProto& proto);
void ToProto(GDataEntryProto* proto) const; void ToProto(GDataEntryProto* proto) const;
...@@ -81,20 +93,20 @@ class GDataEntry { ...@@ -81,20 +93,20 @@ class GDataEntry {
GDataDirectory* parent() { return parent_; } GDataDirectory* parent() { return parent_; }
const base::PlatformFileInfo& file_info() const { return file_info_; } const base::PlatformFileInfo& file_info() const { return file_info_; }
const FilePath::StringType& file_name() const { return file_name_; } const FilePath::StringType& file_name() const { return file_name_; }
const FilePath::StringType& title() const {
return title_;
}
void set_title(const FilePath::StringType& title) {
title_ = title;
}
void set_file_name(const FilePath::StringType& name) { file_name_ = name; } void set_file_name(const FilePath::StringType& name) { file_name_ = name; }
const FilePath::StringType& title() const { return title_; }
void set_title(const FilePath::StringType& title) { title_ = title; }
// The unique resource ID associated with this file system entry. // The unique resource ID associated with this file system entry.
const std::string& resource_id() const { return resource_id_; } const std::string& resource_id() const { return resource_id_; }
void set_resource_id(const std::string& res_id) { resource_id_ = res_id; }
// The content URL is used for downloading regular files as is. // The content URL is used for downloading regular files as is.
const GURL& content_url() const { return content_url_; } const GURL& content_url() const { return content_url_; }
void set_content_url(const GURL& url) { content_url_ = url; }
// The edit URL is used for removing files and hosted documents. // The edit URL is used for removing files and hosted documents.
const GURL& edit_url() const { return edit_url_; } const GURL& edit_url() const { return edit_url_; }
...@@ -111,7 +123,7 @@ class GDataEntry { ...@@ -111,7 +123,7 @@ class GDataEntry {
// Returns virtual file path representing this file system entry. This path // Returns virtual file path representing this file system entry. This path
// corresponds to file path expected by public methods of GDataFileSyste // corresponds to file path expected by public methods of GDataFileSyste
// class. // class.
FilePath GetFilePath(); FilePath GetFilePath() const;
// Sets |file_name_| based on the value of |title_| without name // Sets |file_name_| based on the value of |title_| without name
// de-duplication (see AddEntry() for details on de-duplication). // de-duplication (see AddEntry() for details on de-duplication).
...@@ -221,6 +233,7 @@ class GDataFile : public GDataEntry { ...@@ -221,6 +233,7 @@ class GDataFile : public GDataEntry {
const std::string& etag() const { return etag_; } const std::string& etag() const { return etag_; }
const std::string& id() const { return id_; } const std::string& id() const { return id_; }
const std::string& file_md5() const { return file_md5_; } const std::string& file_md5() const { return file_md5_; }
void set_file_md5(const std::string& file_md5) { file_md5_ = file_md5; }
const std::string& document_extension() const { return document_extension_; } const std::string& document_extension() const { return document_extension_; }
bool is_hosted_document() const { return is_hosted_document_; } bool is_hosted_document() const { return is_hosted_document_; }
...@@ -398,7 +411,6 @@ class GDataRootDirectory : public GDataDirectory { ...@@ -398,7 +411,6 @@ class GDataRootDirectory : public GDataDirectory {
void set_serialized_size(size_t size) { serialized_size_ = size; } void set_serialized_size(size_t size) { serialized_size_ = size; }
// GDataEntry implementation. // GDataEntry implementation.
virtual GDataRootDirectory* AsGDataRootDirectory() OVERRIDE; virtual GDataRootDirectory* AsGDataRootDirectory() OVERRIDE;
// Add the entry to resource map. // Add the entry to resource map.
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/gdata/gdata_leveldb.h"
#include <string>
#include "base/logging.h"
#include "chrome/browser/chromeos/gdata/gdata_files.h"
#include "leveldb/write_batch.h"
namespace gdata {
namespace {
const char kResourceIdPrefix[] = "r:";
const char kPathPrefix[] = "p:";
// Append prefix id: to |resource_id|.
std::string ResourceIdToKey(const std::string& resource_id) {
return std::string(kResourceIdPrefix) + resource_id;
}
// Append prefix path: to |path|.
std::string PathToKey(const FilePath& path) {
return std::string(kPathPrefix) + path.value();
}
GDataDB::Status GetStatus(const leveldb::Status& db_status) {
if (db_status.ok())
return GDataDB::DB_OK;
if (db_status.IsNotFound())
return GDataDB::DB_KEY_NOT_FOUND;
if (db_status.IsCorruption())
return GDataDB::DB_CORRUPTION;
if (db_status.IsIOError())
return GDataDB::DB_IO_ERROR;
NOTREACHED();
return GDataDB::DB_INTERNAL_ERROR;
}
} // namespace
GDataLevelDB::GDataLevelDB() {
}
GDataLevelDB::~GDataLevelDB() {
}
void GDataLevelDB::Init(const FilePath& db_path) {
leveldb::DB* level_db = NULL;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status db_status = leveldb::DB::Open(options,
db_path.Append("level_db").value(), &level_db);
DCHECK(level_db);
// TODO(achuith): If db cannot be opened, we should try to recover it.
// If that fails, we should just delete it and create a new file.
DCHECK(db_status.ok());
level_db_.reset(level_db);
}
GDataDB::Status GDataLevelDB::Put(const GDataEntry& entry) {
// Write the serialized proto.
std::string serialized_proto;
entry.SerializeToString(&serialized_proto);
leveldb::WriteBatch batch;
const std::string resource_id_key =
ResourceIdToKey(entry.resource_id());
const std::string path_key = PathToKey(entry.GetFilePath());
batch.Put(leveldb::Slice(resource_id_key), leveldb::Slice(serialized_proto));
// Note we store the resource_id without prefix when it's the value.
batch.Put(leveldb::Slice(path_key), leveldb::Slice(entry.resource_id()));
leveldb::Status db_status = level_db_->Write(
leveldb::WriteOptions(),
&batch);
DVLOG(1) << "GDataLevelDB::Put resource_id key = " << resource_id_key
<< ", path key = " << path_key;
return GetStatus(db_status);
}
GDataDB::Status GDataLevelDB::DeleteByResourceId(
const std::string& resource_id) {
scoped_ptr<GDataEntry> entry;
Status status = GetByResourceId(resource_id, &entry);
if (status == DB_KEY_NOT_FOUND)
return DB_OK;
else if (status != DB_OK)
return status;
leveldb::WriteBatch batch;
const std::string resource_id_key = ResourceIdToKey(resource_id);
const std::string path_key = PathToKey(entry->GetFilePath());
batch.Delete(leveldb::Slice(resource_id_key));
batch.Delete(leveldb::Slice(path_key));
leveldb::Status db_status = level_db_->Write(leveldb::WriteOptions(),
&batch);
return GetStatus(db_status);
}
GDataDB::Status GDataLevelDB::DeleteByPath(
const FilePath& path) {
std::string resource_id;
const Status status = ResourceIdForPath(path, &resource_id);
if (status != DB_OK)
return status;
return DeleteByResourceId(resource_id);
}
GDataDB::Status GDataLevelDB::GetByResourceId(const std::string& resource_id,
scoped_ptr<GDataEntry>* entry) {
entry->reset();
std::string serialized_proto;
const std::string resource_id_key = ResourceIdToKey(resource_id);
const leveldb::Status db_status = level_db_->Get(leveldb::ReadOptions(),
leveldb::Slice(resource_id_key), &serialized_proto);
if (db_status.IsNotFound())
return DB_KEY_NOT_FOUND;
if (db_status.ok()) {
DCHECK(!serialized_proto.empty());
*entry = GDataEntry::FromProtoString(serialized_proto);
DCHECK(entry->get());
return DB_OK;
}
return GetStatus(db_status);
}
GDataDB::Status GDataLevelDB::GetByPath(const FilePath& path,
scoped_ptr<GDataEntry>* entry) {
entry->reset();
std::string resource_id;
const Status status = ResourceIdForPath(path, &resource_id);
if (status != DB_OK)
return status;
return GetByResourceId(resource_id, entry);
}
GDataDB::Status GDataLevelDB::ResourceIdForPath(const FilePath& path,
std::string* resource_id) {
const std::string path_key = PathToKey(path);
const leveldb::Status db_status = level_db_->Get(
leveldb::ReadOptions(), path_key, resource_id);
return GetStatus(db_status);
}
scoped_ptr<GDataDBIter> GDataLevelDB::CreateIterator(const FilePath& path) {
return scoped_ptr<GDataDBIter>(new GDataLevelDBIter(
scoped_ptr<leveldb::Iterator>(
level_db_->NewIterator(leveldb::ReadOptions())),
this,
path));
}
GDataLevelDBIter::GDataLevelDBIter(scoped_ptr<leveldb::Iterator> level_db_iter,
GDataDB* db,
const FilePath& path)
: level_db_iter_(level_db_iter.Pass()),
db_(db),
path_(path) {
const std::string path_key = PathToKey(path);
level_db_iter_->Seek(leveldb::Slice(path_key));
}
GDataLevelDBIter::~GDataLevelDBIter() {
}
bool GDataLevelDBIter::GetNext(std::string* path,
scoped_ptr<GDataEntry>* entry) {
DCHECK(path);
DCHECK(entry);
path->clear();
entry->reset();
if (!level_db_iter_->Valid())
return false;
// Only consider keys under |path|.
const std::string path_key = PathToKey(path_);
leveldb::Slice key_slice(level_db_iter_->key());
if (!key_slice.starts_with(path_key))
return false;
GDataDB::Status status =
db_->GetByResourceId(level_db_iter_->value().ToString(), entry);
DCHECK_EQ(GDataDB::DB_OK, status);
key_slice.remove_prefix(sizeof(kPathPrefix) - 1);
path->assign(key_slice.ToString());
level_db_iter_->Next();
return true;
}
} // namespace gdata
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_GDATA_GDATA_LEVELDB_H_
#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_LEVELDB_H_
#pragma once
#include <leveldb/db.h>
#include <string>
#include "base/file_path.h"
#include "chrome/browser/chromeos/gdata/gdata_db.h"
namespace gdata {
class GDataLevelDB : public GDataDB {
public:
GDataLevelDB();
void Init(const FilePath& db_path);
private:
virtual ~GDataLevelDB();
// GDataDB implementation.
virtual Status Put(const GDataEntry& file) OVERRIDE;
virtual Status DeleteByResourceId(const std::string& resource_id) OVERRIDE;
virtual Status DeleteByPath(const FilePath& path) OVERRIDE;
virtual Status GetByResourceId(const std::string& resource_id,
scoped_ptr<GDataEntry>* file) OVERRIDE;
virtual Status GetByPath(const FilePath& path,
scoped_ptr<GDataEntry>* file) OVERRIDE;
virtual scoped_ptr<GDataDBIter> CreateIterator(const FilePath& path) OVERRIDE;
// Returns |resource_id| for |path| by looking up path_db_.
Status ResourceIdForPath(const FilePath& path, std::string* resource_id);
scoped_ptr<leveldb::DB> level_db_;
};
class GDataLevelDBIter : public GDataDBIter {
public:
GDataLevelDBIter(scoped_ptr<leveldb::Iterator> level_db_iter,
GDataDB* db, const FilePath& path);
private:
virtual ~GDataLevelDBIter();
// GDataDBIter implementation.
virtual bool GetNext(std::string* path,
scoped_ptr<GDataEntry>* entry) OVERRIDE;
scoped_ptr<leveldb::Iterator> level_db_iter_;
GDataDB* db_;
const FilePath path_;
};
} // namespace gdata
#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_LEVELDB_H_
...@@ -509,6 +509,9 @@ ...@@ -509,6 +509,9 @@
'browser/chromeos/external_protocol_dialog.h', 'browser/chromeos/external_protocol_dialog.h',
'browser/chromeos/gdata/gdata_auth_service.cc', 'browser/chromeos/gdata/gdata_auth_service.cc',
'browser/chromeos/gdata/gdata_auth_service.h', 'browser/chromeos/gdata/gdata_auth_service.h',
'browser/chromeos/gdata/gdata_db.h',
'browser/chromeos/gdata/gdata_db_factory.cc',
'browser/chromeos/gdata/gdata_db_factory.h',
'browser/chromeos/gdata/gdata_documents_service.cc', 'browser/chromeos/gdata/gdata_documents_service.cc',
'browser/chromeos/gdata/gdata_documents_service.h', 'browser/chromeos/gdata/gdata_documents_service.h',
'browser/chromeos/gdata/gdata_download_observer.cc', 'browser/chromeos/gdata/gdata_download_observer.cc',
...@@ -520,6 +523,8 @@ ...@@ -520,6 +523,8 @@
'browser/chromeos/gdata/gdata_file_system_proxy.h', 'browser/chromeos/gdata/gdata_file_system_proxy.h',
'browser/chromeos/gdata/gdata_files.cc', 'browser/chromeos/gdata/gdata_files.cc',
'browser/chromeos/gdata/gdata_files.h', 'browser/chromeos/gdata/gdata_files.h',
'browser/chromeos/gdata/gdata_leveldb.cc',
'browser/chromeos/gdata/gdata_leveldb.h',
'browser/chromeos/gdata/gdata_operation_registry.cc', 'browser/chromeos/gdata/gdata_operation_registry.cc',
'browser/chromeos/gdata/gdata_operation_registry.h', 'browser/chromeos/gdata/gdata_operation_registry.h',
'browser/chromeos/gdata/gdata_operations.cc', 'browser/chromeos/gdata/gdata_operations.cc',
......
...@@ -1203,6 +1203,7 @@ ...@@ -1203,6 +1203,7 @@
'browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc', 'browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc',
'browser/chromeos/extensions/file_browser_notifications_unittest.cc', 'browser/chromeos/extensions/file_browser_notifications_unittest.cc',
'browser/chromeos/external_metrics_unittest.cc', 'browser/chromeos/external_metrics_unittest.cc',
'browser/chromeos/gdata/gdata_db_unittest.cc',
'browser/chromeos/gdata/gdata_file_system_unittest.cc', 'browser/chromeos/gdata/gdata_file_system_unittest.cc',
'browser/chromeos/gdata/gdata_files_unittest.cc', 'browser/chromeos/gdata/gdata_files_unittest.cc',
'browser/chromeos/gdata/gdata_operation_registry_unittest.cc', 'browser/chromeos/gdata/gdata_operation_registry_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment