Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: sync/internal_api/attachments/on_disk_attachment_store.cc

Issue 647553009: Introduce AttachmentStore metadata record (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: GN fix Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sync/BUILD.gn ('k') | sync/internal_api/attachments/on_disk_attachment_store_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/internal_api/public/attachments/on_disk_attachment_store.h" 5 #include "sync/internal_api/public/attachments/on_disk_attachment_store.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/sequenced_task_runner.h" 11 #include "base/sequenced_task_runner.h"
12 #include "sync/internal_api/attachments/proto/attachment_store.pb.h"
12 #include "sync/protocol/attachments.pb.h" 13 #include "sync/protocol/attachments.pb.h"
13 #include "third_party/leveldatabase/src/include/leveldb/db.h" 14 #include "third_party/leveldatabase/src/include/leveldb/db.h"
14 #include "third_party/leveldatabase/src/include/leveldb/options.h" 15 #include "third_party/leveldatabase/src/include/leveldb/options.h"
15 #include "third_party/leveldatabase/src/include/leveldb/slice.h" 16 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
16 #include "third_party/leveldatabase/src/include/leveldb/status.h" 17 #include "third_party/leveldatabase/src/include/leveldb/status.h"
17 18
18 namespace syncer { 19 namespace syncer {
19 20
20 namespace { 21 namespace {
21 22
22 // Prefix for records containing attachment data. 23 // Prefix for records containing attachment data.
23 const char kDataPrefix[] = "data-"; 24 const char kDataPrefix[] = "data-";
24 25
26 const char kDatabaseMetadataKey[] = "database-metadata";
27
28 const int32 kCurrentSchemaVersion = 1;
29
25 const base::FilePath::CharType kLeveldbDirectory[] = 30 const base::FilePath::CharType kLeveldbDirectory[] =
26 FILE_PATH_LITERAL("leveldb"); 31 FILE_PATH_LITERAL("leveldb");
32
33 leveldb::WriteOptions MakeWriteOptions() {
34 leveldb::WriteOptions write_options;
35 write_options.sync = true;
36 return write_options;
37 }
38
39 leveldb::Status ReadStoreMetadata(
40 leveldb::DB* db,
41 attachment_store_pb::AttachmentStoreMetadata* metadata) {
42 std::string data_str;
43 leveldb::ReadOptions read_options;
44 read_options.fill_cache = false;
45 read_options.verify_checksums = true;
46
47 leveldb::Status status =
48 db->Get(read_options, kDatabaseMetadataKey, &data_str);
49 if (!status.ok())
50 return status;
51 if (!metadata->ParseFromString(data_str))
52 return leveldb::Status::Corruption("Metadata record corruption");
53 return leveldb::Status::OK();
54 }
55
56 leveldb::Status WriteStoreMetadata(
57 leveldb::DB* db,
58 const attachment_store_pb::AttachmentStoreMetadata& metadata) {
59 std::string data_str;
60
61 metadata.SerializeToString(&data_str);
62 return db->Put(MakeWriteOptions(), kDatabaseMetadataKey, data_str);
63 }
64
27 } // namespace 65 } // namespace
28 66
29 OnDiskAttachmentStore::OnDiskAttachmentStore( 67 OnDiskAttachmentStore::OnDiskAttachmentStore(
30 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner) 68 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner)
31 : callback_task_runner_(callback_task_runner) { 69 : callback_task_runner_(callback_task_runner) {
32 } 70 }
33 71
34 OnDiskAttachmentStore::~OnDiskAttachmentStore() { 72 OnDiskAttachmentStore::~OnDiskAttachmentStore() {
35 } 73 }
36 74
37 void OnDiskAttachmentStore::Read(const AttachmentIdList& ids, 75 void OnDiskAttachmentStore::Read(const AttachmentIdList& ids,
38 const ReadCallback& callback) { 76 const ReadCallback& callback) {
39 DCHECK(CalledOnValidThread()); 77 DCHECK(CalledOnValidThread());
40 DCHECK(db_); 78 DCHECK(db_);
41 scoped_ptr<AttachmentMap> result_map(new AttachmentMap()); 79 scoped_ptr<AttachmentMap> result_map(new AttachmentMap());
42 scoped_ptr<AttachmentIdList> unavailable_attachments(new AttachmentIdList()); 80 scoped_ptr<AttachmentIdList> unavailable_attachments(new AttachmentIdList());
43 81
44 leveldb::ReadOptions read_options; 82 leveldb::ReadOptions read_options;
45 // Attachment content is typically large and only read once. Don't cache it on 83 // Attachment content is typically large and only read once. Don't cache it on
46 // db level. 84 // db level.
47 read_options.fill_cache = false; 85 read_options.fill_cache = false;
48 read_options.verify_checksums = true; 86 read_options.verify_checksums = true;
49 87
50 AttachmentIdList::const_iterator iter = ids.begin(); 88 AttachmentIdList::const_iterator iter = ids.begin();
51 const AttachmentIdList::const_iterator end = ids.end(); 89 const AttachmentIdList::const_iterator end = ids.end();
52 for (; iter != end; ++iter) { 90 for (; iter != end; ++iter) {
53 const std::string key = CreateDataKeyFromAttachmentId(*iter); 91 const std::string key = MakeDataKeyFromAttachmentId(*iter);
54 std::string data_str; 92 std::string data_str;
55 leveldb::Status status = db_->Get(read_options, key, &data_str); 93 leveldb::Status status = db_->Get(read_options, key, &data_str);
56 if (!status.ok()) { 94 if (!status.ok()) {
57 DVLOG(1) << "DB::Get failed: status=" << status.ToString(); 95 DVLOG(1) << "DB::Get failed: status=" << status.ToString();
58 unavailable_attachments->push_back(*iter); 96 unavailable_attachments->push_back(*iter);
59 continue; 97 continue;
60 } 98 }
61 scoped_refptr<base::RefCountedMemory> data = 99 scoped_refptr<base::RefCountedMemory> data =
62 base::RefCountedString::TakeString(&data_str); 100 base::RefCountedString::TakeString(&data_str);
63 Attachment attachment = Attachment::CreateWithId(*iter, data); 101 Attachment attachment = Attachment::CreateWithId(*iter, data);
(...skipping 13 matching lines...) Expand all
77 void OnDiskAttachmentStore::Write(const AttachmentList& attachments, 115 void OnDiskAttachmentStore::Write(const AttachmentList& attachments,
78 const WriteCallback& callback) { 116 const WriteCallback& callback) {
79 DCHECK(CalledOnValidThread()); 117 DCHECK(CalledOnValidThread());
80 DCHECK(db_); 118 DCHECK(db_);
81 Result result_code = SUCCESS; 119 Result result_code = SUCCESS;
82 120
83 leveldb::ReadOptions read_options; 121 leveldb::ReadOptions read_options;
84 read_options.fill_cache = false; 122 read_options.fill_cache = false;
85 read_options.verify_checksums = true; 123 read_options.verify_checksums = true;
86 124
87 leveldb::WriteOptions write_options; 125 leveldb::WriteOptions write_options = MakeWriteOptions();
88 write_options.sync = true;
89 126
90 AttachmentList::const_iterator iter = attachments.begin(); 127 AttachmentList::const_iterator iter = attachments.begin();
91 const AttachmentList::const_iterator end = attachments.end(); 128 const AttachmentList::const_iterator end = attachments.end();
92 for (; iter != end; ++iter) { 129 for (; iter != end; ++iter) {
93 const std::string key = CreateDataKeyFromAttachmentId(iter->GetId()); 130 const std::string key = MakeDataKeyFromAttachmentId(iter->GetId());
94 131
95 std::string data_str; 132 std::string data_str;
96 // TODO(pavely): crbug/424304 This read is expensive. When I add metadata 133 // TODO(pavely): crbug/424304 This read is expensive. When I add metadata
97 // records this read will target metadata record instead of payload record. 134 // records this read will target metadata record instead of payload record.
98 leveldb::Status status = db_->Get(read_options, key, &data_str); 135 leveldb::Status status = db_->Get(read_options, key, &data_str);
99 if (status.ok()) { 136 if (status.ok()) {
100 // Entry exists, don't overwrite. 137 // Entry exists, don't overwrite.
101 continue; 138 continue;
102 } else if (!status.IsNotFound()) { 139 } else if (!status.IsNotFound()) {
103 // Entry exists but failed to read. 140 // Entry exists but failed to read.
(...skipping 13 matching lines...) Expand all
117 } 154 }
118 } 155 }
119 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code)); 156 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code));
120 } 157 }
121 158
122 void OnDiskAttachmentStore::Drop(const AttachmentIdList& ids, 159 void OnDiskAttachmentStore::Drop(const AttachmentIdList& ids,
123 const DropCallback& callback) { 160 const DropCallback& callback) {
124 DCHECK(CalledOnValidThread()); 161 DCHECK(CalledOnValidThread());
125 DCHECK(db_); 162 DCHECK(db_);
126 Result result_code = SUCCESS; 163 Result result_code = SUCCESS;
127 leveldb::WriteOptions write_options; 164 leveldb::WriteOptions write_options = MakeWriteOptions();
128 write_options.sync = true;
129 AttachmentIdList::const_iterator iter = ids.begin(); 165 AttachmentIdList::const_iterator iter = ids.begin();
130 const AttachmentIdList::const_iterator end = ids.end(); 166 const AttachmentIdList::const_iterator end = ids.end();
131 for (; iter != end; ++iter) { 167 for (; iter != end; ++iter) {
132 const std::string key = CreateDataKeyFromAttachmentId(*iter); 168 const std::string key = MakeDataKeyFromAttachmentId(*iter);
133 leveldb::Status status = db_->Delete(write_options, key); 169 leveldb::Status status = db_->Delete(write_options, key);
134 if (!status.ok()) { 170 if (!status.ok()) {
135 // DB::Delete doesn't check if record exists, it returns ok just like 171 // DB::Delete doesn't check if record exists, it returns ok just like
136 // AttachmentStore::Drop should. 172 // AttachmentStore::Drop should.
137 DVLOG(1) << "DB::Delete failed: status=" << status.ToString(); 173 DVLOG(1) << "DB::Delete failed: status=" << status.ToString();
138 result_code = UNSPECIFIED_ERROR; 174 result_code = UNSPECIFIED_ERROR;
139 } 175 }
140 } 176 }
141 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code)); 177 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code));
142 } 178 }
143 179
144 AttachmentStore::Result OnDiskAttachmentStore::OpenOrCreate( 180 AttachmentStore::Result OnDiskAttachmentStore::OpenOrCreate(
145 const base::FilePath& path) { 181 const base::FilePath& path) {
146 DCHECK(CalledOnValidThread()); 182 DCHECK(CalledOnValidThread());
147 DCHECK(!db_); 183 DCHECK(!db_);
148 Result result_code = UNSPECIFIED_ERROR;
149 base::FilePath leveldb_path = path.Append(kLeveldbDirectory); 184 base::FilePath leveldb_path = path.Append(kLeveldbDirectory);
150 185
151 leveldb::DB* db; 186 leveldb::DB* db_raw;
187 scoped_ptr<leveldb::DB> db;
152 leveldb::Options options; 188 leveldb::Options options;
153 options.create_if_missing = true; 189 options.create_if_missing = true;
154 // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and 190 // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and
155 // filter_policy to options. 191 // filter_policy to options.
156 leveldb::Status status = 192 leveldb::Status status =
157 leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db); 193 leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db_raw);
158 if (!status.ok()) { 194 if (!status.ok()) {
159 DVLOG(1) << "DB::Open failed: status=" << status.ToString() 195 DVLOG(1) << "DB::Open failed: status=" << status.ToString()
160 << ", path=" << path.AsUTF8Unsafe(); 196 << ", path=" << path.AsUTF8Unsafe();
161 } else { 197 return UNSPECIFIED_ERROR;
162 db_.reset(db);
163 result_code = SUCCESS;
164 } 198 }
165 return result_code; 199
200 db.reset(db_raw);
201
202 attachment_store_pb::AttachmentStoreMetadata metadata;
203 status = ReadStoreMetadata(db.get(), &metadata);
204 if (!status.ok() && !status.IsNotFound()) {
205 DVLOG(1) << "ReadStoreMetadata failed: status=" << status.ToString();
206 return UNSPECIFIED_ERROR;
207 }
208 if (status.IsNotFound()) {
209 // Brand new database.
210 metadata.set_schema_version(kCurrentSchemaVersion);
211 status = WriteStoreMetadata(db.get(), metadata);
212 if (!status.ok()) {
213 DVLOG(1) << "WriteStoreMetadata failed: status=" << status.ToString();
214 return UNSPECIFIED_ERROR;
215 }
216 }
217 DCHECK(status.ok());
218
219 // Upgrade code goes here.
220
221 if (metadata.schema_version() != kCurrentSchemaVersion) {
222 DVLOG(1) << "Unknown schema version: " << metadata.schema_version();
223 return UNSPECIFIED_ERROR;
224 }
225
226 db_ = db.Pass();
227 return SUCCESS;
166 } 228 }
167 229
168 std::string OnDiskAttachmentStore::CreateDataKeyFromAttachmentId( 230 std::string OnDiskAttachmentStore::MakeDataKeyFromAttachmentId(
169 const AttachmentId& attachment_id) { 231 const AttachmentId& attachment_id) {
170 std::string key = kDataPrefix + attachment_id.GetProto().unique_id(); 232 std::string key = kDataPrefix + attachment_id.GetProto().unique_id();
171 return key; 233 return key;
172 } 234 }
173 235
174 } // namespace syncer 236 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/BUILD.gn ('k') | sync/internal_api/attachments/on_disk_attachment_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698