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

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

Issue 652723003: Implementation of OnDiskAttachmentStore. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes after feedback from Nick Created 6 years, 2 months 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "sync/internal_api/public/attachments/on_disk_attachment_store.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/sequenced_task_runner.h"
12 #include "sync/protocol/attachments.pb.h"
13 #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/slice.h"
16 #include "third_party/leveldatabase/src/include/leveldb/status.h"
17
18 namespace syncer {
19
20 namespace {
21
22 // Prefix for records containing attachment data.
23 const char kDataPrefix[] = "data-";
24
25 const base::FilePath::CharType kLeveldbDirectory[] =
26 FILE_PATH_LITERAL("leveldb");
27 } // namespace
28
29 OnDiskAttachmentStore::OnDiskAttachmentStore(
30 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner)
31 : callback_task_runner_(callback_task_runner) {
32 }
33
34 OnDiskAttachmentStore::~OnDiskAttachmentStore() {
35 }
36
37 void OnDiskAttachmentStore::Read(const AttachmentIdList& ids,
38 const ReadCallback& callback) {
39 DCHECK(CalledOnValidThread());
40 DCHECK(db_);
41 scoped_ptr<AttachmentMap> result_map(new AttachmentMap());
42 scoped_ptr<AttachmentIdList> unavailable_attachments(new AttachmentIdList());
43
44 leveldb::ReadOptions read_options;
45 // Attachment content is typically large and only read once. Don't cache it on
46 // db level.
47 read_options.fill_cache = false;
48 read_options.verify_checksums = true;
49
50 AttachmentIdList::const_iterator iter = ids.begin();
51 const AttachmentIdList::const_iterator end = ids.end();
52 for (; iter != end; ++iter) {
53 std::string key = CreateDataKeyFromAttachmentId(*iter);
maniscalco 2014/10/17 00:00:19 Opportunity for const.
pavely 2014/10/17 00:13:25 Done.
54 std::string data_str;
55 leveldb::Status status = db_->Get(read_options, key, &data_str);
56 if (!status.ok()) {
57 DVLOG(1) << "DB::Get failed: status=" << status.ToString();
58 unavailable_attachments->push_back(*iter);
59 continue;
60 }
61 scoped_refptr<base::RefCountedMemory> data =
62 base::RefCountedString::TakeString(&data_str);
63 Attachment attachment = Attachment::CreateWithId(*iter, data);
64 result_map->insert(std::make_pair(*iter, attachment));
65 }
66
67 Result result_code =
68 unavailable_attachments->empty() ? SUCCESS : UNSPECIFIED_ERROR;
69 callback_task_runner_->PostTask(
70 FROM_HERE,
71 base::Bind(callback,
72 result_code,
73 base::Passed(&result_map),
74 base::Passed(&unavailable_attachments)));
75 }
76
77 void OnDiskAttachmentStore::Write(const AttachmentList& attachments,
78 const WriteCallback& callback) {
79 DCHECK(CalledOnValidThread());
80 DCHECK(db_);
81 Result result_code = SUCCESS;
82
83 leveldb::ReadOptions read_options;
84 read_options.fill_cache = false;
85 read_options.verify_checksums = true;
86
87 leveldb::WriteOptions write_options;
88 write_options.sync = true;
89
90 AttachmentList::const_iterator iter = attachments.begin();
91 const AttachmentList::const_iterator end = attachments.end();
92 for (; iter != end; ++iter) {
maniscalco 2014/10/17 00:00:19 Opportunity for const. I often wish automatic var
pavely 2014/10/17 00:13:25 Done.
93 std::string key = CreateDataKeyFromAttachmentId(iter->GetId());
94
95 std::string data_str;
96 // TODO(pavely): crbug/424304 This read is expensive. When I add metadata
97 // records this read will target metadata record instead of payload record.
98 leveldb::Status status = db_->Get(read_options, key, &data_str);
99 if (status.ok()) {
100 // Entry exists, don't overwrite.
101 continue;
102 } else if (!status.IsNotFound()) {
103 // Entry exists but failed to read.
104 DVLOG(1) << "DB::Get failed: status=" << status.ToString();
105 result_code = UNSPECIFIED_ERROR;
106 continue;
107 }
108 DCHECK(status.IsNotFound());
109
110 scoped_refptr<base::RefCountedMemory> data = iter->GetData();
111 leveldb::Slice data_slice(data->front_as<char>(), data->size());
112 status = db_->Put(write_options, key, data_slice);
113 if (!status.ok()) {
114 // Failed to write.
115 DVLOG(1) << "DB::Put failed: status=" << status.ToString();
116 result_code = UNSPECIFIED_ERROR;
117 }
118 }
119 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code));
120 }
121
122 void OnDiskAttachmentStore::Drop(const AttachmentIdList& ids,
123 const DropCallback& callback) {
124 DCHECK(CalledOnValidThread());
125 DCHECK(db_);
126 Result result_code = SUCCESS;
127 leveldb::WriteOptions write_options;
128 write_options.sync = true;
129 AttachmentIdList::const_iterator iter = ids.begin();
130 const AttachmentIdList::const_iterator end = ids.end();
131 for (; iter != end; ++iter) {
132 std::string key = CreateDataKeyFromAttachmentId(*iter);
133 leveldb::Status status = db_->Delete(write_options, key);
134 if (!status.ok()) {
135 // DB::Delete doesn't check if record exists, it returns ok just like
136 // AttachmentStore::Drop should.
137 DVLOG(1) << "DB::Delete failed: status=" << status.ToString();
138 result_code = UNSPECIFIED_ERROR;
139 }
140 }
141 callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback, result_code));
142 }
143
144 AttachmentStore::Result OnDiskAttachmentStore::OpenOrCreate(
145 const base::FilePath& path) {
146 DCHECK(CalledOnValidThread());
147 DCHECK(!db_);
148 Result result_code = UNSPECIFIED_ERROR;
149 base::FilePath leveldb_path = path.Append(kLeveldbDirectory);
150
151 leveldb::DB* db;
152 leveldb::Options options;
153 options.create_if_missing = true;
154 // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and
155 // filter_policy to options.
156 leveldb::Status status =
157 leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db);
158 if (!status.ok()) {
159 DVLOG(1) << "DB::Open failed: status=" << status.ToString()
160 << ", path=" << path.AsUTF8Unsafe();
161 } else {
162 db_.reset(db);
163 result_code = SUCCESS;
164 }
165 return result_code;
166 }
167
168 std::string OnDiskAttachmentStore::CreateDataKeyFromAttachmentId(
169 const AttachmentId& attachment_id) {
170 std::string key = kDataPrefix + attachment_id.GetProto().unique_id();
171 return key;
172 }
173
174 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698