OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "net/disk_cache/entry_impl.h" | 5 #include "net/disk_cache/entry_impl.h" |
6 | 6 |
7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
11 #include "net/disk_cache/backend_impl.h" | 11 #include "net/disk_cache/backend_impl.h" |
12 #include "net/disk_cache/cache_util.h" | 12 #include "net/disk_cache/cache_util.h" |
13 | 13 |
14 using base::Time; | 14 using base::Time; |
15 using base::TimeDelta; | 15 using base::TimeDelta; |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
| 19 // Index for the file used to store the key, if any (files_[kKeyFileIndex]). |
| 20 const int kKeyFileIndex = 3; |
| 21 |
19 // This class implements FileIOCallback to buffer the callback from a file IO | 22 // This class implements FileIOCallback to buffer the callback from a file IO |
20 // operation from the actual net class. | 23 // operation from the actual net class. |
21 class SyncCallback: public disk_cache::FileIOCallback { | 24 class SyncCallback: public disk_cache::FileIOCallback { |
22 public: | 25 public: |
23 SyncCallback(disk_cache::EntryImpl* entry, | 26 SyncCallback(disk_cache::EntryImpl* entry, |
24 net::CompletionCallback* callback ) | 27 net::CompletionCallback* callback ) |
25 : entry_(entry), callback_(callback) { | 28 : entry_(entry), callback_(callback) { |
26 entry->AddRef(); | 29 entry->AddRef(); |
27 entry->IncrementIoCount(); | 30 entry->IncrementIoCount(); |
28 } | 31 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 | 68 |
66 } // namespace | 69 } // namespace |
67 | 70 |
68 namespace disk_cache { | 71 namespace disk_cache { |
69 | 72 |
70 EntryImpl::EntryImpl(BackendImpl* backend, Addr address) | 73 EntryImpl::EntryImpl(BackendImpl* backend, Addr address) |
71 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) { | 74 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) { |
72 entry_.LazyInit(backend->File(address), address); | 75 entry_.LazyInit(backend->File(address), address); |
73 doomed_ = false; | 76 doomed_ = false; |
74 backend_ = backend; | 77 backend_ = backend; |
75 unreported_size_[0] = unreported_size_[1] = 0; | 78 for (int i = 0; i < NUM_STREAMS; i++) |
| 79 unreported_size_[i] = 0; |
76 } | 80 } |
77 | 81 |
78 // When an entry is deleted from the cache, we clean up all the data associated | 82 // When an entry is deleted from the cache, we clean up all the data associated |
79 // with it for two reasons: to simplify the reuse of the block (we know that any | 83 // with it for two reasons: to simplify the reuse of the block (we know that any |
80 // unused block is filled with zeros), and to simplify the handling of write / | 84 // unused block is filled with zeros), and to simplify the handling of write / |
81 // read partial information from an entry (don't have to worry about returning | 85 // read partial information from an entry (don't have to worry about returning |
82 // data related to a previous cache entry because the range was not fully | 86 // data related to a previous cache entry because the range was not fully |
83 // written before). | 87 // written before). |
84 EntryImpl::~EntryImpl() { | 88 EntryImpl::~EntryImpl() { |
85 if (doomed_) { | 89 if (doomed_) { |
86 UMA_HISTOGRAM_COUNTS(L"DiskCache.DeleteHeader", GetDataSize(0)); | 90 UMA_HISTOGRAM_COUNTS(L"DiskCache.DeleteHeader", GetDataSize(0)); |
87 UMA_HISTOGRAM_COUNTS(L"DiskCache.DeleteData", GetDataSize(1)); | 91 UMA_HISTOGRAM_COUNTS(L"DiskCache.DeleteData", GetDataSize(1)); |
88 for (int index = 0; index < kKeyFileIndex; index++) { | 92 for (int index = 0; index < NUM_STREAMS; index++) { |
89 Addr address(entry_.Data()->data_addr[index]); | 93 Addr address(entry_.Data()->data_addr[index]); |
90 if (address.is_initialized()) { | 94 if (address.is_initialized()) { |
91 DeleteData(address, index); | 95 DeleteData(address, index); |
92 backend_->ModifyStorageSize(entry_.Data()->data_size[index] - | 96 backend_->ModifyStorageSize(entry_.Data()->data_size[index] - |
93 unreported_size_[index], 0); | 97 unreported_size_[index], 0); |
94 } | 98 } |
95 } | 99 } |
96 Addr address(entry_.Data()->long_key); | 100 Addr address(entry_.Data()->long_key); |
97 DeleteData(address, kKeyFileIndex); | 101 DeleteData(address, kKeyFileIndex); |
98 backend_->ModifyStorageSize(entry_.Data()->key_len, 0); | 102 backend_->ModifyStorageSize(entry_.Data()->key_len, 0); |
99 | 103 |
100 memset(node_.buffer(), 0, node_.size()); | 104 memset(node_.buffer(), 0, node_.size()); |
101 memset(entry_.buffer(), 0, entry_.size()); | 105 memset(entry_.buffer(), 0, entry_.size()); |
102 node_.Store(); | 106 node_.Store(); |
103 entry_.Store(); | 107 entry_.Store(); |
104 | 108 |
105 backend_->DeleteBlock(node_.address(), false); | 109 backend_->DeleteBlock(node_.address(), false); |
106 backend_->DeleteBlock(entry_.address(), false); | 110 backend_->DeleteBlock(entry_.address(), false); |
107 } else { | 111 } else { |
108 bool ret = true; | 112 bool ret = true; |
109 for (int index = 0; index < kKeyFileIndex; index++) { | 113 for (int index = 0; index < NUM_STREAMS; index++) { |
110 if (user_buffers_[index].get()) { | 114 if (user_buffers_[index].get()) { |
111 if (!(ret = Flush(index, entry_.Data()->data_size[index], false))) | 115 if (!(ret = Flush(index, entry_.Data()->data_size[index], false))) |
112 LOG(ERROR) << "Failed to save user data"; | 116 LOG(ERROR) << "Failed to save user data"; |
113 } else if (unreported_size_[index]) { | 117 } else if (unreported_size_[index]) { |
114 backend_->ModifyStorageSize( | 118 backend_->ModifyStorageSize( |
115 entry_.Data()->data_size[index] - unreported_size_[index], | 119 entry_.Data()->data_size[index] - unreported_size_[index], |
116 entry_.Data()->data_size[index]); | 120 entry_.Data()->data_size[index]); |
117 } | 121 } |
118 } | 122 } |
119 if (node_.HasData() && this == node_.Data()->pointer) { | 123 if (node_.HasData() && this == node_.Data()->pointer) { |
(...skipping 27 matching lines...) Expand all Loading... |
147 | 151 |
148 void EntryImpl::Close() { | 152 void EntryImpl::Close() { |
149 Release(); | 153 Release(); |
150 } | 154 } |
151 | 155 |
152 std::string EntryImpl::GetKey() const { | 156 std::string EntryImpl::GetKey() const { |
153 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); | 157 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); |
154 if (entry->Data()->key_len > kMaxInternalKeyLength) { | 158 if (entry->Data()->key_len > kMaxInternalKeyLength) { |
155 Addr address(entry->Data()->long_key); | 159 Addr address(entry->Data()->long_key); |
156 DCHECK(address.is_initialized()); | 160 DCHECK(address.is_initialized()); |
| 161 COMPILE_ASSERT(NUM_STREAMS == kKeyFileIndex, invalid_key_index); |
157 File* file = const_cast<EntryImpl*>(this)->GetBackingFile(address, | 162 File* file = const_cast<EntryImpl*>(this)->GetBackingFile(address, |
158 kKeyFileIndex); | 163 kKeyFileIndex); |
159 | 164 |
160 size_t offset = 0; | 165 size_t offset = 0; |
161 if (address.is_block_file()) | 166 if (address.is_block_file()) |
162 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; | 167 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; |
163 | 168 |
164 std::string key; | 169 std::string key; |
165 if (!file || !file->Read(WriteInto(&key, entry->Data()->key_len + 1), | 170 if (!file || !file->Read(WriteInto(&key, entry->Data()->key_len + 1), |
166 entry->Data()->key_len + 1, offset)) | 171 entry->Data()->key_len + 1, offset)) |
167 key.clear(); | 172 key.clear(); |
168 return key; | 173 return key; |
169 } else { | 174 } else { |
170 return std::string(entry->Data()->key); | 175 return std::string(entry->Data()->key); |
171 } | 176 } |
172 } | 177 } |
173 | 178 |
174 Time EntryImpl::GetLastUsed() const { | 179 Time EntryImpl::GetLastUsed() const { |
175 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); | 180 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); |
176 return Time::FromInternalValue(node->Data()->last_used); | 181 return Time::FromInternalValue(node->Data()->last_used); |
177 } | 182 } |
178 | 183 |
179 Time EntryImpl::GetLastModified() const { | 184 Time EntryImpl::GetLastModified() const { |
180 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); | 185 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); |
181 return Time::FromInternalValue(node->Data()->last_modified); | 186 return Time::FromInternalValue(node->Data()->last_modified); |
182 } | 187 } |
183 | 188 |
184 int32 EntryImpl::GetDataSize(int index) const { | 189 int32 EntryImpl::GetDataSize(int index) const { |
185 if (index < 0 || index > 1) | 190 if (index < 0 || index >= NUM_STREAMS) |
186 return 0; | 191 return 0; |
187 | 192 |
188 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); | 193 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); |
189 return entry->Data()->data_size[index]; | 194 return entry->Data()->data_size[index]; |
190 } | 195 } |
191 | 196 |
192 int EntryImpl::ReadData(int index, int offset, char* buf, int buf_len, | 197 int EntryImpl::ReadData(int index, int offset, char* buf, int buf_len, |
193 net::CompletionCallback* completion_callback) { | 198 net::CompletionCallback* completion_callback) { |
194 DCHECK(node_.Data()->dirty); | 199 DCHECK(node_.Data()->dirty); |
195 if (index < 0 || index > 1) | 200 if (index < 0 || index >= NUM_STREAMS) |
196 return net::ERR_INVALID_ARGUMENT; | 201 return net::ERR_INVALID_ARGUMENT; |
197 | 202 |
198 int entry_size = entry_.Data()->data_size[index]; | 203 int entry_size = entry_.Data()->data_size[index]; |
199 if (offset >= entry_size || offset < 0 || !buf_len) | 204 if (offset >= entry_size || offset < 0 || !buf_len) |
200 return 0; | 205 return 0; |
201 | 206 |
202 if (buf_len < 0) | 207 if (buf_len < 0) |
203 return net::ERR_INVALID_ARGUMENT; | 208 return net::ERR_INVALID_ARGUMENT; |
204 | 209 |
205 Time start = Time::Now(); | 210 Time start = Time::Now(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 io_callback->Discard(); | 256 io_callback->Discard(); |
252 | 257 |
253 stats.AddTime(Time::Now() - start); | 258 stats.AddTime(Time::Now() - start); |
254 return (completed || !completion_callback) ? buf_len : net::ERR_IO_PENDING; | 259 return (completed || !completion_callback) ? buf_len : net::ERR_IO_PENDING; |
255 } | 260 } |
256 | 261 |
257 int EntryImpl::WriteData(int index, int offset, const char* buf, int buf_len, | 262 int EntryImpl::WriteData(int index, int offset, const char* buf, int buf_len, |
258 net::CompletionCallback* completion_callback, | 263 net::CompletionCallback* completion_callback, |
259 bool truncate) { | 264 bool truncate) { |
260 DCHECK(node_.Data()->dirty); | 265 DCHECK(node_.Data()->dirty); |
261 if (index < 0 || index > 1) | 266 if (index < 0 || index >= NUM_STREAMS) |
262 return net::ERR_INVALID_ARGUMENT; | 267 return net::ERR_INVALID_ARGUMENT; |
263 | 268 |
264 if (offset < 0 || buf_len < 0) | 269 if (offset < 0 || buf_len < 0) |
265 return net::ERR_INVALID_ARGUMENT; | 270 return net::ERR_INVALID_ARGUMENT; |
266 | 271 |
267 int max_file_size = backend_->MaxFileSize(); | 272 int max_file_size = backend_->MaxFileSize(); |
268 | 273 |
269 // offset of buf_len could be negative numbers. | 274 // offset of buf_len could be negative numbers. |
270 if (offset > max_file_size || buf_len > max_file_size || | 275 if (offset > max_file_size || buf_len > max_file_size || |
271 offset + buf_len > max_file_size) { | 276 offset + buf_len > max_file_size) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks()); | 370 memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks()); |
366 memset(node, 0, sizeof(RankingsNode)); | 371 memset(node, 0, sizeof(RankingsNode)); |
367 if (!node_.LazyInit(backend_->File(node_address), node_address)) | 372 if (!node_.LazyInit(backend_->File(node_address), node_address)) |
368 return false; | 373 return false; |
369 | 374 |
370 entry_store->rankings_node = node_address.value(); | 375 entry_store->rankings_node = node_address.value(); |
371 node->contents = entry_.address().value(); | 376 node->contents = entry_.address().value(); |
372 node->pointer = this; | 377 node->pointer = this; |
373 | 378 |
374 entry_store->hash = hash; | 379 entry_store->hash = hash; |
| 380 entry_store->creation_time = Time::Now().ToInternalValue(); |
375 entry_store->key_len = static_cast<int32>(key.size()); | 381 entry_store->key_len = static_cast<int32>(key.size()); |
376 if (entry_store->key_len > kMaxInternalKeyLength) { | 382 if (entry_store->key_len > kMaxInternalKeyLength) { |
377 Addr address(0); | 383 Addr address(0); |
378 if (!CreateBlock(entry_store->key_len + 1, &address)) | 384 if (!CreateBlock(entry_store->key_len + 1, &address)) |
379 return false; | 385 return false; |
380 | 386 |
381 entry_store->long_key = address.value(); | 387 entry_store->long_key = address.value(); |
382 File* file = GetBackingFile(address, kKeyFileIndex); | 388 File* file = GetBackingFile(address, kKeyFileIndex); |
383 | 389 |
384 size_t offset = 0; | 390 size_t offset = 0; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 } | 506 } |
501 | 507 |
502 void EntryImpl::SetTimes(base::Time last_used, base::Time last_modified) { | 508 void EntryImpl::SetTimes(base::Time last_used, base::Time last_modified) { |
503 node_.Data()->last_used = last_used.ToInternalValue(); | 509 node_.Data()->last_used = last_used.ToInternalValue(); |
504 node_.Data()->last_modified = last_modified.ToInternalValue(); | 510 node_.Data()->last_modified = last_modified.ToInternalValue(); |
505 node_.set_modified(); | 511 node_.set_modified(); |
506 } | 512 } |
507 | 513 |
508 bool EntryImpl::CreateDataBlock(int index, int size) { | 514 bool EntryImpl::CreateDataBlock(int index, int size) { |
509 Addr address(entry_.Data()->data_addr[index]); | 515 Addr address(entry_.Data()->data_addr[index]); |
510 DCHECK(0 == index || 1 == index); | 516 DCHECK(index >= 0 && index < NUM_STREAMS); |
511 | 517 |
512 if (!CreateBlock(size, &address)) | 518 if (!CreateBlock(size, &address)) |
513 return false; | 519 return false; |
514 | 520 |
515 entry_.Data()->data_addr[index] = address.value(); | 521 entry_.Data()->data_addr[index] = address.value(); |
516 entry_.Store(); | 522 entry_.Store(); |
517 return true; | 523 return true; |
518 } | 524 } |
519 | 525 |
520 bool EntryImpl::CreateBlock(int size, Addr* address) { | 526 bool EntryImpl::CreateBlock(int size, Addr* address) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 File* EntryImpl::GetBackingFile(Addr address, int index) { | 576 File* EntryImpl::GetBackingFile(Addr address, int index) { |
571 File* file; | 577 File* file; |
572 if (address.is_separate_file()) | 578 if (address.is_separate_file()) |
573 file = GetExternalFile(address, index); | 579 file = GetExternalFile(address, index); |
574 else | 580 else |
575 file = backend_->File(address); | 581 file = backend_->File(address); |
576 return file; | 582 return file; |
577 } | 583 } |
578 | 584 |
579 File* EntryImpl::GetExternalFile(Addr address, int index) { | 585 File* EntryImpl::GetExternalFile(Addr address, int index) { |
580 DCHECK(index >= 0 && index <= 2); | 586 DCHECK(index >= 0 && index <= kKeyFileIndex); |
581 if (!files_[index].get()) { | 587 if (!files_[index].get()) { |
582 // For a key file, use mixed mode IO. | 588 // For a key file, use mixed mode IO. |
583 scoped_refptr<File> file(new File(2 == index)); | 589 scoped_refptr<File> file(new File(kKeyFileIndex == index)); |
584 if (file->Init(backend_->GetFileName(address))) | 590 if (file->Init(backend_->GetFileName(address))) |
585 files_[index].swap(file); | 591 files_[index].swap(file); |
586 } | 592 } |
587 return files_[index].get(); | 593 return files_[index].get(); |
588 } | 594 } |
589 | 595 |
590 bool EntryImpl::PrepareTarget(int index, int offset, int buf_len, | 596 bool EntryImpl::PrepareTarget(int index, int offset, int buf_len, |
591 bool truncate) { | 597 bool truncate) { |
592 Addr address(entry_.Data()->data_addr[index]); | 598 Addr address(entry_.Data()->data_addr[index]); |
593 if (address.is_initialized() || user_buffers_[index].get()) | 599 if (address.is_initialized() || user_buffers_[index].get()) |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 entry_.address().value(), node_.address().value()); | 772 entry_.address().value(), node_.address().value()); |
767 | 773 |
768 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], | 774 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], |
769 entry_.Data()->data_addr[1], entry_.Data()->long_key); | 775 entry_.Data()->data_addr[1], entry_.Data()->long_key); |
770 | 776 |
771 Trace(" doomed: %d 0x%p 0x%x", doomed_, pointer, dirty); | 777 Trace(" doomed: %d 0x%p 0x%x", doomed_, pointer, dirty); |
772 } | 778 } |
773 | 779 |
774 } // namespace disk_cache | 780 } // namespace disk_cache |
775 | 781 |
OLD | NEW |