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

Side by Side Diff: net/disk_cache/simple/simple_synchronous_entry.cc

Issue 2874833005: SimpleCache: read small files all at once. (Closed)
Patch Set: Add some metrics and an experiment knob. Not really happy with coverage, though. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
11 11
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
14 #include "base/hash.h" 14 #include "base/hash.h"
15 #include "base/location.h" 15 #include "base/location.h"
16 #include "base/memory/ptr_util.h"
16 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
17 #include "base/numerics/safe_conversions.h" 18 #include "base/numerics/safe_conversions.h"
18 #include "base/sha1.h" 19 #include "base/sha1.h"
19 #include "base/timer/elapsed_timer.h" 20 #include "base/timer/elapsed_timer.h"
20 #include "crypto/secure_hash.h" 21 #include "crypto/secure_hash.h"
21 #include "net/base/hash_value.h" 22 #include "net/base/hash_value.h"
22 #include "net/base/io_buffer.h" 23 #include "net/base/io_buffer.h"
23 #include "net/base/net_errors.h" 24 #include "net/base/net_errors.h"
24 #include "net/disk_cache/simple/simple_backend_version.h" 25 #include "net/disk_cache/simple/simple_backend_version.h"
26 #include "net/disk_cache/simple/simple_experiment.h"
25 #include "net/disk_cache/simple/simple_histogram_macros.h" 27 #include "net/disk_cache/simple/simple_histogram_macros.h"
26 #include "net/disk_cache/simple/simple_util.h" 28 #include "net/disk_cache/simple/simple_util.h"
27 #include "third_party/zlib/zlib.h" 29 #include "third_party/zlib/zlib.h"
28 30
29 using base::File; 31 using base::File;
30 using base::FilePath; 32 using base::FilePath;
31 using base::Time; 33 using base::Time;
32 34
33 namespace { 35 namespace {
34 36
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 SIMPLE_CACHE_UMA(ENUMERATION, 113 SIMPLE_CACHE_UMA(ENUMERATION,
112 "SyncCloseResult", cache_type, result, CLOSE_RESULT_MAX); 114 "SyncCloseResult", cache_type, result, CLOSE_RESULT_MAX);
113 } 115 }
114 116
115 void RecordKeySHA256Result(net::CacheType cache_type, KeySHA256Result result) { 117 void RecordKeySHA256Result(net::CacheType cache_type, KeySHA256Result result) {
116 SIMPLE_CACHE_UMA(ENUMERATION, "SyncKeySHA256Result", cache_type, 118 SIMPLE_CACHE_UMA(ENUMERATION, "SyncKeySHA256Result", cache_type,
117 static_cast<int>(result), 119 static_cast<int>(result),
118 static_cast<int>(KeySHA256Result::MAX)); 120 static_cast<int>(KeySHA256Result::MAX));
119 } 121 }
120 122
123 void RecordSyncOpenPrefetchStatus(net::CacheType cache_type, bool result) {
pasko 2017/07/18 13:46:31 my favorite: nit on naming, because it is always p
Maks Orlovich 2017/07/21 18:37:33 Done'ish
124 SIMPLE_CACHE_UMA(BOOLEAN, "SyncOpenDidPrefetch", cache_type, result);
125 }
126
121 bool CanOmitEmptyFile(int file_index) { 127 bool CanOmitEmptyFile(int file_index) {
122 DCHECK_GE(file_index, 0); 128 DCHECK_GE(file_index, 0);
123 DCHECK_LT(file_index, disk_cache::kSimpleEntryFileCount); 129 DCHECK_LT(file_index, disk_cache::kSimpleEntryFileCount);
124 return file_index == disk_cache::simple_util::GetFileIndexFromStreamIndex(2); 130 return file_index == disk_cache::simple_util::GetFileIndexFromStreamIndex(2);
125 } 131 }
126 132
127 bool TruncatePath(const FilePath& filename_to_truncate) { 133 bool TruncatePath(const FilePath& filename_to_truncate) {
128 File file_to_truncate; 134 File file_to_truncate;
129 int flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE | 135 int flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE |
130 File::FLAG_SHARE_DELETE; 136 File::FLAG_SHARE_DELETE;
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 const base::TimeTicks& time_enqueued, 268 const base::TimeTicks& time_enqueued,
263 SimpleEntryCreationResults* out_results) { 269 SimpleEntryCreationResults* out_results) {
264 base::TimeTicks start_sync_open_entry = base::TimeTicks::Now(); 270 base::TimeTicks start_sync_open_entry = base::TimeTicks::Now();
265 SIMPLE_CACHE_UMA(TIMES, "QueueLatency.OpenEntry", cache_type, 271 SIMPLE_CACHE_UMA(TIMES, "QueueLatency.OpenEntry", cache_type,
266 (start_sync_open_entry - time_enqueued)); 272 (start_sync_open_entry - time_enqueued));
267 273
268 SimpleSynchronousEntry* sync_entry = 274 SimpleSynchronousEntry* sync_entry =
269 new SimpleSynchronousEntry(cache_type, path, key, entry_hash, had_index); 275 new SimpleSynchronousEntry(cache_type, path, key, entry_hash, had_index);
270 out_results->result = sync_entry->InitializeForOpen( 276 out_results->result = sync_entry->InitializeForOpen(
271 &out_results->entry_stat, &out_results->stream_0_data, 277 &out_results->entry_stat, &out_results->stream_0_data,
272 &out_results->stream_0_crc32); 278 &out_results->stream_0_crc32, &out_results->stream_1_data,
279 &out_results->stream_1_crc32);
pasko 2017/07/18 13:46:31 too many output arguments some set under non-trivi
Maks Orlovich 2017/07/28 17:27:35 Ended up grouping into array of structs, also simp
273 if (out_results->result != net::OK) { 280 if (out_results->result != net::OK) {
274 sync_entry->Doom(); 281 sync_entry->Doom();
275 delete sync_entry; 282 delete sync_entry;
276 out_results->sync_entry = NULL; 283 out_results->sync_entry = NULL;
277 out_results->stream_0_data = NULL; 284 out_results->stream_0_data = NULL;
278 return; 285 return;
279 } 286 }
280 SIMPLE_CACHE_UMA(TIMES, "DiskOpenLatency", cache_type, 287 SIMPLE_CACHE_UMA(TIMES, "DiskOpenLatency", cache_type,
281 base::TimeTicks::Now() - start_sync_open_entry); 288 base::TimeTicks::Now() - start_sync_open_entry);
282 out_results->sync_entry = sync_entry; 289 out_results->sync_entry = sync_entry;
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 ++it; 692 ++it;
686 } 693 }
687 694
688 int64_t len_from_start = len - (start - offset); 695 int64_t len_from_start = len - (start - offset);
689 *out_start = start; 696 *out_start = start;
690 *out_result = static_cast<int>(std::min(avail_so_far, len_from_start)); 697 *out_result = static_cast<int>(std::min(avail_so_far, len_from_start));
691 } 698 }
692 699
693 int SimpleSynchronousEntry::CheckEOFRecord(int index, 700 int SimpleSynchronousEntry::CheckEOFRecord(int index,
694 const SimpleEntryStat& entry_stat, 701 const SimpleEntryStat& entry_stat,
695 uint32_t expected_crc32) const { 702 uint32_t expected_crc32) {
696 DCHECK(initialized_); 703 DCHECK(initialized_);
697 uint32_t crc32; 704 SimpleFileEOF eof_record;
698 bool has_crc32; 705 int rv = GetEOFRecordData(nullptr, 0, index, entry_stat, &eof_record);
699 bool has_key_sha256; 706
700 int32_t stream_size;
701 int rv = GetEOFRecordData(index, entry_stat, &has_crc32, &has_key_sha256,
702 &crc32, &stream_size);
703 if (rv != net::OK) { 707 if (rv != net::OK) {
704 Doom(); 708 Doom();
705 return rv; 709 return rv;
706 } 710 }
707 if (has_crc32 && crc32 != expected_crc32) { 711 if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
712 eof_record.data_crc32 != expected_crc32) {
708 DVLOG(1) << "EOF record had bad crc."; 713 DVLOG(1) << "EOF record had bad crc.";
709 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); 714 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
710 Doom(); 715 Doom();
711 return net::ERR_CACHE_CHECKSUM_MISMATCH; 716 return net::ERR_CACHE_CHECKSUM_MISMATCH;
712 } 717 }
713 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); 718 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
714 return net::OK; 719 return net::OK;
715 } 720 }
716 721
722 int SimpleSynchronousEntry::PreReadStreamPayload(
pasko 2017/07/18 13:46:31 Why Pre? It just reads, no?
morlovich 2017/07/18 14:32:31 Because it's only used in the prefetch path?
pasko 2017/07/19 16:28:26 ah, ok
Maks Orlovich 2017/07/21 18:37:34 Acknowledged.
723 char* prefetch_buf,
724 int file_size,
725 int stream_index,
726 int extra_size,
727 const SimpleEntryStat& entry_stat,
728 const SimpleFileEOF& eof_record,
729 scoped_refptr<net::GrowableIOBuffer>* stream_data,
730 uint32_t* out_crc32) {
731 int stream_size = entry_stat.data_size(stream_index);
732 int read_size = stream_size + extra_size;
733 *stream_data = new net::GrowableIOBuffer();
734 (*stream_data)->SetCapacity(read_size);
735 int file_offset = entry_stat.GetOffsetInFile(key_.size(), 0, stream_index);
736 if (!ReadFromFileOrPrefetched(prefetch_buf, file_size, file_offset, read_size,
737 (*stream_data)->data()))
738 return net::ERR_FAILED;
739
740 // Check the CRC32.
741 uint32_t expected_crc32 =
742 stream_size == 0
743 ? crc32(0, Z_NULL, 0)
744 : crc32(crc32(0, Z_NULL, 0),
745 reinterpret_cast<const Bytef*>((*stream_data)->data()),
pasko 2017/07/19 16:28:26 In case you have similar allergies to reinterpret_
Maks Orlovich 2017/07/25 16:06:29 Split out into https://chromium-review.googlesourc
746 stream_size);
747 if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
748 eof_record.data_crc32 != expected_crc32) {
749 DVLOG(1) << "EOF record had bad crc.";
750 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
pasko 2017/07/19 16:28:26 just realized that this might slightly increase th
Maks Orlovich 2017/07/21 18:37:34 Acknowledged.
751 return net::ERR_CACHE_CHECKSUM_MISMATCH;
752 }
753 *out_crc32 = expected_crc32;
754 return net::OK;
755 }
756
717 void SimpleSynchronousEntry::Close( 757 void SimpleSynchronousEntry::Close(
718 const SimpleEntryStat& entry_stat, 758 const SimpleEntryStat& entry_stat,
719 std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write, 759 std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write,
720 net::GrowableIOBuffer* stream_0_data) { 760 net::GrowableIOBuffer* stream_0_data) {
721 base::ElapsedTimer close_time; 761 base::ElapsedTimer close_time;
722 DCHECK(stream_0_data); 762 DCHECK(stream_0_data);
723 763
724 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin(); 764 for (std::vector<CRCRecord>::const_iterator it = crc32s_to_write->begin();
725 it != crc32s_to_write->end(); ++it) { 765 it != crc32s_to_write->end(); ++it) {
726 const int stream_index = it->index; 766 const int stream_index = it->index;
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 } 1129 }
1090 } 1130 }
1091 1131
1092 header_and_key_check_needed_[file_index] = false; 1132 header_and_key_check_needed_[file_index] = false;
1093 return true; 1133 return true;
1094 } 1134 }
1095 1135
1096 int SimpleSynchronousEntry::InitializeForOpen( 1136 int SimpleSynchronousEntry::InitializeForOpen(
1097 SimpleEntryStat* out_entry_stat, 1137 SimpleEntryStat* out_entry_stat,
1098 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, 1138 scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
1099 uint32_t* out_stream_0_crc32) { 1139 uint32_t* out_stream_0_crc32,
1140 scoped_refptr<net::GrowableIOBuffer>* stream_1_data,
1141 uint32_t* out_stream_1_crc32) {
1100 DCHECK(!initialized_); 1142 DCHECK(!initialized_);
1101 if (!OpenFiles(out_entry_stat)) { 1143 if (!OpenFiles(out_entry_stat)) {
1102 DLOG(WARNING) << "Could not open platform files for entry."; 1144 DLOG(WARNING) << "Could not open platform files for entry.";
1103 return net::ERR_FAILED; 1145 return net::ERR_FAILED;
1104 } 1146 }
1105 for (int i = 0; i < kSimpleEntryFileCount; ++i) { 1147 for (int i = 0; i < kSimpleEntryFileCount; ++i) {
1106 if (empty_file_omitted_[i]) 1148 if (empty_file_omitted_[i])
1107 continue; 1149 continue;
1108 1150
1109 if (key_.empty()) { 1151 if (key_.empty()) {
1110 // If |key_| is empty, we were opened via the iterator interface, without 1152 // If |key_| is empty, we were opened via the iterator interface, without
1111 // knowing what our key is. We must therefore read the header immediately 1153 // knowing what our key is. We must therefore read the header immediately
1112 // to discover it, so SimpleEntryImpl can make it available to 1154 // to discover it, so SimpleEntryImpl can make it available to
1113 // disk_cache::Entry::GetKey(). 1155 // disk_cache::Entry::GetKey().
1114 if (!CheckHeaderAndKey(i)) 1156 if (!CheckHeaderAndKey(i))
1115 return net::ERR_FAILED; 1157 return net::ERR_FAILED;
1116 } else { 1158 } else {
1117 // If we do know which key were are looking for, we still need to 1159 // If we do know which key were are looking for, we still need to
1118 // check that the file actually has it (rather than just being a hash 1160 // check that the file actually has it (rather than just being a hash
1119 // collision or some sort of file system accident), but that can be put 1161 // collision or some sort of file system accident), but that can be put
1120 // off until opportune time: either the read of the footer, or when we 1162 // off until opportune time: either the read of the footer, or when we
1121 // start reading in the data, depending on stream # and format revision. 1163 // start reading in the data, depending on stream # and format revision.
1122 header_and_key_check_needed_[i] = true; 1164 header_and_key_check_needed_[i] = true;
1123 } 1165 }
1124 1166
1125 if (i == 0) { 1167 if (i == 0) {
1126 // File size for stream 0 has been stored temporarily in data_size[1]. 1168 // File size for stream 0 has been stored temporarily in data_size[1].
1127 int ret_value_stream_0 = 1169 int ret_value_stream_0 = ReadAndValidateStream0(
1128 ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat, 1170 out_entry_stat->data_size(1), out_entry_stat, stream_0_data,
1129 stream_0_data, out_stream_0_crc32); 1171 out_stream_0_crc32, stream_1_data, out_stream_1_crc32);
1130 if (ret_value_stream_0 != net::OK) 1172 if (ret_value_stream_0 != net::OK)
1131 return ret_value_stream_0; 1173 return ret_value_stream_0;
1132 } else { 1174 } else {
1133 out_entry_stat->set_data_size( 1175 out_entry_stat->set_data_size(
1134 2, 1176 2,
1135 GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2))); 1177 GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2)));
1136 if (out_entry_stat->data_size(2) < 0) { 1178 if (out_entry_stat->data_size(2) < 0) {
1137 DLOG(WARNING) << "Stream 2 file is too small."; 1179 DLOG(WARNING) << "Stream 2 file is too small.";
1138 return net::ERR_FAILED; 1180 return net::ERR_FAILED;
1139 } 1181 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1210 if (!InitializeCreatedFile(i, &result)) { 1252 if (!InitializeCreatedFile(i, &result)) {
1211 RecordSyncCreateResult(result, had_index_); 1253 RecordSyncCreateResult(result, had_index_);
1212 return net::ERR_FAILED; 1254 return net::ERR_FAILED;
1213 } 1255 }
1214 } 1256 }
1215 RecordSyncCreateResult(CREATE_ENTRY_SUCCESS, had_index_); 1257 RecordSyncCreateResult(CREATE_ENTRY_SUCCESS, had_index_);
1216 initialized_ = true; 1258 initialized_ = true;
1217 return net::OK; 1259 return net::OK;
1218 } 1260 }
1219 1261
1220 int SimpleSynchronousEntry::ReadAndValidateStream0( 1262 int SimpleSynchronousEntry::ReadAndValidateStream0(
pasko 2017/07/18 13:46:31 this fetches stream 1 as well, so the name of the
morlovich 2017/07/18 14:32:31 How awful is ReadAndValidateStream0AndMaybe1 ? Any
pasko 2017/07/19 16:28:26 As a name it sounds good to me
1221 int file_size, 1263 int file_size,
1222 SimpleEntryStat* out_entry_stat, 1264 SimpleEntryStat* out_entry_stat,
1223 scoped_refptr<net::GrowableIOBuffer>* stream_0_data, 1265 scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
1224 uint32_t* out_stream_0_crc32) { 1266 uint32_t* out_stream_0_crc32,
1267 scoped_refptr<net::GrowableIOBuffer>* stream_1_data,
1268 uint32_t* out_stream_1_crc32) {
1269 // If the file is sufficiently small, we will prefetch everything --
1270 // in which case |prefetch_buf| will be non-null, and we should look at it
1271 // rather than call ::Read for the bits.
1272 std::unique_ptr<char[]> prefetch_buf;
1273
1274 if (file_size <= GetSimpleCachePrefetchSize()) {
1275 RecordSyncOpenPrefetchStatus(cache_type_, true);
1276 prefetch_buf = base::MakeUnique<char[]>(file_size);
1277 if (files_[0].Read(0, prefetch_buf.get(), file_size) != file_size)
1278 return net::ERR_FAILED;
1279 } else {
1280 RecordSyncOpenPrefetchStatus(cache_type_, false);
pasko 2017/07/18 13:46:31 nit: it is usually easier to read if the short bra
Maks Orlovich 2017/07/21 18:37:33 [Citation needed], but done.
pasko 2017/07/24 12:22:45 unfortunately, could not find a good one, and now
1281 }
1282
1225 // Pretend this file has a null stream zero, and contains the optional key 1283 // Pretend this file has a null stream zero, and contains the optional key
1226 // SHA256. This is good enough to read the EOF record on the file, which gives 1284 // SHA256. This is good enough to read the EOF record on the file, which gives
1227 // the actual size of stream 0. 1285 // the actual size of stream 0.
1228 int temp_data_size = GetDataSizeFromFileSize(key_.size(), file_size); 1286 int temp_data_size = GetDataSizeFromFileSize(key_.size(), file_size);
1229 out_entry_stat->set_data_size(0, 0); 1287 out_entry_stat->set_data_size(0, 0);
1230 out_entry_stat->set_data_size( 1288 out_entry_stat->set_data_size(
1231 1, temp_data_size - sizeof(net::SHA256HashValue) - sizeof(SimpleFileEOF)); 1289 1, temp_data_size - sizeof(net::SHA256HashValue) - sizeof(SimpleFileEOF));
1232 1290
1233 bool has_crc32; 1291 SimpleFileEOF stream_0_eof;
1234 bool has_key_sha256; 1292 int rv = GetEOFRecordData(prefetch_buf.get(), file_size, 0, *out_entry_stat,
1235 uint32_t read_crc32; 1293 &stream_0_eof);
1236 int32_t stream_0_size; 1294 if (rv != net::OK)
1237 int ret_value_crc32 = 1295 return rv;
1238 GetEOFRecordData(0, *out_entry_stat, &has_crc32, &has_key_sha256, 1296
1239 &read_crc32, &stream_0_size); 1297 bool has_key_sha256 =
1240 if (ret_value_crc32 != net::OK) 1298 (stream_0_eof.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
1241 return ret_value_crc32; 1299 SimpleFileEOF::FLAG_HAS_KEY_SHA256;
1300 int32_t stream_0_size = stream_0_eof.stream_size;
1242 1301
1243 // Calculate and set the real values for the two streams. 1302 // Calculate and set the real values for the two streams.
1244 int32_t total_size = out_entry_stat->data_size(1); 1303 int32_t total_size = out_entry_stat->data_size(1);
1245 if (!has_key_sha256) 1304 if (!has_key_sha256)
1246 total_size += sizeof(net::SHA256HashValue); 1305 total_size += sizeof(net::SHA256HashValue);
1306
1307 // Sanity-check: don't want to be allocating a gigantic buffer > file size
1308 // just because of a header field.
1247 if (stream_0_size > total_size) 1309 if (stream_0_size > total_size)
1248 return net::ERR_FAILED; 1310 return net::ERR_FAILED;
1249 out_entry_stat->set_data_size(0, stream_0_size); 1311 out_entry_stat->set_data_size(0, stream_0_size);
1250 out_entry_stat->set_data_size(1, total_size - stream_0_size); 1312 out_entry_stat->set_data_size(1, total_size - stream_0_size);
1251 1313
1252 // Put stream 0 data in memory. 1314 // Put stream 0 data in memory --- plus maybe the sha256(key) footer.
1253 *stream_0_data = new net::GrowableIOBuffer(); 1315 int extra_stream_0_read = 0;
1254 (*stream_0_data)->SetCapacity(stream_0_size + sizeof(net::SHA256HashValue));
1255 int file_offset = out_entry_stat->GetOffsetInFile(key_.size(), 0, 0);
1256 int read_size = stream_0_size;
1257 if (has_key_sha256) 1316 if (has_key_sha256)
1258 read_size += sizeof(net::SHA256HashValue); 1317 extra_stream_0_read += sizeof(net::SHA256HashValue);
1259 if (files_[0].Read(file_offset, (*stream_0_data)->data(), read_size) != 1318 rv = PreReadStreamPayload(prefetch_buf.get(), file_size, 0,
1260 read_size) 1319 extra_stream_0_read, *out_entry_stat, stream_0_eof,
1261 return net::ERR_FAILED; 1320 stream_0_data, out_stream_0_crc32);
1321 if (rv != net::OK)
1322 return rv;
1262 1323
1263 // Check the CRC32. 1324 // If prefetch buffer is available, and we have sha256(key) (so we don't need
1264 uint32_t expected_crc32 = 1325 // to look at the header), extract out stream 1 info as well.
1265 stream_0_size == 0 1326 if (prefetch_buf && has_key_sha256) {
1266 ? crc32(0, Z_NULL, 0) 1327 SimpleFileEOF stream_1_eof;
1267 : crc32(crc32(0, Z_NULL, 0), 1328 rv = GetEOFRecordData(prefetch_buf.get(), file_size, 1, *out_entry_stat,
1268 reinterpret_cast<const Bytef*>((*stream_0_data)->data()), 1329 &stream_1_eof);
1269 stream_0_size); 1330 if (rv != net::OK)
1270 if (has_crc32 && read_crc32 != expected_crc32) { 1331 return rv;
1271 DVLOG(1) << "EOF record had bad crc."; 1332
1272 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH); 1333 rv = PreReadStreamPayload(prefetch_buf.get(), file_size, 1, 0,
1273 return net::ERR_FAILED; 1334 *out_entry_stat, stream_1_eof, stream_1_data,
1335 out_stream_1_crc32);
1336 if (rv != net::OK)
1337 return rv;
1338 } else {
1339 *stream_1_data = nullptr;
1274 } 1340 }
1275 *out_stream_0_crc32 = expected_crc32;
1276 1341
1277 // If present, check the key SHA256. 1342 // If present, check the key SHA256.
1278 if (has_key_sha256) { 1343 if (has_key_sha256) {
1279 net::SHA256HashValue hash_value; 1344 net::SHA256HashValue hash_value;
1280 CalculateSHA256OfKey(key_, &hash_value); 1345 CalculateSHA256OfKey(key_, &hash_value);
1281 bool matched = 1346 bool matched =
1282 std::memcmp(&hash_value, (*stream_0_data)->data() + stream_0_size, 1347 std::memcmp(&hash_value, (*stream_0_data)->data() + stream_0_size,
1283 sizeof(hash_value)) == 0; 1348 sizeof(hash_value)) == 0;
1284 if (!matched) { 1349 if (!matched) {
1285 RecordKeySHA256Result(cache_type_, KeySHA256Result::NO_MATCH); 1350 RecordKeySHA256Result(cache_type_, KeySHA256Result::NO_MATCH);
1286 return net::ERR_FAILED; 1351 return net::ERR_FAILED;
1287 } 1352 }
1288 // Elide header check if we verified sha256(key) via footer. 1353 // Elide header check if we verified sha256(key) via footer.
1289 header_and_key_check_needed_[0] = false; 1354 header_and_key_check_needed_[0] = false;
1290 RecordKeySHA256Result(cache_type_, KeySHA256Result::MATCHED); 1355 RecordKeySHA256Result(cache_type_, KeySHA256Result::MATCHED);
1291 } else { 1356 } else {
1292 RecordKeySHA256Result(cache_type_, KeySHA256Result::NOT_PRESENT); 1357 RecordKeySHA256Result(cache_type_, KeySHA256Result::NOT_PRESENT);
1293 } 1358 }
1294 1359
1295 // Ensure the key is validated before completion. 1360 // Ensure the key is validated before completion.
1296 if (!has_key_sha256 && header_and_key_check_needed_[0]) 1361 if (!has_key_sha256 && header_and_key_check_needed_[0])
1297 CheckHeaderAndKey(0); 1362 CheckHeaderAndKey(0);
1298 1363
1299 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS); 1364 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
1300 return net::OK; 1365 return net::OK;
1301 } 1366 }
1302 1367
1303 int SimpleSynchronousEntry::GetEOFRecordData(int index, 1368 bool SimpleSynchronousEntry::ReadFromFileOrPrefetched(char* prefetch_buf,
1369 int file_size,
1370 int offset,
1371 int size,
1372 char* dest) {
1373 if (!prefetch_buf) {
1374 return files_[0].Read(offset, dest, size) == size;
1375 } else {
1376 if (offset < 0 || size < 0)
1377 return false;
1378 base::CheckedNumeric<int> end =
1379 base::CheckedNumeric<int>(offset) + size - 1;
1380 if (!end.IsValid())
1381 return false;
1382 if (offset >= file_size || end.ValueOrDie() >= file_size)
pasko 2017/07/18 13:46:31 feel free to insert a DCHECK for the overflow, but
morlovich 2017/07/18 14:32:31 See the conditional in line 1380, this can't actua
pasko 2017/07/19 16:28:26 Ah, missed that. AssignIfValid() looks lengthy, I'
Maks Orlovich 2017/07/21 18:37:33 Ended up with AssignIfValid anyway, but I think it
1383 return false;
1384
1385 memcpy(dest, prefetch_buf + offset, size);
1386 return true;
1387 }
1388 }
1389
1390 int SimpleSynchronousEntry::GetEOFRecordData(char* prefetch_buf,
1391 int file_size,
1392 int stream_index,
1304 const SimpleEntryStat& entry_stat, 1393 const SimpleEntryStat& entry_stat,
1305 bool* out_has_crc32, 1394 SimpleFileEOF* eof_record) {
1306 bool* out_has_key_sha256, 1395 int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
1307 uint32_t* out_crc32, 1396 int file_index = GetFileIndexFromStreamIndex(stream_index);
1308 int32_t* out_data_size) const { 1397
pasko 2017/07/18 13:46:31 Following how the state migrates from disk to the
morlovich 2017/07/18 14:32:31 So my idea was that ReadFromFileOrPrefetched would
pasko 2017/07/19 16:28:26 Yeah, I understand your way to put ReadFromFileOrP
1309 SimpleFileEOF eof_record; 1398 // Should only have prefetch_buf when reading things in file 0.
1310 int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), index); 1399 DCHECK(file_index == 0 || !prefetch_buf);
1311 int file_index = GetFileIndexFromStreamIndex(index); 1400 bool ok;
1312 File* file = const_cast<File*>(&files_[file_index]); 1401 if (prefetch_buf)
1313 if (file->Read(file_offset, reinterpret_cast<char*>(&eof_record), 1402 ok = ReadFromFileOrPrefetched(prefetch_buf, file_size, file_offset,
1314 sizeof(eof_record)) != 1403 sizeof(SimpleFileEOF),
1315 sizeof(eof_record)) { 1404 reinterpret_cast<char*>(eof_record));
1405 else
1406 // Need to support files_[1], so can't use ReadFromFileOrPrefetched
1407 // in this case.
1408 ok = files_[file_index].Read(
1409 file_offset, reinterpret_cast<char*>(eof_record),
1410 sizeof(SimpleFileEOF)) == sizeof(SimpleFileEOF);
1411
1412 if (!ok) {
1316 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE); 1413 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE);
1317 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; 1414 return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
1318 } 1415 }
1319 1416
1320 if (eof_record.final_magic_number != kSimpleFinalMagicNumber) { 1417 if (eof_record->final_magic_number != kSimpleFinalMagicNumber) {
1321 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH); 1418 RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH);
1322 DVLOG(1) << "EOF record had bad magic number."; 1419 DVLOG(1) << "EOF record had bad magic number.";
1323 return net::ERR_CACHE_CHECKSUM_READ_FAILURE; 1420 return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
1324 } 1421 }
1325 1422
1326 if (!base::IsValueInRangeForNumericType<int32_t>(eof_record.stream_size)) 1423 if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size))
1327 return net::ERR_FAILED; 1424 return net::ERR_FAILED;
1328 1425 SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_,
1329 *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) == 1426 (eof_record->flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
1330 SimpleFileEOF::FLAG_HAS_CRC32; 1427 SimpleFileEOF::FLAG_HAS_CRC32);
1331 *out_has_key_sha256 =
1332 (eof_record.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
1333 SimpleFileEOF::FLAG_HAS_KEY_SHA256;
1334 *out_crc32 = eof_record.data_crc32;
1335 *out_data_size = eof_record.stream_size;
1336 SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32);
1337 return net::OK; 1428 return net::OK;
1338 } 1429 }
1339 1430
1340 void SimpleSynchronousEntry::Doom() const { 1431 void SimpleSynchronousEntry::Doom() const {
1341 DeleteFilesForEntryHash(path_, entry_hash_); 1432 DeleteFilesForEntryHash(path_, entry_hash_);
1342 } 1433 }
1343 1434
1344 // static 1435 // static
1345 bool SimpleSynchronousEntry::DeleteFileForEntryHash(const FilePath& path, 1436 bool SimpleSynchronousEntry::DeleteFileForEntryHash(const FilePath& path,
1346 const uint64_t entry_hash, 1437 const uint64_t entry_hash,
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
1651 range.offset = offset; 1742 range.offset = offset;
1652 range.length = len; 1743 range.length = len;
1653 range.data_crc32 = data_crc32; 1744 range.data_crc32 = data_crc32;
1654 range.file_offset = data_file_offset; 1745 range.file_offset = data_file_offset;
1655 sparse_ranges_.insert(std::make_pair(offset, range)); 1746 sparse_ranges_.insert(std::make_pair(offset, range));
1656 1747
1657 return true; 1748 return true;
1658 } 1749 }
1659 1750
1660 } // namespace disk_cache 1751 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698