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

Side by Side Diff: net/disk_cache/simple/simple_synchronous_entry.cc

Issue 12192005: Add new simple disk cache backend. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: build fix Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « net/disk_cache/simple/simple_synchronous_entry.h ('k') | net/net.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 "net/disk_cache/simple/simple_synchronous_entry.h"
6
7 #include <algorithm>
8 #include <cstring>
9 #include <limits>
10
11 #include "base/basictypes.h"
12 #include "base/compiler_specific.h"
13 #include "base/file_util.h"
14 #include "base/hash.h"
15 #include "base/location.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop_proxy.h"
18 #include "base/sha1.h"
19 #include "base/stringprintf.h"
20 #include "base/task_runner.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23 #include "net/disk_cache/simple/simple_disk_format.h"
24
25 using base::ClosePlatformFile;
26 using base::FilePath;
27 using base::GetPlatformFileInfo;
28 using base::PlatformFileError;
29 using base::PlatformFileInfo;
30 using base::PLATFORM_FILE_CREATE;
31 using base::PLATFORM_FILE_OK;
32 using base::PLATFORM_FILE_OPEN;
33 using base::PLATFORM_FILE_READ;
34 using base::PLATFORM_FILE_WRITE;
35 using base::ReadPlatformFile;
36 using base::TaskRunner;
37 using base::Time;
38 using base::TruncatePlatformFile;
39 using base::WritePlatformFile;
40
41 namespace {
42
43 std::string GetFilenameForKeyAndIndex(const std::string& key, int index) {
44 const std::string sha_hash = base::SHA1HashString(key);
45 return StringPrintf("%02x%02x%02x%02x%02x_%1d",
46 implicit_cast<unsigned char>(sha_hash[0]),
47 implicit_cast<unsigned char>(sha_hash[1]),
48 implicit_cast<unsigned char>(sha_hash[2]),
49 implicit_cast<unsigned char>(sha_hash[3]),
50 implicit_cast<unsigned char>(sha_hash[4]), index);
51 }
52
53 int32 DataSizeFromKeyAndFileSize(size_t key_size, int64 file_size) {
54 int64 data_size = file_size - key_size - sizeof(disk_cache::SimpleFileHeader);
55 DCHECK_GE(implicit_cast<int64>(std::numeric_limits<int32>::max()), data_size);
56 return data_size;
57 }
58
59 int64 FileOffsetFromDataOffset(size_t key_size, int data_offset) {
60 const int64 headers_size = sizeof(disk_cache::SimpleFileHeader) +
61 key_size;
62 return headers_size + data_offset;
63 }
64
65 } // namespace
66
67 namespace disk_cache {
68
69 // static
70 void SimpleSynchronousEntry::OpenEntry(
71 const FilePath& path,
72 const std::string& key,
73 const scoped_refptr<TaskRunner>& callback_runner,
74 const SynchronousCreationCallback& callback) {
75 SimpleSynchronousEntry* sync_entry =
76 new SimpleSynchronousEntry(callback_runner, path, key);
77
78 if (!sync_entry->InitializeForOpen()) {
79 delete sync_entry;
80 sync_entry = NULL;
81 }
82 callback_runner->PostTask(FROM_HERE, base::Bind(callback, sync_entry));
83 }
84
85 // static
86 void SimpleSynchronousEntry::CreateEntry(
87 const FilePath& path,
88 const std::string& key,
89 const scoped_refptr<TaskRunner>& callback_runner,
90 const SynchronousCreationCallback& callback) {
91 SimpleSynchronousEntry* sync_entry =
92 new SimpleSynchronousEntry(callback_runner, path, key);
93
94 if (!sync_entry->InitializeForCreate()) {
95 delete sync_entry;
96 sync_entry = NULL;
97 }
98 callback_runner->PostTask(FROM_HERE, base::Bind(callback, sync_entry));
99 }
100
101 // static
102 void SimpleSynchronousEntry::DoomEntry(
103 const FilePath& path,
104 const std::string& key,
105 scoped_refptr<TaskRunner> callback_runner,
106 const net::CompletionCallback& callback) {
107 for (int i = 0; i < kIndexCount; ++i) {
108 FilePath to_delete = path.AppendASCII(GetFilenameForKeyAndIndex(key, i));
109 bool ALLOW_UNUSED result = file_util::Delete(to_delete, false);
110 DLOG_IF(ERROR, !result) << "Could not delete " << to_delete.MaybeAsASCII();
111 }
112 if (!callback.is_null())
113 callback_runner->PostTask(FROM_HERE, base::Bind(callback, net::OK));
114 }
115
116 void SimpleSynchronousEntry::DoomAndClose() {
117 scoped_refptr<TaskRunner> callback_runner = callback_runner_;
118 FilePath path = path_;
119 std::string key = key_;
120
121 Close();
122 // |this| is now deleted.
123
124 DoomEntry(path, key, callback_runner, net::CompletionCallback());
125 }
126
127 void SimpleSynchronousEntry::Close() {
128 for (int i = 0; i < kIndexCount; ++i) {
129 bool ALLOW_UNUSED result = ClosePlatformFile(files_[i]);
130 DLOG_IF(INFO, !result) << "Could not Close() file.";
131 }
132 delete this;
133 }
134
135 void SimpleSynchronousEntry::ReadData(
136 int index,
137 int offset,
138 net::IOBuffer* buf,
139 int buf_len,
140 const SynchronousOperationCallback& callback) {
141 DCHECK(initialized_);
142
143 int64 file_offset = FileOffsetFromDataOffset(key_.size(), offset);
144 int bytes_read = ReadPlatformFile(files_[index], file_offset,
145 buf->data(), buf_len);
146 if (bytes_read > 0)
147 last_used_ = Time::Now();
148 int result = (bytes_read >= 0) ? bytes_read : net::ERR_FAILED;
149 callback_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
150 }
151
152 void SimpleSynchronousEntry::WriteData(
153 int index,
154 int offset,
155 net::IOBuffer* buf,
156 int buf_len,
157 const SynchronousOperationCallback& callback,
158 bool truncate) {
159 DCHECK(initialized_);
160
161 int64 file_offset = FileOffsetFromDataOffset(key_.size(), offset);
162 if (buf_len > 0) {
163 if (WritePlatformFile(files_[index], file_offset, buf->data(), buf_len) !=
164 buf_len) {
165 callback_runner_->PostTask(FROM_HERE,
166 base::Bind(callback, net::ERR_FAILED));
167 return;
168 }
169 data_size_[index] = std::max(data_size_[index], offset + buf_len);
170 }
171 if (truncate) {
172 data_size_[index] = offset + buf_len;
173 if (!TruncatePlatformFile(files_[index], file_offset + buf_len)) {
174 callback_runner_->PostTask(FROM_HERE,
175 base::Bind(callback, net::ERR_FAILED));
176 return;
177 }
178 }
179 last_modified_ = Time::Now();
180 callback_runner_->PostTask(FROM_HERE, base::Bind(callback, buf_len));
181 }
182
183 SimpleSynchronousEntry::SimpleSynchronousEntry(
184 const scoped_refptr<TaskRunner>& callback_runner,
185 const FilePath& path,
186 const std::string& key)
187 : callback_runner_(callback_runner),
188 path_(path),
189 key_(key),
190 initialized_(false) {
191 }
192
193 SimpleSynchronousEntry::~SimpleSynchronousEntry() {
194 }
195
196 bool SimpleSynchronousEntry::OpenOrCreateFiles(bool create) {
197 for (int i = 0; i < kIndexCount; ++i) {
198 FilePath filename = path_.AppendASCII(GetFilenameForKeyAndIndex(key_, i));
199 int flags = PLATFORM_FILE_READ | PLATFORM_FILE_WRITE;
200 if (create)
201 flags |= PLATFORM_FILE_CREATE;
202 else
203 flags |= PLATFORM_FILE_OPEN;
204 PlatformFileError error;
205 files_[i] = CreatePlatformFile(filename, flags, NULL, &error);
206 if (error != PLATFORM_FILE_OK) {
207 DVLOG(8) << "CreatePlatformFile error " << error << " while "
208 << (create ? "creating " : "opening ")
209 << filename.MaybeAsASCII();
210 while (--i >= 0) {
211 bool ALLOW_UNUSED did_close = ClosePlatformFile(files_[i]);
212 DLOG_IF(INFO, !did_close) << "Could not close file "
213 << filename.MaybeAsASCII();
214 }
215 return false;
216 }
217 }
218
219 for (int i = 0; i < kIndexCount; ++i) {
220 PlatformFileInfo file_info;
221 bool success = GetPlatformFileInfo(files_[i], &file_info);
222 if (!success) {
223 DLOG(WARNING) << "Could not get platform file info.";
224 continue;
225 }
226 last_used_ = std::max(last_used_, file_info.last_accessed);
227 last_modified_ = std::max(last_modified_, file_info.last_modified);
228 data_size_[i] = DataSizeFromKeyAndFileSize(key_.size(), file_info.size);
229 }
230
231 return true;
232 }
233
234 bool SimpleSynchronousEntry::InitializeForOpen() {
235 DCHECK(!initialized_);
236 if (!OpenOrCreateFiles(false))
237 return false;
238
239 for (int i = 0; i < kIndexCount; ++i) {
240 SimpleFileHeader header;
241 int header_read_result =
242 ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header),
243 sizeof(header));
244 if (header_read_result != sizeof(header)) {
245 DLOG(WARNING) << "Cannot read header from entry.";
246 return false;
247 }
248
249 if (header.initial_magic_number != kSimpleInitialMagicNumber) {
250 // TODO(gavinp): This seems very bad; for now we log at WARNING, but we
251 // should give consideration to not saturating the log with these if that
252 // becomes a problem.
253 DLOG(WARNING) << "Magic number did not match.";
254 return false;
255 }
256
257 if (header.version != kSimpleVersion) {
258 DLOG(WARNING) << "Unreadable version.";
259 return false;
260 }
261
262 scoped_ptr<char[]> key(new char[header.key_length]);
263 int key_read_result = ReadPlatformFile(files_[i], sizeof(header),
264 key.get(), header.key_length);
265 if (key_read_result != implicit_cast<int>(header.key_length)) {
266 DLOG(WARNING) << "Cannot read key from entry.";
267 return false;
268 }
269 if (header.key_length != key_.size() ||
270 std::memcmp(key_.data(), key.get(), key_.size()) != 0) {
271 // TODO(gavinp): Since the way we use Entry SHA to name entries means this
272 // is expected to occur at some frequency, add unit_tests that this does
273 // is handled gracefully at higher levels.
274 DLOG(WARNING) << "Key mismatch on open.";
275 return false;
276 }
277
278 if (base::Hash(key.get(), header.key_length) != header.key_hash) {
279 DLOG(WARNING) << "Hash mismatch on key.";
280 return false;
281 }
282 }
283
284 initialized_ = true;
285 return true;
286 }
287
288 bool SimpleSynchronousEntry::InitializeForCreate() {
289 DCHECK(!initialized_);
290 if (!OpenOrCreateFiles(true)) {
291 DLOG(WARNING) << "Could not create platform files.";
292 return false;
293 }
294
295 for (int i = 0; i < kIndexCount; ++i) {
296 SimpleFileHeader header;
297 header.initial_magic_number = kSimpleInitialMagicNumber;
298 header.version = kSimpleVersion;
299
300 header.key_length = key_.size();
301 header.key_hash = base::Hash(key_);
302
303 if (WritePlatformFile(files_[i], 0, reinterpret_cast<char*>(&header),
304 sizeof(header)) != sizeof(header)) {
305 // TODO(gavinp): Clean up created files.
306 DLOG(WARNING) << "Could not write headers to new cache entry.";
307 return false;
308 }
309
310 if (WritePlatformFile(files_[i], sizeof(header), key_.data(),
311 key_.size()) != implicit_cast<int>(key_.size())) {
312 // TODO(gavinp): Clean up created files.
313 DLOG(WARNING) << "Could not write keys to new cache entry.";
314 return false;
315 }
316 }
317
318 initialized_ = true;
319 return true;
320 }
321
322 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/simple/simple_synchronous_entry.h ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698