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