OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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/simple/simple_synchronous_entry.h" | 5 #include "net/disk_cache/simple/simple_synchronous_entry.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <functional> | 9 #include <functional> |
10 #include <limits> | 10 #include <limits> |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 | 134 |
135 void RecordCloseResult(net::CacheType cache_type, CloseResult result) { | 135 void RecordCloseResult(net::CacheType cache_type, CloseResult result) { |
136 SIMPLE_CACHE_UMA(ENUMERATION, | 136 SIMPLE_CACHE_UMA(ENUMERATION, |
137 "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX); | 137 "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX); |
138 } | 138 } |
139 | 139 |
140 } // namespace | 140 } // namespace |
141 | 141 |
142 namespace disk_cache { | 142 namespace disk_cache { |
143 | 143 |
144 using simple_util::ConvertEntryHashKeyToHexString; | |
145 using simple_util::GetEntryHashKey; | 144 using simple_util::GetEntryHashKey; |
146 using simple_util::GetFilenameFromEntryHashAndIndex; | 145 using simple_util::GetFilenameFromEntryHashAndFileIndex; |
147 using simple_util::GetDataSizeFromKeyAndFileSize; | 146 using simple_util::GetDataSizeFromKeyAndFileSize; |
148 using simple_util::GetFileSizeFromKeyAndDataSize; | 147 using simple_util::GetFileSizeFromKeyAndDataSize; |
149 using simple_util::GetFileOffsetFromKeyAndDataOffset; | 148 using simple_util::GetFileIndexFromStreamIndex; |
150 | 149 |
151 SimpleEntryStat::SimpleEntryStat() {} | 150 SimpleEntryStat::SimpleEntryStat(base::Time last_used, |
| 151 base::Time last_modified, |
| 152 const int32 data_size[]) |
| 153 : last_used_(last_used), |
| 154 last_modified_(last_modified) { |
| 155 memcpy(data_size_, data_size, sizeof(data_size_)); |
| 156 } |
152 | 157 |
153 SimpleEntryStat::SimpleEntryStat(base::Time last_used_p, | 158 int SimpleEntryStat::GetOffsetInFile(const std::string& key, |
154 base::Time last_modified_p, | 159 int offset, |
155 const int32 data_size_p[]) | 160 int stream_index) const { |
156 : last_used(last_used_p), | 161 const int64 headers_size = sizeof(SimpleFileHeader) + key.size(); |
157 last_modified(last_modified_p) { | 162 const int64 additional_offset = |
158 memcpy(data_size, data_size_p, sizeof(data_size)); | 163 stream_index == 0 ? data_size_[1] + sizeof(SimpleFileEOF) : 0; |
| 164 return headers_size + offset + additional_offset; |
| 165 } |
| 166 |
| 167 int SimpleEntryStat::GetEOFOffsetInFile(const std::string& key, |
| 168 int stream_index) const { |
| 169 return GetOffsetInFile(key, data_size_[stream_index], stream_index); |
| 170 } |
| 171 |
| 172 int SimpleEntryStat::GetLastEOFOffsetInFile(const std::string& key, |
| 173 int stream_index) const { |
| 174 const int file_index = GetFileIndexFromStreamIndex(stream_index); |
| 175 const int eof_data_offset = |
| 176 file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF) |
| 177 : data_size_[2]; |
| 178 return GetOffsetInFile(key, eof_data_offset, stream_index); |
| 179 } |
| 180 |
| 181 int SimpleEntryStat::GetFileSize(const std::string& key, int file_index) const { |
| 182 const int total_data_size = |
| 183 file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF) |
| 184 : data_size_[2]; |
| 185 return GetFileSizeFromKeyAndDataSize(key, total_data_size); |
159 } | 186 } |
160 | 187 |
161 SimpleEntryCreationResults::SimpleEntryCreationResults( | 188 SimpleEntryCreationResults::SimpleEntryCreationResults( |
162 SimpleEntryStat entry_stat) | 189 SimpleEntryStat entry_stat) |
163 : sync_entry(NULL), | 190 : sync_entry(NULL), |
164 entry_stat(entry_stat), | 191 entry_stat(entry_stat), |
| 192 stream_0_crc32(crc32(0, Z_NULL, 0)), |
165 result(net::OK) { | 193 result(net::OK) { |
166 } | 194 } |
167 | 195 |
168 SimpleEntryCreationResults::~SimpleEntryCreationResults() { | 196 SimpleEntryCreationResults::~SimpleEntryCreationResults() { |
169 } | 197 } |
170 | 198 |
171 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1), | 199 SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1), |
172 has_crc32(false), | 200 has_crc32(false), |
173 data_crc32(0) { | 201 data_crc32(0) { |
174 } | 202 } |
(...skipping 23 matching lines...) Expand all Loading... |
198 | 226 |
199 // static | 227 // static |
200 void SimpleSynchronousEntry::OpenEntry( | 228 void SimpleSynchronousEntry::OpenEntry( |
201 net::CacheType cache_type, | 229 net::CacheType cache_type, |
202 const FilePath& path, | 230 const FilePath& path, |
203 const uint64 entry_hash, | 231 const uint64 entry_hash, |
204 bool had_index, | 232 bool had_index, |
205 SimpleEntryCreationResults *out_results) { | 233 SimpleEntryCreationResults *out_results) { |
206 SimpleSynchronousEntry* sync_entry = | 234 SimpleSynchronousEntry* sync_entry = |
207 new SimpleSynchronousEntry(cache_type, path, "", entry_hash); | 235 new SimpleSynchronousEntry(cache_type, path, "", entry_hash); |
208 out_results->result = sync_entry->InitializeForOpen( | 236 out_results->result = |
209 had_index, &out_results->entry_stat); | 237 sync_entry->InitializeForOpen(had_index, |
| 238 &out_results->entry_stat, |
| 239 &out_results->stream_0_data, |
| 240 &out_results->stream_0_crc32); |
210 if (out_results->result != net::OK) { | 241 if (out_results->result != net::OK) { |
211 sync_entry->Doom(); | 242 sync_entry->Doom(); |
212 delete sync_entry; | 243 delete sync_entry; |
213 out_results->sync_entry = NULL; | 244 out_results->sync_entry = NULL; |
| 245 out_results->stream_0_data = NULL; |
214 return; | 246 return; |
215 } | 247 } |
216 out_results->sync_entry = sync_entry; | 248 out_results->sync_entry = sync_entry; |
217 } | 249 } |
218 | 250 |
219 // static | 251 // static |
220 void SimpleSynchronousEntry::CreateEntry( | 252 void SimpleSynchronousEntry::CreateEntry( |
221 net::CacheType cache_type, | 253 net::CacheType cache_type, |
222 const FilePath& path, | 254 const FilePath& path, |
223 const std::string& key, | 255 const std::string& key, |
(...skipping 15 matching lines...) Expand all Loading... |
239 out_results->sync_entry = sync_entry; | 271 out_results->sync_entry = sync_entry; |
240 } | 272 } |
241 | 273 |
242 // TODO(gavinp): Move this function to its correct location in this .cc file. | 274 // TODO(gavinp): Move this function to its correct location in this .cc file. |
243 // static | 275 // static |
244 bool SimpleSynchronousEntry::DeleteFilesForEntryHash( | 276 bool SimpleSynchronousEntry::DeleteFilesForEntryHash( |
245 const FilePath& path, | 277 const FilePath& path, |
246 const uint64 entry_hash) { | 278 const uint64 entry_hash) { |
247 bool result = true; | 279 bool result = true; |
248 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 280 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
249 FilePath to_delete = path.AppendASCII( | 281 FilePath to_delete = |
250 GetFilenameFromEntryHashAndIndex(entry_hash, i)); | 282 path.AppendASCII(GetFilenameFromEntryHashAndFileIndex(entry_hash, i)); |
251 if (!base::DeleteFile(to_delete, false)) { | 283 if (!base::DeleteFile(to_delete, false)) { |
252 result = false; | 284 result = false; |
253 DLOG(ERROR) << "Could not delete " << to_delete.MaybeAsASCII(); | 285 DLOG(ERROR) << "Could not delete " << to_delete.MaybeAsASCII(); |
254 } | 286 } |
255 } | 287 } |
256 return result; | 288 return result; |
257 } | 289 } |
258 | 290 |
259 // static | 291 // static |
260 int SimpleSynchronousEntry::DoomEntry( | 292 int SimpleSynchronousEntry::DoomEntry( |
(...skipping 11 matching lines...) Expand all Loading... |
272 const FilePath& path) { | 304 const FilePath& path) { |
273 const size_t did_delete_count = std::count_if( | 305 const size_t did_delete_count = std::count_if( |
274 key_hashes->begin(), key_hashes->end(), std::bind1st( | 306 key_hashes->begin(), key_hashes->end(), std::bind1st( |
275 std::ptr_fun(SimpleSynchronousEntry::DeleteFilesForEntryHash), path)); | 307 std::ptr_fun(SimpleSynchronousEntry::DeleteFilesForEntryHash), path)); |
276 return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED; | 308 return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED; |
277 } | 309 } |
278 | 310 |
279 void SimpleSynchronousEntry::ReadData(const EntryOperationData& in_entry_op, | 311 void SimpleSynchronousEntry::ReadData(const EntryOperationData& in_entry_op, |
280 net::IOBuffer* out_buf, | 312 net::IOBuffer* out_buf, |
281 uint32* out_crc32, | 313 uint32* out_crc32, |
282 base::Time* out_last_used, | 314 SimpleEntryStat* entry_stat, |
283 int* out_result) const { | 315 int* out_result) const { |
284 DCHECK(initialized_); | 316 DCHECK(initialized_); |
285 int64 file_offset = | 317 DCHECK_NE(0, in_entry_op.index); |
286 GetFileOffsetFromKeyAndDataOffset(key_, in_entry_op.offset); | 318 const int64 file_offset = |
287 int bytes_read = ReadPlatformFile(files_[in_entry_op.index], | 319 entry_stat->GetOffsetInFile(key_, in_entry_op.offset, in_entry_op.index); |
288 file_offset, | 320 int file_index = GetFileIndexFromStreamIndex(in_entry_op.index); |
289 out_buf->data(), | 321 int bytes_read = ReadPlatformFile( |
290 in_entry_op.buf_len); | 322 files_[file_index], file_offset, out_buf->data(), in_entry_op.buf_len); |
291 if (bytes_read > 0) { | 323 if (bytes_read > 0) { |
292 *out_last_used = Time::Now(); | 324 entry_stat->set_last_used(Time::Now()); |
293 *out_crc32 = crc32(crc32(0L, Z_NULL, 0), | 325 *out_crc32 = crc32(crc32(0L, Z_NULL, 0), |
294 reinterpret_cast<const Bytef*>(out_buf->data()), | 326 reinterpret_cast<const Bytef*>(out_buf->data()), |
295 bytes_read); | 327 bytes_read); |
296 } | 328 } |
297 if (bytes_read >= 0) { | 329 if (bytes_read >= 0) { |
298 *out_result = bytes_read; | 330 *out_result = bytes_read; |
299 } else { | 331 } else { |
300 *out_result = net::ERR_CACHE_READ_FAILURE; | 332 *out_result = net::ERR_CACHE_READ_FAILURE; |
301 Doom(); | 333 Doom(); |
302 } | 334 } |
303 } | 335 } |
304 | 336 |
305 void SimpleSynchronousEntry::WriteData(const EntryOperationData& in_entry_op, | 337 void SimpleSynchronousEntry::WriteData(const EntryOperationData& in_entry_op, |
306 net::IOBuffer* in_buf, | 338 net::IOBuffer* in_buf, |
307 SimpleEntryStat* out_entry_stat, | 339 SimpleEntryStat* out_entry_stat, |
308 int* out_result) const { | 340 int* out_result) const { |
309 DCHECK(initialized_); | 341 DCHECK(initialized_); |
| 342 DCHECK_NE(0, in_entry_op.index); |
310 int index = in_entry_op.index; | 343 int index = in_entry_op.index; |
| 344 int file_index = GetFileIndexFromStreamIndex(index); |
311 int offset = in_entry_op.offset; | 345 int offset = in_entry_op.offset; |
312 int buf_len = in_entry_op.buf_len; | 346 int buf_len = in_entry_op.buf_len; |
313 int truncate = in_entry_op.truncate; | 347 int truncate = in_entry_op.truncate; |
314 | 348 const int64 file_offset = out_entry_stat->GetOffsetInFile( |
315 bool extending_by_write = offset + buf_len > out_entry_stat->data_size[index]; | 349 key_, in_entry_op.offset, in_entry_op.index); |
| 350 bool extending_by_write = offset + buf_len > out_entry_stat->data_size(index); |
316 if (extending_by_write) { | 351 if (extending_by_write) { |
317 // We are extending the file, and need to insure the EOF record is zeroed. | 352 // The EOF record and the eventual stream afterward need to be zeroed out. |
318 const int64 file_eof_offset = GetFileOffsetFromKeyAndDataOffset( | 353 const int64 file_eof_offset = |
319 key_, out_entry_stat->data_size[index]); | 354 out_entry_stat->GetEOFOffsetInFile(key_, index); |
320 if (!TruncatePlatformFile(files_[index], file_eof_offset)) { | 355 if (!TruncatePlatformFile(files_[file_index], file_eof_offset)) { |
321 RecordWriteResult(cache_type_, WRITE_RESULT_PRETRUNCATE_FAILURE); | 356 RecordWriteResult(cache_type_, WRITE_RESULT_PRETRUNCATE_FAILURE); |
322 Doom(); | 357 Doom(); |
323 *out_result = net::ERR_CACHE_WRITE_FAILURE; | 358 *out_result = net::ERR_CACHE_WRITE_FAILURE; |
324 return; | 359 return; |
325 } | 360 } |
326 } | 361 } |
327 const int64 file_offset = GetFileOffsetFromKeyAndDataOffset(key_, offset); | |
328 if (buf_len > 0) { | 362 if (buf_len > 0) { |
329 if (WritePlatformFile( | 363 if (WritePlatformFile( |
330 files_[index], file_offset, in_buf->data(), buf_len) != buf_len) { | 364 files_[file_index], file_offset, in_buf->data(), buf_len) != |
| 365 buf_len) { |
331 RecordWriteResult(cache_type_, WRITE_RESULT_WRITE_FAILURE); | 366 RecordWriteResult(cache_type_, WRITE_RESULT_WRITE_FAILURE); |
332 Doom(); | 367 Doom(); |
333 *out_result = net::ERR_CACHE_WRITE_FAILURE; | 368 *out_result = net::ERR_CACHE_WRITE_FAILURE; |
334 return; | 369 return; |
335 } | 370 } |
336 } | 371 } |
337 if (!truncate && (buf_len > 0 || !extending_by_write)) { | 372 if (!truncate && (buf_len > 0 || !extending_by_write)) { |
338 out_entry_stat->data_size[index] = | 373 out_entry_stat->set_data_size( |
339 std::max(out_entry_stat->data_size[index], offset + buf_len); | 374 index, std::max(out_entry_stat->data_size(index), offset + buf_len)); |
340 } else { | 375 } else { |
341 if (!TruncatePlatformFile(files_[index], file_offset + buf_len)) { | 376 out_entry_stat->set_data_size(index, offset + buf_len); |
| 377 int file_eof_offset = out_entry_stat->GetLastEOFOffsetInFile(key_, index); |
| 378 if (!TruncatePlatformFile(files_[file_index], file_eof_offset)) { |
342 RecordWriteResult(cache_type_, WRITE_RESULT_TRUNCATE_FAILURE); | 379 RecordWriteResult(cache_type_, WRITE_RESULT_TRUNCATE_FAILURE); |
343 Doom(); | 380 Doom(); |
344 *out_result = net::ERR_CACHE_WRITE_FAILURE; | 381 *out_result = net::ERR_CACHE_WRITE_FAILURE; |
345 return; | 382 return; |
346 } | 383 } |
347 out_entry_stat->data_size[index] = offset + buf_len; | |
348 } | 384 } |
349 | 385 |
350 RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS); | 386 RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS); |
351 out_entry_stat->last_used = out_entry_stat->last_modified = Time::Now(); | 387 base::Time modification_time = Time::Now(); |
| 388 out_entry_stat->set_last_used(modification_time); |
| 389 out_entry_stat->set_last_modified(modification_time); |
352 *out_result = buf_len; | 390 *out_result = buf_len; |
353 } | 391 } |
354 | 392 |
355 void SimpleSynchronousEntry::CheckEOFRecord(int index, | 393 void SimpleSynchronousEntry::CheckEOFRecord(int index, |
356 int32 data_size, | 394 const SimpleEntryStat& entry_stat, |
357 uint32 expected_crc32, | 395 uint32 expected_crc32, |
358 int* out_result) const { | 396 int* out_result) const { |
359 DCHECK(initialized_); | 397 DCHECK(initialized_); |
360 | 398 uint32 crc32; |
361 SimpleFileEOF eof_record; | 399 bool has_crc32; |
362 int64 file_offset = GetFileOffsetFromKeyAndDataOffset(key_, data_size); | 400 int stream_size; |
363 if (ReadPlatformFile(files_[index], | 401 *out_result = |
364 file_offset, | 402 GetEOFRecordData(index, entry_stat, &has_crc32, &crc32, &stream_size); |
365 reinterpret_cast<char*>(&eof_record), | 403 if (*out_result != net::OK) { |
366 sizeof(eof_record)) != sizeof(eof_record)) { | |
367 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE); | |
368 Doom(); | 404 Doom(); |
369 *out_result = net::ERR_CACHE_CHECKSUM_READ_FAILURE; | |
370 return; | 405 return; |
371 } | 406 } |
372 | 407 if (has_crc32 && crc32 != expected_crc32) { |
373 if (eof_record.final_magic_number != kSimpleFinalMagicNumber) { | 408 DLOG(INFO) << "EOF record had bad crc."; |
374 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH); | 409 *out_result = net::ERR_CACHE_CHECKSUM_MISMATCH; |
375 DLOG(INFO) << "eof record had bad magic number."; | 410 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); |
376 Doom(); | 411 Doom(); |
377 *out_result = net::ERR_CACHE_CHECKSUM_READ_FAILURE; | |
378 return; | 412 return; |
379 } | 413 } |
380 | |
381 const bool has_crc = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) == | |
382 SimpleFileEOF::FLAG_HAS_CRC32; | |
383 SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, has_crc); | |
384 if (has_crc && eof_record.data_crc32 != expected_crc32) { | |
385 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); | |
386 DLOG(INFO) << "eof record had bad crc."; | |
387 Doom(); | |
388 *out_result = net::ERR_CACHE_CHECKSUM_MISMATCH; | |
389 return; | |
390 } | |
391 | |
392 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); | 414 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); |
393 *out_result = net::OK; | |
394 } | 415 } |
395 | 416 |
396 void SimpleSynchronousEntry::Close( | 417 void SimpleSynchronousEntry::Close( |
397 const SimpleEntryStat& entry_stat, | 418 const SimpleEntryStat& entry_stat, |
398 scoped_ptr<std::vector<CRCRecord> > crc32s_to_write) { | 419 scoped_ptr<std::vector<CRCRecord> > crc32s_to_write, |
| 420 net::GrowableIOBuffer* stream_0_data) { |
| 421 DCHECK(stream_0_data); |
| 422 // Write stream 0 data. |
| 423 int stream_0_offset = entry_stat.GetOffsetInFile(key_, 0, 0); |
| 424 if (WritePlatformFile(files_[0], |
| 425 stream_0_offset, |
| 426 stream_0_data->data(), |
| 427 entry_stat.data_size(0)) != entry_stat.data_size(0)) { |
| 428 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); |
| 429 DLOG(INFO) << "Could not write stream 0 data."; |
| 430 Doom(); |
| 431 } |
| 432 |
399 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin(); | 433 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin(); |
400 it != crc32s_to_write->end(); ++it) { | 434 it != crc32s_to_write->end(); ++it) { |
401 SimpleFileEOF eof_record; | 435 SimpleFileEOF eof_record; |
| 436 int index = it->index; |
| 437 eof_record.stream_size = entry_stat.data_size(index); |
402 eof_record.final_magic_number = kSimpleFinalMagicNumber; | 438 eof_record.final_magic_number = kSimpleFinalMagicNumber; |
403 eof_record.flags = 0; | 439 eof_record.flags = 0; |
404 if (it->has_crc32) | 440 if (it->has_crc32) |
405 eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32; | 441 eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32; |
406 eof_record.data_crc32 = it->data_crc32; | 442 eof_record.data_crc32 = it->data_crc32; |
407 int64 file_offset = GetFileOffsetFromKeyAndDataOffset( | 443 int file_index = GetFileIndexFromStreamIndex(index); |
408 key_, entry_stat.data_size[it->index]); | 444 int eof_offset = entry_stat.GetEOFOffsetInFile(key_, index); |
409 if (WritePlatformFile(files_[it->index], | 445 // If stream 0 changed size, the file needs to be resized, otherwise the |
410 file_offset, | 446 // next open will yield wrong stream sizes. On stream 1 and stream 2 proper |
| 447 // resizing of the file is handled in SimpleSynchronousEntry::WriteData(). |
| 448 if (index == 0 && !TruncatePlatformFile(files_[file_index], eof_offset)) { |
| 449 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); |
| 450 DLOG(INFO) << "Could not truncate stream 0 file."; |
| 451 Doom(); |
| 452 break; |
| 453 } |
| 454 if (WritePlatformFile(files_[file_index], |
| 455 eof_offset, |
411 reinterpret_cast<const char*>(&eof_record), | 456 reinterpret_cast<const char*>(&eof_record), |
412 sizeof(eof_record)) != sizeof(eof_record)) { | 457 sizeof(eof_record)) != sizeof(eof_record)) { |
413 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); | 458 RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE); |
414 DLOG(INFO) << "Could not write eof record."; | 459 DLOG(INFO) << "Could not write eof record."; |
415 Doom(); | 460 Doom(); |
416 break; | 461 break; |
417 } | 462 } |
418 const int64 file_size = file_offset + sizeof(eof_record); | 463 } |
| 464 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
| 465 bool did_close_file = ClosePlatformFile(files_[i]); |
| 466 DCHECK(did_close_file); |
| 467 const int64 file_size = entry_stat.GetFileSize(key_, i); |
419 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, | 468 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, |
420 "LastClusterSize", cache_type_, | 469 "LastClusterSize", cache_type_, |
421 file_size % 4096, 0, 4097, 50); | 470 file_size % 4096, 0, 4097, 50); |
422 const int64 cluster_loss = file_size % 4096 ? 4096 - file_size % 4096 : 0; | 471 const int64 cluster_loss = file_size % 4096 ? 4096 - file_size % 4096 : 0; |
423 SIMPLE_CACHE_UMA(PERCENTAGE, | 472 SIMPLE_CACHE_UMA(PERCENTAGE, |
424 "LastClusterLossPercent", cache_type_, | 473 "LastClusterLossPercent", cache_type_, |
425 cluster_loss * 100 / (cluster_loss + file_size)); | 474 cluster_loss * 100 / (cluster_loss + file_size)); |
426 } | 475 } |
427 | |
428 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | |
429 bool did_close_file = ClosePlatformFile(files_[i]); | |
430 CHECK(did_close_file); | |
431 } | |
432 RecordCloseResult(cache_type_, CLOSE_RESULT_SUCCESS); | 476 RecordCloseResult(cache_type_, CLOSE_RESULT_SUCCESS); |
433 have_open_files_ = false; | 477 have_open_files_ = false; |
434 delete this; | 478 delete this; |
435 } | 479 } |
436 | 480 |
437 SimpleSynchronousEntry::SimpleSynchronousEntry(net::CacheType cache_type, | 481 SimpleSynchronousEntry::SimpleSynchronousEntry(net::CacheType cache_type, |
438 const FilePath& path, | 482 const FilePath& path, |
439 const std::string& key, | 483 const std::string& key, |
440 const uint64 entry_hash) | 484 const uint64 entry_hash) |
441 : cache_type_(cache_type), | 485 : cache_type_(cache_type), |
(...skipping 11 matching lines...) Expand all Loading... |
453 DCHECK(!(have_open_files_ && initialized_)); | 497 DCHECK(!(have_open_files_ && initialized_)); |
454 if (have_open_files_) | 498 if (have_open_files_) |
455 CloseFiles(); | 499 CloseFiles(); |
456 } | 500 } |
457 | 501 |
458 bool SimpleSynchronousEntry::OpenOrCreateFiles( | 502 bool SimpleSynchronousEntry::OpenOrCreateFiles( |
459 bool create, | 503 bool create, |
460 bool had_index, | 504 bool had_index, |
461 SimpleEntryStat* out_entry_stat) { | 505 SimpleEntryStat* out_entry_stat) { |
462 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 506 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
463 FilePath filename = path_.AppendASCII( | 507 FilePath filename = |
464 GetFilenameFromEntryHashAndIndex(entry_hash_, i)); | 508 path_.AppendASCII(GetFilenameFromEntryHashAndFileIndex(entry_hash_, i)); |
465 int flags = PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; | 509 int flags = PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; |
466 if (create) | 510 if (create) |
467 flags |= PLATFORM_FILE_CREATE; | 511 flags |= PLATFORM_FILE_CREATE; |
468 else | 512 else |
469 flags |= PLATFORM_FILE_OPEN; | 513 flags |= PLATFORM_FILE_OPEN; |
470 PlatformFileError error; | 514 PlatformFileError error; |
471 files_[i] = CreatePlatformFile(filename, flags, NULL, &error); | 515 files_[i] = CreatePlatformFile(filename, flags, NULL, &error); |
472 if (error != PLATFORM_FILE_OK) { | 516 if (error != PLATFORM_FILE_OK) { |
473 // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms. | 517 // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms. |
474 // We can calculate the third as the sum or difference of the other two. | 518 // We can calculate the third as the sum or difference of the other two. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 bool ALLOW_UNUSED did_close = ClosePlatformFile(files_[i]); | 553 bool ALLOW_UNUSED did_close = ClosePlatformFile(files_[i]); |
510 DLOG_IF(INFO, !did_close) << "Could not close file " | 554 DLOG_IF(INFO, !did_close) << "Could not close file " |
511 << filename.MaybeAsASCII(); | 555 << filename.MaybeAsASCII(); |
512 } | 556 } |
513 return false; | 557 return false; |
514 } | 558 } |
515 } | 559 } |
516 | 560 |
517 have_open_files_ = true; | 561 have_open_files_ = true; |
518 if (create) { | 562 if (create) { |
519 out_entry_stat->last_modified = out_entry_stat->last_used = Time::Now(); | 563 base::Time creation_time = Time::Now(); |
520 for (int i = 0; i < kSimpleEntryFileCount; ++i) | 564 out_entry_stat->set_last_modified(creation_time); |
521 out_entry_stat->data_size[i] = 0; | 565 out_entry_stat->set_last_used(creation_time); |
| 566 for (int i = 0; i < kSimpleEntryStreamCount; ++i) |
| 567 out_entry_stat->set_data_size(i, 0); |
522 } else { | 568 } else { |
523 base::TimeDelta entry_age = base::Time::Now() - base::Time::UnixEpoch(); | 569 base::TimeDelta entry_age = base::Time::Now() - base::Time::UnixEpoch(); |
524 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 570 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
525 PlatformFileInfo file_info; | 571 PlatformFileInfo file_info; |
526 bool success = GetPlatformFileInfo(files_[i], &file_info); | 572 bool success = GetPlatformFileInfo(files_[i], &file_info); |
527 base::Time file_last_modified; | 573 base::Time file_last_modified; |
528 if (!success) { | 574 if (!success) { |
529 DLOG(WARNING) << "Could not get platform file info."; | 575 DLOG(WARNING) << "Could not get platform file info."; |
530 continue; | 576 continue; |
531 } | 577 } |
532 out_entry_stat->last_used = file_info.last_accessed; | 578 out_entry_stat->set_last_used(file_info.last_accessed); |
533 if (simple_util::GetMTime(path_, &file_last_modified)) | 579 if (simple_util::GetMTime(path_, &file_last_modified)) |
534 out_entry_stat->last_modified = file_last_modified; | 580 out_entry_stat->set_last_modified(file_last_modified); |
535 else | 581 else |
536 out_entry_stat->last_modified = file_info.last_modified; | 582 out_entry_stat->set_last_modified(file_info.last_modified); |
537 | 583 |
538 base::TimeDelta stream_age = | 584 base::TimeDelta stream_age = |
539 base::Time::Now() - out_entry_stat->last_modified; | 585 base::Time::Now() - out_entry_stat->last_modified(); |
540 if (stream_age < entry_age) | 586 if (stream_age < entry_age) |
541 entry_age = stream_age; | 587 entry_age = stream_age; |
542 | 588 |
543 // Keep the file size in |data size_| briefly until the key is initialized | 589 // Two things prevent from knowing the right values for |data_size|: |
544 // properly. | 590 // 1) The key is not known, hence its length is unknown. |
545 out_entry_stat->data_size[i] = file_info.size; | 591 // 2) Stream 0 and stream 1 are in the same file, and the exact size for |
| 592 // each will only be known when reading the EOF record for stream 0. |
| 593 // |
| 594 // The size for file 0 and 1 is temporarily kept in |
| 595 // |data_size(1)| and |data_size(2)| respectively. Reading the key in |
| 596 // InitializeForOpen yields the data size for each file. In the case of |
| 597 // file hash_1, this is the total size of stream 2, and is assigned to |
| 598 // data_size(2). In the case of file 0, it is the combined size of stream |
| 599 // 0, stream 1 and one EOF record. The exact distribution of sizes between |
| 600 // stream 1 and stream 0 is only determined after reading the EOF record |
| 601 // for stream 0 in ReadAndValidateStream0. |
| 602 out_entry_stat->set_data_size(i + 1, file_info.size); |
546 } | 603 } |
547 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, | 604 SIMPLE_CACHE_UMA(CUSTOM_COUNTS, |
548 "SyncOpenEntryAge", cache_type_, | 605 "SyncOpenEntryAge", cache_type_, |
549 entry_age.InHours(), 1, 1000, 50); | 606 entry_age.InHours(), 1, 1000, 50); |
550 } | 607 } |
551 | 608 |
552 return true; | 609 return true; |
553 } | 610 } |
554 | 611 |
555 void SimpleSynchronousEntry::CloseFiles() { | 612 void SimpleSynchronousEntry::CloseFiles() { |
556 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 613 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
557 DCHECK_NE(kInvalidPlatformFileValue, files_[i]); | 614 DCHECK_NE(kInvalidPlatformFileValue, files_[i]); |
558 bool did_close = ClosePlatformFile(files_[i]); | 615 bool did_close = ClosePlatformFile(files_[i]); |
559 DCHECK(did_close); | 616 DCHECK(did_close); |
560 } | 617 } |
561 } | 618 } |
562 | 619 |
563 int SimpleSynchronousEntry::InitializeForOpen(bool had_index, | 620 int SimpleSynchronousEntry::InitializeForOpen( |
564 SimpleEntryStat* out_entry_stat) { | 621 bool had_index, |
| 622 SimpleEntryStat* out_entry_stat, |
| 623 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
| 624 uint32* out_stream_0_crc32) { |
565 DCHECK(!initialized_); | 625 DCHECK(!initialized_); |
566 if (!OpenOrCreateFiles(false, had_index, out_entry_stat)) | 626 if (!OpenOrCreateFiles(false, had_index, out_entry_stat)) |
567 return net::ERR_FAILED; | 627 return net::ERR_FAILED; |
568 | |
569 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 628 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
570 SimpleFileHeader header; | 629 SimpleFileHeader header; |
571 int header_read_result = | 630 int header_read_result = |
572 ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), | 631 ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), |
573 sizeof(header)); | 632 sizeof(header)); |
574 if (header_read_result != sizeof(header)) { | 633 if (header_read_result != sizeof(header)) { |
575 DLOG(WARNING) << "Cannot read header from entry."; | 634 DLOG(WARNING) << "Cannot read header from entry."; |
576 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER, had_index); | 635 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER, had_index); |
577 return net::ERR_FAILED; | 636 return net::ERR_FAILED; |
578 } | 637 } |
(...skipping 16 matching lines...) Expand all Loading... |
595 scoped_ptr<char[]> key(new char[header.key_length]); | 654 scoped_ptr<char[]> key(new char[header.key_length]); |
596 int key_read_result = ReadPlatformFile(files_[i], sizeof(header), | 655 int key_read_result = ReadPlatformFile(files_[i], sizeof(header), |
597 key.get(), header.key_length); | 656 key.get(), header.key_length); |
598 if (key_read_result != implicit_cast<int>(header.key_length)) { | 657 if (key_read_result != implicit_cast<int>(header.key_length)) { |
599 DLOG(WARNING) << "Cannot read key from entry."; | 658 DLOG(WARNING) << "Cannot read key from entry."; |
600 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY, had_index); | 659 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY, had_index); |
601 return net::ERR_FAILED; | 660 return net::ERR_FAILED; |
602 } | 661 } |
603 | 662 |
604 key_ = std::string(key.get(), header.key_length); | 663 key_ = std::string(key.get(), header.key_length); |
605 out_entry_stat->data_size[i] = | 664 if (i == 0) { |
606 GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size[i]); | 665 // File size for stream 0 has been stored temporarily in data_size[1]. |
607 if (out_entry_stat->data_size[i] < 0) { | 666 int total_data_size = |
608 // This entry can't possibly be valid, as it does not have enough space to | 667 GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(1)); |
609 // store a valid SimpleFileEOF record. | 668 int ret_value_stream_0 = ReadAndValidateStream0( |
610 return net::ERR_FAILED; | 669 total_data_size, out_entry_stat, stream_0_data, out_stream_0_crc32); |
| 670 if (ret_value_stream_0 != net::OK) |
| 671 return ret_value_stream_0; |
| 672 } else { |
| 673 out_entry_stat->set_data_size( |
| 674 2, GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(2))); |
| 675 if (out_entry_stat->data_size(2) < 0) |
| 676 return net::ERR_FAILED; |
611 } | 677 } |
612 | 678 |
613 if (base::Hash(key.get(), header.key_length) != header.key_hash) { | 679 if (base::Hash(key.get(), header.key_length) != header.key_hash) { |
614 DLOG(WARNING) << "Hash mismatch on key."; | 680 DLOG(WARNING) << "Hash mismatch on key."; |
615 RecordSyncOpenResult( | 681 RecordSyncOpenResult( |
616 cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH, had_index); | 682 cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH, had_index); |
617 return net::ERR_FAILED; | 683 return net::ERR_FAILED; |
618 } | 684 } |
619 } | 685 } |
620 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS, had_index); | 686 RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS, had_index); |
(...skipping 10 matching lines...) Expand all Loading... |
631 return net::ERR_FILE_EXISTS; | 697 return net::ERR_FILE_EXISTS; |
632 } | 698 } |
633 for (int i = 0; i < kSimpleEntryFileCount; ++i) { | 699 for (int i = 0; i < kSimpleEntryFileCount; ++i) { |
634 SimpleFileHeader header; | 700 SimpleFileHeader header; |
635 header.initial_magic_number = kSimpleInitialMagicNumber; | 701 header.initial_magic_number = kSimpleInitialMagicNumber; |
636 header.version = kSimpleVersion; | 702 header.version = kSimpleVersion; |
637 | 703 |
638 header.key_length = key_.size(); | 704 header.key_length = key_.size(); |
639 header.key_hash = base::Hash(key_); | 705 header.key_hash = base::Hash(key_); |
640 | 706 |
641 if (WritePlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), | 707 if (WritePlatformFile( |
642 sizeof(header)) != sizeof(header)) { | 708 files_[i], 0, reinterpret_cast<char*>(&header), sizeof(header)) != |
643 DLOG(WARNING) << "Could not write headers to new cache entry."; | 709 sizeof(header)) { |
| 710 DLOG(WARNING) << "Could not write cache file header to cache entry."; |
644 RecordSyncCreateResult( | 711 RecordSyncCreateResult( |
645 cache_type_, CREATE_ENTRY_CANT_WRITE_HEADER, had_index); | 712 cache_type_, CREATE_ENTRY_CANT_WRITE_HEADER, had_index); |
646 return net::ERR_FAILED; | 713 return net::ERR_FAILED; |
647 } | 714 } |
648 | 715 |
649 if (WritePlatformFile(files_[i], sizeof(header), key_.data(), | 716 if (WritePlatformFile( |
650 key_.size()) != implicit_cast<int>(key_.size())) { | 717 files_[i], sizeof(SimpleFileHeader), key_.data(), key_.size()) != |
| 718 implicit_cast<int>(key_.size())) { |
651 DLOG(WARNING) << "Could not write keys to new cache entry."; | 719 DLOG(WARNING) << "Could not write keys to new cache entry."; |
652 RecordSyncCreateResult( | 720 RecordSyncCreateResult( |
653 cache_type_, CREATE_ENTRY_CANT_WRITE_KEY, had_index); | 721 cache_type_, CREATE_ENTRY_CANT_WRITE_KEY, had_index); |
654 return net::ERR_FAILED; | 722 return net::ERR_FAILED; |
655 } | 723 } |
656 } | 724 } |
657 RecordSyncCreateResult(cache_type_, CREATE_ENTRY_SUCCESS, had_index); | 725 RecordSyncCreateResult(cache_type_, CREATE_ENTRY_SUCCESS, had_index); |
658 initialized_ = true; | 726 initialized_ = true; |
659 return net::OK; | 727 return net::OK; |
660 } | 728 } |
661 | 729 |
| 730 int SimpleSynchronousEntry::ReadAndValidateStream0( |
| 731 int total_data_size, |
| 732 SimpleEntryStat* out_entry_stat, |
| 733 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, |
| 734 uint32* out_stream_0_crc32) const { |
| 735 // Temporarily assign all the data size to stream 1 in order to read the |
| 736 // EOF record for stream 0, which contains the size of stream 0. |
| 737 out_entry_stat->set_data_size(0, 0); |
| 738 out_entry_stat->set_data_size(1, total_data_size - sizeof(SimpleFileEOF)); |
| 739 |
| 740 bool has_crc32; |
| 741 uint32 read_crc32; |
| 742 int stream_0_size; |
| 743 int ret_value_crc32 = GetEOFRecordData( |
| 744 0, *out_entry_stat, &has_crc32, &read_crc32, &stream_0_size); |
| 745 if (ret_value_crc32 != net::OK) |
| 746 return ret_value_crc32; |
| 747 |
| 748 if (stream_0_size > out_entry_stat->data_size(1)) |
| 749 return net::ERR_FAILED; |
| 750 |
| 751 // These are the real values of data size. |
| 752 out_entry_stat->set_data_size(0, stream_0_size); |
| 753 out_entry_stat->set_data_size( |
| 754 1, out_entry_stat->data_size(1) - stream_0_size); |
| 755 |
| 756 // Put stream 0 data in memory. |
| 757 *stream_0_data = new net::GrowableIOBuffer(); |
| 758 (*stream_0_data)->SetCapacity(stream_0_size); |
| 759 int file_offset = out_entry_stat->GetOffsetInFile(key_, 0, 0); |
| 760 int bytes_read = ReadPlatformFile( |
| 761 files_[0], file_offset, (*stream_0_data)->data(), stream_0_size); |
| 762 if (bytes_read != stream_0_size) |
| 763 return net::ERR_FAILED; |
| 764 |
| 765 // Check the CRC32. |
| 766 uint32 expected_crc32 = |
| 767 stream_0_size == 0 |
| 768 ? crc32(0, Z_NULL, 0) |
| 769 : crc32(crc32(0, Z_NULL, 0), |
| 770 reinterpret_cast<const Bytef*>((*stream_0_data)->data()), |
| 771 stream_0_size); |
| 772 if (has_crc32 && read_crc32 != expected_crc32) { |
| 773 DLOG(INFO) << "EOF record had bad crc."; |
| 774 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); |
| 775 return net::ERR_FAILED; |
| 776 } |
| 777 *out_stream_0_crc32 = read_crc32; |
| 778 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); |
| 779 return net::OK; |
| 780 } |
| 781 |
| 782 int SimpleSynchronousEntry::GetEOFRecordData(int index, |
| 783 const SimpleEntryStat& entry_stat, |
| 784 bool* out_has_crc32, |
| 785 uint32* out_crc32, |
| 786 int* out_data_size) const { |
| 787 SimpleFileEOF eof_record; |
| 788 int file_offset = entry_stat.GetEOFOffsetInFile(key_, index); |
| 789 int file_index = GetFileIndexFromStreamIndex(index); |
| 790 if (ReadPlatformFile(files_[file_index], |
| 791 file_offset, |
| 792 reinterpret_cast<char*>(&eof_record), |
| 793 sizeof(eof_record)) != sizeof(eof_record)) { |
| 794 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE); |
| 795 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; |
| 796 } |
| 797 |
| 798 if (eof_record.final_magic_number != kSimpleFinalMagicNumber) { |
| 799 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH); |
| 800 DLOG(INFO) << "EOF record had bad magic number."; |
| 801 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; |
| 802 } |
| 803 |
| 804 *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) == |
| 805 SimpleFileEOF::FLAG_HAS_CRC32; |
| 806 *out_crc32 = eof_record.data_crc32; |
| 807 *out_data_size = eof_record.stream_size; |
| 808 SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32); |
| 809 return net::OK; |
| 810 } |
| 811 |
662 void SimpleSynchronousEntry::Doom() const { | 812 void SimpleSynchronousEntry::Doom() const { |
663 // TODO(gavinp): Consider if we should guard against redundant Doom() calls. | 813 // TODO(gavinp): Consider if we should guard against redundant Doom() calls. |
664 DeleteFilesForEntryHash(path_, entry_hash_); | 814 DeleteFilesForEntryHash(path_, entry_hash_); |
665 } | 815 } |
666 | 816 |
667 } // namespace disk_cache | 817 } // namespace disk_cache |
OLD | NEW |