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

Side by Side Diff: net/disk_cache/v3/backend_work_item.cc

Issue 15203004: Disk cache: Reference CL for the implementation of file format version 3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 6 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/v3/backend_work_item.h ('k') | net/disk_cache/v3/backend_worker.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/v3/backend_work_item.h"
6
7 #include "base/hash.h"
8 #include "base/sha1.h"
9 #include "net/base/net_errors.h"
10 #include "net/disk_cache/errors.h"
11 #include "net/disk_cache/file.h"
12 #include "net/disk_cache/storage_block-inl.h"
13 #include "net/disk_cache/v3/backend_worker.h"
14 #include "net/disk_cache/v3/entry_impl_v3.h"
15
16 namespace {
17
18 // Simple adaptor for the sha1 interface.
19 void ComputeCryptoHash(const std::string& source,
20 disk_cache::ShortEntryRecord* record) {
21 DCHECK(!source.empty());
22 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(source.data()),
23 source.size(),
24 reinterpret_cast<unsigned char*>(record->long_hash));
25 }
26
27 bool CryptoHashMatches(const std::string& source,
28 const disk_cache::ShortEntryRecord& record) {
29 DCHECK(!source.empty());
30 unsigned char result[20];
31 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(source.data()),
32 source.size(), result);
33
34 return !memcmp(result, record.long_hash, sizeof(result));
35 }
36
37 } // namespace
38
39 // ------------------------------------------------------------------------
40
41 namespace disk_cache {
42
43 class BackendImplV3::IOCallback : public disk_cache::FileIOCallback {
44 public:
45 explicit IOCallback(BackendImplV3::WorkItem* work_item);
46 virtual ~IOCallback() {}
47
48 // FileIOCallback implementation.
49 virtual void OnFileIOComplete(int bytes_copied) OVERRIDE;
50 void Discard();
51
52 private:
53 // Even though we need the work item alive until the operation completes, we
54 // don't grab an extra reference because the work item itself keeps an extra
55 // reference until it reaches the main thread again.
56 BackendImplV3::WorkItem* work_item_;
57
58 DISALLOW_COPY_AND_ASSIGN(IOCallback);
59 };
60
61 BackendImplV3::IOCallback::IOCallback(BackendImplV3::WorkItem* work_item)
62 : work_item_(work_item) {
63 }
64
65 void BackendImplV3::IOCallback::OnFileIOComplete(int bytes_copied) {
66 if (work_item_)
67 work_item_->DoLoop(bytes_copied);
68
69 delete this;
70 }
71
72 void BackendImplV3::IOCallback::Discard() {
73 work_item_ = NULL;
74 OnFileIOComplete(0);
75 }
76
77 // ------------------------------------------------------------------------
78
79 BackendImplV3::WorkItem::WorkItem(WorkType type)
80 : type_(type),
81 result_(0),
82 flags_(0) {//init everything
83 }
84
85 void BackendImplV3::WorkItem::Start(BackendImplV3::Worker* worker) {
86 Trace("Work 0x%p %d", this, type());
87 worker_ = worker;
88 switch (type_) {
89 case WORK_INIT:
90 return CompleteItem(worker_->Init(flags_, &init_result_));
91 case WORK_RESTART:
92 return CompleteItem(worker_->Restart(flags_, &init_result_));
93 case WORK_GROW_INDEX:
94 return CompleteItem(worker_->GrowIndex(flags_, &init_result_));
95 case WORK_GROW_FILES:
96 return CompleteItem(worker_->GrowFiles(flags_, &init_result_));
97 case WORK_NONE:
98 return CompleteItem(ERR_NO_ERROR);
99 case WORK_OPEN_ENTRY:
100 next_state_ = STATE_OPEN_ENTRY;
101 break;
102 case WORK_READ_DATA:
103 next_state_ = STATE_READ_DATA;
104 break;
105 case WORK_WRITE_DATA:
106 next_state_ = STATE_WRITE_DATA;
107 break;
108 case WORK_MOVE_DATA:
109 next_state_ = STATE_MOVE_DATA;
110 break;
111 case WORK_TRUNCATE:
112 next_state_ = STATE_TRUNCATE_DATA;
113 break;
114 case WORK_DELETE:
115 return CompleteItem(worker_->Delete(address_));
116 case WORK_CLOSE:
117 return CompleteItem(worker_->Close(address_));
118 default: NOTREACHED();
119 }
120 DoLoop(ERR_NO_ERROR);
121 }
122
123 void BackendImplV3::WorkItem::DoLoop(int result) {
124 DCHECK(next_state_ != STATE_NONE);
125 if (!worker_->IsValid())
126 return CompleteItem(result);
127
128 int rv = result;
129 do {
130 State state = next_state_;
131 next_state_ = STATE_NONE;
132 switch (state) {
133 case STATE_OPEN_ENTRY:
134 DCHECK_EQ(ERR_NO_ERROR, rv);
135 rv = DoOpenEntry();
136 break;
137 case STATE_OPEN_ENTRY_COMPLETE:
138 rv = DoOpenEntryComplete(rv);
139 break;
140 case STATE_READ_KEY:
141 DCHECK_EQ(ERR_NO_ERROR, rv);
142 rv = DoReadKey();
143 break;
144 case STATE_READ_KEY_COMPLETE:
145 DCHECK_EQ(ERR_NO_ERROR, rv);
146 rv = DoReadKeyComplete();
147 break;
148 case STATE_READ_DATA:
149 DCHECK_EQ(ERR_NO_ERROR, rv);
150 rv = DoReadData();
151 break;
152 case STATE_READ_DATA_COMPLETE:
153 rv = DoReadDataComplete(rv);
154 break;
155 case STATE_WRITE_DATA:
156 DCHECK_EQ(ERR_NO_ERROR, rv);
157 rv = DoWriteData();
158 break;
159 case STATE_WRITE_DATA_COMPLETE:
160 rv = DoWriteDataComplete(rv);
161 break;
162 case STATE_MOVE_DATA:
163 DCHECK_EQ(ERR_NO_ERROR, rv);
164 rv = DoMoveData();
165 break;
166 case STATE_TRUNCATE_DATA:
167 DCHECK_EQ(ERR_NO_ERROR, rv);
168 rv = DoTruncateData();
169 break;
170 case STATE_COPY_ENTRY:
171 DCHECK_EQ(ERR_NO_ERROR, rv);
172 rv = DoCopyEntry();
173 break;
174 case STATE_COPY_ENTRY_COMPLETE:
175 rv = DoCopyEntryComplete(rv);
176 break;
177 }
178 } while (rv != ERR_PENDING && next_state_ != STATE_NONE);
179
180 if (rv != ERR_PENDING)
181 CompleteItem(rv);
182 }
183
184 void BackendImplV3::WorkItem::OnDone() {
185 closure_.Run(this);
186 }
187
188 // ------------------------------------------------------------------------
189
190 BackendImplV3::WorkItem::~WorkItem() {
191 }
192
193 void BackendImplV3::WorkItem::CompleteItem(int result) {
194 Trace("Work done 0x%p %d %d", this, type(), result);
195 result_ = result;
196 entry_block_.reset(); // Release resources while on the worker thread.
197 worker_->DoneWithItem(this);
198 }
199
200 int BackendImplV3::WorkItem::DoOpenEntry() {
201 next_state_ = STATE_OPEN_ENTRY_COMPLETE;
202 for (; entries_.current < entries_.cells.size(); entries_.current++) {
203 Addr address = entries_.cells[entries_.current].GetAddress();
204 if (entries_.cells[entries_.current].group() == ENTRY_EVICTED) {
205 if (flags_ & WORK_FOR_RESURRECT)
206 return LoadShortEntryBlock(address);
207 continue;
208 }
209
210 if (flags_ & WORK_FOR_RESURRECT)
211 continue;
212 return LoadEntryBlock(address);
213 }
214 next_state_ = STATE_NONE;
215 return ERR_OPERATION_FAILED;
216 }
217
218 int BackendImplV3::WorkItem::DoOpenEntryComplete(int result) {
219 if (entries_.cells[entries_.current].group() == ENTRY_EVICTED) {
220 if (result != static_cast<int>(sizeof(ShortEntryRecord)))
221 return ERR_READ_FAILURE;
222
223 if (!EntryImplV3::DeletedSanityCheck(*short_entry_block_->Data()))
224 return ERR_INVALID_ENTRY;
225 } else {
226 if (result != static_cast<int>(sizeof(EntryRecord)))
227 return ERR_READ_FAILURE;
228
229 if (!EntryImplV3::BasicSanityCheck(*entry_block_->Data()))
230 return ERR_INVALID_ENTRY;
231 }
232
233 if (entries_.cells[entries_.current].group() == ENTRY_EVICTED) {
234 DCHECK(!(flags_ & WORK_FOR_EVICT));
235 if (CryptoHashMatches(key_, *short_entry_block_->Data())) {
236 // We have a match.
237 short_entry_record_.reset(short_entry_block_->ReleaseData());
238 return ERR_NO_ERROR;
239 }
240 } else {
241 next_state_ = STATE_READ_KEY;
242 return ERR_NO_ERROR;
243 }
244
245 next_state_ = STATE_OPEN_ENTRY;
246 entries_.current++;
247 return ERR_NO_ERROR;
248 }
249
250 int BackendImplV3::WorkItem::DoReadKey() {
251 address_.set_value(entry_block_->Data()->data_addr[0]);
252 offset_ = 0;
253 buffer_ = new net::IOBuffer(entry_block_->Data()->key_len);
254 buffer_len_ = entry_block_->Data()->key_len;
255
256 next_state_ = STATE_READ_DATA;
257 return ERR_NO_ERROR;
258 }
259
260 int BackendImplV3::WorkItem::DoReadKeyComplete() {
261 std::string key(buffer_->data(), buffer_len_);
262 uint32 hash = base::Hash(key);
263 Trace("DoReadKeyComplete hash 0x%x, 0x%p", hash, this);
264 DCHECK_EQ(hash, entries_.cells[entries_.current].hash());
265 if (flags() & WORK_FOR_ITERATION)
266 key_ = key;
267
268 if (flags_ & WORK_FOR_EVICT) {
269 key_ = key;
270 if (!(flags_ & WORK_NO_COPY)) {
271 next_state_ = STATE_COPY_ENTRY;
272 return ERR_NO_ERROR;
273 }
274 }
275
276 if (key == key_) {
277 // We have a match.
278 entry_record_.reset(entry_block_->ReleaseData());
279 return ERR_NO_ERROR;
280 }
281
282 next_state_ = STATE_OPEN_ENTRY;
283 entries_.current++;
284 return ERR_NO_ERROR;
285 }
286
287 int BackendImplV3::WorkItem::DoReadData() {
288 disk_cache::File* file = worker_->GetBackingFile(address_, false);
289 if (!file)
290 return net::ERR_FILE_NOT_FOUND;
291
292
293 size_t file_offset = offset_;
294 if (address_.is_block_file()) {
295 DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
296 file_offset += address_.start_block() * address_.BlockSize();
297 }
298 DCHECK(buffer_len_);
299
300 bool completed;
301 IOCallback* callback = new IOCallback(this);
302
303 if (!file->Read(buffer_->data(), buffer_len_, file_offset, callback,
304 &completed)) {
305 callback->Discard();
306 return net::ERR_CACHE_READ_FAILURE;
307 }
308 next_state_ = STATE_READ_DATA_COMPLETE;
309
310 if (completed) {
311 callback->Discard();
312 return NO_ERROR;
313 }
314
315 return ERR_PENDING;
316 }
317
318 int BackendImplV3::WorkItem::DoReadDataComplete(int result) {
319 if (result != buffer_len_)
320 return net::ERR_CACHE_READ_FAILURE;
321
322 if (type() == WORK_OPEN_ENTRY) {
323 next_state_ = STATE_READ_KEY_COMPLETE;
324 return ERR_NO_ERROR;
325 }
326
327 return result;
328 }
329
330 int BackendImplV3::WorkItem::DoWriteData() {
331 disk_cache::File* file = worker_->GetBackingFile(address_, true);
332 if (!file)
333 return net::ERR_CACHE_WRITE_FAILURE;
334
335 DCHECK(buffer_len_);
336
337 size_t file_offset = offset_;
338 if (address_.is_block_file()) {
339 DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
340 file_offset += address_.start_block() * address_.BlockSize();
341 }
342
343 bool completed;
344 IOCallback* callback = new IOCallback(this);
345
346 if (!file->Write(buffer_->data(), buffer_len_, file_offset, callback,
347 &completed)) {
348 callback->Discard();
349 return net::ERR_CACHE_WRITE_FAILURE;
350 }
351 next_state_ = STATE_WRITE_DATA_COMPLETE;
352
353 if (completed) {
354 callback->Discard();
355 return NO_ERROR;
356 }
357
358 return ERR_PENDING;
359 }
360
361 int BackendImplV3::WorkItem::DoWriteDataComplete(int result) {
362 if (result != buffer_len_)
363 return net::ERR_CACHE_WRITE_FAILURE;
364
365 return result;
366 }
367
368 int BackendImplV3::WorkItem::DoMoveData() {
369 disk_cache::File* file = worker_->GetBackingFile(address_, false);
370 if (!file)
371 return ERR_OPERATION_FAILED;
372
373 DCHECK(buffer_len_);
374
375 if (!address_.is_block_file()) {
376 NOTREACHED();
377 return ERR_OPERATION_FAILED;
378 }
379
380 offset_ = 0;
381 size_t file_offset = 0;
382 DCHECK_LE(buffer_len_, kMaxBlockSize);
383 file_offset += address_.start_block() * address_.BlockSize();
384
385 buffer_ = new net::IOBufferWithSize(buffer_len_);
386
387 // We could optimize this to be an async read, but we'd have to do that from
388 // the main thread, not from here.
389 if (!file->Read(buffer_->data(), buffer_len_, file_offset))
390 return ERR_WRITE_FAILURE;
391
392 address_ = address2_;
393 next_state_ = STATE_WRITE_DATA;
394 return NO_ERROR;
395 }
396
397 int BackendImplV3::WorkItem::DoTruncateData() {
398 if (address_.is_block_file())
399 return ERR_OPERATION_FAILED;
400
401 disk_cache::File* file = worker_->GetBackingFile(address_, false);
402 if (!file)
403 return ERR_OPERATION_FAILED;
404
405 if (!file->SetLength(offset_))
406 return ERR_OPERATION_FAILED;
407
408 return ERR_NO_ERROR;
409 }
410
411 int BackendImplV3::WorkItem::DoCopyEntry() {
412 next_state_ = STATE_COPY_ENTRY_COMPLETE;
413 Addr address = entries_.cells[1].GetAddress();
414 short_entry_block_.reset(
415 new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
416
417 ShortEntryRecord* short_record = short_entry_block_->Data();
418 EntryRecord* long_record = entry_block_->Data();
419
420 short_record->hash = long_record->hash;
421 short_record->reuse_count = long_record->reuse_count;
422 short_record->refetch_count = long_record->refetch_count;
423 short_record->refetch_count = long_record->refetch_count;
424 short_record->key_len = long_record->key_len;
425 short_record->last_access_time = long_record->last_access_time;
426 ComputeCryptoHash(key_, short_record);
427
428 bool completed;
429 IOCallback* callback = new IOCallback(this);
430 if (!short_entry_block_->Store(callback, &completed)) {
431 callback->Discard();
432 next_state_ = STATE_NONE;
433 return ERR_OPERATION_FAILED;
434 }
435
436 if (completed) {
437 callback->Discard();
438 return ERR_NO_ERROR;
439 }
440
441 return ERR_PENDING;
442 }
443
444 int BackendImplV3::WorkItem::DoCopyEntryComplete(int result) {
445 if (result != static_cast<int>(sizeof(ShortEntryRecord)))
446 return ERR_READ_FAILURE;
447
448 entry_record_.reset(entry_block_->ReleaseData());
449 return ERR_NO_ERROR;
450 }
451
452 int BackendImplV3::WorkItem::LoadEntryBlock(Addr address) {
453 entry_block_.reset(new CacheEntryBlockV3(worker_->GetMappedFile(address),
454 address));
455 bool completed;
456 IOCallback* callback = new IOCallback(this);
457 if (!entry_block_->Load(callback, &completed)) {
458 callback->Discard();
459 next_state_ = STATE_NONE;
460 return ERR_OPERATION_FAILED;
461 }
462
463 if (completed) {
464 callback->Discard();
465 return ERR_NO_ERROR;
466 }
467
468 return ERR_PENDING;
469 }
470
471 int BackendImplV3::WorkItem::LoadShortEntryBlock(Addr address) {
472 short_entry_block_.reset(
473 new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
474 bool completed;
475 IOCallback* callback = new IOCallback(this);
476 if (!short_entry_block_->Load(callback, &completed)) {
477 callback->Discard();
478 next_state_ = STATE_NONE;
479 return ERR_OPERATION_FAILED;
480 }
481
482 if (completed) {
483 callback->Discard();
484 return ERR_NO_ERROR;
485 }
486
487 return ERR_PENDING;
488 }
489
490 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/v3/backend_work_item.h ('k') | net/disk_cache/v3/backend_worker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698