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

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: IndexTable review Created 7 years 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_WRITE_INDEX:
98 next_state_ = STATE_WRITE_DATA;
99 break;
100 case WORK_OPEN_ENTRY:
101 next_state_ = STATE_OPEN_ENTRY;
102 break;
103 case WORK_READ_DATA:
104 next_state_ = STATE_READ_DATA;
105 break;
106 case WORK_WRITE_DATA:
107 next_state_ = STATE_WRITE_DATA;
108 break;
109 case WORK_MOVE_DATA:
110 next_state_ = STATE_MOVE_DATA;
111 break;
112 case WORK_TRUNCATE:
113 next_state_ = STATE_TRUNCATE_DATA;
114 break;
115 case WORK_DELETE:
116 return CompleteItem(worker_->Delete(address_));
117 case WORK_CLOSE:
118 return CompleteItem(worker_->Close(address_));
119 case WORK_NONE:
120 return CompleteItem(ERR_NO_ERROR);
121 default: NOTREACHED();
122 }
123 DoLoop(ERR_NO_ERROR);
124 }
125
126 void BackendImplV3::WorkItem::DoLoop(int result) {
127 DCHECK(next_state_ != STATE_NONE);
128 if (!worker_->IsValid())
129 return CompleteItem(result);
130
131 int rv = result;
132 do {
133 State state = next_state_;
134 next_state_ = STATE_NONE;
135 switch (state) {
136 case STATE_OPEN_ENTRY:
137 DCHECK_EQ(ERR_NO_ERROR, rv);
138 rv = DoOpenEntry();
139 break;
140 case STATE_OPEN_ENTRY_COMPLETE:
141 rv = DoOpenEntryComplete(rv);
142 break;
143 case STATE_READ_KEY:
144 DCHECK_EQ(ERR_NO_ERROR, rv);
145 rv = DoReadKey();
146 break;
147 case STATE_READ_KEY_COMPLETE:
148 DCHECK_EQ(ERR_NO_ERROR, rv);
149 rv = DoReadKeyComplete();
150 break;
151 case STATE_READ_DATA:
152 DCHECK_EQ(ERR_NO_ERROR, rv);
153 rv = DoReadData();
154 break;
155 case STATE_READ_DATA_COMPLETE:
156 rv = DoReadDataComplete(rv);
157 break;
158 case STATE_WRITE_DATA:
159 DCHECK_EQ(ERR_NO_ERROR, rv);
160 rv = DoWriteData();
161 break;
162 case STATE_WRITE_DATA_COMPLETE:
163 rv = DoWriteDataComplete(rv);
164 break;
165 case STATE_MOVE_DATA:
166 DCHECK_EQ(ERR_NO_ERROR, rv);
167 rv = DoMoveData();
168 break;
169 case STATE_TRUNCATE_DATA:
170 DCHECK_EQ(ERR_NO_ERROR, rv);
171 rv = DoTruncateData();
172 break;
173 case STATE_COPY_ENTRY:
174 DCHECK_EQ(ERR_NO_ERROR, rv);
175 rv = DoCopyEntry();
176 break;
177 case STATE_COPY_ENTRY_COMPLETE:
178 rv = DoCopyEntryComplete(rv);
179 break;
180 }
181 } while (rv != ERR_PENDING && next_state_ != STATE_NONE);
182
183 if (rv != ERR_PENDING)
184 CompleteItem(rv);
185 }
186
187 void BackendImplV3::WorkItem::OnDone() {
188 closure_.Run(this);
189 }
190
191 // ------------------------------------------------------------------------
192
193 BackendImplV3::WorkItem::~WorkItem() {
194 }
195
196 void BackendImplV3::WorkItem::CompleteItem(int result) {
197 Trace("Work done 0x%p %d %d", this, type(), result);
198 result_ = result;
199 entry_block_.reset(); // Release resources while on the worker thread.
200 worker_->DoneWithItem(this);
201 }
202
203 int BackendImplV3::WorkItem::DoOpenEntry() {
204 next_state_ = STATE_OPEN_ENTRY_COMPLETE;
205 for (; entries_.current < entries_.cells.size(); entries_.current++) {
206 Addr address = entries_.cells[entries_.current].GetAddress();
207 if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
208 if (flags_ & WORK_FOR_RESURRECT)
209 return LoadShortEntryBlock(address);
210 continue;
211 }
212
213 if (flags_ & WORK_FOR_RESURRECT)
214 continue;
215 return LoadEntryBlock(address);
216 }
217 next_state_ = STATE_NONE;
218 return ERR_OPERATION_FAILED;
219 }
220
221 int BackendImplV3::WorkItem::DoOpenEntryComplete(int result) {
222 if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
223 if (result != static_cast<int>(sizeof(ShortEntryRecord)))
224 return ERR_READ_FAILURE;
225
226 if (!EntryImplV3::DeletedSanityCheck(*short_entry_block_->Data()))
227 return ERR_INVALID_ENTRY;
228 } else {
229 if (result != static_cast<int>(sizeof(EntryRecord)))
230 return ERR_READ_FAILURE;
231
232 if (!EntryImplV3::BasicSanityCheck(*entry_block_->Data()))
233 return ERR_INVALID_ENTRY;
234 }
235
236 if (entries_.cells[entries_.current].GetGroup() == ENTRY_EVICTED) {
237 DCHECK(!(flags_ & WORK_FOR_EVICT));
238 if (CryptoHashMatches(key_, *short_entry_block_->Data())) {
239 // We have a match.
240 short_entry_record_.reset(short_entry_block_->ReleaseData());
241 return ERR_NO_ERROR;
242 }
243 } else {
244 next_state_ = STATE_READ_KEY;
245 return ERR_NO_ERROR;
246 }
247
248 next_state_ = STATE_OPEN_ENTRY;
249 entries_.current++;
250 return ERR_NO_ERROR;
251 }
252
253 int BackendImplV3::WorkItem::DoReadKey() {
254 address_.set_value(entry_block_->Data()->data_addr[0]);
255 offset_ = 0;
256 buffer_ = new net::IOBuffer(entry_block_->Data()->key_len);
257 buffer_len_ = entry_block_->Data()->key_len;
258
259 next_state_ = STATE_READ_DATA;
260 return ERR_NO_ERROR;
261 }
262
263 int BackendImplV3::WorkItem::DoReadKeyComplete() {
264 std::string key(buffer_->data(), buffer_len_);
265 uint32 hash = base::Hash(key);
266 Trace("DoReadKeyComplete hash 0x%x, 0x%p", hash, this);
267 DCHECK_EQ(hash, entries_.cells[entries_.current].hash());
268 if (flags() & WORK_FOR_ITERATION)
269 key_ = key;
270
271 if (flags_ & WORK_FOR_EVICT) {
272 key_ = key;
273 if (!(flags_ & WORK_NO_COPY)) {
274 next_state_ = STATE_COPY_ENTRY;
275 return ERR_NO_ERROR;
276 }
277 }
278
279 if (key == key_) {
280 // We have a match.
281 entry_record_.reset(entry_block_->ReleaseData());
282 return ERR_NO_ERROR;
283 }
284
285 next_state_ = STATE_OPEN_ENTRY;
286 entries_.current++;
287 return ERR_NO_ERROR;
288 }
289
290 int BackendImplV3::WorkItem::DoReadData() {
291 disk_cache::File* file = worker_->GetBackingFile(address_, false);
292 if (!file)
293 return net::ERR_FILE_NOT_FOUND;
294
295
296 size_t file_offset = offset_;
297 if (address_.is_block_file()) {
298 DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
299 file_offset += address_.start_block() * address_.BlockSize();
300 }
301 DCHECK(buffer_len_);
302
303 bool completed;
304 IOCallback* callback = new IOCallback(this);
305
306 if (!file->Read(buffer_->data(), buffer_len_, file_offset, callback,
307 &completed)) {
308 callback->Discard();
309 return net::ERR_CACHE_READ_FAILURE;
310 }
311 next_state_ = STATE_READ_DATA_COMPLETE;
312
313 if (completed) {
314 callback->Discard();
315 return NO_ERROR;
316 }
317
318 return ERR_PENDING;
319 }
320
321 int BackendImplV3::WorkItem::DoReadDataComplete(int result) {
322 if (result != buffer_len_)
323 return net::ERR_CACHE_READ_FAILURE;
324
325 if (type() == WORK_OPEN_ENTRY) {
326 next_state_ = STATE_READ_KEY_COMPLETE;
327 return ERR_NO_ERROR;
328 }
329
330 return result;
331 }
332
333 int BackendImplV3::WorkItem::DoWriteData() {
334 disk_cache::File* file = NULL;
335 if (type_ == WORK_WRITE_INDEX)
336 file = worker_->GetBackupIndexFile();
337 else
338 file = worker_->GetBackingFile(address_, true);
339
340 if (!file)
341 return net::ERR_CACHE_WRITE_FAILURE;
342
343 DCHECK(buffer_len_);
344
345 size_t file_offset = offset_;
346 if (type_ != WORK_WRITE_INDEX && address_.is_block_file()) {
347 DCHECK_LE(offset_ + buffer_len_, kMaxBlockSize);
348 file_offset += address_.start_block() * address_.BlockSize();
349 }
350
351 bool completed;
352 IOCallback* callback = new IOCallback(this);
353
354 if (!file->Write(buffer_->data(), buffer_len_, file_offset, callback,
355 &completed)) {
356 callback->Discard();
357 return net::ERR_CACHE_WRITE_FAILURE;
358 }
359 next_state_ = STATE_WRITE_DATA_COMPLETE;
360
361 if (completed) {
362 callback->Discard();
363 return NO_ERROR;
364 }
365
366 return ERR_PENDING;
367 }
368
369 int BackendImplV3::WorkItem::DoWriteDataComplete(int result) {
370 if (type_ == WORK_WRITE_INDEX)
371 worker_->CloseBackupIndexFile();
372
373 if (result != buffer_len_)
374 return net::ERR_CACHE_WRITE_FAILURE;
375
376 return result;
377 }
378
379 int BackendImplV3::WorkItem::DoMoveData() {
380 disk_cache::File* file = worker_->GetBackingFile(address_, false);
381 if (!file)
382 return ERR_OPERATION_FAILED;
383
384 DCHECK(buffer_len_);
385
386 if (!address_.is_block_file()) {
387 NOTREACHED();
388 return ERR_OPERATION_FAILED;
389 }
390
391 offset_ = 0;
392 size_t file_offset = 0;
393 DCHECK_LE(buffer_len_, kMaxBlockSize);
394 file_offset += address_.start_block() * address_.BlockSize();
395
396 buffer_ = new net::IOBufferWithSize(buffer_len_);
397
398 // We could optimize this to be an async read, but we'd have to do that from
399 // the main thread, not from here.
400 if (!file->Read(buffer_->data(), buffer_len_, file_offset))
401 return ERR_WRITE_FAILURE;
402
403 address_ = address2_;
404 next_state_ = STATE_WRITE_DATA;
405 return NO_ERROR;
406 }
407
408 int BackendImplV3::WorkItem::DoTruncateData() {
409 if (address_.is_block_file())
410 return ERR_OPERATION_FAILED;
411
412 disk_cache::File* file = worker_->GetBackingFile(address_, false);
413 if (!file)
414 return ERR_OPERATION_FAILED;
415
416 if (!file->SetLength(offset_))
417 return ERR_OPERATION_FAILED;
418
419 return ERR_NO_ERROR;
420 }
421
422 int BackendImplV3::WorkItem::DoCopyEntry() {
423 next_state_ = STATE_COPY_ENTRY_COMPLETE;
424 Addr address = entries_.cells[1].GetAddress();
425 short_entry_block_.reset(
426 new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
427
428 ShortEntryRecord* short_record = short_entry_block_->Data();
429 EntryRecord* long_record = entry_block_->Data();
430
431 short_record->hash = long_record->hash;
432 short_record->reuse_count = long_record->reuse_count;
433 short_record->refetch_count = long_record->refetch_count;
434 short_record->refetch_count = long_record->refetch_count;
435 short_record->key_len = long_record->key_len;
436 short_record->last_access_time = long_record->last_access_time;
437 ComputeCryptoHash(key_, short_record);
438
439 bool completed;
440 IOCallback* callback = new IOCallback(this);
441 if (!short_entry_block_->Store(callback, &completed)) {
442 callback->Discard();
443 next_state_ = STATE_NONE;
444 return ERR_OPERATION_FAILED;
445 }
446
447 if (completed) {
448 callback->Discard();
449 return ERR_NO_ERROR;
450 }
451
452 return ERR_PENDING;
453 }
454
455 int BackendImplV3::WorkItem::DoCopyEntryComplete(int result) {
456 if (result != static_cast<int>(sizeof(ShortEntryRecord)))
457 return ERR_READ_FAILURE;
458
459 entry_record_.reset(entry_block_->ReleaseData());
460 return ERR_NO_ERROR;
461 }
462
463 int BackendImplV3::WorkItem::LoadEntryBlock(Addr address) {
464 entry_block_.reset(new CacheEntryBlockV3(worker_->GetMappedFile(address),
465 address));
466 bool completed;
467 IOCallback* callback = new IOCallback(this);
468 if (!entry_block_->Load(callback, &completed)) {
469 callback->Discard();
470 next_state_ = STATE_NONE;
471 return ERR_OPERATION_FAILED;
472 }
473
474 if (completed) {
475 callback->Discard();
476 return ERR_NO_ERROR;
477 }
478
479 return ERR_PENDING;
480 }
481
482 int BackendImplV3::WorkItem::LoadShortEntryBlock(Addr address) {
483 short_entry_block_.reset(
484 new CacheShortEntryBlock(worker_->GetMappedFile(address), address));
485 bool completed;
486 IOCallback* callback = new IOCallback(this);
487 if (!short_entry_block_->Load(callback, &completed)) {
488 callback->Discard();
489 next_state_ = STATE_NONE;
490 return ERR_OPERATION_FAILED;
491 }
492
493 if (completed) {
494 callback->Discard();
495 return ERR_NO_ERROR;
496 }
497
498 return ERR_PENDING;
499 }
500
501 } // 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