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