| Index: net/disk_cache/simple/simple_synchronous_entry.cc
|
| diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
|
| deleted file mode 100644
|
| index f85910550ee2e3836d01e07d0df001b1d2c9928b..0000000000000000000000000000000000000000
|
| --- a/net/disk_cache/simple/simple_synchronous_entry.cc
|
| +++ /dev/null
|
| @@ -1,1436 +0,0 @@
|
| -// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/disk_cache/simple/simple_synchronous_entry.h"
|
| -
|
| -#include <algorithm>
|
| -#include <cstring>
|
| -#include <functional>
|
| -#include <limits>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/hash.h"
|
| -#include "base/location.h"
|
| -#include "base/numerics/safe_conversions.h"
|
| -#include "base/sha1.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/disk_cache/simple/simple_backend_version.h"
|
| -#include "net/disk_cache/simple/simple_histogram_macros.h"
|
| -#include "net/disk_cache/simple/simple_util.h"
|
| -#include "third_party/zlib/zlib.h"
|
| -
|
| -using base::File;
|
| -using base::FilePath;
|
| -using base::Time;
|
| -
|
| -namespace {
|
| -
|
| -// Used in histograms, please only add entries at the end.
|
| -enum OpenEntryResult {
|
| - OPEN_ENTRY_SUCCESS = 0,
|
| - OPEN_ENTRY_PLATFORM_FILE_ERROR = 1,
|
| - OPEN_ENTRY_CANT_READ_HEADER = 2,
|
| - OPEN_ENTRY_BAD_MAGIC_NUMBER = 3,
|
| - OPEN_ENTRY_BAD_VERSION = 4,
|
| - OPEN_ENTRY_CANT_READ_KEY = 5,
|
| - // OPEN_ENTRY_KEY_MISMATCH = 6, Deprecated.
|
| - OPEN_ENTRY_KEY_HASH_MISMATCH = 7,
|
| - OPEN_ENTRY_SPARSE_OPEN_FAILED = 8,
|
| - OPEN_ENTRY_MAX = 9,
|
| -};
|
| -
|
| -// Used in histograms, please only add entries at the end.
|
| -enum WriteResult {
|
| - WRITE_RESULT_SUCCESS = 0,
|
| - WRITE_RESULT_PRETRUNCATE_FAILURE,
|
| - WRITE_RESULT_WRITE_FAILURE,
|
| - WRITE_RESULT_TRUNCATE_FAILURE,
|
| - WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED,
|
| - WRITE_RESULT_LAZY_CREATE_FAILURE,
|
| - WRITE_RESULT_LAZY_INITIALIZE_FAILURE,
|
| - WRITE_RESULT_MAX,
|
| -};
|
| -
|
| -// Used in histograms, please only add entries at the end.
|
| -enum CheckEOFResult {
|
| - CHECK_EOF_RESULT_SUCCESS,
|
| - CHECK_EOF_RESULT_READ_FAILURE,
|
| - CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH,
|
| - CHECK_EOF_RESULT_CRC_MISMATCH,
|
| - CHECK_EOF_RESULT_MAX,
|
| -};
|
| -
|
| -// Used in histograms, please only add entries at the end.
|
| -enum CloseResult {
|
| - CLOSE_RESULT_SUCCESS,
|
| - CLOSE_RESULT_WRITE_FAILURE,
|
| -};
|
| -
|
| -void RecordSyncOpenResult(net::CacheType cache_type,
|
| - OpenEntryResult result,
|
| - bool had_index) {
|
| - DCHECK_LT(result, OPEN_ENTRY_MAX);
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenResult", cache_type, result, OPEN_ENTRY_MAX);
|
| - if (had_index) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenResult_WithIndex", cache_type,
|
| - result, OPEN_ENTRY_MAX);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenResult_WithoutIndex", cache_type,
|
| - result, OPEN_ENTRY_MAX);
|
| - }
|
| -}
|
| -
|
| -void RecordWriteResult(net::CacheType cache_type, WriteResult result) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncWriteResult", cache_type, result, WRITE_RESULT_MAX);
|
| -}
|
| -
|
| -void RecordCheckEOFResult(net::CacheType cache_type, CheckEOFResult result) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCheckEOFResult", cache_type,
|
| - result, CHECK_EOF_RESULT_MAX);
|
| -}
|
| -
|
| -void RecordCloseResult(net::CacheType cache_type, CloseResult result) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCloseResult", cache_type, result, WRITE_RESULT_MAX);
|
| -}
|
| -
|
| -bool CanOmitEmptyFile(int file_index) {
|
| - DCHECK_GE(file_index, 0);
|
| - DCHECK_LT(file_index, disk_cache::kSimpleEntryFileCount);
|
| - return file_index == disk_cache::simple_util::GetFileIndexFromStreamIndex(2);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace disk_cache {
|
| -
|
| -using simple_util::GetEntryHashKey;
|
| -using simple_util::GetFilenameFromEntryHashAndFileIndex;
|
| -using simple_util::GetSparseFilenameFromEntryHash;
|
| -using simple_util::GetDataSizeFromKeyAndFileSize;
|
| -using simple_util::GetFileSizeFromKeyAndDataSize;
|
| -using simple_util::GetFileIndexFromStreamIndex;
|
| -
|
| -SimpleEntryStat::SimpleEntryStat(base::Time last_used,
|
| - base::Time last_modified,
|
| - const int32 data_size[],
|
| - const int32 sparse_data_size)
|
| - : last_used_(last_used),
|
| - last_modified_(last_modified),
|
| - sparse_data_size_(sparse_data_size) {
|
| - memcpy(data_size_, data_size, sizeof(data_size_));
|
| -}
|
| -
|
| -int SimpleEntryStat::GetOffsetInFile(const std::string& key,
|
| - int offset,
|
| - int stream_index) const {
|
| - const size_t headers_size = sizeof(SimpleFileHeader) + key.size();
|
| - const size_t additional_offset =
|
| - stream_index == 0 ? data_size_[1] + sizeof(SimpleFileEOF) : 0;
|
| - return headers_size + offset + additional_offset;
|
| -}
|
| -
|
| -int SimpleEntryStat::GetEOFOffsetInFile(const std::string& key,
|
| - int stream_index) const {
|
| - return GetOffsetInFile(key, data_size_[stream_index], stream_index);
|
| -}
|
| -
|
| -int SimpleEntryStat::GetLastEOFOffsetInFile(const std::string& key,
|
| - int stream_index) const {
|
| - const int file_index = GetFileIndexFromStreamIndex(stream_index);
|
| - const int eof_data_offset =
|
| - file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF)
|
| - : data_size_[2];
|
| - return GetOffsetInFile(key, eof_data_offset, stream_index);
|
| -}
|
| -
|
| -int64 SimpleEntryStat::GetFileSize(const std::string& key,
|
| - int file_index) const {
|
| - const int32 total_data_size =
|
| - file_index == 0 ? data_size_[0] + data_size_[1] + sizeof(SimpleFileEOF)
|
| - : data_size_[2];
|
| - return GetFileSizeFromKeyAndDataSize(key, total_data_size);
|
| -}
|
| -
|
| -SimpleEntryCreationResults::SimpleEntryCreationResults(
|
| - SimpleEntryStat entry_stat)
|
| - : sync_entry(NULL),
|
| - entry_stat(entry_stat),
|
| - stream_0_crc32(crc32(0, Z_NULL, 0)),
|
| - result(net::OK) {
|
| -}
|
| -
|
| -SimpleEntryCreationResults::~SimpleEntryCreationResults() {
|
| -}
|
| -
|
| -SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1),
|
| - has_crc32(false),
|
| - data_crc32(0) {
|
| -}
|
| -
|
| -SimpleSynchronousEntry::CRCRecord::CRCRecord(int index_p,
|
| - bool has_crc32_p,
|
| - uint32 data_crc32_p)
|
| - : index(index_p),
|
| - has_crc32(has_crc32_p),
|
| - data_crc32(data_crc32_p) {}
|
| -
|
| -SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p,
|
| - int offset_p,
|
| - int buf_len_p)
|
| - : index(index_p),
|
| - offset(offset_p),
|
| - buf_len(buf_len_p) {}
|
| -
|
| -SimpleSynchronousEntry::EntryOperationData::EntryOperationData(int index_p,
|
| - int offset_p,
|
| - int buf_len_p,
|
| - bool truncate_p,
|
| - bool doomed_p)
|
| - : index(index_p),
|
| - offset(offset_p),
|
| - buf_len(buf_len_p),
|
| - truncate(truncate_p),
|
| - doomed(doomed_p) {}
|
| -
|
| -SimpleSynchronousEntry::EntryOperationData::EntryOperationData(
|
| - int64 sparse_offset_p,
|
| - int buf_len_p)
|
| - : sparse_offset(sparse_offset_p),
|
| - buf_len(buf_len_p) {}
|
| -
|
| -// static
|
| -void SimpleSynchronousEntry::OpenEntry(
|
| - net::CacheType cache_type,
|
| - const FilePath& path,
|
| - const uint64 entry_hash,
|
| - bool had_index,
|
| - SimpleEntryCreationResults *out_results) {
|
| - SimpleSynchronousEntry* sync_entry =
|
| - new SimpleSynchronousEntry(cache_type, path, "", entry_hash);
|
| - out_results->result =
|
| - sync_entry->InitializeForOpen(had_index,
|
| - &out_results->entry_stat,
|
| - &out_results->stream_0_data,
|
| - &out_results->stream_0_crc32);
|
| - if (out_results->result != net::OK) {
|
| - sync_entry->Doom();
|
| - delete sync_entry;
|
| - out_results->sync_entry = NULL;
|
| - out_results->stream_0_data = NULL;
|
| - return;
|
| - }
|
| - out_results->sync_entry = sync_entry;
|
| -}
|
| -
|
| -// static
|
| -void SimpleSynchronousEntry::CreateEntry(
|
| - net::CacheType cache_type,
|
| - const FilePath& path,
|
| - const std::string& key,
|
| - const uint64 entry_hash,
|
| - bool had_index,
|
| - SimpleEntryCreationResults *out_results) {
|
| - DCHECK_EQ(entry_hash, GetEntryHashKey(key));
|
| - SimpleSynchronousEntry* sync_entry =
|
| - new SimpleSynchronousEntry(cache_type, path, key, entry_hash);
|
| - out_results->result = sync_entry->InitializeForCreate(
|
| - had_index, &out_results->entry_stat);
|
| - if (out_results->result != net::OK) {
|
| - if (out_results->result != net::ERR_FILE_EXISTS)
|
| - sync_entry->Doom();
|
| - delete sync_entry;
|
| - out_results->sync_entry = NULL;
|
| - return;
|
| - }
|
| - out_results->sync_entry = sync_entry;
|
| -}
|
| -
|
| -// static
|
| -int SimpleSynchronousEntry::DoomEntry(
|
| - const FilePath& path,
|
| - uint64 entry_hash) {
|
| - const bool deleted_well = DeleteFilesForEntryHash(path, entry_hash);
|
| - return deleted_well ? net::OK : net::ERR_FAILED;
|
| -}
|
| -
|
| -// static
|
| -int SimpleSynchronousEntry::DoomEntrySet(
|
| - const std::vector<uint64>* key_hashes,
|
| - const FilePath& path) {
|
| - const size_t did_delete_count = std::count_if(
|
| - key_hashes->begin(), key_hashes->end(), std::bind1st(
|
| - std::ptr_fun(SimpleSynchronousEntry::DeleteFilesForEntryHash), path));
|
| - return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::ReadData(const EntryOperationData& in_entry_op,
|
| - net::IOBuffer* out_buf,
|
| - uint32* out_crc32,
|
| - SimpleEntryStat* entry_stat,
|
| - int* out_result) const {
|
| - DCHECK(initialized_);
|
| - DCHECK_NE(0, in_entry_op.index);
|
| - const int64 file_offset =
|
| - entry_stat->GetOffsetInFile(key_, in_entry_op.offset, in_entry_op.index);
|
| - int file_index = GetFileIndexFromStreamIndex(in_entry_op.index);
|
| - // Zero-length reads and reads to the empty streams of omitted files should
|
| - // be handled in the SimpleEntryImpl.
|
| - DCHECK_GT(in_entry_op.buf_len, 0);
|
| - DCHECK(!empty_file_omitted_[file_index]);
|
| - File* file = const_cast<File*>(&files_[file_index]);
|
| - int bytes_read =
|
| - file->Read(file_offset, out_buf->data(), in_entry_op.buf_len);
|
| - if (bytes_read > 0) {
|
| - entry_stat->set_last_used(Time::Now());
|
| - *out_crc32 = crc32(crc32(0L, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>(out_buf->data()),
|
| - bytes_read);
|
| - }
|
| - if (bytes_read >= 0) {
|
| - *out_result = bytes_read;
|
| - } else {
|
| - *out_result = net::ERR_CACHE_READ_FAILURE;
|
| - Doom();
|
| - }
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::WriteData(const EntryOperationData& in_entry_op,
|
| - net::IOBuffer* in_buf,
|
| - SimpleEntryStat* out_entry_stat,
|
| - int* out_result) {
|
| - DCHECK(initialized_);
|
| - DCHECK_NE(0, in_entry_op.index);
|
| - int index = in_entry_op.index;
|
| - int file_index = GetFileIndexFromStreamIndex(index);
|
| - int offset = in_entry_op.offset;
|
| - int buf_len = in_entry_op.buf_len;
|
| - bool truncate = in_entry_op.truncate;
|
| - bool doomed = in_entry_op.doomed;
|
| - const int64 file_offset = out_entry_stat->GetOffsetInFile(
|
| - key_, in_entry_op.offset, in_entry_op.index);
|
| - bool extending_by_write = offset + buf_len > out_entry_stat->data_size(index);
|
| -
|
| - if (empty_file_omitted_[file_index]) {
|
| - // Don't create a new file if the entry has been doomed, to avoid it being
|
| - // mixed up with a newly-created entry with the same key.
|
| - if (doomed) {
|
| - DLOG(WARNING) << "Rejecting write to lazily omitted stream "
|
| - << in_entry_op.index << " of doomed cache entry.";
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED);
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - File::Error error;
|
| - if (!MaybeCreateFile(file_index, FILE_REQUIRED, &error)) {
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_CREATE_FAILURE);
|
| - Doom();
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - CreateEntryResult result;
|
| - if (!InitializeCreatedFile(file_index, &result)) {
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_LAZY_INITIALIZE_FAILURE);
|
| - Doom();
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - }
|
| - DCHECK(!empty_file_omitted_[file_index]);
|
| -
|
| - if (extending_by_write) {
|
| - // The EOF record and the eventual stream afterward need to be zeroed out.
|
| - const int64 file_eof_offset =
|
| - out_entry_stat->GetEOFOffsetInFile(key_, index);
|
| - if (!files_[file_index].SetLength(file_eof_offset)) {
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_PRETRUNCATE_FAILURE);
|
| - Doom();
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - }
|
| - if (buf_len > 0) {
|
| - if (files_[file_index].Write(file_offset, in_buf->data(), buf_len) !=
|
| - buf_len) {
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_WRITE_FAILURE);
|
| - Doom();
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - }
|
| - if (!truncate && (buf_len > 0 || !extending_by_write)) {
|
| - out_entry_stat->set_data_size(
|
| - index, std::max(out_entry_stat->data_size(index), offset + buf_len));
|
| - } else {
|
| - out_entry_stat->set_data_size(index, offset + buf_len);
|
| - int file_eof_offset = out_entry_stat->GetLastEOFOffsetInFile(key_, index);
|
| - if (!files_[file_index].SetLength(file_eof_offset)) {
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_TRUNCATE_FAILURE);
|
| - Doom();
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - }
|
| -
|
| - RecordWriteResult(cache_type_, WRITE_RESULT_SUCCESS);
|
| - base::Time modification_time = Time::Now();
|
| - out_entry_stat->set_last_used(modification_time);
|
| - out_entry_stat->set_last_modified(modification_time);
|
| - *out_result = buf_len;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::ReadSparseData(
|
| - const EntryOperationData& in_entry_op,
|
| - net::IOBuffer* out_buf,
|
| - base::Time* out_last_used,
|
| - int* out_result) {
|
| - DCHECK(initialized_);
|
| - int64 offset = in_entry_op.sparse_offset;
|
| - int buf_len = in_entry_op.buf_len;
|
| -
|
| - char* buf = out_buf->data();
|
| - int read_so_far = 0;
|
| -
|
| - // Find the first sparse range at or after the requested offset.
|
| - SparseRangeIterator it = sparse_ranges_.lower_bound(offset);
|
| -
|
| - if (it != sparse_ranges_.begin()) {
|
| - // Hop back one range and read the one overlapping with the start.
|
| - --it;
|
| - SparseRange* found_range = &it->second;
|
| - DCHECK_EQ(it->first, found_range->offset);
|
| - if (found_range->offset + found_range->length > offset) {
|
| - DCHECK_GE(found_range->length, 0);
|
| - DCHECK_LE(found_range->length, kint32max);
|
| - DCHECK_GE(offset - found_range->offset, 0);
|
| - DCHECK_LE(offset - found_range->offset, kint32max);
|
| - int net_offset = static_cast<int>(offset - found_range->offset);
|
| - int range_len_after_offset =
|
| - static_cast<int>(found_range->length - net_offset);
|
| - DCHECK_GE(range_len_after_offset, 0);
|
| -
|
| - int len_to_read = std::min(buf_len, range_len_after_offset);
|
| - if (!ReadSparseRange(found_range, net_offset, len_to_read, buf)) {
|
| - *out_result = net::ERR_CACHE_READ_FAILURE;
|
| - return;
|
| - }
|
| - read_so_far += len_to_read;
|
| - }
|
| - ++it;
|
| - }
|
| -
|
| - // Keep reading until the buffer is full or there is not another contiguous
|
| - // range.
|
| - while (read_so_far < buf_len &&
|
| - it != sparse_ranges_.end() &&
|
| - it->second.offset == offset + read_so_far) {
|
| - SparseRange* found_range = &it->second;
|
| - DCHECK_EQ(it->first, found_range->offset);
|
| - int range_len = base::saturated_cast<int>(found_range->length);
|
| - int len_to_read = std::min(buf_len - read_so_far, range_len);
|
| - if (!ReadSparseRange(found_range, 0, len_to_read, buf + read_so_far)) {
|
| - *out_result = net::ERR_CACHE_READ_FAILURE;
|
| - return;
|
| - }
|
| - read_so_far += len_to_read;
|
| - ++it;
|
| - }
|
| -
|
| - *out_result = read_so_far;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::WriteSparseData(
|
| - const EntryOperationData& in_entry_op,
|
| - net::IOBuffer* in_buf,
|
| - uint64 max_sparse_data_size,
|
| - SimpleEntryStat* out_entry_stat,
|
| - int* out_result) {
|
| - DCHECK(initialized_);
|
| - int64 offset = in_entry_op.sparse_offset;
|
| - int buf_len = in_entry_op.buf_len;
|
| -
|
| - const char* buf = in_buf->data();
|
| - int written_so_far = 0;
|
| - int appended_so_far = 0;
|
| -
|
| - if (!sparse_file_open() && !CreateSparseFile()) {
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| -
|
| - uint64 sparse_data_size = out_entry_stat->sparse_data_size();
|
| - // This is a pessimistic estimate; it assumes the entire buffer is going to
|
| - // be appended as a new range, not written over existing ranges.
|
| - if (sparse_data_size + buf_len > max_sparse_data_size) {
|
| - DVLOG(1) << "Truncating sparse data file (" << sparse_data_size << " + "
|
| - << buf_len << " > " << max_sparse_data_size << ")";
|
| - TruncateSparseFile();
|
| - }
|
| -
|
| - SparseRangeIterator it = sparse_ranges_.lower_bound(offset);
|
| -
|
| - if (it != sparse_ranges_.begin()) {
|
| - --it;
|
| - SparseRange* found_range = &it->second;
|
| - if (found_range->offset + found_range->length > offset) {
|
| - DCHECK_GE(found_range->length, 0);
|
| - DCHECK_LE(found_range->length, kint32max);
|
| - DCHECK_GE(offset - found_range->offset, 0);
|
| - DCHECK_LE(offset - found_range->offset, kint32max);
|
| - int net_offset = static_cast<int>(offset - found_range->offset);
|
| - int range_len_after_offset =
|
| - static_cast<int>(found_range->length - net_offset);
|
| - DCHECK_GE(range_len_after_offset, 0);
|
| -
|
| - int len_to_write = std::min(buf_len, range_len_after_offset);
|
| - if (!WriteSparseRange(found_range, net_offset, len_to_write, buf)) {
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - written_so_far += len_to_write;
|
| - }
|
| - ++it;
|
| - }
|
| -
|
| - while (written_so_far < buf_len &&
|
| - it != sparse_ranges_.end() &&
|
| - it->second.offset < offset + buf_len) {
|
| - SparseRange* found_range = &it->second;
|
| - if (offset + written_so_far < found_range->offset) {
|
| - int len_to_append =
|
| - static_cast<int>(found_range->offset - (offset + written_so_far));
|
| - if (!AppendSparseRange(offset + written_so_far,
|
| - len_to_append,
|
| - buf + written_so_far)) {
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - written_so_far += len_to_append;
|
| - appended_so_far += len_to_append;
|
| - }
|
| - int range_len = base::saturated_cast<int>(found_range->length);
|
| - int len_to_write = std::min(buf_len - written_so_far, range_len);
|
| - if (!WriteSparseRange(found_range,
|
| - 0,
|
| - len_to_write,
|
| - buf + written_so_far)) {
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - written_so_far += len_to_write;
|
| - ++it;
|
| - }
|
| -
|
| - if (written_so_far < buf_len) {
|
| - int len_to_append = buf_len - written_so_far;
|
| - if (!AppendSparseRange(offset + written_so_far,
|
| - len_to_append,
|
| - buf + written_so_far)) {
|
| - *out_result = net::ERR_CACHE_WRITE_FAILURE;
|
| - return;
|
| - }
|
| - written_so_far += len_to_append;
|
| - appended_so_far += len_to_append;
|
| - }
|
| -
|
| - DCHECK_EQ(buf_len, written_so_far);
|
| -
|
| - base::Time modification_time = Time::Now();
|
| - out_entry_stat->set_last_used(modification_time);
|
| - out_entry_stat->set_last_modified(modification_time);
|
| - int32 old_sparse_data_size = out_entry_stat->sparse_data_size();
|
| - out_entry_stat->set_sparse_data_size(old_sparse_data_size + appended_so_far);
|
| - *out_result = written_so_far;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::GetAvailableRange(
|
| - const EntryOperationData& in_entry_op,
|
| - int64* out_start,
|
| - int* out_result) {
|
| - DCHECK(initialized_);
|
| - int64 offset = in_entry_op.sparse_offset;
|
| - int len = in_entry_op.buf_len;
|
| -
|
| - SparseRangeIterator it = sparse_ranges_.lower_bound(offset);
|
| -
|
| - int64 start = offset;
|
| - int64 avail_so_far = 0;
|
| -
|
| - if (it != sparse_ranges_.end() && it->second.offset < offset + len)
|
| - start = it->second.offset;
|
| -
|
| - if ((it == sparse_ranges_.end() || it->second.offset > offset) &&
|
| - it != sparse_ranges_.begin()) {
|
| - --it;
|
| - if (it->second.offset + it->second.length > offset) {
|
| - start = offset;
|
| - avail_so_far = (it->second.offset + it->second.length) - offset;
|
| - }
|
| - ++it;
|
| - }
|
| -
|
| - while (start + avail_so_far < offset + len &&
|
| - it != sparse_ranges_.end() &&
|
| - it->second.offset == start + avail_so_far) {
|
| - avail_so_far += it->second.length;
|
| - ++it;
|
| - }
|
| -
|
| - int64 len_from_start = len - (start - offset);
|
| - *out_start = start;
|
| - *out_result = static_cast<int>(std::min(avail_so_far, len_from_start));
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::CheckEOFRecord(int index,
|
| - const SimpleEntryStat& entry_stat,
|
| - uint32 expected_crc32,
|
| - int* out_result) const {
|
| - DCHECK(initialized_);
|
| - uint32 crc32;
|
| - bool has_crc32;
|
| - int stream_size;
|
| - *out_result =
|
| - GetEOFRecordData(index, entry_stat, &has_crc32, &crc32, &stream_size);
|
| - if (*out_result != net::OK) {
|
| - Doom();
|
| - return;
|
| - }
|
| - if (has_crc32 && crc32 != expected_crc32) {
|
| - DVLOG(1) << "EOF record had bad crc.";
|
| - *out_result = net::ERR_CACHE_CHECKSUM_MISMATCH;
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
|
| - Doom();
|
| - return;
|
| - }
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::Close(
|
| - const SimpleEntryStat& entry_stat,
|
| - scoped_ptr<std::vector<CRCRecord> > crc32s_to_write,
|
| - net::GrowableIOBuffer* stream_0_data) {
|
| - DCHECK(stream_0_data);
|
| - // Write stream 0 data.
|
| - int stream_0_offset = entry_stat.GetOffsetInFile(key_, 0, 0);
|
| - if (files_[0].Write(stream_0_offset, stream_0_data->data(),
|
| - entry_stat.data_size(0)) !=
|
| - entry_stat.data_size(0)) {
|
| - RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
|
| - DVLOG(1) << "Could not write stream 0 data.";
|
| - Doom();
|
| - }
|
| -
|
| - for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin();
|
| - it != crc32s_to_write->end(); ++it) {
|
| - const int stream_index = it->index;
|
| - const int file_index = GetFileIndexFromStreamIndex(stream_index);
|
| - if (empty_file_omitted_[file_index])
|
| - continue;
|
| -
|
| - SimpleFileEOF eof_record;
|
| - eof_record.stream_size = entry_stat.data_size(stream_index);
|
| - eof_record.final_magic_number = kSimpleFinalMagicNumber;
|
| - eof_record.flags = 0;
|
| - if (it->has_crc32)
|
| - eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32;
|
| - eof_record.data_crc32 = it->data_crc32;
|
| - int eof_offset = entry_stat.GetEOFOffsetInFile(key_, stream_index);
|
| - // If stream 0 changed size, the file needs to be resized, otherwise the
|
| - // next open will yield wrong stream sizes. On stream 1 and stream 2 proper
|
| - // resizing of the file is handled in SimpleSynchronousEntry::WriteData().
|
| - if (stream_index == 0 &&
|
| - !files_[file_index].SetLength(eof_offset)) {
|
| - RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
|
| - DVLOG(1) << "Could not truncate stream 0 file.";
|
| - Doom();
|
| - break;
|
| - }
|
| - if (files_[file_index].Write(eof_offset,
|
| - reinterpret_cast<const char*>(&eof_record),
|
| - sizeof(eof_record)) !=
|
| - sizeof(eof_record)) {
|
| - RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
|
| - DVLOG(1) << "Could not write eof record.";
|
| - Doom();
|
| - break;
|
| - }
|
| - }
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - if (empty_file_omitted_[i])
|
| - continue;
|
| -
|
| - files_[i].Close();
|
| - const int64 file_size = entry_stat.GetFileSize(key_, i);
|
| - SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
|
| - "LastClusterSize", cache_type_,
|
| - file_size % 4096, 0, 4097, 50);
|
| - const int64 cluster_loss = file_size % 4096 ? 4096 - file_size % 4096 : 0;
|
| - SIMPLE_CACHE_UMA(PERCENTAGE,
|
| - "LastClusterLossPercent", cache_type_,
|
| - static_cast<base::HistogramBase::Sample>(
|
| - cluster_loss * 100 / (cluster_loss + file_size)));
|
| - }
|
| -
|
| - if (sparse_file_open())
|
| - sparse_file_.Close();
|
| -
|
| - if (files_created_) {
|
| - const int stream2_file_index = GetFileIndexFromStreamIndex(2);
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "EntryCreatedAndStream2Omitted", cache_type_,
|
| - empty_file_omitted_[stream2_file_index]);
|
| - }
|
| - RecordCloseResult(cache_type_, CLOSE_RESULT_SUCCESS);
|
| - have_open_files_ = false;
|
| - delete this;
|
| -}
|
| -
|
| -SimpleSynchronousEntry::SimpleSynchronousEntry(net::CacheType cache_type,
|
| - const FilePath& path,
|
| - const std::string& key,
|
| - const uint64 entry_hash)
|
| - : cache_type_(cache_type),
|
| - path_(path),
|
| - entry_hash_(entry_hash),
|
| - key_(key),
|
| - have_open_files_(false),
|
| - initialized_(false) {
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i)
|
| - empty_file_omitted_[i] = false;
|
| -}
|
| -
|
| -SimpleSynchronousEntry::~SimpleSynchronousEntry() {
|
| - DCHECK(!(have_open_files_ && initialized_));
|
| - if (have_open_files_)
|
| - CloseFiles();
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::MaybeOpenFile(
|
| - int file_index,
|
| - File::Error* out_error) {
|
| - DCHECK(out_error);
|
| -
|
| - FilePath filename = GetFilenameFromFileIndex(file_index);
|
| - int flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE |
|
| - File::FLAG_SHARE_DELETE;
|
| - files_[file_index].Initialize(filename, flags);
|
| - *out_error = files_[file_index].error_details();
|
| -
|
| - if (CanOmitEmptyFile(file_index) && !files_[file_index].IsValid() &&
|
| - *out_error == File::FILE_ERROR_NOT_FOUND) {
|
| - empty_file_omitted_[file_index] = true;
|
| - return true;
|
| - }
|
| -
|
| - return files_[file_index].IsValid();
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::MaybeCreateFile(
|
| - int file_index,
|
| - FileRequired file_required,
|
| - File::Error* out_error) {
|
| - DCHECK(out_error);
|
| -
|
| - if (CanOmitEmptyFile(file_index) && file_required == FILE_NOT_REQUIRED) {
|
| - empty_file_omitted_[file_index] = true;
|
| - return true;
|
| - }
|
| -
|
| - FilePath filename = GetFilenameFromFileIndex(file_index);
|
| - int flags = File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
|
| - File::FLAG_SHARE_DELETE;
|
| - files_[file_index].Initialize(filename, flags);
|
| - *out_error = files_[file_index].error_details();
|
| -
|
| - empty_file_omitted_[file_index] = false;
|
| -
|
| - return files_[file_index].IsValid();
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::OpenFiles(
|
| - bool had_index,
|
| - SimpleEntryStat* out_entry_stat) {
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - File::Error error;
|
| - if (!MaybeOpenFile(i, &error)) {
|
| - // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms.
|
| - // We can calculate the third as the sum or difference of the other two.
|
| - RecordSyncOpenResult(
|
| - cache_type_, OPEN_ENTRY_PLATFORM_FILE_ERROR, had_index);
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenPlatformFileError", cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - if (had_index) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenPlatformFileError_WithIndex", cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncOpenPlatformFileError_WithoutIndex",
|
| - cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - }
|
| - while (--i >= 0)
|
| - CloseFile(i);
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - have_open_files_ = true;
|
| -
|
| - base::TimeDelta entry_age = base::Time::Now() - base::Time::UnixEpoch();
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - if (empty_file_omitted_[i]) {
|
| - out_entry_stat->set_data_size(i + 1, 0);
|
| - continue;
|
| - }
|
| -
|
| - File::Info file_info;
|
| - bool success = files_[i].GetInfo(&file_info);
|
| - base::Time file_last_modified;
|
| - if (!success) {
|
| - DLOG(WARNING) << "Could not get platform file info.";
|
| - continue;
|
| - }
|
| - out_entry_stat->set_last_used(file_info.last_accessed);
|
| - if (simple_util::GetMTime(path_, &file_last_modified))
|
| - out_entry_stat->set_last_modified(file_last_modified);
|
| - else
|
| - out_entry_stat->set_last_modified(file_info.last_modified);
|
| -
|
| - base::TimeDelta stream_age =
|
| - base::Time::Now() - out_entry_stat->last_modified();
|
| - if (stream_age < entry_age)
|
| - entry_age = stream_age;
|
| -
|
| - // Two things prevent from knowing the right values for |data_size|:
|
| - // 1) The key is not known, hence its length is unknown.
|
| - // 2) Stream 0 and stream 1 are in the same file, and the exact size for
|
| - // each will only be known when reading the EOF record for stream 0.
|
| - //
|
| - // The size for file 0 and 1 is temporarily kept in
|
| - // |data_size(1)| and |data_size(2)| respectively. Reading the key in
|
| - // InitializeForOpen yields the data size for each file. In the case of
|
| - // file hash_1, this is the total size of stream 2, and is assigned to
|
| - // data_size(2). In the case of file 0, it is the combined size of stream
|
| - // 0, stream 1 and one EOF record. The exact distribution of sizes between
|
| - // stream 1 and stream 0 is only determined after reading the EOF record
|
| - // for stream 0 in ReadAndValidateStream0.
|
| - out_entry_stat->set_data_size(i + 1, static_cast<int>(file_info.size));
|
| - }
|
| - SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
|
| - "SyncOpenEntryAge", cache_type_,
|
| - entry_age.InHours(), 1, 1000, 50);
|
| -
|
| - files_created_ = false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::CreateFiles(
|
| - bool had_index,
|
| - SimpleEntryStat* out_entry_stat) {
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - File::Error error;
|
| - if (!MaybeCreateFile(i, FILE_NOT_REQUIRED, &error)) {
|
| - // TODO(ttuttle,gavinp): Remove one each of these triplets of histograms.
|
| - // We can calculate the third as the sum or difference of the other two.
|
| - RecordSyncCreateResult(CREATE_ENTRY_PLATFORM_FILE_ERROR, had_index);
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreatePlatformFileError", cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - if (had_index) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreatePlatformFileError_WithIndex", cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreatePlatformFileError_WithoutIndex",
|
| - cache_type_,
|
| - -error, -base::File::FILE_ERROR_MAX);
|
| - }
|
| - while (--i >= 0)
|
| - CloseFile(i);
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - have_open_files_ = true;
|
| -
|
| - base::Time creation_time = Time::Now();
|
| - out_entry_stat->set_last_modified(creation_time);
|
| - out_entry_stat->set_last_used(creation_time);
|
| - for (int i = 0; i < kSimpleEntryStreamCount; ++i)
|
| - out_entry_stat->set_data_size(i, 0);
|
| -
|
| - files_created_ = true;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::CloseFile(int index) {
|
| - if (empty_file_omitted_[index]) {
|
| - empty_file_omitted_[index] = false;
|
| - } else {
|
| - DCHECK(files_[index].IsValid());
|
| - files_[index].Close();
|
| - }
|
| -
|
| - if (sparse_file_open())
|
| - CloseSparseFile();
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::CloseFiles() {
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i)
|
| - CloseFile(i);
|
| -}
|
| -
|
| -int SimpleSynchronousEntry::InitializeForOpen(
|
| - bool had_index,
|
| - SimpleEntryStat* out_entry_stat,
|
| - scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| - uint32* out_stream_0_crc32) {
|
| - DCHECK(!initialized_);
|
| - if (!OpenFiles(had_index, out_entry_stat)) {
|
| - DLOG(WARNING) << "Could not open platform files for entry.";
|
| - return net::ERR_FAILED;
|
| - }
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - if (empty_file_omitted_[i])
|
| - continue;
|
| -
|
| - SimpleFileHeader header;
|
| - int header_read_result =
|
| - files_[i].Read(0, reinterpret_cast<char*>(&header), sizeof(header));
|
| - if (header_read_result != sizeof(header)) {
|
| - DLOG(WARNING) << "Cannot read header from entry.";
|
| - RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - if (header.initial_magic_number != kSimpleInitialMagicNumber) {
|
| - // TODO(gavinp): This seems very bad; for now we log at WARNING, but we
|
| - // should give consideration to not saturating the log with these if that
|
| - // becomes a problem.
|
| - DLOG(WARNING) << "Magic number did not match.";
|
| - RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_MAGIC_NUMBER, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - if (header.version != kSimpleEntryVersionOnDisk) {
|
| - DLOG(WARNING) << "Unreadable version.";
|
| - RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_VERSION, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - scoped_ptr<char[]> key(new char[header.key_length]);
|
| - int key_read_result = files_[i].Read(sizeof(header), key.get(),
|
| - header.key_length);
|
| - if (key_read_result != implicit_cast<int>(header.key_length)) {
|
| - DLOG(WARNING) << "Cannot read key from entry.";
|
| - RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - key_ = std::string(key.get(), header.key_length);
|
| - if (i == 0) {
|
| - // File size for stream 0 has been stored temporarily in data_size[1].
|
| - int total_data_size =
|
| - GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(1));
|
| - int ret_value_stream_0 = ReadAndValidateStream0(
|
| - total_data_size, out_entry_stat, stream_0_data, out_stream_0_crc32);
|
| - if (ret_value_stream_0 != net::OK)
|
| - return ret_value_stream_0;
|
| - } else {
|
| - out_entry_stat->set_data_size(
|
| - 2, GetDataSizeFromKeyAndFileSize(key_, out_entry_stat->data_size(2)));
|
| - if (out_entry_stat->data_size(2) < 0) {
|
| - DLOG(WARNING) << "Stream 2 file is too small.";
|
| - return net::ERR_FAILED;
|
| - }
|
| - }
|
| -
|
| - if (base::Hash(key.get(), header.key_length) != header.key_hash) {
|
| - DLOG(WARNING) << "Hash mismatch on key.";
|
| - RecordSyncOpenResult(
|
| - cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| - }
|
| -
|
| - int32 sparse_data_size = 0;
|
| - if (!OpenSparseFileIfExists(&sparse_data_size)) {
|
| - RecordSyncOpenResult(
|
| - cache_type_, OPEN_ENTRY_SPARSE_OPEN_FAILED, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| - out_entry_stat->set_sparse_data_size(sparse_data_size);
|
| -
|
| - bool removed_stream2 = false;
|
| - const int stream2_file_index = GetFileIndexFromStreamIndex(2);
|
| - DCHECK(CanOmitEmptyFile(stream2_file_index));
|
| - if (!empty_file_omitted_[stream2_file_index] &&
|
| - out_entry_stat->data_size(2) == 0) {
|
| - DVLOG(1) << "Removing empty stream 2 file.";
|
| - CloseFile(stream2_file_index);
|
| - DeleteFileForEntryHash(path_, entry_hash_, stream2_file_index);
|
| - empty_file_omitted_[stream2_file_index] = true;
|
| - removed_stream2 = true;
|
| - }
|
| -
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "EntryOpenedAndStream2Removed", cache_type_,
|
| - removed_stream2);
|
| -
|
| - RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS, had_index);
|
| - initialized_ = true;
|
| - return net::OK;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::InitializeCreatedFile(
|
| - int file_index,
|
| - CreateEntryResult* out_result) {
|
| - SimpleFileHeader header;
|
| - header.initial_magic_number = kSimpleInitialMagicNumber;
|
| - header.version = kSimpleEntryVersionOnDisk;
|
| -
|
| - header.key_length = key_.size();
|
| - header.key_hash = base::Hash(key_);
|
| -
|
| - int bytes_written = files_[file_index].Write(
|
| - 0, reinterpret_cast<char*>(&header), sizeof(header));
|
| - if (bytes_written != sizeof(header)) {
|
| - *out_result = CREATE_ENTRY_CANT_WRITE_HEADER;
|
| - return false;
|
| - }
|
| -
|
| - bytes_written = files_[file_index].Write(sizeof(header), key_.data(),
|
| - key_.size());
|
| - if (bytes_written != implicit_cast<int>(key_.size())) {
|
| - *out_result = CREATE_ENTRY_CANT_WRITE_KEY;
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -int SimpleSynchronousEntry::InitializeForCreate(
|
| - bool had_index,
|
| - SimpleEntryStat* out_entry_stat) {
|
| - DCHECK(!initialized_);
|
| - if (!CreateFiles(had_index, out_entry_stat)) {
|
| - DLOG(WARNING) << "Could not create platform files.";
|
| - return net::ERR_FILE_EXISTS;
|
| - }
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - if (empty_file_omitted_[i])
|
| - continue;
|
| -
|
| - CreateEntryResult result;
|
| - if (!InitializeCreatedFile(i, &result)) {
|
| - RecordSyncCreateResult(result, had_index);
|
| - return net::ERR_FAILED;
|
| - }
|
| - }
|
| - RecordSyncCreateResult(CREATE_ENTRY_SUCCESS, had_index);
|
| - initialized_ = true;
|
| - return net::OK;
|
| -}
|
| -
|
| -int SimpleSynchronousEntry::ReadAndValidateStream0(
|
| - int total_data_size,
|
| - SimpleEntryStat* out_entry_stat,
|
| - scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
|
| - uint32* out_stream_0_crc32) const {
|
| - // Temporarily assign all the data size to stream 1 in order to read the
|
| - // EOF record for stream 0, which contains the size of stream 0.
|
| - out_entry_stat->set_data_size(0, 0);
|
| - out_entry_stat->set_data_size(1, total_data_size - sizeof(SimpleFileEOF));
|
| -
|
| - bool has_crc32;
|
| - uint32 read_crc32;
|
| - int stream_0_size;
|
| - int ret_value_crc32 = GetEOFRecordData(
|
| - 0, *out_entry_stat, &has_crc32, &read_crc32, &stream_0_size);
|
| - if (ret_value_crc32 != net::OK)
|
| - return ret_value_crc32;
|
| -
|
| - if (stream_0_size > out_entry_stat->data_size(1))
|
| - return net::ERR_FAILED;
|
| -
|
| - // These are the real values of data size.
|
| - out_entry_stat->set_data_size(0, stream_0_size);
|
| - out_entry_stat->set_data_size(
|
| - 1, out_entry_stat->data_size(1) - stream_0_size);
|
| -
|
| - // Put stream 0 data in memory.
|
| - *stream_0_data = new net::GrowableIOBuffer();
|
| - (*stream_0_data)->SetCapacity(stream_0_size);
|
| - int file_offset = out_entry_stat->GetOffsetInFile(key_, 0, 0);
|
| - File* file = const_cast<File*>(&files_[0]);
|
| - int bytes_read =
|
| - file->Read(file_offset, (*stream_0_data)->data(), stream_0_size);
|
| - if (bytes_read != stream_0_size)
|
| - return net::ERR_FAILED;
|
| -
|
| - // Check the CRC32.
|
| - uint32 expected_crc32 =
|
| - stream_0_size == 0
|
| - ? crc32(0, Z_NULL, 0)
|
| - : crc32(crc32(0, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>((*stream_0_data)->data()),
|
| - stream_0_size);
|
| - if (has_crc32 && read_crc32 != expected_crc32) {
|
| - DVLOG(1) << "EOF record had bad crc.";
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
|
| - return net::ERR_FAILED;
|
| - }
|
| - *out_stream_0_crc32 = expected_crc32;
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
|
| - return net::OK;
|
| -}
|
| -
|
| -int SimpleSynchronousEntry::GetEOFRecordData(int index,
|
| - const SimpleEntryStat& entry_stat,
|
| - bool* out_has_crc32,
|
| - uint32* out_crc32,
|
| - int* out_data_size) const {
|
| - SimpleFileEOF eof_record;
|
| - int file_offset = entry_stat.GetEOFOffsetInFile(key_, index);
|
| - int file_index = GetFileIndexFromStreamIndex(index);
|
| - File* file = const_cast<File*>(&files_[file_index]);
|
| - if (file->Read(file_offset, reinterpret_cast<char*>(&eof_record),
|
| - sizeof(eof_record)) !=
|
| - sizeof(eof_record)) {
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE);
|
| - return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
|
| - }
|
| -
|
| - if (eof_record.final_magic_number != kSimpleFinalMagicNumber) {
|
| - RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH);
|
| - DVLOG(1) << "EOF record had bad magic number.";
|
| - return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
|
| - }
|
| -
|
| - *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
|
| - SimpleFileEOF::FLAG_HAS_CRC32;
|
| - *out_crc32 = eof_record.data_crc32;
|
| - *out_data_size = eof_record.stream_size;
|
| - SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32);
|
| - return net::OK;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::Doom() const {
|
| - DeleteFilesForEntryHash(path_, entry_hash_);
|
| -}
|
| -
|
| -// static
|
| -bool SimpleSynchronousEntry::DeleteFileForEntryHash(
|
| - const FilePath& path,
|
| - const uint64 entry_hash,
|
| - const int file_index) {
|
| - FilePath to_delete = path.AppendASCII(
|
| - GetFilenameFromEntryHashAndFileIndex(entry_hash, file_index));
|
| - return simple_util::SimpleCacheDeleteFile(to_delete);
|
| -}
|
| -
|
| -// static
|
| -bool SimpleSynchronousEntry::DeleteFilesForEntryHash(
|
| - const FilePath& path,
|
| - const uint64 entry_hash) {
|
| - bool result = true;
|
| - for (int i = 0; i < kSimpleEntryFileCount; ++i) {
|
| - if (!DeleteFileForEntryHash(path, entry_hash, i) && !CanOmitEmptyFile(i))
|
| - result = false;
|
| - }
|
| - FilePath to_delete = path.AppendASCII(
|
| - GetSparseFilenameFromEntryHash(entry_hash));
|
| - simple_util::SimpleCacheDeleteFile(to_delete);
|
| - return result;
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::RecordSyncCreateResult(CreateEntryResult result,
|
| - bool had_index) {
|
| - DCHECK_LT(result, CREATE_ENTRY_MAX);
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreateResult", cache_type_, result, CREATE_ENTRY_MAX);
|
| - if (had_index) {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreateResult_WithIndex", cache_type_,
|
| - result, CREATE_ENTRY_MAX);
|
| - } else {
|
| - SIMPLE_CACHE_UMA(ENUMERATION,
|
| - "SyncCreateResult_WithoutIndex", cache_type_,
|
| - result, CREATE_ENTRY_MAX);
|
| - }
|
| -}
|
| -
|
| -FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(int file_index) {
|
| - return path_.AppendASCII(
|
| - GetFilenameFromEntryHashAndFileIndex(entry_hash_, file_index));
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::OpenSparseFileIfExists(
|
| - int32* out_sparse_data_size) {
|
| - DCHECK(!sparse_file_open());
|
| -
|
| - FilePath filename = path_.AppendASCII(
|
| - GetSparseFilenameFromEntryHash(entry_hash_));
|
| - int flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE |
|
| - File::FLAG_SHARE_DELETE;
|
| - sparse_file_.Initialize(filename, flags);
|
| - if (sparse_file_.IsValid())
|
| - return ScanSparseFile(out_sparse_data_size);
|
| -
|
| - return sparse_file_.error_details() == File::FILE_ERROR_NOT_FOUND;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::CreateSparseFile() {
|
| - DCHECK(!sparse_file_open());
|
| -
|
| - FilePath filename = path_.AppendASCII(
|
| - GetSparseFilenameFromEntryHash(entry_hash_));
|
| - int flags = File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE |
|
| - File::FLAG_SHARE_DELETE;
|
| - sparse_file_.Initialize(filename, flags);
|
| - if (!sparse_file_.IsValid())
|
| - return false;
|
| -
|
| - return InitializeSparseFile();
|
| -}
|
| -
|
| -void SimpleSynchronousEntry::CloseSparseFile() {
|
| - DCHECK(sparse_file_open());
|
| - sparse_file_.Close();
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::TruncateSparseFile() {
|
| - DCHECK(sparse_file_open());
|
| -
|
| - int64 header_and_key_length = sizeof(SimpleFileHeader) + key_.size();
|
| - if (!sparse_file_.SetLength(header_and_key_length)) {
|
| - DLOG(WARNING) << "Could not truncate sparse file";
|
| - return false;
|
| - }
|
| -
|
| - sparse_ranges_.clear();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::InitializeSparseFile() {
|
| - DCHECK(sparse_file_open());
|
| -
|
| - SimpleFileHeader header;
|
| - header.initial_magic_number = kSimpleInitialMagicNumber;
|
| - header.version = kSimpleVersion;
|
| - header.key_length = key_.size();
|
| - header.key_hash = base::Hash(key_);
|
| -
|
| - int header_write_result =
|
| - sparse_file_.Write(0, reinterpret_cast<char*>(&header), sizeof(header));
|
| - if (header_write_result != sizeof(header)) {
|
| - DLOG(WARNING) << "Could not write sparse file header";
|
| - return false;
|
| - }
|
| -
|
| - int key_write_result = sparse_file_.Write(sizeof(header), key_.data(),
|
| - key_.size());
|
| - if (key_write_result != implicit_cast<int>(key_.size())) {
|
| - DLOG(WARNING) << "Could not write sparse file key";
|
| - return false;
|
| - }
|
| -
|
| - sparse_ranges_.clear();
|
| - sparse_tail_offset_ = sizeof(header) + key_.size();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::ScanSparseFile(int32* out_sparse_data_size) {
|
| - DCHECK(sparse_file_open());
|
| -
|
| - int64 sparse_data_size = 0;
|
| -
|
| - SimpleFileHeader header;
|
| - int header_read_result =
|
| - sparse_file_.Read(0, reinterpret_cast<char*>(&header), sizeof(header));
|
| - if (header_read_result != sizeof(header)) {
|
| - DLOG(WARNING) << "Could not read header from sparse file.";
|
| - return false;
|
| - }
|
| -
|
| - if (header.initial_magic_number != kSimpleInitialMagicNumber) {
|
| - DLOG(WARNING) << "Sparse file magic number did not match.";
|
| - return false;
|
| - }
|
| -
|
| - if (header.version != kSimpleVersion) {
|
| - DLOG(WARNING) << "Sparse file unreadable version.";
|
| - return false;
|
| - }
|
| -
|
| - sparse_ranges_.clear();
|
| -
|
| - int64 range_header_offset = sizeof(header) + key_.size();
|
| - while (1) {
|
| - SimpleFileSparseRangeHeader range_header;
|
| - int range_header_read_result =
|
| - sparse_file_.Read(range_header_offset,
|
| - reinterpret_cast<char*>(&range_header),
|
| - sizeof(range_header));
|
| - if (range_header_read_result == 0)
|
| - break;
|
| - if (range_header_read_result != sizeof(range_header)) {
|
| - DLOG(WARNING) << "Could not read sparse range header.";
|
| - return false;
|
| - }
|
| -
|
| - if (range_header.sparse_range_magic_number !=
|
| - kSimpleSparseRangeMagicNumber) {
|
| - DLOG(WARNING) << "Invalid sparse range header magic number.";
|
| - return false;
|
| - }
|
| -
|
| - SparseRange range;
|
| - range.offset = range_header.offset;
|
| - range.length = range_header.length;
|
| - range.data_crc32 = range_header.data_crc32;
|
| - range.file_offset = range_header_offset + sizeof(range_header);
|
| - sparse_ranges_.insert(std::make_pair(range.offset, range));
|
| -
|
| - range_header_offset += sizeof(range_header) + range.length;
|
| -
|
| - DCHECK_GE(sparse_data_size + range.length, sparse_data_size);
|
| - sparse_data_size += range.length;
|
| - }
|
| -
|
| - *out_sparse_data_size = static_cast<int32>(sparse_data_size);
|
| - sparse_tail_offset_ = range_header_offset;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::ReadSparseRange(const SparseRange* range,
|
| - int offset, int len, char* buf) {
|
| - DCHECK(range);
|
| - DCHECK(buf);
|
| - DCHECK_LE(offset, range->length);
|
| - DCHECK_LE(offset + len, range->length);
|
| -
|
| - int bytes_read = sparse_file_.Read(range->file_offset + offset, buf, len);
|
| - if (bytes_read < len) {
|
| - DLOG(WARNING) << "Could not read sparse range.";
|
| - return false;
|
| - }
|
| -
|
| - // If we read the whole range and we have a crc32, check it.
|
| - if (offset == 0 && len == range->length && range->data_crc32 != 0) {
|
| - uint32 actual_crc32 = crc32(crc32(0L, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>(buf),
|
| - len);
|
| - if (actual_crc32 != range->data_crc32) {
|
| - DLOG(WARNING) << "Sparse range crc32 mismatch.";
|
| - return false;
|
| - }
|
| - }
|
| - // TODO(ttuttle): Incremental crc32 calculation?
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::WriteSparseRange(SparseRange* range,
|
| - int offset, int len,
|
| - const char* buf) {
|
| - DCHECK(range);
|
| - DCHECK(buf);
|
| - DCHECK_LE(offset, range->length);
|
| - DCHECK_LE(offset + len, range->length);
|
| -
|
| - uint32 new_crc32 = 0;
|
| - if (offset == 0 && len == range->length) {
|
| - new_crc32 = crc32(crc32(0L, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>(buf),
|
| - len);
|
| - }
|
| -
|
| - if (new_crc32 != range->data_crc32) {
|
| - range->data_crc32 = new_crc32;
|
| -
|
| - SimpleFileSparseRangeHeader header;
|
| - header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber;
|
| - header.offset = range->offset;
|
| - header.length = range->length;
|
| - header.data_crc32 = range->data_crc32;
|
| -
|
| - int bytes_written = sparse_file_.Write(range->file_offset - sizeof(header),
|
| - reinterpret_cast<char*>(&header),
|
| - sizeof(header));
|
| - if (bytes_written != implicit_cast<int>(sizeof(header))) {
|
| - DLOG(WARNING) << "Could not rewrite sparse range header.";
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - int bytes_written = sparse_file_.Write(range->file_offset + offset, buf, len);
|
| - if (bytes_written < len) {
|
| - DLOG(WARNING) << "Could not write sparse range.";
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SimpleSynchronousEntry::AppendSparseRange(int64 offset,
|
| - int len,
|
| - const char* buf) {
|
| - DCHECK_GE(offset, 0);
|
| - DCHECK_GT(len, 0);
|
| - DCHECK(buf);
|
| -
|
| - uint32 data_crc32 = crc32(crc32(0L, Z_NULL, 0),
|
| - reinterpret_cast<const Bytef*>(buf),
|
| - len);
|
| -
|
| - SimpleFileSparseRangeHeader header;
|
| - header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber;
|
| - header.offset = offset;
|
| - header.length = len;
|
| - header.data_crc32 = data_crc32;
|
| -
|
| - int bytes_written = sparse_file_.Write(sparse_tail_offset_,
|
| - reinterpret_cast<char*>(&header),
|
| - sizeof(header));
|
| - if (bytes_written != implicit_cast<int>(sizeof(header))) {
|
| - DLOG(WARNING) << "Could not append sparse range header.";
|
| - return false;
|
| - }
|
| - sparse_tail_offset_ += bytes_written;
|
| -
|
| - bytes_written = sparse_file_.Write(sparse_tail_offset_, buf, len);
|
| - if (bytes_written < len) {
|
| - DLOG(WARNING) << "Could not append sparse range data.";
|
| - return false;
|
| - }
|
| - int64 data_file_offset = sparse_tail_offset_;
|
| - sparse_tail_offset_ += bytes_written;
|
| -
|
| - SparseRange range;
|
| - range.offset = offset;
|
| - range.length = len;
|
| - range.data_crc32 = data_crc32;
|
| - range.file_offset = data_file_offset;
|
| - sparse_ranges_.insert(std::make_pair(offset, range));
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace disk_cache
|
|
|