1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104 |
- // 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/compiler_specific.h"
- #include "base/containers/stack_container.h"
- #include "base/files/file_util.h"
- #include "base/hash/hash.h"
- #include "base/location.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/metrics/field_trial_params.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/metrics/histogram_macros_local.h"
- #include "base/numerics/checked_math.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/strings/string_piece.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/timer/elapsed_timer.h"
- #include "crypto/secure_hash.h"
- #include "net/base/hash_value.h"
- #include "net/base/io_buffer.h"
- #include "net/base/net_errors.h"
- #include "net/disk_cache/cache_util.h"
- #include "net/disk_cache/simple/simple_backend_version.h"
- #include "net/disk_cache/simple/simple_histogram_enums.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::FilePath;
- using base::Time;
- namespace disk_cache {
- namespace {
- void RecordSyncOpenResult(net::CacheType cache_type, OpenEntryResult result) {
- DCHECK_LT(result, OPEN_ENTRY_MAX);
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncOpenResult", cache_type, result,
- OPEN_ENTRY_MAX);
- }
- void RecordWriteResult(net::CacheType cache_type, SyncWriteResult result) {
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncWriteResult", cache_type, result,
- SYNC_WRITE_RESULT_MAX);
- }
- void RecordCheckEOFResult(net::CacheType cache_type, CheckEOFResult result) {
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCheckEOFResult", cache_type, result,
- CHECK_EOF_RESULT_MAX);
- }
- void RecordCloseResult(net::CacheType cache_type, CloseResult result) {
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCloseResult", cache_type, result,
- CLOSE_RESULT_MAX);
- }
- void RecordOpenPrefetchMode(net::CacheType cache_type, OpenPrefetchMode mode) {
- SIMPLE_CACHE_UMA(ENUMERATION, "SyncOpenPrefetchMode", cache_type, mode,
- OPEN_PREFETCH_MAX);
- }
- void RecordDiskCreateLatency(net::CacheType cache_type, base::TimeDelta delay) {
- SIMPLE_CACHE_LOCAL(TIMES, "DiskCreateLatency", cache_type, delay);
- }
- bool CanOmitEmptyFile(int file_index) {
- DCHECK_GE(file_index, 0);
- DCHECK_LT(file_index, kSimpleEntryNormalFileCount);
- return file_index == simple_util::GetFileIndexFromStreamIndex(2);
- }
- bool TruncatePath(const FilePath& filename_to_truncate,
- BackendFileOperations* file_operations) {
- int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
- base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
- base::File file_to_truncate =
- file_operations->OpenFile(filename_to_truncate, flags);
- if (!file_to_truncate.IsValid())
- return false;
- if (!file_to_truncate.SetLength(0))
- return false;
- return true;
- }
- void CalculateSHA256OfKey(const std::string& key,
- net::SHA256HashValue* out_hash_value) {
- std::unique_ptr<crypto::SecureHash> hash(
- crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- hash->Update(key.data(), key.size());
- hash->Finish(out_hash_value, sizeof(*out_hash_value));
- }
- SimpleFileTracker::SubFile SubFileForFileIndex(int file_index) {
- DCHECK_GT(kSimpleEntryNormalFileCount, file_index);
- return file_index == 0 ? SimpleFileTracker::SubFile::FILE_0
- : SimpleFileTracker::SubFile::FILE_1;
- }
- int FileIndexForSubFile(SimpleFileTracker::SubFile sub_file) {
- DCHECK_NE(SimpleFileTracker::SubFile::FILE_SPARSE, sub_file);
- return sub_file == SimpleFileTracker::SubFile::FILE_0 ? 0 : 1;
- }
- } // namespace
- // Helper class to track a range of data prefetched from a file.
- class SimpleSynchronousEntry::PrefetchData final {
- public:
- explicit PrefetchData(size_t file_size)
- : file_size_(file_size), earliest_requested_offset_(file_size) {}
- // Returns true if the specified range within the file has been completely
- // prefetched. Returns false if any part of the range has not been
- // prefetched.
- bool HasData(size_t offset, size_t length) {
- size_t end = 0;
- if (!base::CheckAdd(offset, length).AssignIfValid(&end))
- return false;
- UpdateEarliestOffset(offset);
- return offset >= offset_in_file_ &&
- end <= (offset_in_file_ + buffer_->size());
- }
- // Read the given range out of the prefetch buffer into the target
- // destination buffer. If the range is not wholely contained within
- // the prefetch buffer than no data will be written to the target
- // buffer. Returns true if the range has been copied.
- bool ReadData(size_t offset, size_t length, char* dest) {
- DCHECK(dest);
- if (!length)
- return true;
- if (!HasData(offset, length))
- return false;
- DCHECK(offset >= offset_in_file_);
- size_t buffer_offset = offset - offset_in_file_;
- memcpy(dest, buffer_->data() + buffer_offset, length);
- return true;
- }
- // Populate the prefetch buffer from the given file and range. Returns
- // true if the data is successfully read.
- bool PrefetchFromFile(SimpleFileTracker::FileHandle* file,
- size_t offset,
- size_t length) {
- DCHECK(file);
- if (!buffer_->empty())
- return false;
- buffer_->resize(length);
- if (file->get()->Read(offset, buffer_->data(), length) !=
- static_cast<int>(length)) {
- buffer_->resize(0);
- return false;
- }
- offset_in_file_ = offset;
- return true;
- }
- // Return how much trailing data has been requested via HasData() or
- // ReadData(). The intent is that this value can be used to tune
- // future prefetching behavior.
- size_t GetDesiredTrailerPrefetchSize() const {
- return file_size_ - earliest_requested_offset_;
- }
- private:
- // Track the earliest offset requested in order to return an optimal trailer
- // prefetch amount in GetDesiredTrailerPrefetchSize().
- void UpdateEarliestOffset(size_t offset) {
- DCHECK_LE(earliest_requested_offset_, file_size_);
- earliest_requested_offset_ = std::min(earliest_requested_offset_, offset);
- }
- const size_t file_size_;
- // Prefer to read the prefetch data into a stack buffer to minimize
- // memory pressure on the OS disk cache.
- base::StackVector<char, 1024> buffer_;
- size_t offset_in_file_ = 0;
- size_t earliest_requested_offset_;
- };
- class SimpleSynchronousEntry::ScopedFileOperationsBinding final {
- public:
- ScopedFileOperationsBinding(SimpleSynchronousEntry* owner,
- BackendFileOperations** file_operations)
- : owner_(owner),
- file_operations_(owner->unbound_file_operations_->Bind(
- base::SequencedTaskRunnerHandle::Get())) {
- *file_operations = file_operations_.get();
- }
- ~ScopedFileOperationsBinding() {
- owner_->unbound_file_operations_ = file_operations_->Unbind();
- }
- private:
- const raw_ptr<SimpleSynchronousEntry> owner_;
- std::unique_ptr<BackendFileOperations> file_operations_;
- };
- using simple_util::GetEntryHashKey;
- using simple_util::GetFilenameFromEntryFileKeyAndFileIndex;
- using simple_util::GetSparseFilenameFromEntryFileKey;
- using simple_util::GetHeaderSize;
- using simple_util::GetDataSizeFromFileSize;
- using simple_util::GetFileSizeFromDataSize;
- using simple_util::GetFileIndexFromStreamIndex;
- const base::Feature kSimpleCachePrefetchExperiment = {
- "SimpleCachePrefetchExperiment2", base::FEATURE_DISABLED_BY_DEFAULT};
- const char kSimpleCacheFullPrefetchBytesParam[] = "FullPrefetchBytes";
- constexpr base::FeatureParam<int> kSimpleCacheFullPrefetchSize{
- &kSimpleCachePrefetchExperiment, kSimpleCacheFullPrefetchBytesParam, 0};
- const char kSimpleCacheTrailerPrefetchSpeculativeBytesParam[] =
- "TrailerPrefetchSpeculativeBytes";
- constexpr base::FeatureParam<int> kSimpleCacheTrailerPrefetchSpeculativeBytes{
- &kSimpleCachePrefetchExperiment,
- kSimpleCacheTrailerPrefetchSpeculativeBytesParam, 0};
- int GetSimpleCacheFullPrefetchSize() {
- return kSimpleCacheFullPrefetchSize.Get();
- }
- int GetSimpleCacheTrailerPrefetchSize(int hint_size) {
- if (hint_size > 0)
- return hint_size;
- return kSimpleCacheTrailerPrefetchSpeculativeBytes.Get();
- }
- SimpleEntryStat::SimpleEntryStat(base::Time last_used,
- base::Time last_modified,
- const int32_t data_size[],
- const int32_t 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_));
- }
- // These size methods all assume the presence of the SHA256 on stream zero,
- // since this version of the cache always writes it. In the read case, it may
- // not be present and these methods can't be relied upon.
- int SimpleEntryStat::GetOffsetInFile(size_t key_length,
- int offset,
- int stream_index) const {
- const size_t headers_size = sizeof(SimpleFileHeader) + key_length;
- const size_t additional_offset =
- stream_index == 0 ? data_size_[1] + sizeof(SimpleFileEOF) : 0;
- return headers_size + offset + additional_offset;
- }
- int SimpleEntryStat::GetEOFOffsetInFile(size_t key_length,
- int stream_index) const {
- size_t additional_offset;
- if (stream_index != 0)
- additional_offset = 0;
- else
- additional_offset = sizeof(net::SHA256HashValue);
- return additional_offset +
- GetOffsetInFile(key_length, data_size_[stream_index], stream_index);
- }
- int SimpleEntryStat::GetLastEOFOffsetInFile(size_t key_length,
- int stream_index) const {
- if (stream_index == 1)
- return GetEOFOffsetInFile(key_length, 0);
- return GetEOFOffsetInFile(key_length, stream_index);
- }
- int64_t SimpleEntryStat::GetFileSize(size_t key_length, int file_index) const {
- int32_t total_data_size;
- if (file_index == 0) {
- total_data_size = data_size_[0] + data_size_[1] +
- sizeof(net::SHA256HashValue) + sizeof(SimpleFileEOF);
- } else {
- total_data_size = data_size_[2];
- }
- return GetFileSizeFromDataSize(key_length, total_data_size);
- }
- SimpleStreamPrefetchData::SimpleStreamPrefetchData()
- : stream_crc32(crc32(0, Z_NULL, 0)) {}
- SimpleStreamPrefetchData::~SimpleStreamPrefetchData() = default;
- SimpleEntryCreationResults::SimpleEntryCreationResults(
- SimpleEntryStat entry_stat)
- : sync_entry(nullptr), entry_stat(entry_stat) {}
- SimpleEntryCreationResults::~SimpleEntryCreationResults() = default;
- SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1),
- has_crc32(false),
- data_crc32(0) {
- }
- SimpleSynchronousEntry::CRCRecord::CRCRecord(int index_p,
- bool has_crc32_p,
- uint32_t data_crc32_p)
- : index(index_p), has_crc32(has_crc32_p), data_crc32(data_crc32_p) {}
- SimpleSynchronousEntry::ReadRequest::ReadRequest(int index_p,
- int offset_p,
- int buf_len_p)
- : index(index_p), offset(offset_p), buf_len(buf_len_p) {}
- SimpleSynchronousEntry::WriteRequest::WriteRequest(int index_p,
- int offset_p,
- int buf_len_p,
- uint32_t previous_crc32_p,
- bool truncate_p,
- bool doomed_p,
- bool request_update_crc_p)
- : index(index_p),
- offset(offset_p),
- buf_len(buf_len_p),
- previous_crc32(previous_crc32_p),
- truncate(truncate_p),
- doomed(doomed_p),
- request_update_crc(request_update_crc_p) {}
- SimpleSynchronousEntry::SparseRequest::SparseRequest(int64_t 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 std::string& key,
- const uint64_t entry_hash,
- SimpleFileTracker* file_tracker,
- std::unique_ptr<UnboundBackendFileOperations> file_operations,
- int32_t trailer_prefetch_size,
- SimpleEntryCreationResults* out_results) {
- base::TimeTicks start_sync_open_entry = base::TimeTicks::Now();
- auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
- cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), trailer_prefetch_size);
- {
- BackendFileOperations* bound_file_operations = nullptr;
- ScopedFileOperationsBinding binding(sync_entry.get(),
- &bound_file_operations);
- out_results->result = sync_entry->InitializeForOpen(
- bound_file_operations, &out_results->entry_stat,
- out_results->stream_prefetch_data);
- }
- if (out_results->result != net::OK) {
- sync_entry->Doom();
- sync_entry->CloseFiles();
- out_results->sync_entry = nullptr;
- out_results->unbound_file_operations =
- std::move(sync_entry->unbound_file_operations_);
- out_results->stream_prefetch_data[0].data = nullptr;
- out_results->stream_prefetch_data[1].data = nullptr;
- return;
- }
- SIMPLE_CACHE_UMA(TIMES, "DiskOpenLatency", cache_type,
- base::TimeTicks::Now() - start_sync_open_entry);
- out_results->sync_entry = sync_entry.release();
- out_results->computed_trailer_prefetch_size =
- out_results->sync_entry->computed_trailer_prefetch_size();
- }
- // static
- void SimpleSynchronousEntry::CreateEntry(
- net::CacheType cache_type,
- const FilePath& path,
- const std::string& key,
- const uint64_t entry_hash,
- SimpleFileTracker* file_tracker,
- std::unique_ptr<UnboundBackendFileOperations> file_operations,
- SimpleEntryCreationResults* out_results) {
- DCHECK_EQ(entry_hash, GetEntryHashKey(key));
- base::TimeTicks start_sync_create_entry = base::TimeTicks::Now();
- auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
- cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), -1);
- {
- BackendFileOperations* bound_file_operations = nullptr;
- ScopedFileOperationsBinding binding(sync_entry.get(),
- &bound_file_operations);
- out_results->result = sync_entry->InitializeForCreate(
- bound_file_operations, &out_results->entry_stat);
- }
- if (out_results->result != net::OK) {
- if (out_results->result != net::ERR_FILE_EXISTS)
- sync_entry->Doom();
- sync_entry->CloseFiles();
- out_results->unbound_file_operations =
- std::move(sync_entry->unbound_file_operations_);
- out_results->sync_entry = nullptr;
- return;
- }
- out_results->sync_entry = sync_entry.release();
- out_results->created = true;
- RecordDiskCreateLatency(cache_type,
- base::TimeTicks::Now() - start_sync_create_entry);
- }
- // static
- void SimpleSynchronousEntry::OpenOrCreateEntry(
- net::CacheType cache_type,
- const FilePath& path,
- const std::string& key,
- const uint64_t entry_hash,
- OpenEntryIndexEnum index_state,
- bool optimistic_create,
- SimpleFileTracker* file_tracker,
- std::unique_ptr<UnboundBackendFileOperations> file_operations,
- int32_t trailer_prefetch_size,
- SimpleEntryCreationResults* out_results) {
- base::TimeTicks start = base::TimeTicks::Now();
- if (index_state == INDEX_MISS) {
- // Try to just create.
- auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
- cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), trailer_prefetch_size);
- {
- BackendFileOperations* bound_file_operations = nullptr;
- ScopedFileOperationsBinding binding(sync_entry.get(),
- &bound_file_operations);
- out_results->result = sync_entry->InitializeForCreate(
- bound_file_operations, &out_results->entry_stat);
- }
- switch (out_results->result) {
- case net::OK:
- out_results->sync_entry = sync_entry.release();
- out_results->created = true;
- RecordDiskCreateLatency(cache_type, base::TimeTicks::Now() - start);
- return;
- case net::ERR_FILE_EXISTS:
- // Our index was messed up.
- if (optimistic_create) {
- // In this case, ::OpenOrCreateEntry already returned claiming it made
- // a new entry. Try extra-hard to make that the actual case.
- sync_entry->Doom();
- sync_entry->CloseFiles();
- file_operations = std::move(sync_entry->unbound_file_operations_);
- sync_entry = nullptr;
- CreateEntry(cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), out_results);
- return;
- }
- // Otherwise can just try opening.
- break;
- default:
- // Trouble. Fail this time.
- sync_entry->Doom();
- sync_entry->CloseFiles();
- out_results->unbound_file_operations =
- std::move(sync_entry->unbound_file_operations_);
- return;
- }
- file_operations = std::move(sync_entry->unbound_file_operations_);
- }
- DCHECK(file_operations);
- // Try open, then if that fails create.
- OpenEntry(cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), trailer_prefetch_size, out_results);
- if (out_results->sync_entry)
- return;
- file_operations = std::move(out_results->unbound_file_operations);
- DCHECK(file_operations);
- CreateEntry(cache_type, path, key, entry_hash, file_tracker,
- std::move(file_operations), out_results);
- }
- // static
- int SimpleSynchronousEntry::DeleteEntryFiles(
- const FilePath& path,
- net::CacheType cache_type,
- uint64_t entry_hash,
- std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
- auto file_operations =
- unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
- return DeleteEntryFilesInternal(path, cache_type, entry_hash,
- file_operations.get());
- }
- // static
- int SimpleSynchronousEntry::DeleteEntryFilesInternal(
- const FilePath& path,
- net::CacheType cache_type,
- uint64_t entry_hash,
- BackendFileOperations* file_operations) {
- base::TimeTicks start = base::TimeTicks::Now();
- const bool deleted_well =
- DeleteFilesForEntryHash(path, entry_hash, file_operations);
- SIMPLE_CACHE_UMA(TIMES, "DiskDoomLatency", cache_type,
- base::TimeTicks::Now() - start);
- return deleted_well ? net::OK : net::ERR_FAILED;
- }
- int SimpleSynchronousEntry::Doom() {
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- return DoomInternal(file_operations);
- }
- int SimpleSynchronousEntry::DoomInternal(
- BackendFileOperations* file_operations) {
- if (entry_file_key_.doom_generation != 0u) {
- // Already doomed.
- return true;
- }
- if (have_open_files_) {
- base::TimeTicks start = base::TimeTicks::Now();
- bool ok = true;
- SimpleFileTracker::EntryFileKey orig_key = entry_file_key_;
- file_tracker_->Doom(this, &entry_file_key_);
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (!empty_file_omitted_[i]) {
- base::File::Error out_error;
- FilePath old_name = path_.AppendASCII(
- GetFilenameFromEntryFileKeyAndFileIndex(orig_key, i));
- FilePath new_name = path_.AppendASCII(
- GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, i));
- ok = file_operations->ReplaceFile(old_name, new_name, &out_error) && ok;
- }
- }
- if (sparse_file_open()) {
- base::File::Error out_error;
- FilePath old_name =
- path_.AppendASCII(GetSparseFilenameFromEntryFileKey(orig_key));
- FilePath new_name =
- path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
- ok = file_operations->ReplaceFile(old_name, new_name, &out_error) && ok;
- }
- SIMPLE_CACHE_UMA(TIMES, "DiskDoomLatency", cache_type_,
- base::TimeTicks::Now() - start);
- return ok ? net::OK : net::ERR_FAILED;
- } else {
- // No one has ever called Create or Open on us, so we don't have to worry
- // about being accessible to other ops after doom.
- return DeleteEntryFilesInternal(
- path_, cache_type_, entry_file_key_.entry_hash, file_operations);
- }
- }
- // static
- int SimpleSynchronousEntry::TruncateEntryFiles(
- const base::FilePath& path,
- uint64_t entry_hash,
- std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
- auto file_operations =
- unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
- const bool deleted_well =
- TruncateFilesForEntryHash(path, entry_hash, file_operations.get());
- return deleted_well ? net::OK : net::ERR_FAILED;
- }
- // static
- int SimpleSynchronousEntry::DeleteEntrySetFiles(
- const std::vector<uint64_t>* key_hashes,
- const FilePath& path,
- std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
- auto file_operations =
- unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
- const size_t did_delete_count =
- std::count_if(key_hashes->begin(), key_hashes->end(),
- [&path, &file_operations](const uint64_t& key_hash) {
- return SimpleSynchronousEntry::DeleteFilesForEntryHash(
- path, key_hash, file_operations.get());
- });
- return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED;
- }
- void SimpleSynchronousEntry::ReadData(const ReadRequest& in_entry_op,
- SimpleEntryStat* entry_stat,
- net::IOBuffer* out_buf,
- ReadResult* out_result) {
- DCHECK(initialized_);
- DCHECK_NE(0, in_entry_op.index);
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- int file_index = GetFileIndexFromStreamIndex(in_entry_op.index);
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations, this, SubFileForFileIndex(file_index));
- out_result->crc_updated = false;
- if (!file.IsOK() || (header_and_key_check_needed_[file_index] &&
- !CheckHeaderAndKey(file.get(), file_index))) {
- out_result->result = net::ERR_FAILED;
- DoomInternal(file_operations);
- return;
- }
- const int64_t file_offset = entry_stat->GetOffsetInFile(
- key_.size(), in_entry_op.offset, 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]);
- 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());
- if (in_entry_op.request_update_crc) {
- out_result->updated_crc32 = simple_util::IncrementalCrc32(
- in_entry_op.previous_crc32, out_buf->data(), bytes_read);
- out_result->crc_updated = true;
- // Verify checksum after last read, if we've been asked to.
- if (in_entry_op.request_verify_crc &&
- in_entry_op.offset + bytes_read ==
- entry_stat->data_size(in_entry_op.index)) {
- int checksum_result =
- CheckEOFRecord(file_operations, file.get(), in_entry_op.index,
- *entry_stat, out_result->updated_crc32);
- if (checksum_result < 0) {
- out_result->result = checksum_result;
- return;
- }
- }
- }
- }
- if (bytes_read >= 0) {
- out_result->result = bytes_read;
- } else {
- out_result->result = net::ERR_CACHE_READ_FAILURE;
- DoomInternal(file_operations);
- }
- }
- void SimpleSynchronousEntry::WriteData(const WriteRequest& in_entry_op,
- net::IOBuffer* in_buf,
- SimpleEntryStat* out_entry_stat,
- WriteResult* out_write_result) {
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- base::ElapsedTimer write_time;
- DCHECK(initialized_);
- DCHECK_NE(0, in_entry_op.index);
- int index = in_entry_op.index;
- int file_index = GetFileIndexFromStreamIndex(index);
- if (header_and_key_check_needed_[file_index] &&
- !empty_file_omitted_[file_index]) {
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations, this, SubFileForFileIndex(file_index));
- if (!file.IsOK() || !CheckHeaderAndKey(file.get(), file_index)) {
- out_write_result->result = net::ERR_FAILED;
- DoomInternal(file_operations);
- return;
- }
- }
- 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_t file_offset = out_entry_stat->GetOffsetInFile(
- key_.size(), 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_,
- SYNC_WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED);
- out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- base::File::Error error;
- if (!MaybeCreateFile(file_operations, file_index, FILE_REQUIRED, &error)) {
- RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_LAZY_CREATE_FAILURE);
- DoomInternal(file_operations);
- out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- if (!InitializeCreatedFile(file_operations, file_index)) {
- RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_LAZY_INITIALIZE_FAILURE);
- DoomInternal(file_operations);
- out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- }
- DCHECK(!empty_file_omitted_[file_index]);
- // This needs to be grabbed after the above block, since that's what may
- // create the file (for stream 2/file 1).
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations, this, SubFileForFileIndex(file_index));
- if (!file.IsOK()) {
- out_write_result->result = net::ERR_FAILED;
- DoomInternal(file_operations);
- return;
- }
- if (extending_by_write) {
- // The EOF record and the eventual stream afterward need to be zeroed out.
- const int64_t file_eof_offset =
- out_entry_stat->GetEOFOffsetInFile(key_.size(), index);
- if (!file->SetLength(file_eof_offset)) {
- RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_PRETRUNCATE_FAILURE);
- DoomInternal(file_operations);
- out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- }
- if (buf_len > 0) {
- if (file->Write(file_offset, in_buf->data(), buf_len) != buf_len) {
- RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_WRITE_FAILURE);
- DoomInternal(file_operations);
- out_write_result->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_.size(), index);
- if (!file->SetLength(file_eof_offset)) {
- RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_TRUNCATE_FAILURE);
- DoomInternal(file_operations);
- out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- }
- if (in_entry_op.request_update_crc && buf_len > 0) {
- out_write_result->updated_crc32 = simple_util::IncrementalCrc32(
- in_entry_op.previous_crc32, in_buf->data(), buf_len);
- out_write_result->crc_updated = true;
- }
- SIMPLE_CACHE_UMA(TIMES, "DiskWriteLatency", cache_type_,
- write_time.Elapsed());
- RecordWriteResult(cache_type_, SYNC_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_write_result->result = buf_len;
- }
- void SimpleSynchronousEntry::ReadSparseData(const SparseRequest& in_entry_op,
- net::IOBuffer* out_buf,
- base::Time* out_last_used,
- int* out_result) {
- DCHECK(initialized_);
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- int64_t offset = in_entry_op.sparse_offset;
- int buf_len = in_entry_op.buf_len;
- char* buf = out_buf->data();
- int read_so_far = 0;
- if (!sparse_file_open()) {
- *out_result = 0;
- return;
- }
- SimpleFileTracker::FileHandle sparse_file = file_tracker_->Acquire(
- file_operations, this, SimpleFileTracker::SubFile::FILE_SPARSE);
- if (!sparse_file.IsOK()) {
- DoomInternal(file_operations);
- *out_result = net::ERR_CACHE_READ_FAILURE;
- return;
- }
- // Find the first sparse range at or after the requested offset.
- auto 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, std::numeric_limits<int32_t>::max());
- DCHECK_GE(offset - found_range->offset, 0);
- DCHECK_LE(offset - found_range->offset,
- std::numeric_limits<int32_t>::max());
- 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(sparse_file.get(), found_range, net_offset,
- len_to_read, buf)) {
- DoomInternal(file_operations);
- *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(sparse_file.get(), found_range, 0, len_to_read,
- buf + read_so_far)) {
- DoomInternal(file_operations);
- *out_result = net::ERR_CACHE_READ_FAILURE;
- return;
- }
- read_so_far += len_to_read;
- ++it;
- }
- *out_result = read_so_far;
- }
- void SimpleSynchronousEntry::WriteSparseData(const SparseRequest& in_entry_op,
- net::IOBuffer* in_buf,
- uint64_t max_sparse_data_size,
- SimpleEntryStat* out_entry_stat,
- int* out_result) {
- DCHECK(initialized_);
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- int64_t 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(file_operations)) {
- DoomInternal(file_operations);
- *out_result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- SimpleFileTracker::FileHandle sparse_file = file_tracker_->Acquire(
- file_operations, this, SimpleFileTracker::SubFile::FILE_SPARSE);
- if (!sparse_file.IsOK()) {
- DoomInternal(file_operations);
- *out_result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- int32_t sparse_data_size = out_entry_stat->sparse_data_size();
- int32_t future_sparse_data_size;
- if (!base::CheckAdd(sparse_data_size, buf_len)
- .AssignIfValid(&future_sparse_data_size) ||
- future_sparse_data_size < 0) {
- DoomInternal(file_operations);
- *out_result = net::ERR_CACHE_WRITE_FAILURE;
- return;
- }
- // 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 (static_cast<uint64_t>(future_sparse_data_size) > max_sparse_data_size) {
- DVLOG(1) << "Truncating sparse data file (" << sparse_data_size << " + "
- << buf_len << " > " << max_sparse_data_size << ")";
- TruncateSparseFile(sparse_file.get());
- out_entry_stat->set_sparse_data_size(0);
- }
- auto 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, std::numeric_limits<int32_t>::max());
- DCHECK_GE(offset - found_range->offset, 0);
- DCHECK_LE(offset - found_range->offset,
- std::numeric_limits<int32_t>::max());
- 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(sparse_file.get(), found_range, net_offset,
- len_to_write, buf)) {
- DoomInternal(file_operations);
- *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(sparse_file.get(), offset + written_so_far,
- len_to_append, buf + written_so_far)) {
- DoomInternal(file_operations);
- *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(sparse_file.get(), found_range, 0, len_to_write,
- buf + written_so_far)) {
- DoomInternal(file_operations);
- *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(sparse_file.get(), offset + written_so_far,
- len_to_append, buf + written_so_far)) {
- DoomInternal(file_operations);
- *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_t 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 SparseRequest& in_entry_op,
- RangeResult* out_result) {
- DCHECK(initialized_);
- int64_t offset = in_entry_op.sparse_offset;
- int len = in_entry_op.buf_len;
- auto it = sparse_ranges_.lower_bound(offset);
- int64_t start = offset;
- int64_t 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_t len_from_start = len - (start - offset);
- *out_result = RangeResult(
- start, static_cast<int>(std::min(avail_so_far, len_from_start)));
- }
- int SimpleSynchronousEntry::CheckEOFRecord(
- BackendFileOperations* file_operations,
- base::File* file,
- int stream_index,
- const SimpleEntryStat& entry_stat,
- uint32_t expected_crc32) {
- DCHECK(initialized_);
- SimpleFileEOF eof_record;
- int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
- int file_index = GetFileIndexFromStreamIndex(stream_index);
- int rv =
- GetEOFRecordData(file, nullptr, file_index, file_offset, &eof_record);
- if (rv != net::OK) {
- DoomInternal(file_operations);
- return rv;
- }
- if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
- eof_record.data_crc32 != expected_crc32) {
- DVLOG(1) << "EOF record had bad crc.";
- RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
- DoomInternal(file_operations);
- return net::ERR_CACHE_CHECKSUM_MISMATCH;
- }
- RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
- return net::OK;
- }
- int SimpleSynchronousEntry::PreReadStreamPayload(
- base::File* file,
- PrefetchData* prefetch_data,
- int stream_index,
- int extra_size,
- const SimpleEntryStat& entry_stat,
- const SimpleFileEOF& eof_record,
- SimpleStreamPrefetchData* out) {
- DCHECK(stream_index == 0 || stream_index == 1);
- int stream_size = entry_stat.data_size(stream_index);
- int read_size = stream_size + extra_size;
- out->data = base::MakeRefCounted<net::GrowableIOBuffer>();
- out->data->SetCapacity(read_size);
- int file_offset = entry_stat.GetOffsetInFile(key_.size(), 0, stream_index);
- if (!ReadFromFileOrPrefetched(file, prefetch_data, 0, file_offset, read_size,
- out->data->data()))
- return net::ERR_FAILED;
- // Check the CRC32.
- uint32_t expected_crc32 = simple_util::Crc32(out->data->data(), stream_size);
- if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
- eof_record.data_crc32 != expected_crc32) {
- DVLOG(1) << "EOF record had bad crc.";
- RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
- return net::ERR_CACHE_CHECKSUM_MISMATCH;
- }
- out->stream_crc32 = expected_crc32;
- RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
- return net::OK;
- }
- void SimpleSynchronousEntry::Close(
- const SimpleEntryStat& entry_stat,
- std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write,
- net::GrowableIOBuffer* stream_0_data,
- SimpleEntryCloseResults* out_results) {
- // As we delete `this`, we cannot use ScopedFileOperationsBinding here.
- std::unique_ptr<BackendFileOperations> file_operations =
- unbound_file_operations_->Bind(base::SequencedTaskRunnerHandle::Get());
- unbound_file_operations_ = nullptr;
- base::ElapsedTimer close_time;
- DCHECK(stream_0_data);
- for (auto& crc_record : *crc32s_to_write) {
- const int stream_index = crc_record.index;
- const int file_index = GetFileIndexFromStreamIndex(stream_index);
- if (empty_file_omitted_[file_index])
- continue;
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations.get(), this, SubFileForFileIndex(file_index));
- if (!file.IsOK()) {
- RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
- DoomInternal(file_operations.get());
- break;
- }
- if (stream_index == 0) {
- // Write stream 0 data.
- int stream_0_offset = entry_stat.GetOffsetInFile(key_.size(), 0, 0);
- if (file->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.";
- DoomInternal(file_operations.get());
- }
- net::SHA256HashValue hash_value;
- CalculateSHA256OfKey(key_, &hash_value);
- if (file->Write(stream_0_offset + entry_stat.data_size(0),
- reinterpret_cast<char*>(hash_value.data),
- sizeof(hash_value)) != sizeof(hash_value)) {
- RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
- DVLOG(1) << "Could not write stream 0 data.";
- DoomInternal(file_operations.get());
- }
- // Re-compute stream 0 CRC if the data got changed (we may be here even
- // if it didn't change if stream 0's position on disk got changed due to
- // stream 1 write).
- if (!crc_record.has_crc32) {
- crc_record.data_crc32 =
- simple_util::Crc32(stream_0_data->data(), entry_stat.data_size(0));
- crc_record.has_crc32 = true;
- }
- out_results->estimated_trailer_prefetch_size =
- entry_stat.data_size(0) + sizeof(hash_value) + sizeof(SimpleFileEOF);
- }
- SimpleFileEOF eof_record;
- eof_record.stream_size = entry_stat.data_size(stream_index);
- eof_record.final_magic_number = kSimpleFinalMagicNumber;
- eof_record.flags = 0;
- if (crc_record.has_crc32)
- eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32;
- if (stream_index == 0)
- eof_record.flags |= SimpleFileEOF::FLAG_HAS_KEY_SHA256;
- eof_record.data_crc32 = crc_record.data_crc32;
- int eof_offset = entry_stat.GetEOFOffsetInFile(key_.size(), 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 && !file->SetLength(eof_offset)) {
- RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
- DVLOG(1) << "Could not truncate stream 0 file.";
- DoomInternal(file_operations.get());
- break;
- }
- if (file->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.";
- DoomInternal(file_operations.get());
- break;
- }
- }
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (empty_file_omitted_[i])
- continue;
- if (header_and_key_check_needed_[i]) {
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations.get(), this, SubFileForFileIndex(i));
- if (!file.IsOK() || !CheckHeaderAndKey(file.get(), i))
- DoomInternal(file_operations.get());
- }
- CloseFile(file_operations.get(), i);
- }
- if (sparse_file_open()) {
- CloseSparseFile(file_operations.get());
- }
- SIMPLE_CACHE_UMA(TIMES, "DiskCloseLatency", cache_type_,
- close_time.Elapsed());
- 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_t entry_hash,
- SimpleFileTracker* file_tracker,
- std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations,
- int32_t trailer_prefetch_size)
- : cache_type_(cache_type),
- path_(path),
- entry_file_key_(entry_hash),
- key_(key),
- file_tracker_(file_tracker),
- unbound_file_operations_(std::move(unbound_file_operations)),
- trailer_prefetch_size_(trailer_prefetch_size) {
- for (bool& empty_file_omitted : empty_file_omitted_) {
- empty_file_omitted = false;
- }
- }
- SimpleSynchronousEntry::~SimpleSynchronousEntry() {
- DCHECK(!have_open_files_);
- }
- bool SimpleSynchronousEntry::MaybeOpenFile(
- BackendFileOperations* file_operations,
- int file_index,
- base::File::Error* out_error) {
- DCHECK(out_error);
- FilePath filename = GetFilenameFromFileIndex(file_index);
- int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
- base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
- auto file = std::make_unique<base::File>();
- *file = file_operations->OpenFile(filename, flags);
- *out_error = file->error_details();
- if (CanOmitEmptyFile(file_index) && !file->IsValid() &&
- *out_error == base::File::FILE_ERROR_NOT_FOUND) {
- empty_file_omitted_[file_index] = true;
- return true;
- }
- if (file->IsValid()) {
- file_tracker_->Register(this, SubFileForFileIndex(file_index),
- std::move(file));
- return true;
- }
- return false;
- }
- bool SimpleSynchronousEntry::MaybeCreateFile(
- BackendFileOperations* file_operations,
- int file_index,
- FileRequired file_required,
- base::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 = base::File::FLAG_CREATE | base::File::FLAG_READ |
- base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
- auto file =
- std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
- // It's possible that the creation failed because someone deleted the
- // directory (e.g. because someone pressed "clear cache" on Android).
- // If so, we would keep failing for a while until periodic index snapshot
- // re-creates the cache dir, so try to recover from it quickly here.
- //
- // This previously also checked whether the directory was missing, but that
- // races against other entry creations attempting the same recovery.
- if (!file->IsValid() &&
- file->error_details() == base::File::FILE_ERROR_NOT_FOUND) {
- file_operations->CreateDirectory(path_);
- *file = file_operations->OpenFile(filename, flags);
- }
- *out_error = file->error_details();
- if (file->IsValid()) {
- file_tracker_->Register(this, SubFileForFileIndex(file_index),
- std::move(file));
- empty_file_omitted_[file_index] = false;
- return true;
- }
- return false;
- }
- bool SimpleSynchronousEntry::OpenFiles(BackendFileOperations* file_operations,
- SimpleEntryStat* out_entry_stat) {
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- base::File::Error error;
- if (!MaybeOpenFile(file_operations, i, &error)) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_PLATFORM_FILE_ERROR);
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncOpenPlatformFileError", cache_type_,
- -error, -base::File::FILE_ERROR_MAX);
- while (--i >= 0)
- CloseFile(file_operations, i);
- return false;
- }
- }
- have_open_files_ = true;
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (empty_file_omitted_[i]) {
- out_entry_stat->set_data_size(i + 1, 0);
- continue;
- }
- base::File::Info file_info;
- SimpleFileTracker::FileHandle file =
- file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(i));
- bool success = file.IsOK() && file->GetInfo(&file_info);
- if (!success) {
- DLOG(WARNING) << "Could not get platform file info.";
- continue;
- }
- out_entry_stat->set_last_used(file_info.last_accessed);
- out_entry_stat->set_last_modified(file_info.last_modified);
- // Two things prevent from knowing the right values for |data_size|:
- // 1) The key might not be known, hence its length might be 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 ReadAndValidateStream0AndMaybe1.
- if (!base::IsValueInRangeForNumericType<int>(file_info.size)) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_INVALID_FILE_LENGTH);
- return false;
- }
- out_entry_stat->set_data_size(i + 1, static_cast<int>(file_info.size));
- }
- return true;
- }
- bool SimpleSynchronousEntry::CreateFiles(BackendFileOperations* file_operations,
- SimpleEntryStat* out_entry_stat) {
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- base::File::Error error;
- if (!MaybeCreateFile(file_operations, i, FILE_NOT_REQUIRED, &error)) {
- SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCreatePlatformFileError",
- cache_type_, -error, -base::File::FILE_ERROR_MAX);
- while (--i >= 0)
- CloseFile(file_operations, 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 < kSimpleEntryNormalFileCount; ++i)
- out_entry_stat->set_data_size(i, 0);
- return true;
- }
- void SimpleSynchronousEntry::CloseFile(BackendFileOperations* file_operations,
- int index) {
- if (empty_file_omitted_[index]) {
- empty_file_omitted_[index] = false;
- } else {
- // We want to delete files that were renamed for doom here; and we should do
- // this before calling SimpleFileTracker::Close, since that would make the
- // name available to other threads.
- if (entry_file_key_.doom_generation != 0u) {
- file_operations->DeleteFile(path_.AppendASCII(
- GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, index)));
- }
- file_tracker_->Close(this, SubFileForFileIndex(index));
- }
- }
- void SimpleSynchronousEntry::CloseFiles() {
- if (!have_open_files_) {
- return;
- }
- BackendFileOperations* file_operations = nullptr;
- ScopedFileOperationsBinding binding(this, &file_operations);
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i)
- CloseFile(file_operations, i);
- if (sparse_file_open())
- CloseSparseFile(file_operations);
- have_open_files_ = false;
- }
- bool SimpleSynchronousEntry::CheckHeaderAndKey(base::File* file,
- int file_index) {
- std::vector<char> header_data(key_.empty() ? kInitialHeaderRead
- : GetHeaderSize(key_.size()));
- int bytes_read = file->Read(0, header_data.data(), header_data.size());
- const SimpleFileHeader* header =
- reinterpret_cast<const SimpleFileHeader*>(header_data.data());
- if (bytes_read == -1 || static_cast<size_t>(bytes_read) < sizeof(*header)) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER);
- return false;
- }
- // This resize will not invalidate iterators since it does not enlarge the
- // header_data.
- DCHECK_LE(static_cast<size_t>(bytes_read), header_data.size());
- header_data.resize(bytes_read);
- if (header->initial_magic_number != kSimpleInitialMagicNumber) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_MAGIC_NUMBER);
- return false;
- }
- if (header->version != kSimpleEntryVersionOnDisk) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_VERSION);
- return false;
- }
- size_t expected_header_size = GetHeaderSize(header->key_length);
- if (header_data.size() < expected_header_size) {
- size_t old_size = header_data.size();
- int bytes_to_read = expected_header_size - old_size;
- // This resize will invalidate iterators, since it is enlarging header_data.
- header_data.resize(expected_header_size);
- int read_result =
- file->Read(old_size, header_data.data() + old_size, bytes_to_read);
- if (read_result != bytes_to_read) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY);
- return false;
- }
- header = reinterpret_cast<const SimpleFileHeader*>(header_data.data());
- }
- char* key_data = header_data.data() + sizeof(*header);
- if (base::PersistentHash(key_data, header->key_length) != header->key_hash) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH);
- return false;
- }
- std::string key_from_header(key_data, header->key_length);
- if (key_.empty()) {
- key_.swap(key_from_header);
- } else {
- if (key_ != key_from_header) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_MISMATCH);
- return false;
- }
- }
- header_and_key_check_needed_[file_index] = false;
- return true;
- }
- int SimpleSynchronousEntry::InitializeForOpen(
- BackendFileOperations* file_operations,
- SimpleEntryStat* out_entry_stat,
- SimpleStreamPrefetchData stream_prefetch_data[2]) {
- DCHECK(!initialized_);
- if (!OpenFiles(file_operations, out_entry_stat)) {
- DLOG(WARNING) << "Could not open platform files for entry.";
- return net::ERR_FAILED;
- }
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (empty_file_omitted_[i])
- continue;
- if (key_.empty()) {
- SimpleFileTracker::FileHandle file =
- file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(i));
- // If |key_| is empty, we were opened via the iterator interface, without
- // knowing what our key is. We must therefore read the header immediately
- // to discover it, so SimpleEntryImpl can make it available to
- // disk_cache::Entry::GetKey().
- if (!file.IsOK() || !CheckHeaderAndKey(file.get(), i))
- return net::ERR_FAILED;
- } else {
- // If we do know which key were are looking for, we still need to
- // check that the file actually has it (rather than just being a hash
- // collision or some sort of file system accident), but that can be put
- // off until opportune time: either the read of the footer, or when we
- // start reading in the data, depending on stream # and format revision.
- header_and_key_check_needed_[i] = true;
- }
- if (i == 0) {
- // File size for stream 0 has been stored temporarily in data_size[1].
- int ret_value_stream_0 = ReadAndValidateStream0AndMaybe1(
- file_operations, out_entry_stat->data_size(1), out_entry_stat,
- stream_prefetch_data);
- if (ret_value_stream_0 != net::OK)
- return ret_value_stream_0;
- } else {
- out_entry_stat->set_data_size(
- 2,
- GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2)));
- const int32_t data_size_2 = out_entry_stat->data_size(2);
- int ret_value_stream_2 = net::OK;
- if (data_size_2 < 0) {
- DLOG(WARNING) << "Stream 2 file is too small.";
- ret_value_stream_2 = net::ERR_FAILED;
- } else if (data_size_2 > 0) {
- // Validate non empty stream 2.
- SimpleFileEOF eof_record;
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations, this, SubFileForFileIndex(i));
- int file_offset =
- out_entry_stat->GetEOFOffsetInFile(key_.size(), 2 /*stream index*/);
- ret_value_stream_2 =
- GetEOFRecordData(file.get(), nullptr, i, file_offset, &eof_record);
- }
- if (ret_value_stream_2 != net::OK) {
- DCHECK_EQ(i, GetFileIndexFromStreamIndex(2));
- DCHECK(CanOmitEmptyFile(GetFileIndexFromStreamIndex(2)));
- // Stream 2 is broken, set its size to zero to have it automatically
- // deleted further down in this function. For V8 this preserves the
- // cached source when only the code cache was corrupted.
- out_entry_stat->set_data_size(2, 0);
- }
- }
- }
- int32_t sparse_data_size = 0;
- if (!OpenSparseFileIfExists(file_operations, &sparse_data_size)) {
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SPARSE_OPEN_FAILED);
- return net::ERR_FAILED;
- }
- out_entry_stat->set_sparse_data_size(sparse_data_size);
- 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) {
- CloseFile(file_operations, stream2_file_index);
- DeleteFileForEntryHash(path_, entry_file_key_.entry_hash,
- stream2_file_index, file_operations);
- empty_file_omitted_[stream2_file_index] = true;
- }
- RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS);
- initialized_ = true;
- return net::OK;
- }
- bool SimpleSynchronousEntry::InitializeCreatedFile(
- BackendFileOperations* file_operations,
- int file_index) {
- SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
- file_operations, this, SubFileForFileIndex(file_index));
- if (!file.IsOK())
- return false;
- SimpleFileHeader header;
- header.initial_magic_number = kSimpleInitialMagicNumber;
- header.version = kSimpleEntryVersionOnDisk;
- header.key_length = key_.size();
- header.key_hash = base::PersistentHash(key_);
- int bytes_written =
- file->Write(0, reinterpret_cast<char*>(&header), sizeof(header));
- if (bytes_written != sizeof(header))
- return false;
- bytes_written = file->Write(sizeof(header), key_.data(), key_.size());
- if (bytes_written != base::checked_cast<int>(key_.size()))
- return false;
- return true;
- }
- int SimpleSynchronousEntry::InitializeForCreate(
- BackendFileOperations* file_operations,
- SimpleEntryStat* out_entry_stat) {
- DCHECK(!initialized_);
- if (!CreateFiles(file_operations, out_entry_stat)) {
- DLOG(WARNING) << "Could not create platform files.";
- return net::ERR_FILE_EXISTS;
- }
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (empty_file_omitted_[i])
- continue;
- if (!InitializeCreatedFile(file_operations, i))
- return net::ERR_FAILED;
- }
- initialized_ = true;
- return net::OK;
- }
- int SimpleSynchronousEntry::ReadAndValidateStream0AndMaybe1(
- BackendFileOperations* file_operations,
- int file_size,
- SimpleEntryStat* out_entry_stat,
- SimpleStreamPrefetchData stream_prefetch_data[2]) {
- SimpleFileTracker::FileHandle file =
- file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(0));
- if (!file.IsOK())
- return net::ERR_FAILED;
- // We may prefetch data from file in a couple cases:
- // 1) If the file is small enough we may prefetch it entirely.
- // 2) We may also prefetch a block of trailer bytes from the end of
- // the file.
- // In these cases the PrefetchData object is used to store the
- // bytes read from the file. The PrefetchData object also keeps track
- // of what range within the file has been prefetched. It will only
- // allow reads wholely within this range to be accessed via its
- // ReadData() method.
- PrefetchData prefetch_data(file_size);
- // Determine a threshold for fully prefetching the entire entry file. If
- // the entry file is less than or equal to this number of bytes it will
- // be fully prefetched.
- int full_prefetch_size = GetSimpleCacheFullPrefetchSize();
- // Determine how much trailer data to prefetch. If the full file prefetch
- // does not trigger then this is the number of bytes to read from the end
- // of the file in a single file operation. Ideally the trailer prefetch
- // will contain at least stream 0 and its EOF record.
- int trailer_prefetch_size =
- GetSimpleCacheTrailerPrefetchSize(trailer_prefetch_size_);
- OpenPrefetchMode prefetch_mode = OPEN_PREFETCH_NONE;
- if (file_size <= full_prefetch_size || file_size <= trailer_prefetch_size) {
- // Prefetch the entire file.
- prefetch_mode = OPEN_PREFETCH_FULL;
- RecordOpenPrefetchMode(cache_type_, prefetch_mode);
- if (!prefetch_data.PrefetchFromFile(&file, 0, file_size))
- return net::ERR_FAILED;
- } else if (trailer_prefetch_size > 0) {
- // Prefetch trailer data from the end of the file.
- prefetch_mode = OPEN_PREFETCH_TRAILER;
- RecordOpenPrefetchMode(cache_type_, prefetch_mode);
- size_t length = std::min(trailer_prefetch_size, file_size);
- size_t offset = file_size - length;
- if (!prefetch_data.PrefetchFromFile(&file, offset, length))
- return net::ERR_FAILED;
- } else {
- // Do no prefetching.
- RecordOpenPrefetchMode(cache_type_, prefetch_mode);
- }
- // Read stream 0 footer first --- it has size/feature info required to figure
- // out file 0's layout.
- SimpleFileEOF stream_0_eof;
- int rv = GetEOFRecordData(
- file.get(), &prefetch_data, /* file_index = */ 0,
- /* file_offset = */ file_size - sizeof(SimpleFileEOF), &stream_0_eof);
- if (rv != net::OK)
- return rv;
- int32_t stream_0_size = stream_0_eof.stream_size;
- if (stream_0_size < 0 || stream_0_size > file_size)
- return net::ERR_FAILED;
- out_entry_stat->set_data_size(0, stream_0_size);
- // Calculate size for stream 1, now we know stream 0's.
- // See comments in simple_entry_format.h for background.
- bool has_key_sha256 =
- (stream_0_eof.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
- SimpleFileEOF::FLAG_HAS_KEY_SHA256;
- int extra_post_stream_0_read = 0;
- if (has_key_sha256)
- extra_post_stream_0_read += sizeof(net::SHA256HashValue);
- int32_t stream1_size = file_size - 2 * sizeof(SimpleFileEOF) - stream_0_size -
- sizeof(SimpleFileHeader) - key_.size() -
- extra_post_stream_0_read;
- if (stream1_size < 0 || stream1_size > file_size)
- return net::ERR_FAILED;
- out_entry_stat->set_data_size(1, stream1_size);
- // Put stream 0 data in memory --- plus maybe the sha256(key) footer.
- rv = PreReadStreamPayload(file.get(), &prefetch_data, /* stream_index = */ 0,
- extra_post_stream_0_read, *out_entry_stat,
- stream_0_eof, &stream_prefetch_data[0]);
- if (rv != net::OK)
- return rv;
- // Note the exact range needed in order to read the EOF record and stream 0.
- // In APP_CACHE mode this will be stored directly in the index so we can
- // know exactly how much to read next time.
- computed_trailer_prefetch_size_ =
- prefetch_data.GetDesiredTrailerPrefetchSize();
- // If prefetch buffer is available, and we have sha256(key) (so we don't need
- // to look at the header), extract out stream 1 info as well.
- int stream_1_offset = out_entry_stat->GetOffsetInFile(
- key_.size(), /* offset= */ 0, /* stream_index = */ 1);
- int stream_1_read_size =
- sizeof(SimpleFileEOF) + out_entry_stat->data_size(/* stream_index = */ 1);
- if (has_key_sha256 &&
- prefetch_data.HasData(stream_1_offset, stream_1_read_size)) {
- SimpleFileEOF stream_1_eof;
- int stream_1_eof_offset =
- out_entry_stat->GetEOFOffsetInFile(key_.size(), /* stream_index = */ 1);
- rv = GetEOFRecordData(file.get(), &prefetch_data, /* file_index = */ 0,
- stream_1_eof_offset, &stream_1_eof);
- if (rv != net::OK)
- return rv;
- rv = PreReadStreamPayload(file.get(), &prefetch_data,
- /* stream_index = */ 1,
- /* extra_size = */ 0, *out_entry_stat,
- stream_1_eof, &stream_prefetch_data[1]);
- if (rv != net::OK)
- return rv;
- }
- // If present, check the key SHA256.
- if (has_key_sha256) {
- net::SHA256HashValue hash_value;
- CalculateSHA256OfKey(key_, &hash_value);
- bool matched =
- std::memcmp(&hash_value,
- stream_prefetch_data[0].data->data() + stream_0_size,
- sizeof(hash_value)) == 0;
- if (!matched)
- return net::ERR_FAILED;
- // Elide header check if we verified sha256(key) via footer.
- header_and_key_check_needed_[0] = false;
- }
- // Ensure the key is validated before completion.
- if (!has_key_sha256 && header_and_key_check_needed_[0])
- CheckHeaderAndKey(file.get(), 0);
- return net::OK;
- }
- bool SimpleSynchronousEntry::ReadFromFileOrPrefetched(
- base::File* file,
- PrefetchData* prefetch_data,
- int file_index,
- int offset,
- int size,
- char* dest) {
- if (offset < 0 || size < 0)
- return false;
- if (size == 0)
- return true;
- base::CheckedNumeric<size_t> start(offset);
- size_t start_numeric;
- if (!start.AssignIfValid(&start_numeric))
- return false;
- base::CheckedNumeric<size_t> length(size);
- size_t length_numeric;
- if (!length.AssignIfValid(&length_numeric))
- return false;
- // First try to extract the desired range from the PrefetchData.
- if (file_index == 0 && prefetch_data &&
- prefetch_data->ReadData(start_numeric, length_numeric, dest)) {
- return true;
- }
- // If we have not prefetched the range then we must read it from disk.
- return file->Read(start_numeric, dest, length_numeric) == size;
- }
- int SimpleSynchronousEntry::GetEOFRecordData(base::File* file,
- PrefetchData* prefetch_data,
- int file_index,
- int file_offset,
- SimpleFileEOF* eof_record) {
- if (!ReadFromFileOrPrefetched(file, prefetch_data, file_index, file_offset,
- sizeof(SimpleFileEOF),
- reinterpret_cast<char*>(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;
- }
- if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size))
- return net::ERR_FAILED;
- return net::OK;
- }
- // static
- bool SimpleSynchronousEntry::DeleteFileForEntryHash(
- const FilePath& path,
- const uint64_t entry_hash,
- const int file_index,
- BackendFileOperations* file_operations) {
- FilePath to_delete = path.AppendASCII(GetFilenameFromEntryFileKeyAndFileIndex(
- SimpleFileTracker::EntryFileKey(entry_hash), file_index));
- return file_operations->DeleteFile(to_delete);
- }
- // static
- bool SimpleSynchronousEntry::DeleteFilesForEntryHash(
- const FilePath& path,
- const uint64_t entry_hash,
- BackendFileOperations* file_operations) {
- bool result = true;
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- if (!DeleteFileForEntryHash(path, entry_hash, i, file_operations) &&
- !CanOmitEmptyFile(i)) {
- result = false;
- }
- }
- FilePath to_delete = path.AppendASCII(GetSparseFilenameFromEntryFileKey(
- SimpleFileTracker::EntryFileKey(entry_hash)));
- file_operations->DeleteFile(
- to_delete,
- BackendFileOperations::DeleteFileMode::kEnsureImmediateAvailability);
- return result;
- }
- // static
- bool SimpleSynchronousEntry::TruncateFilesForEntryHash(
- const FilePath& path,
- const uint64_t entry_hash,
- BackendFileOperations* file_operations) {
- SimpleFileTracker::EntryFileKey file_key(entry_hash);
- bool result = true;
- for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
- FilePath filename_to_truncate =
- path.AppendASCII(GetFilenameFromEntryFileKeyAndFileIndex(file_key, i));
- if (!TruncatePath(filename_to_truncate, file_operations))
- result = false;
- }
- FilePath to_delete =
- path.AppendASCII(GetSparseFilenameFromEntryFileKey(file_key));
- TruncatePath(to_delete, file_operations);
- return result;
- }
- FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(
- int file_index) const {
- return path_.AppendASCII(
- GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, file_index));
- }
- base::FilePath SimpleSynchronousEntry::GetFilenameForSubfile(
- SimpleFileTracker::SubFile sub_file) const {
- if (sub_file == SimpleFileTracker::SubFile::FILE_SPARSE)
- return path_.AppendASCII(
- GetSparseFilenameFromEntryFileKey(entry_file_key_));
- else
- return GetFilenameFromFileIndex(FileIndexForSubFile(sub_file));
- }
- bool SimpleSynchronousEntry::OpenSparseFileIfExists(
- BackendFileOperations* file_operations,
- int32_t* out_sparse_data_size) {
- DCHECK(!sparse_file_open());
- FilePath filename =
- path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
- int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
- base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
- auto sparse_file =
- std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
- if (!sparse_file->IsValid()) {
- // No file -> OK, file open error -> 'trouble.
- return sparse_file->error_details() == base::File::FILE_ERROR_NOT_FOUND;
- }
- if (!ScanSparseFile(sparse_file.get(), out_sparse_data_size))
- return false;
- file_tracker_->Register(this, SimpleFileTracker::SubFile::FILE_SPARSE,
- std::move(sparse_file));
- sparse_file_open_ = true;
- return true;
- }
- bool SimpleSynchronousEntry::CreateSparseFile(
- BackendFileOperations* file_operations) {
- DCHECK(!sparse_file_open());
- FilePath filename =
- path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
- int flags = base::File::FLAG_CREATE | base::File::FLAG_READ |
- base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
- std::unique_ptr<base::File> sparse_file =
- std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
- if (!sparse_file->IsValid())
- return false;
- if (!InitializeSparseFile(sparse_file.get()))
- return false;
- file_tracker_->Register(this, SimpleFileTracker::SubFile::FILE_SPARSE,
- std::move(sparse_file));
- sparse_file_open_ = true;
- return true;
- }
- void SimpleSynchronousEntry::CloseSparseFile(
- BackendFileOperations* file_operations) {
- DCHECK(sparse_file_open());
- if (entry_file_key_.doom_generation != 0u) {
- file_operations->DeleteFile(
- path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_)));
- }
- file_tracker_->Close(this, SimpleFileTracker::SubFile::FILE_SPARSE);
- sparse_file_open_ = false;
- }
- bool SimpleSynchronousEntry::TruncateSparseFile(base::File* sparse_file) {
- DCHECK(sparse_file_open());
- int64_t 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();
- sparse_tail_offset_ = header_and_key_length;
- return true;
- }
- bool SimpleSynchronousEntry::InitializeSparseFile(base::File* sparse_file) {
- SimpleFileHeader header;
- header.initial_magic_number = kSimpleInitialMagicNumber;
- header.version = kSimpleVersion;
- header.key_length = key_.size();
- header.key_hash = base::PersistentHash(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 != base::checked_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(base::File* sparse_file,
- int32_t* out_sparse_data_size) {
- int64_t 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 < kLastCompatSparseVersion ||
- header.version > kSimpleVersion) {
- DLOG(WARNING) << "Sparse file unreadable version.";
- return false;
- }
- sparse_ranges_.clear();
- int64_t range_header_offset = sizeof(header) + key_.size();
- while (true) {
- 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_t>(sparse_data_size);
- sparse_tail_offset_ = range_header_offset;
- return true;
- }
- bool SimpleSynchronousEntry::ReadSparseRange(base::File* sparse_file,
- 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) {
- if (simple_util::Crc32(buf, len) != range->data_crc32) {
- DLOG(WARNING) << "Sparse range crc32 mismatch.";
- return false;
- }
- }
- // TODO(morlovich): Incremental crc32 calculation?
- return true;
- }
- bool SimpleSynchronousEntry::WriteSparseRange(base::File* sparse_file,
- 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_t new_crc32 = 0;
- if (offset == 0 && len == range->length) {
- new_crc32 = simple_util::Crc32(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 != base::checked_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(base::File* sparse_file,
- int64_t offset,
- int len,
- const char* buf) {
- DCHECK_GE(offset, 0);
- DCHECK_GT(len, 0);
- DCHECK(buf);
- uint32_t data_crc32 = simple_util::Crc32(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 != base::checked_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_t 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
|