| Index: sync/internal_api/attachments/on_disk_attachment_store.cc
|
| diff --git a/sync/internal_api/attachments/on_disk_attachment_store.cc b/sync/internal_api/attachments/on_disk_attachment_store.cc
|
| index 2c27e3be186b21ef7310c48ec25d93d69e806f90..09b4811681307271f13e938e8bad9a0536ebf635 100644
|
| --- a/sync/internal_api/attachments/on_disk_attachment_store.cc
|
| +++ b/sync/internal_api/attachments/on_disk_attachment_store.cc
|
| @@ -9,6 +9,7 @@
|
| #include "base/location.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/sequenced_task_runner.h"
|
| +#include "sync/internal_api/attachments/proto/attachment_store.pb.h"
|
| #include "sync/protocol/attachments.pb.h"
|
| #include "third_party/leveldatabase/src/include/leveldb/db.h"
|
| #include "third_party/leveldatabase/src/include/leveldb/options.h"
|
| @@ -22,8 +23,45 @@ namespace {
|
| // Prefix for records containing attachment data.
|
| const char kDataPrefix[] = "data-";
|
|
|
| +const char kDatabaseMetadataKey[] = "database-metadata";
|
| +
|
| +const int32 kCurrentSchemaVersion = 1;
|
| +
|
| const base::FilePath::CharType kLeveldbDirectory[] =
|
| FILE_PATH_LITERAL("leveldb");
|
| +
|
| +leveldb::WriteOptions MakeWriteOptions() {
|
| + leveldb::WriteOptions write_options;
|
| + write_options.sync = true;
|
| + return write_options;
|
| +}
|
| +
|
| +leveldb::Status ReadStoreMetadata(
|
| + leveldb::DB* db,
|
| + attachment_store_pb::AttachmentStoreMetadata* metadata) {
|
| + std::string data_str;
|
| + leveldb::ReadOptions read_options;
|
| + read_options.fill_cache = false;
|
| + read_options.verify_checksums = true;
|
| +
|
| + leveldb::Status status =
|
| + db->Get(read_options, kDatabaseMetadataKey, &data_str);
|
| + if (!status.ok())
|
| + return status;
|
| + if (!metadata->ParseFromString(data_str))
|
| + return leveldb::Status::Corruption("Metadata record corruption");
|
| + return leveldb::Status::OK();
|
| +}
|
| +
|
| +leveldb::Status WriteStoreMetadata(
|
| + leveldb::DB* db,
|
| + const attachment_store_pb::AttachmentStoreMetadata& metadata) {
|
| + std::string data_str;
|
| +
|
| + metadata.SerializeToString(&data_str);
|
| + return db->Put(MakeWriteOptions(), kDatabaseMetadataKey, data_str);
|
| +}
|
| +
|
| } // namespace
|
|
|
| OnDiskAttachmentStore::OnDiskAttachmentStore(
|
| @@ -50,7 +88,7 @@ void OnDiskAttachmentStore::Read(const AttachmentIdList& ids,
|
| AttachmentIdList::const_iterator iter = ids.begin();
|
| const AttachmentIdList::const_iterator end = ids.end();
|
| for (; iter != end; ++iter) {
|
| - const std::string key = CreateDataKeyFromAttachmentId(*iter);
|
| + const std::string key = MakeDataKeyFromAttachmentId(*iter);
|
| std::string data_str;
|
| leveldb::Status status = db_->Get(read_options, key, &data_str);
|
| if (!status.ok()) {
|
| @@ -84,13 +122,12 @@ void OnDiskAttachmentStore::Write(const AttachmentList& attachments,
|
| read_options.fill_cache = false;
|
| read_options.verify_checksums = true;
|
|
|
| - leveldb::WriteOptions write_options;
|
| - write_options.sync = true;
|
| + leveldb::WriteOptions write_options = MakeWriteOptions();
|
|
|
| AttachmentList::const_iterator iter = attachments.begin();
|
| const AttachmentList::const_iterator end = attachments.end();
|
| for (; iter != end; ++iter) {
|
| - const std::string key = CreateDataKeyFromAttachmentId(iter->GetId());
|
| + const std::string key = MakeDataKeyFromAttachmentId(iter->GetId());
|
|
|
| std::string data_str;
|
| // TODO(pavely): crbug/424304 This read is expensive. When I add metadata
|
| @@ -124,12 +161,11 @@ void OnDiskAttachmentStore::Drop(const AttachmentIdList& ids,
|
| DCHECK(CalledOnValidThread());
|
| DCHECK(db_);
|
| Result result_code = SUCCESS;
|
| - leveldb::WriteOptions write_options;
|
| - write_options.sync = true;
|
| + leveldb::WriteOptions write_options = MakeWriteOptions();
|
| AttachmentIdList::const_iterator iter = ids.begin();
|
| const AttachmentIdList::const_iterator end = ids.end();
|
| for (; iter != end; ++iter) {
|
| - const std::string key = CreateDataKeyFromAttachmentId(*iter);
|
| + const std::string key = MakeDataKeyFromAttachmentId(*iter);
|
| leveldb::Status status = db_->Delete(write_options, key);
|
| if (!status.ok()) {
|
| // DB::Delete doesn't check if record exists, it returns ok just like
|
| @@ -145,27 +181,53 @@ AttachmentStore::Result OnDiskAttachmentStore::OpenOrCreate(
|
| const base::FilePath& path) {
|
| DCHECK(CalledOnValidThread());
|
| DCHECK(!db_);
|
| - Result result_code = UNSPECIFIED_ERROR;
|
| base::FilePath leveldb_path = path.Append(kLeveldbDirectory);
|
|
|
| - leveldb::DB* db;
|
| + leveldb::DB* db_raw;
|
| + scoped_ptr<leveldb::DB> db;
|
| leveldb::Options options;
|
| options.create_if_missing = true;
|
| // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and
|
| // filter_policy to options.
|
| leveldb::Status status =
|
| - leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db);
|
| + leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db_raw);
|
| if (!status.ok()) {
|
| DVLOG(1) << "DB::Open failed: status=" << status.ToString()
|
| << ", path=" << path.AsUTF8Unsafe();
|
| - } else {
|
| - db_.reset(db);
|
| - result_code = SUCCESS;
|
| + return UNSPECIFIED_ERROR;
|
| + }
|
| +
|
| + db.reset(db_raw);
|
| +
|
| + attachment_store_pb::AttachmentStoreMetadata metadata;
|
| + status = ReadStoreMetadata(db.get(), &metadata);
|
| + if (!status.ok() && !status.IsNotFound()) {
|
| + DVLOG(1) << "ReadStoreMetadata failed: status=" << status.ToString();
|
| + return UNSPECIFIED_ERROR;
|
| }
|
| - return result_code;
|
| + if (status.IsNotFound()) {
|
| + // Brand new database.
|
| + metadata.set_schema_version(kCurrentSchemaVersion);
|
| + status = WriteStoreMetadata(db.get(), metadata);
|
| + if (!status.ok()) {
|
| + DVLOG(1) << "WriteStoreMetadata failed: status=" << status.ToString();
|
| + return UNSPECIFIED_ERROR;
|
| + }
|
| + }
|
| + DCHECK(status.ok());
|
| +
|
| + // Upgrade code goes here.
|
| +
|
| + if (metadata.schema_version() != kCurrentSchemaVersion) {
|
| + DVLOG(1) << "Unknown schema version: " << metadata.schema_version();
|
| + return UNSPECIFIED_ERROR;
|
| + }
|
| +
|
| + db_ = db.Pass();
|
| + return SUCCESS;
|
| }
|
|
|
| -std::string OnDiskAttachmentStore::CreateDataKeyFromAttachmentId(
|
| +std::string OnDiskAttachmentStore::MakeDataKeyFromAttachmentId(
|
| const AttachmentId& attachment_id) {
|
| std::string key = kDataPrefix + attachment_id.GetProto().unique_id();
|
| return key;
|
|
|