1 // Copyright 2013 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_DISK_CACHE_SIMPLE_SIMPLE_SYNCHRONOUS_ENTRY_H_ 6 #define NET_DISK_CACHE_SIMPLE_SIMPLE_SYNCHRONOUS_ENTRY_H_ 7 8 #include <stdint.h> 9 10 #include <algorithm> 11 #include <map> 12 #include <memory> 13 #include <string> 14 #include <utility> 15 #include <vector> 16 17 #include "base/feature_list.h" 18 #include "base/files/file.h" 19 #include "base/files/file_path.h" 20 #include "base/gtest_prod_util.h" 21 #include "base/memory/raw_ptr.h" 22 #include "base/memory/scoped_refptr.h" 23 #include "base/strings/string_piece_forward.h" 24 #include "base/time/time.h" 25 #include "net/base/cache_type.h" 26 #include "net/base/net_errors.h" 27 #include "net/base/net_export.h" 28 #include "net/disk_cache/simple/simple_entry_format.h" 29 #include "net/disk_cache/simple/simple_file_tracker.h" 30 #include "net/disk_cache/simple/simple_histogram_enums.h" 31 32 namespace net { 33 class GrowableIOBuffer; 34 class IOBuffer; 35 } 36 37 FORWARD_DECLARE_TEST(DiskCacheBackendTest, SimpleCacheEnumerationLongKeys); 38 39 namespace disk_cache { 40 41 class BackendFileOperations; 42 class UnboundBackendFileOperations; 43 44 NET_EXPORT_PRIVATE BASE_DECLARE_FEATURE(kSimpleCachePrefetchExperiment); 45 NET_EXPORT_PRIVATE extern const char kSimpleCacheFullPrefetchBytesParam[]; 46 NET_EXPORT_PRIVATE extern const char 47 kSimpleCacheTrailerPrefetchSpeculativeBytesParam[]; 48 49 // Returns how large a file would get prefetched on reading the entry. 50 // If the experiment is disabled, returns 0. 51 NET_EXPORT_PRIVATE int GetSimpleCachePrefetchSize(); 52 53 class SimpleSynchronousEntry; 54 struct RangeResult; 55 56 // This class handles the passing of data about the entry between 57 // SimpleEntryImplementation and SimpleSynchronousEntry and the computation of 58 // file offsets based on the data size for all streams. 59 class NET_EXPORT_PRIVATE SimpleEntryStat { 60 public: 61 SimpleEntryStat(base::Time last_used, 62 base::Time last_modified, 63 const int32_t data_size[], 64 const int32_t sparse_data_size); 65 66 int GetOffsetInFile(size_t key_length, int offset, int stream_index) const; 67 int GetEOFOffsetInFile(size_t key_length, int stream_index) const; 68 int GetLastEOFOffsetInFile(size_t key_length, int file_index) const; 69 int64_t GetFileSize(size_t key_length, int file_index) const; 70 last_used()71 base::Time last_used() const { return last_used_; } last_modified()72 base::Time last_modified() const { return last_modified_; } set_last_used(base::Time last_used)73 void set_last_used(base::Time last_used) { last_used_ = last_used; } set_last_modified(base::Time last_modified)74 void set_last_modified(base::Time last_modified) { 75 last_modified_ = last_modified; 76 } 77 data_size(int stream_index)78 int32_t data_size(int stream_index) const { return data_size_[stream_index]; } set_data_size(int stream_index,int data_size)79 void set_data_size(int stream_index, int data_size) { 80 data_size_[stream_index] = data_size; 81 } 82 sparse_data_size()83 int32_t sparse_data_size() const { return sparse_data_size_; } set_sparse_data_size(int32_t sparse_data_size)84 void set_sparse_data_size(int32_t sparse_data_size) { 85 sparse_data_size_ = sparse_data_size; 86 } 87 88 private: 89 base::Time last_used_; 90 base::Time last_modified_; 91 int32_t data_size_[kSimpleEntryStreamCount]; 92 int32_t sparse_data_size_; 93 }; 94 95 struct SimpleStreamPrefetchData { 96 SimpleStreamPrefetchData(); 97 ~SimpleStreamPrefetchData(); 98 99 scoped_refptr<net::GrowableIOBuffer> data; 100 uint32_t stream_crc32; 101 }; 102 103 struct SimpleEntryCreationResults { 104 explicit SimpleEntryCreationResults(SimpleEntryStat entry_stat); 105 ~SimpleEntryCreationResults(); 106 107 raw_ptr<SimpleSynchronousEntry> sync_entry; 108 // This is set when `sync_entry` is null. 109 std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations; 110 111 // Expectation is that [0] will always be filled in, but [1] might not be. 112 SimpleStreamPrefetchData stream_prefetch_data[2]; 113 114 SimpleEntryStat entry_stat; 115 int32_t computed_trailer_prefetch_size = -1; 116 int result = net::OK; 117 bool created = false; 118 }; 119 120 struct SimpleEntryCloseResults { 121 int32_t estimated_trailer_prefetch_size = -1; 122 }; 123 124 // Worker thread interface to the very simple cache. This interface is not 125 // thread safe, and callers must ensure that it is only ever accessed from 126 // a single thread between synchronization points. 127 class SimpleSynchronousEntry { 128 public: 129 struct CRCRecord { 130 CRCRecord(); 131 CRCRecord(int index_p, bool has_crc32_p, uint32_t data_crc32_p); 132 133 int index; 134 bool has_crc32; 135 uint32_t data_crc32; 136 }; 137 138 struct ReadRequest { 139 // Also sets request_update_crc to false. 140 ReadRequest(int index_p, int offset_p, int buf_len_p); 141 int index; 142 int offset; 143 int buf_len; 144 145 // Partial CRC of data immediately preceeding this read. Only relevant if 146 // request_update_crc is set. 147 uint32_t previous_crc32; 148 bool request_update_crc = false; 149 bool request_verify_crc; // only relevant if request_update_crc is set 150 }; 151 152 struct ReadResult { 153 ReadResult() = default; 154 int result; 155 uint32_t updated_crc32; // only relevant if crc_updated set 156 bool crc_updated = false; 157 }; 158 159 struct WriteRequest { 160 WriteRequest(int index_p, 161 int offset_p, 162 int buf_len_p, 163 uint32_t previous_crc32_p, 164 bool truncate_p, 165 bool doomed_p, 166 bool request_update_crc_p); 167 int index; 168 int offset; 169 int buf_len; 170 uint32_t previous_crc32; 171 bool truncate; 172 bool doomed; 173 bool request_update_crc; 174 }; 175 176 struct WriteResult { 177 WriteResult() = default; 178 int result; 179 uint32_t updated_crc32; // only relevant if crc_updated set 180 bool crc_updated = false; 181 }; 182 183 struct SparseRequest { 184 SparseRequest(int64_t sparse_offset_p, int buf_len_p); 185 186 int64_t sparse_offset; 187 int buf_len; 188 }; 189 190 NET_EXPORT_PRIVATE SimpleSynchronousEntry( 191 net::CacheType cache_type, 192 const base::FilePath& path, 193 const std::string& key, 194 uint64_t entry_hash, 195 SimpleFileTracker* simple_file_tracker, 196 std::unique_ptr<UnboundBackendFileOperations> file_operations, 197 int32_t stream_0_size); 198 199 // Like Entry, the SimpleSynchronousEntry self releases when Close() is 200 // called, but sometimes temporary ones are kept in unique_ptr. 201 NET_EXPORT_PRIVATE ~SimpleSynchronousEntry(); 202 203 // Opens a disk cache entry on disk. The |key| parameter is optional, if empty 204 // the operation may be slower. The |entry_hash| parameter is required. 205 static void OpenEntry( 206 net::CacheType cache_type, 207 const base::FilePath& path, 208 const std::string& key, 209 uint64_t entry_hash, 210 SimpleFileTracker* file_tracker, 211 std::unique_ptr<UnboundBackendFileOperations> file_operations, 212 int32_t trailer_prefetch_size, 213 SimpleEntryCreationResults* out_results); 214 215 static void CreateEntry( 216 net::CacheType cache_type, 217 const base::FilePath& path, 218 const std::string& key, 219 uint64_t entry_hash, 220 SimpleFileTracker* file_tracker, 221 std::unique_ptr<UnboundBackendFileOperations> file_operations, 222 SimpleEntryCreationResults* out_results); 223 224 static void OpenOrCreateEntry( 225 net::CacheType cache_type, 226 const base::FilePath& path, 227 const std::string& key, 228 uint64_t entry_hash, 229 OpenEntryIndexEnum index_state, 230 bool optimistic_create, 231 SimpleFileTracker* file_tracker, 232 std::unique_ptr<UnboundBackendFileOperations> file_operations, 233 int32_t trailer_prefetch_size, 234 SimpleEntryCreationResults* out_results); 235 236 // Renames the entry on the file system, making it no longer possible to open 237 // it again, but allowing operations to continue to be executed through that 238 // instance. The renamed file will be removed once the entry is closed. 239 // Returns a net error code. 240 int Doom(); 241 242 // Deletes an entry from the file system. This variant should only be used 243 // if there is no actual open instance around, as it doesn't account for 244 // possibility of it having been renamed to a non-standard name. 245 static int DeleteEntryFiles( 246 const base::FilePath& path, 247 net::CacheType cache_type, 248 uint64_t entry_hash, 249 std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations); 250 251 // Like |DeleteEntryFiles()| above, except that it truncates the entry files 252 // rather than deleting them. Used when dooming entries after the backend has 253 // shutdown. See implementation of |SimpleEntryImpl::DoomEntryInternal()| for 254 // more. 255 static int TruncateEntryFiles( 256 const base::FilePath& path, 257 uint64_t entry_hash, 258 std::unique_ptr<UnboundBackendFileOperations> file_operations); 259 260 // Like |DeleteEntryFiles()| above. Deletes all entries corresponding to the 261 // |key_hashes|. Succeeds only when all entries are deleted. Returns a net 262 // error code. 263 static int DeleteEntrySetFiles( 264 const std::vector<uint64_t>* key_hashes, 265 const base::FilePath& path, 266 std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations); 267 268 // N.B. ReadData(), WriteData(), CheckEOFRecord(), ReadSparseData(), 269 // WriteSparseData() and Close() may block on IO. 270 // 271 // All of these methods will put the //net return value into |*out_result|. 272 273 void ReadData(const ReadRequest& in_entry_op, 274 SimpleEntryStat* entry_stat, 275 net::IOBuffer* out_buf, 276 ReadResult* out_result); 277 void WriteData(const WriteRequest& in_entry_op, 278 net::IOBuffer* in_buf, 279 SimpleEntryStat* out_entry_stat, 280 WriteResult* out_write_result); 281 int CheckEOFRecord(BackendFileOperations* file_operations, 282 base::File* file, 283 int stream_index, 284 const SimpleEntryStat& entry_stat, 285 uint32_t expected_crc32); 286 287 void ReadSparseData(const SparseRequest& in_entry_op, 288 net::IOBuffer* out_buf, 289 base::Time* out_last_used, 290 int* out_result); 291 void WriteSparseData(const SparseRequest& in_entry_op, 292 net::IOBuffer* in_buf, 293 uint64_t max_sparse_data_size, 294 SimpleEntryStat* out_entry_stat, 295 int* out_result); 296 void GetAvailableRange(const SparseRequest& in_entry_op, 297 RangeResult* out_result); 298 299 // Close all streams, and add write EOF records to streams indicated by the 300 // CRCRecord entries in |crc32s_to_write|. 301 void Close(const SimpleEntryStat& entry_stat, 302 std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write, 303 net::GrowableIOBuffer* stream_0_data, 304 SimpleEntryCloseResults* out_results); 305 path()306 const base::FilePath& path() const { return path_; } key()307 std::string key() const { return key_; } entry_file_key()308 const SimpleFileTracker::EntryFileKey& entry_file_key() const { 309 return entry_file_key_; 310 } 311 312 NET_EXPORT_PRIVATE base::FilePath GetFilenameForSubfile( 313 SimpleFileTracker::SubFile sub_file) const; 314 computed_trailer_prefetch_size()315 int32_t computed_trailer_prefetch_size() const { 316 return computed_trailer_prefetch_size_; 317 } 318 319 private: 320 FRIEND_TEST_ALL_PREFIXES(::DiskCacheBackendTest, 321 SimpleCacheEnumerationLongKeys); 322 friend class SimpleFileTrackerTest; 323 class PrefetchData; 324 class ScopedFileOperationsBinding; 325 326 enum FileRequired { 327 FILE_NOT_REQUIRED, 328 FILE_REQUIRED 329 }; 330 331 struct SparseRange { 332 int64_t offset; 333 int64_t length; 334 uint32_t data_crc32; 335 int64_t file_offset; 336 337 bool operator<(const SparseRange& other) const { 338 return offset < other.offset; 339 } 340 }; 341 342 // When opening an entry without knowing the key, the header must be read 343 // without knowing the size of the key. This is how much to read initially, to 344 // make it likely the entire key is read. 345 static const size_t kInitialHeaderRead = 64 * 1024; 346 347 // Tries to open one of the cache entry files. Succeeds if the open succeeds 348 // or if the file was not found and is allowed to be omitted if the 349 // corresponding stream is empty. 350 bool MaybeOpenFile(BackendFileOperations* file_operations, 351 int file_index, 352 base::File::Error* out_error); 353 // Creates one of the cache entry files if necessary. If the file is allowed 354 // to be omitted if the corresponding stream is empty, and if |file_required| 355 // is FILE_NOT_REQUIRED, then the file is not created; otherwise, it is. 356 bool MaybeCreateFile(BackendFileOperations* file_operations, 357 int file_index, 358 FileRequired file_required, 359 base::File::Error* out_error); 360 bool OpenFiles(BackendFileOperations* file_operations, 361 SimpleEntryStat* out_entry_stat); 362 bool CreateFiles(BackendFileOperations* file_operations, 363 SimpleEntryStat* out_entry_stat); 364 void CloseFile(BackendFileOperations* file_operations, int index); 365 void CloseFiles(); 366 367 // Read the header and key at the beginning of the file, and validate that 368 // they are correct. If this entry was opened with a key, the key is checked 369 // for a match. If not, then the |key_| member is set based on the value in 370 // this header. Records histograms if any check is failed. 371 bool CheckHeaderAndKey(base::File* file, int file_index); 372 373 // Returns a net error, i.e. net::OK on success. 374 int InitializeForOpen(BackendFileOperations* file_operations, 375 SimpleEntryStat* out_entry_stat, 376 SimpleStreamPrefetchData stream_prefetch_data[2]); 377 378 // Writes the header and key to a newly-created stream file. |index| is the 379 // index of the stream. Returns true on success; returns false and failure. 380 bool InitializeCreatedFile(BackendFileOperations* file_operations, int index); 381 382 // Returns a net error, including net::OK on success and net::FILE_EXISTS 383 // when the entry already exists. 384 int InitializeForCreate(BackendFileOperations* file_operations, 385 SimpleEntryStat* out_entry_stat); 386 387 // Allocates and fills a buffer with stream 0 data in |stream_0_data|, then 388 // checks its crc32. May also optionally read in |stream_1_data| and its 389 // crc, but might decide not to. 390 int ReadAndValidateStream0AndMaybe1( 391 BackendFileOperations* file_operations, 392 int file_size, 393 SimpleEntryStat* out_entry_stat, 394 SimpleStreamPrefetchData stream_prefetch_data[2]); 395 396 // Reads the EOF record located at |file_offset| in file |file_index|, 397 // with |file_0_prefetch| potentially having prefetched file 0 content. 398 // Puts the result into |*eof_record| and sanity-checks it. 399 // Returns net status, and records any failures to UMA. 400 int GetEOFRecordData(base::File* file, 401 PrefetchData* prefetch_data, 402 int file_index, 403 int file_offset, 404 SimpleFileEOF* eof_record); 405 406 // Reads either from |file_0_prefetch| or |file|. 407 // Range-checks all the in-memory reads. 408 bool ReadFromFileOrPrefetched(base::File* file, 409 PrefetchData* prefetch_data, 410 int file_index, 411 int offset, 412 int size, 413 char* dest); 414 415 // Extracts out the payload of stream |stream_index|, reading either from 416 // |file_0_prefetch|, if available, or |file|. |entry_stat| will be used to 417 // determine file layout, though |extra_size| additional bytes will be read 418 // past the stream payload end. 419 // 420 // |*stream_data| will be pointed to a fresh buffer with the results, 421 // and |*out_crc32| will get the checksum, which will be verified against 422 // |eof_record|. 423 int PreReadStreamPayload(base::File* file, 424 PrefetchData* prefetch_data, 425 int stream_index, 426 int extra_size, 427 const SimpleEntryStat& entry_stat, 428 const SimpleFileEOF& eof_record, 429 SimpleStreamPrefetchData* out); 430 431 // Opens the sparse data file and scans it if it exists. 432 bool OpenSparseFileIfExists(BackendFileOperations* file_operations, 433 int32_t* out_sparse_data_size); 434 435 // Creates and initializes the sparse data file. 436 bool CreateSparseFile(BackendFileOperations* file_operations); 437 438 // Closes the sparse data file. 439 void CloseSparseFile(BackendFileOperations* file_operations); 440 441 // Writes the header to the (newly-created) sparse file. 442 bool InitializeSparseFile(base::File* file); 443 444 // Removes all but the header of the sparse file. 445 bool TruncateSparseFile(base::File* sparse_file); 446 447 // Scans the existing ranges in the sparse file. Populates |sparse_ranges_| 448 // and sets |*out_sparse_data_size| to the total size of all the ranges (not 449 // including headers). 450 bool ScanSparseFile(base::File* sparse_file, int32_t* out_sparse_data_size); 451 452 // Reads from a single sparse range. If asked to read the entire range, also 453 // verifies the CRC32. 454 bool ReadSparseRange(base::File* sparse_file, 455 const SparseRange* range, 456 int offset, 457 int len, 458 char* buf); 459 460 // Writes to a single (existing) sparse range. If asked to write the entire 461 // range, also updates the CRC32; otherwise, invalidates it. 462 bool WriteSparseRange(base::File* sparse_file, 463 SparseRange* range, 464 int offset, 465 int len, 466 const char* buf); 467 468 // Appends a new sparse range to the sparse data file. 469 bool AppendSparseRange(base::File* sparse_file, 470 int64_t offset, 471 int len, 472 const char* buf); 473 474 static int DeleteEntryFilesInternal(const base::FilePath& path, 475 net::CacheType cache_type, 476 uint64_t entry_hash, 477 BackendFileOperations* file_operations); 478 479 static bool DeleteFileForEntryHash(const base::FilePath& path, 480 uint64_t entry_hash, 481 int file_index, 482 BackendFileOperations* file_operations); 483 static bool DeleteFilesForEntryHash(const base::FilePath& path, 484 uint64_t entry_hash, 485 BackendFileOperations* file_operations); 486 static bool TruncateFilesForEntryHash(const base::FilePath& path, 487 uint64_t entry_hash, 488 BackendFileOperations* file_operations); 489 490 int DoomInternal(BackendFileOperations* file_operations); 491 492 base::FilePath GetFilenameFromFileIndex(int file_index) const; 493 sparse_file_open()494 bool sparse_file_open() const { return sparse_file_open_; } 495 496 const net::CacheType cache_type_; 497 const base::FilePath path_; 498 SimpleFileTracker::EntryFileKey entry_file_key_; 499 std::string key_; 500 501 bool have_open_files_ = false; 502 bool initialized_ = false; 503 504 // Normally false. This is set to true when an entry is opened without 505 // checking the file headers. Any subsequent read will perform the check 506 // before completing. 507 bool header_and_key_check_needed_[kSimpleEntryNormalFileCount] = { 508 false, 509 }; 510 511 raw_ptr<SimpleFileTracker> file_tracker_; 512 513 // An interface to allow file operations. This is in an "unbound" state 514 // because each operation can run on different sequence from each other. 515 // Each operation can convert this to a BackendFileOperations with calling 516 // Bind(), relying on that at most one operation runs at a time. 517 std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations_; 518 519 // The number of trailing bytes in file 0 that we believe should be 520 // prefetched in order to read the EOF record and stream 0. This is 521 // a hint from the index and may not be exactly right. -1 if we 522 // don't have a hinted value. 523 int32_t trailer_prefetch_size_; 524 525 // The exact number of trailing bytes that were needed to read the 526 // EOF record and stream 0 when the entry was actually opened. This 527 // may be different from the trailer_prefetch_size_ hint and is 528 // propagated back to the index in order to optimize the next open. 529 int32_t computed_trailer_prefetch_size_ = -1; 530 531 // True if the corresponding stream is empty and therefore no on-disk file 532 // was created to store it. 533 bool empty_file_omitted_[kSimpleEntryNormalFileCount]; 534 535 typedef std::map<int64_t, SparseRange> SparseRangeOffsetMap; 536 typedef SparseRangeOffsetMap::iterator SparseRangeIterator; 537 SparseRangeOffsetMap sparse_ranges_; 538 bool sparse_file_open_ = false; 539 540 // Offset of the end of the sparse file (where the next sparse range will be 541 // written). 542 int64_t sparse_tail_offset_; 543 }; 544 545 } // namespace disk_cache 546 547 #endif // NET_DISK_CACHE_SIMPLE_SIMPLE_SYNCHRONOUS_ENTRY_H_ 548