simple_synchronous_entry.cc 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/disk_cache/simple/simple_synchronous_entry.h"
  5. #include <algorithm>
  6. #include <cstring>
  7. #include <functional>
  8. #include <limits>
  9. #include "base/compiler_specific.h"
  10. #include "base/containers/stack_container.h"
  11. #include "base/files/file_util.h"
  12. #include "base/hash/hash.h"
  13. #include "base/location.h"
  14. #include "base/memory/ptr_util.h"
  15. #include "base/memory/raw_ptr.h"
  16. #include "base/metrics/field_trial_params.h"
  17. #include "base/metrics/histogram_macros.h"
  18. #include "base/metrics/histogram_macros_local.h"
  19. #include "base/numerics/checked_math.h"
  20. #include "base/numerics/safe_conversions.h"
  21. #include "base/strings/string_piece.h"
  22. #include "base/threading/sequenced_task_runner_handle.h"
  23. #include "base/timer/elapsed_timer.h"
  24. #include "crypto/secure_hash.h"
  25. #include "net/base/hash_value.h"
  26. #include "net/base/io_buffer.h"
  27. #include "net/base/net_errors.h"
  28. #include "net/disk_cache/cache_util.h"
  29. #include "net/disk_cache/simple/simple_backend_version.h"
  30. #include "net/disk_cache/simple/simple_histogram_enums.h"
  31. #include "net/disk_cache/simple/simple_histogram_macros.h"
  32. #include "net/disk_cache/simple/simple_util.h"
  33. #include "third_party/zlib/zlib.h"
  34. using base::FilePath;
  35. using base::Time;
  36. namespace disk_cache {
  37. namespace {
  38. void RecordSyncOpenResult(net::CacheType cache_type, OpenEntryResult result) {
  39. DCHECK_LT(result, OPEN_ENTRY_MAX);
  40. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncOpenResult", cache_type, result,
  41. OPEN_ENTRY_MAX);
  42. }
  43. void RecordWriteResult(net::CacheType cache_type, SyncWriteResult result) {
  44. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncWriteResult", cache_type, result,
  45. SYNC_WRITE_RESULT_MAX);
  46. }
  47. void RecordCheckEOFResult(net::CacheType cache_type, CheckEOFResult result) {
  48. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCheckEOFResult", cache_type, result,
  49. CHECK_EOF_RESULT_MAX);
  50. }
  51. void RecordCloseResult(net::CacheType cache_type, CloseResult result) {
  52. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCloseResult", cache_type, result,
  53. CLOSE_RESULT_MAX);
  54. }
  55. void RecordOpenPrefetchMode(net::CacheType cache_type, OpenPrefetchMode mode) {
  56. SIMPLE_CACHE_UMA(ENUMERATION, "SyncOpenPrefetchMode", cache_type, mode,
  57. OPEN_PREFETCH_MAX);
  58. }
  59. void RecordDiskCreateLatency(net::CacheType cache_type, base::TimeDelta delay) {
  60. SIMPLE_CACHE_LOCAL(TIMES, "DiskCreateLatency", cache_type, delay);
  61. }
  62. bool CanOmitEmptyFile(int file_index) {
  63. DCHECK_GE(file_index, 0);
  64. DCHECK_LT(file_index, kSimpleEntryNormalFileCount);
  65. return file_index == simple_util::GetFileIndexFromStreamIndex(2);
  66. }
  67. bool TruncatePath(const FilePath& filename_to_truncate,
  68. BackendFileOperations* file_operations) {
  69. int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
  70. base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
  71. base::File file_to_truncate =
  72. file_operations->OpenFile(filename_to_truncate, flags);
  73. if (!file_to_truncate.IsValid())
  74. return false;
  75. if (!file_to_truncate.SetLength(0))
  76. return false;
  77. return true;
  78. }
  79. void CalculateSHA256OfKey(const std::string& key,
  80. net::SHA256HashValue* out_hash_value) {
  81. std::unique_ptr<crypto::SecureHash> hash(
  82. crypto::SecureHash::Create(crypto::SecureHash::SHA256));
  83. hash->Update(key.data(), key.size());
  84. hash->Finish(out_hash_value, sizeof(*out_hash_value));
  85. }
  86. SimpleFileTracker::SubFile SubFileForFileIndex(int file_index) {
  87. DCHECK_GT(kSimpleEntryNormalFileCount, file_index);
  88. return file_index == 0 ? SimpleFileTracker::SubFile::FILE_0
  89. : SimpleFileTracker::SubFile::FILE_1;
  90. }
  91. int FileIndexForSubFile(SimpleFileTracker::SubFile sub_file) {
  92. DCHECK_NE(SimpleFileTracker::SubFile::FILE_SPARSE, sub_file);
  93. return sub_file == SimpleFileTracker::SubFile::FILE_0 ? 0 : 1;
  94. }
  95. } // namespace
  96. // Helper class to track a range of data prefetched from a file.
  97. class SimpleSynchronousEntry::PrefetchData final {
  98. public:
  99. explicit PrefetchData(size_t file_size)
  100. : file_size_(file_size), earliest_requested_offset_(file_size) {}
  101. // Returns true if the specified range within the file has been completely
  102. // prefetched. Returns false if any part of the range has not been
  103. // prefetched.
  104. bool HasData(size_t offset, size_t length) {
  105. size_t end = 0;
  106. if (!base::CheckAdd(offset, length).AssignIfValid(&end))
  107. return false;
  108. UpdateEarliestOffset(offset);
  109. return offset >= offset_in_file_ &&
  110. end <= (offset_in_file_ + buffer_->size());
  111. }
  112. // Read the given range out of the prefetch buffer into the target
  113. // destination buffer. If the range is not wholely contained within
  114. // the prefetch buffer than no data will be written to the target
  115. // buffer. Returns true if the range has been copied.
  116. bool ReadData(size_t offset, size_t length, char* dest) {
  117. DCHECK(dest);
  118. if (!length)
  119. return true;
  120. if (!HasData(offset, length))
  121. return false;
  122. DCHECK(offset >= offset_in_file_);
  123. size_t buffer_offset = offset - offset_in_file_;
  124. memcpy(dest, buffer_->data() + buffer_offset, length);
  125. return true;
  126. }
  127. // Populate the prefetch buffer from the given file and range. Returns
  128. // true if the data is successfully read.
  129. bool PrefetchFromFile(SimpleFileTracker::FileHandle* file,
  130. size_t offset,
  131. size_t length) {
  132. DCHECK(file);
  133. if (!buffer_->empty())
  134. return false;
  135. buffer_->resize(length);
  136. if (file->get()->Read(offset, buffer_->data(), length) !=
  137. static_cast<int>(length)) {
  138. buffer_->resize(0);
  139. return false;
  140. }
  141. offset_in_file_ = offset;
  142. return true;
  143. }
  144. // Return how much trailing data has been requested via HasData() or
  145. // ReadData(). The intent is that this value can be used to tune
  146. // future prefetching behavior.
  147. size_t GetDesiredTrailerPrefetchSize() const {
  148. return file_size_ - earliest_requested_offset_;
  149. }
  150. private:
  151. // Track the earliest offset requested in order to return an optimal trailer
  152. // prefetch amount in GetDesiredTrailerPrefetchSize().
  153. void UpdateEarliestOffset(size_t offset) {
  154. DCHECK_LE(earliest_requested_offset_, file_size_);
  155. earliest_requested_offset_ = std::min(earliest_requested_offset_, offset);
  156. }
  157. const size_t file_size_;
  158. // Prefer to read the prefetch data into a stack buffer to minimize
  159. // memory pressure on the OS disk cache.
  160. base::StackVector<char, 1024> buffer_;
  161. size_t offset_in_file_ = 0;
  162. size_t earliest_requested_offset_;
  163. };
  164. class SimpleSynchronousEntry::ScopedFileOperationsBinding final {
  165. public:
  166. ScopedFileOperationsBinding(SimpleSynchronousEntry* owner,
  167. BackendFileOperations** file_operations)
  168. : owner_(owner),
  169. file_operations_(owner->unbound_file_operations_->Bind(
  170. base::SequencedTaskRunnerHandle::Get())) {
  171. *file_operations = file_operations_.get();
  172. }
  173. ~ScopedFileOperationsBinding() {
  174. owner_->unbound_file_operations_ = file_operations_->Unbind();
  175. }
  176. private:
  177. const raw_ptr<SimpleSynchronousEntry> owner_;
  178. std::unique_ptr<BackendFileOperations> file_operations_;
  179. };
  180. using simple_util::GetEntryHashKey;
  181. using simple_util::GetFilenameFromEntryFileKeyAndFileIndex;
  182. using simple_util::GetSparseFilenameFromEntryFileKey;
  183. using simple_util::GetHeaderSize;
  184. using simple_util::GetDataSizeFromFileSize;
  185. using simple_util::GetFileSizeFromDataSize;
  186. using simple_util::GetFileIndexFromStreamIndex;
  187. const base::Feature kSimpleCachePrefetchExperiment = {
  188. "SimpleCachePrefetchExperiment2", base::FEATURE_DISABLED_BY_DEFAULT};
  189. const char kSimpleCacheFullPrefetchBytesParam[] = "FullPrefetchBytes";
  190. constexpr base::FeatureParam<int> kSimpleCacheFullPrefetchSize{
  191. &kSimpleCachePrefetchExperiment, kSimpleCacheFullPrefetchBytesParam, 0};
  192. const char kSimpleCacheTrailerPrefetchSpeculativeBytesParam[] =
  193. "TrailerPrefetchSpeculativeBytes";
  194. constexpr base::FeatureParam<int> kSimpleCacheTrailerPrefetchSpeculativeBytes{
  195. &kSimpleCachePrefetchExperiment,
  196. kSimpleCacheTrailerPrefetchSpeculativeBytesParam, 0};
  197. int GetSimpleCacheFullPrefetchSize() {
  198. return kSimpleCacheFullPrefetchSize.Get();
  199. }
  200. int GetSimpleCacheTrailerPrefetchSize(int hint_size) {
  201. if (hint_size > 0)
  202. return hint_size;
  203. return kSimpleCacheTrailerPrefetchSpeculativeBytes.Get();
  204. }
  205. SimpleEntryStat::SimpleEntryStat(base::Time last_used,
  206. base::Time last_modified,
  207. const int32_t data_size[],
  208. const int32_t sparse_data_size)
  209. : last_used_(last_used),
  210. last_modified_(last_modified),
  211. sparse_data_size_(sparse_data_size) {
  212. memcpy(data_size_, data_size, sizeof(data_size_));
  213. }
  214. // These size methods all assume the presence of the SHA256 on stream zero,
  215. // since this version of the cache always writes it. In the read case, it may
  216. // not be present and these methods can't be relied upon.
  217. int SimpleEntryStat::GetOffsetInFile(size_t key_length,
  218. int offset,
  219. int stream_index) const {
  220. const size_t headers_size = sizeof(SimpleFileHeader) + key_length;
  221. const size_t additional_offset =
  222. stream_index == 0 ? data_size_[1] + sizeof(SimpleFileEOF) : 0;
  223. return headers_size + offset + additional_offset;
  224. }
  225. int SimpleEntryStat::GetEOFOffsetInFile(size_t key_length,
  226. int stream_index) const {
  227. size_t additional_offset;
  228. if (stream_index != 0)
  229. additional_offset = 0;
  230. else
  231. additional_offset = sizeof(net::SHA256HashValue);
  232. return additional_offset +
  233. GetOffsetInFile(key_length, data_size_[stream_index], stream_index);
  234. }
  235. int SimpleEntryStat::GetLastEOFOffsetInFile(size_t key_length,
  236. int stream_index) const {
  237. if (stream_index == 1)
  238. return GetEOFOffsetInFile(key_length, 0);
  239. return GetEOFOffsetInFile(key_length, stream_index);
  240. }
  241. int64_t SimpleEntryStat::GetFileSize(size_t key_length, int file_index) const {
  242. int32_t total_data_size;
  243. if (file_index == 0) {
  244. total_data_size = data_size_[0] + data_size_[1] +
  245. sizeof(net::SHA256HashValue) + sizeof(SimpleFileEOF);
  246. } else {
  247. total_data_size = data_size_[2];
  248. }
  249. return GetFileSizeFromDataSize(key_length, total_data_size);
  250. }
  251. SimpleStreamPrefetchData::SimpleStreamPrefetchData()
  252. : stream_crc32(crc32(0, Z_NULL, 0)) {}
  253. SimpleStreamPrefetchData::~SimpleStreamPrefetchData() = default;
  254. SimpleEntryCreationResults::SimpleEntryCreationResults(
  255. SimpleEntryStat entry_stat)
  256. : sync_entry(nullptr), entry_stat(entry_stat) {}
  257. SimpleEntryCreationResults::~SimpleEntryCreationResults() = default;
  258. SimpleSynchronousEntry::CRCRecord::CRCRecord() : index(-1),
  259. has_crc32(false),
  260. data_crc32(0) {
  261. }
  262. SimpleSynchronousEntry::CRCRecord::CRCRecord(int index_p,
  263. bool has_crc32_p,
  264. uint32_t data_crc32_p)
  265. : index(index_p), has_crc32(has_crc32_p), data_crc32(data_crc32_p) {}
  266. SimpleSynchronousEntry::ReadRequest::ReadRequest(int index_p,
  267. int offset_p,
  268. int buf_len_p)
  269. : index(index_p), offset(offset_p), buf_len(buf_len_p) {}
  270. SimpleSynchronousEntry::WriteRequest::WriteRequest(int index_p,
  271. int offset_p,
  272. int buf_len_p,
  273. uint32_t previous_crc32_p,
  274. bool truncate_p,
  275. bool doomed_p,
  276. bool request_update_crc_p)
  277. : index(index_p),
  278. offset(offset_p),
  279. buf_len(buf_len_p),
  280. previous_crc32(previous_crc32_p),
  281. truncate(truncate_p),
  282. doomed(doomed_p),
  283. request_update_crc(request_update_crc_p) {}
  284. SimpleSynchronousEntry::SparseRequest::SparseRequest(int64_t sparse_offset_p,
  285. int buf_len_p)
  286. : sparse_offset(sparse_offset_p), buf_len(buf_len_p) {}
  287. // static
  288. void SimpleSynchronousEntry::OpenEntry(
  289. net::CacheType cache_type,
  290. const FilePath& path,
  291. const std::string& key,
  292. const uint64_t entry_hash,
  293. SimpleFileTracker* file_tracker,
  294. std::unique_ptr<UnboundBackendFileOperations> file_operations,
  295. int32_t trailer_prefetch_size,
  296. SimpleEntryCreationResults* out_results) {
  297. base::TimeTicks start_sync_open_entry = base::TimeTicks::Now();
  298. auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
  299. cache_type, path, key, entry_hash, file_tracker,
  300. std::move(file_operations), trailer_prefetch_size);
  301. {
  302. BackendFileOperations* bound_file_operations = nullptr;
  303. ScopedFileOperationsBinding binding(sync_entry.get(),
  304. &bound_file_operations);
  305. out_results->result = sync_entry->InitializeForOpen(
  306. bound_file_operations, &out_results->entry_stat,
  307. out_results->stream_prefetch_data);
  308. }
  309. if (out_results->result != net::OK) {
  310. sync_entry->Doom();
  311. sync_entry->CloseFiles();
  312. out_results->sync_entry = nullptr;
  313. out_results->unbound_file_operations =
  314. std::move(sync_entry->unbound_file_operations_);
  315. out_results->stream_prefetch_data[0].data = nullptr;
  316. out_results->stream_prefetch_data[1].data = nullptr;
  317. return;
  318. }
  319. SIMPLE_CACHE_UMA(TIMES, "DiskOpenLatency", cache_type,
  320. base::TimeTicks::Now() - start_sync_open_entry);
  321. out_results->sync_entry = sync_entry.release();
  322. out_results->computed_trailer_prefetch_size =
  323. out_results->sync_entry->computed_trailer_prefetch_size();
  324. }
  325. // static
  326. void SimpleSynchronousEntry::CreateEntry(
  327. net::CacheType cache_type,
  328. const FilePath& path,
  329. const std::string& key,
  330. const uint64_t entry_hash,
  331. SimpleFileTracker* file_tracker,
  332. std::unique_ptr<UnboundBackendFileOperations> file_operations,
  333. SimpleEntryCreationResults* out_results) {
  334. DCHECK_EQ(entry_hash, GetEntryHashKey(key));
  335. base::TimeTicks start_sync_create_entry = base::TimeTicks::Now();
  336. auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
  337. cache_type, path, key, entry_hash, file_tracker,
  338. std::move(file_operations), -1);
  339. {
  340. BackendFileOperations* bound_file_operations = nullptr;
  341. ScopedFileOperationsBinding binding(sync_entry.get(),
  342. &bound_file_operations);
  343. out_results->result = sync_entry->InitializeForCreate(
  344. bound_file_operations, &out_results->entry_stat);
  345. }
  346. if (out_results->result != net::OK) {
  347. if (out_results->result != net::ERR_FILE_EXISTS)
  348. sync_entry->Doom();
  349. sync_entry->CloseFiles();
  350. out_results->unbound_file_operations =
  351. std::move(sync_entry->unbound_file_operations_);
  352. out_results->sync_entry = nullptr;
  353. return;
  354. }
  355. out_results->sync_entry = sync_entry.release();
  356. out_results->created = true;
  357. RecordDiskCreateLatency(cache_type,
  358. base::TimeTicks::Now() - start_sync_create_entry);
  359. }
  360. // static
  361. void SimpleSynchronousEntry::OpenOrCreateEntry(
  362. net::CacheType cache_type,
  363. const FilePath& path,
  364. const std::string& key,
  365. const uint64_t entry_hash,
  366. OpenEntryIndexEnum index_state,
  367. bool optimistic_create,
  368. SimpleFileTracker* file_tracker,
  369. std::unique_ptr<UnboundBackendFileOperations> file_operations,
  370. int32_t trailer_prefetch_size,
  371. SimpleEntryCreationResults* out_results) {
  372. base::TimeTicks start = base::TimeTicks::Now();
  373. if (index_state == INDEX_MISS) {
  374. // Try to just create.
  375. auto sync_entry = std::make_unique<SimpleSynchronousEntry>(
  376. cache_type, path, key, entry_hash, file_tracker,
  377. std::move(file_operations), trailer_prefetch_size);
  378. {
  379. BackendFileOperations* bound_file_operations = nullptr;
  380. ScopedFileOperationsBinding binding(sync_entry.get(),
  381. &bound_file_operations);
  382. out_results->result = sync_entry->InitializeForCreate(
  383. bound_file_operations, &out_results->entry_stat);
  384. }
  385. switch (out_results->result) {
  386. case net::OK:
  387. out_results->sync_entry = sync_entry.release();
  388. out_results->created = true;
  389. RecordDiskCreateLatency(cache_type, base::TimeTicks::Now() - start);
  390. return;
  391. case net::ERR_FILE_EXISTS:
  392. // Our index was messed up.
  393. if (optimistic_create) {
  394. // In this case, ::OpenOrCreateEntry already returned claiming it made
  395. // a new entry. Try extra-hard to make that the actual case.
  396. sync_entry->Doom();
  397. sync_entry->CloseFiles();
  398. file_operations = std::move(sync_entry->unbound_file_operations_);
  399. sync_entry = nullptr;
  400. CreateEntry(cache_type, path, key, entry_hash, file_tracker,
  401. std::move(file_operations), out_results);
  402. return;
  403. }
  404. // Otherwise can just try opening.
  405. break;
  406. default:
  407. // Trouble. Fail this time.
  408. sync_entry->Doom();
  409. sync_entry->CloseFiles();
  410. out_results->unbound_file_operations =
  411. std::move(sync_entry->unbound_file_operations_);
  412. return;
  413. }
  414. file_operations = std::move(sync_entry->unbound_file_operations_);
  415. }
  416. DCHECK(file_operations);
  417. // Try open, then if that fails create.
  418. OpenEntry(cache_type, path, key, entry_hash, file_tracker,
  419. std::move(file_operations), trailer_prefetch_size, out_results);
  420. if (out_results->sync_entry)
  421. return;
  422. file_operations = std::move(out_results->unbound_file_operations);
  423. DCHECK(file_operations);
  424. CreateEntry(cache_type, path, key, entry_hash, file_tracker,
  425. std::move(file_operations), out_results);
  426. }
  427. // static
  428. int SimpleSynchronousEntry::DeleteEntryFiles(
  429. const FilePath& path,
  430. net::CacheType cache_type,
  431. uint64_t entry_hash,
  432. std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
  433. auto file_operations =
  434. unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
  435. return DeleteEntryFilesInternal(path, cache_type, entry_hash,
  436. file_operations.get());
  437. }
  438. // static
  439. int SimpleSynchronousEntry::DeleteEntryFilesInternal(
  440. const FilePath& path,
  441. net::CacheType cache_type,
  442. uint64_t entry_hash,
  443. BackendFileOperations* file_operations) {
  444. base::TimeTicks start = base::TimeTicks::Now();
  445. const bool deleted_well =
  446. DeleteFilesForEntryHash(path, entry_hash, file_operations);
  447. SIMPLE_CACHE_UMA(TIMES, "DiskDoomLatency", cache_type,
  448. base::TimeTicks::Now() - start);
  449. return deleted_well ? net::OK : net::ERR_FAILED;
  450. }
  451. int SimpleSynchronousEntry::Doom() {
  452. BackendFileOperations* file_operations = nullptr;
  453. ScopedFileOperationsBinding binding(this, &file_operations);
  454. return DoomInternal(file_operations);
  455. }
  456. int SimpleSynchronousEntry::DoomInternal(
  457. BackendFileOperations* file_operations) {
  458. if (entry_file_key_.doom_generation != 0u) {
  459. // Already doomed.
  460. return true;
  461. }
  462. if (have_open_files_) {
  463. base::TimeTicks start = base::TimeTicks::Now();
  464. bool ok = true;
  465. SimpleFileTracker::EntryFileKey orig_key = entry_file_key_;
  466. file_tracker_->Doom(this, &entry_file_key_);
  467. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  468. if (!empty_file_omitted_[i]) {
  469. base::File::Error out_error;
  470. FilePath old_name = path_.AppendASCII(
  471. GetFilenameFromEntryFileKeyAndFileIndex(orig_key, i));
  472. FilePath new_name = path_.AppendASCII(
  473. GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, i));
  474. ok = file_operations->ReplaceFile(old_name, new_name, &out_error) && ok;
  475. }
  476. }
  477. if (sparse_file_open()) {
  478. base::File::Error out_error;
  479. FilePath old_name =
  480. path_.AppendASCII(GetSparseFilenameFromEntryFileKey(orig_key));
  481. FilePath new_name =
  482. path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
  483. ok = file_operations->ReplaceFile(old_name, new_name, &out_error) && ok;
  484. }
  485. SIMPLE_CACHE_UMA(TIMES, "DiskDoomLatency", cache_type_,
  486. base::TimeTicks::Now() - start);
  487. return ok ? net::OK : net::ERR_FAILED;
  488. } else {
  489. // No one has ever called Create or Open on us, so we don't have to worry
  490. // about being accessible to other ops after doom.
  491. return DeleteEntryFilesInternal(
  492. path_, cache_type_, entry_file_key_.entry_hash, file_operations);
  493. }
  494. }
  495. // static
  496. int SimpleSynchronousEntry::TruncateEntryFiles(
  497. const base::FilePath& path,
  498. uint64_t entry_hash,
  499. std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
  500. auto file_operations =
  501. unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
  502. const bool deleted_well =
  503. TruncateFilesForEntryHash(path, entry_hash, file_operations.get());
  504. return deleted_well ? net::OK : net::ERR_FAILED;
  505. }
  506. // static
  507. int SimpleSynchronousEntry::DeleteEntrySetFiles(
  508. const std::vector<uint64_t>* key_hashes,
  509. const FilePath& path,
  510. std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations) {
  511. auto file_operations =
  512. unbound_file_operations->Bind(base::SequencedTaskRunnerHandle::Get());
  513. const size_t did_delete_count =
  514. std::count_if(key_hashes->begin(), key_hashes->end(),
  515. [&path, &file_operations](const uint64_t& key_hash) {
  516. return SimpleSynchronousEntry::DeleteFilesForEntryHash(
  517. path, key_hash, file_operations.get());
  518. });
  519. return (did_delete_count == key_hashes->size()) ? net::OK : net::ERR_FAILED;
  520. }
  521. void SimpleSynchronousEntry::ReadData(const ReadRequest& in_entry_op,
  522. SimpleEntryStat* entry_stat,
  523. net::IOBuffer* out_buf,
  524. ReadResult* out_result) {
  525. DCHECK(initialized_);
  526. DCHECK_NE(0, in_entry_op.index);
  527. BackendFileOperations* file_operations = nullptr;
  528. ScopedFileOperationsBinding binding(this, &file_operations);
  529. int file_index = GetFileIndexFromStreamIndex(in_entry_op.index);
  530. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  531. file_operations, this, SubFileForFileIndex(file_index));
  532. out_result->crc_updated = false;
  533. if (!file.IsOK() || (header_and_key_check_needed_[file_index] &&
  534. !CheckHeaderAndKey(file.get(), file_index))) {
  535. out_result->result = net::ERR_FAILED;
  536. DoomInternal(file_operations);
  537. return;
  538. }
  539. const int64_t file_offset = entry_stat->GetOffsetInFile(
  540. key_.size(), in_entry_op.offset, in_entry_op.index);
  541. // Zero-length reads and reads to the empty streams of omitted files should
  542. // be handled in the SimpleEntryImpl.
  543. DCHECK_GT(in_entry_op.buf_len, 0);
  544. DCHECK(!empty_file_omitted_[file_index]);
  545. int bytes_read =
  546. file->Read(file_offset, out_buf->data(), in_entry_op.buf_len);
  547. if (bytes_read > 0) {
  548. entry_stat->set_last_used(Time::Now());
  549. if (in_entry_op.request_update_crc) {
  550. out_result->updated_crc32 = simple_util::IncrementalCrc32(
  551. in_entry_op.previous_crc32, out_buf->data(), bytes_read);
  552. out_result->crc_updated = true;
  553. // Verify checksum after last read, if we've been asked to.
  554. if (in_entry_op.request_verify_crc &&
  555. in_entry_op.offset + bytes_read ==
  556. entry_stat->data_size(in_entry_op.index)) {
  557. int checksum_result =
  558. CheckEOFRecord(file_operations, file.get(), in_entry_op.index,
  559. *entry_stat, out_result->updated_crc32);
  560. if (checksum_result < 0) {
  561. out_result->result = checksum_result;
  562. return;
  563. }
  564. }
  565. }
  566. }
  567. if (bytes_read >= 0) {
  568. out_result->result = bytes_read;
  569. } else {
  570. out_result->result = net::ERR_CACHE_READ_FAILURE;
  571. DoomInternal(file_operations);
  572. }
  573. }
  574. void SimpleSynchronousEntry::WriteData(const WriteRequest& in_entry_op,
  575. net::IOBuffer* in_buf,
  576. SimpleEntryStat* out_entry_stat,
  577. WriteResult* out_write_result) {
  578. BackendFileOperations* file_operations = nullptr;
  579. ScopedFileOperationsBinding binding(this, &file_operations);
  580. base::ElapsedTimer write_time;
  581. DCHECK(initialized_);
  582. DCHECK_NE(0, in_entry_op.index);
  583. int index = in_entry_op.index;
  584. int file_index = GetFileIndexFromStreamIndex(index);
  585. if (header_and_key_check_needed_[file_index] &&
  586. !empty_file_omitted_[file_index]) {
  587. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  588. file_operations, this, SubFileForFileIndex(file_index));
  589. if (!file.IsOK() || !CheckHeaderAndKey(file.get(), file_index)) {
  590. out_write_result->result = net::ERR_FAILED;
  591. DoomInternal(file_operations);
  592. return;
  593. }
  594. }
  595. int offset = in_entry_op.offset;
  596. int buf_len = in_entry_op.buf_len;
  597. bool truncate = in_entry_op.truncate;
  598. bool doomed = in_entry_op.doomed;
  599. const int64_t file_offset = out_entry_stat->GetOffsetInFile(
  600. key_.size(), in_entry_op.offset, in_entry_op.index);
  601. bool extending_by_write = offset + buf_len > out_entry_stat->data_size(index);
  602. if (empty_file_omitted_[file_index]) {
  603. // Don't create a new file if the entry has been doomed, to avoid it being
  604. // mixed up with a newly-created entry with the same key.
  605. if (doomed) {
  606. DLOG(WARNING) << "Rejecting write to lazily omitted stream "
  607. << in_entry_op.index << " of doomed cache entry.";
  608. RecordWriteResult(cache_type_,
  609. SYNC_WRITE_RESULT_LAZY_STREAM_ENTRY_DOOMED);
  610. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  611. return;
  612. }
  613. base::File::Error error;
  614. if (!MaybeCreateFile(file_operations, file_index, FILE_REQUIRED, &error)) {
  615. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_LAZY_CREATE_FAILURE);
  616. DoomInternal(file_operations);
  617. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  618. return;
  619. }
  620. if (!InitializeCreatedFile(file_operations, file_index)) {
  621. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_LAZY_INITIALIZE_FAILURE);
  622. DoomInternal(file_operations);
  623. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  624. return;
  625. }
  626. }
  627. DCHECK(!empty_file_omitted_[file_index]);
  628. // This needs to be grabbed after the above block, since that's what may
  629. // create the file (for stream 2/file 1).
  630. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  631. file_operations, this, SubFileForFileIndex(file_index));
  632. if (!file.IsOK()) {
  633. out_write_result->result = net::ERR_FAILED;
  634. DoomInternal(file_operations);
  635. return;
  636. }
  637. if (extending_by_write) {
  638. // The EOF record and the eventual stream afterward need to be zeroed out.
  639. const int64_t file_eof_offset =
  640. out_entry_stat->GetEOFOffsetInFile(key_.size(), index);
  641. if (!file->SetLength(file_eof_offset)) {
  642. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_PRETRUNCATE_FAILURE);
  643. DoomInternal(file_operations);
  644. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  645. return;
  646. }
  647. }
  648. if (buf_len > 0) {
  649. if (file->Write(file_offset, in_buf->data(), buf_len) != buf_len) {
  650. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_WRITE_FAILURE);
  651. DoomInternal(file_operations);
  652. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  653. return;
  654. }
  655. }
  656. if (!truncate && (buf_len > 0 || !extending_by_write)) {
  657. out_entry_stat->set_data_size(
  658. index, std::max(out_entry_stat->data_size(index), offset + buf_len));
  659. } else {
  660. out_entry_stat->set_data_size(index, offset + buf_len);
  661. int file_eof_offset =
  662. out_entry_stat->GetLastEOFOffsetInFile(key_.size(), index);
  663. if (!file->SetLength(file_eof_offset)) {
  664. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_TRUNCATE_FAILURE);
  665. DoomInternal(file_operations);
  666. out_write_result->result = net::ERR_CACHE_WRITE_FAILURE;
  667. return;
  668. }
  669. }
  670. if (in_entry_op.request_update_crc && buf_len > 0) {
  671. out_write_result->updated_crc32 = simple_util::IncrementalCrc32(
  672. in_entry_op.previous_crc32, in_buf->data(), buf_len);
  673. out_write_result->crc_updated = true;
  674. }
  675. SIMPLE_CACHE_UMA(TIMES, "DiskWriteLatency", cache_type_,
  676. write_time.Elapsed());
  677. RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_SUCCESS);
  678. base::Time modification_time = Time::Now();
  679. out_entry_stat->set_last_used(modification_time);
  680. out_entry_stat->set_last_modified(modification_time);
  681. out_write_result->result = buf_len;
  682. }
  683. void SimpleSynchronousEntry::ReadSparseData(const SparseRequest& in_entry_op,
  684. net::IOBuffer* out_buf,
  685. base::Time* out_last_used,
  686. int* out_result) {
  687. DCHECK(initialized_);
  688. BackendFileOperations* file_operations = nullptr;
  689. ScopedFileOperationsBinding binding(this, &file_operations);
  690. int64_t offset = in_entry_op.sparse_offset;
  691. int buf_len = in_entry_op.buf_len;
  692. char* buf = out_buf->data();
  693. int read_so_far = 0;
  694. if (!sparse_file_open()) {
  695. *out_result = 0;
  696. return;
  697. }
  698. SimpleFileTracker::FileHandle sparse_file = file_tracker_->Acquire(
  699. file_operations, this, SimpleFileTracker::SubFile::FILE_SPARSE);
  700. if (!sparse_file.IsOK()) {
  701. DoomInternal(file_operations);
  702. *out_result = net::ERR_CACHE_READ_FAILURE;
  703. return;
  704. }
  705. // Find the first sparse range at or after the requested offset.
  706. auto it = sparse_ranges_.lower_bound(offset);
  707. if (it != sparse_ranges_.begin()) {
  708. // Hop back one range and read the one overlapping with the start.
  709. --it;
  710. SparseRange* found_range = &it->second;
  711. DCHECK_EQ(it->first, found_range->offset);
  712. if (found_range->offset + found_range->length > offset) {
  713. DCHECK_GE(found_range->length, 0);
  714. DCHECK_LE(found_range->length, std::numeric_limits<int32_t>::max());
  715. DCHECK_GE(offset - found_range->offset, 0);
  716. DCHECK_LE(offset - found_range->offset,
  717. std::numeric_limits<int32_t>::max());
  718. int net_offset = static_cast<int>(offset - found_range->offset);
  719. int range_len_after_offset =
  720. static_cast<int>(found_range->length - net_offset);
  721. DCHECK_GE(range_len_after_offset, 0);
  722. int len_to_read = std::min(buf_len, range_len_after_offset);
  723. if (!ReadSparseRange(sparse_file.get(), found_range, net_offset,
  724. len_to_read, buf)) {
  725. DoomInternal(file_operations);
  726. *out_result = net::ERR_CACHE_READ_FAILURE;
  727. return;
  728. }
  729. read_so_far += len_to_read;
  730. }
  731. ++it;
  732. }
  733. // Keep reading until the buffer is full or there is not another contiguous
  734. // range.
  735. while (read_so_far < buf_len &&
  736. it != sparse_ranges_.end() &&
  737. it->second.offset == offset + read_so_far) {
  738. SparseRange* found_range = &it->second;
  739. DCHECK_EQ(it->first, found_range->offset);
  740. int range_len = base::saturated_cast<int>(found_range->length);
  741. int len_to_read = std::min(buf_len - read_so_far, range_len);
  742. if (!ReadSparseRange(sparse_file.get(), found_range, 0, len_to_read,
  743. buf + read_so_far)) {
  744. DoomInternal(file_operations);
  745. *out_result = net::ERR_CACHE_READ_FAILURE;
  746. return;
  747. }
  748. read_so_far += len_to_read;
  749. ++it;
  750. }
  751. *out_result = read_so_far;
  752. }
  753. void SimpleSynchronousEntry::WriteSparseData(const SparseRequest& in_entry_op,
  754. net::IOBuffer* in_buf,
  755. uint64_t max_sparse_data_size,
  756. SimpleEntryStat* out_entry_stat,
  757. int* out_result) {
  758. DCHECK(initialized_);
  759. BackendFileOperations* file_operations = nullptr;
  760. ScopedFileOperationsBinding binding(this, &file_operations);
  761. int64_t offset = in_entry_op.sparse_offset;
  762. int buf_len = in_entry_op.buf_len;
  763. const char* buf = in_buf->data();
  764. int written_so_far = 0;
  765. int appended_so_far = 0;
  766. if (!sparse_file_open() && !CreateSparseFile(file_operations)) {
  767. DoomInternal(file_operations);
  768. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  769. return;
  770. }
  771. SimpleFileTracker::FileHandle sparse_file = file_tracker_->Acquire(
  772. file_operations, this, SimpleFileTracker::SubFile::FILE_SPARSE);
  773. if (!sparse_file.IsOK()) {
  774. DoomInternal(file_operations);
  775. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  776. return;
  777. }
  778. int32_t sparse_data_size = out_entry_stat->sparse_data_size();
  779. int32_t future_sparse_data_size;
  780. if (!base::CheckAdd(sparse_data_size, buf_len)
  781. .AssignIfValid(&future_sparse_data_size) ||
  782. future_sparse_data_size < 0) {
  783. DoomInternal(file_operations);
  784. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  785. return;
  786. }
  787. // This is a pessimistic estimate; it assumes the entire buffer is going to
  788. // be appended as a new range, not written over existing ranges.
  789. if (static_cast<uint64_t>(future_sparse_data_size) > max_sparse_data_size) {
  790. DVLOG(1) << "Truncating sparse data file (" << sparse_data_size << " + "
  791. << buf_len << " > " << max_sparse_data_size << ")";
  792. TruncateSparseFile(sparse_file.get());
  793. out_entry_stat->set_sparse_data_size(0);
  794. }
  795. auto it = sparse_ranges_.lower_bound(offset);
  796. if (it != sparse_ranges_.begin()) {
  797. --it;
  798. SparseRange* found_range = &it->second;
  799. if (found_range->offset + found_range->length > offset) {
  800. DCHECK_GE(found_range->length, 0);
  801. DCHECK_LE(found_range->length, std::numeric_limits<int32_t>::max());
  802. DCHECK_GE(offset - found_range->offset, 0);
  803. DCHECK_LE(offset - found_range->offset,
  804. std::numeric_limits<int32_t>::max());
  805. int net_offset = static_cast<int>(offset - found_range->offset);
  806. int range_len_after_offset =
  807. static_cast<int>(found_range->length - net_offset);
  808. DCHECK_GE(range_len_after_offset, 0);
  809. int len_to_write = std::min(buf_len, range_len_after_offset);
  810. if (!WriteSparseRange(sparse_file.get(), found_range, net_offset,
  811. len_to_write, buf)) {
  812. DoomInternal(file_operations);
  813. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  814. return;
  815. }
  816. written_so_far += len_to_write;
  817. }
  818. ++it;
  819. }
  820. while (written_so_far < buf_len &&
  821. it != sparse_ranges_.end() &&
  822. it->second.offset < offset + buf_len) {
  823. SparseRange* found_range = &it->second;
  824. if (offset + written_so_far < found_range->offset) {
  825. int len_to_append =
  826. static_cast<int>(found_range->offset - (offset + written_so_far));
  827. if (!AppendSparseRange(sparse_file.get(), offset + written_so_far,
  828. len_to_append, buf + written_so_far)) {
  829. DoomInternal(file_operations);
  830. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  831. return;
  832. }
  833. written_so_far += len_to_append;
  834. appended_so_far += len_to_append;
  835. }
  836. int range_len = base::saturated_cast<int>(found_range->length);
  837. int len_to_write = std::min(buf_len - written_so_far, range_len);
  838. if (!WriteSparseRange(sparse_file.get(), found_range, 0, len_to_write,
  839. buf + written_so_far)) {
  840. DoomInternal(file_operations);
  841. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  842. return;
  843. }
  844. written_so_far += len_to_write;
  845. ++it;
  846. }
  847. if (written_so_far < buf_len) {
  848. int len_to_append = buf_len - written_so_far;
  849. if (!AppendSparseRange(sparse_file.get(), offset + written_so_far,
  850. len_to_append, buf + written_so_far)) {
  851. DoomInternal(file_operations);
  852. *out_result = net::ERR_CACHE_WRITE_FAILURE;
  853. return;
  854. }
  855. written_so_far += len_to_append;
  856. appended_so_far += len_to_append;
  857. }
  858. DCHECK_EQ(buf_len, written_so_far);
  859. base::Time modification_time = Time::Now();
  860. out_entry_stat->set_last_used(modification_time);
  861. out_entry_stat->set_last_modified(modification_time);
  862. int32_t old_sparse_data_size = out_entry_stat->sparse_data_size();
  863. out_entry_stat->set_sparse_data_size(old_sparse_data_size + appended_so_far);
  864. *out_result = written_so_far;
  865. }
  866. void SimpleSynchronousEntry::GetAvailableRange(const SparseRequest& in_entry_op,
  867. RangeResult* out_result) {
  868. DCHECK(initialized_);
  869. int64_t offset = in_entry_op.sparse_offset;
  870. int len = in_entry_op.buf_len;
  871. auto it = sparse_ranges_.lower_bound(offset);
  872. int64_t start = offset;
  873. int64_t avail_so_far = 0;
  874. if (it != sparse_ranges_.end() && it->second.offset < offset + len)
  875. start = it->second.offset;
  876. if ((it == sparse_ranges_.end() || it->second.offset > offset) &&
  877. it != sparse_ranges_.begin()) {
  878. --it;
  879. if (it->second.offset + it->second.length > offset) {
  880. start = offset;
  881. avail_so_far = (it->second.offset + it->second.length) - offset;
  882. }
  883. ++it;
  884. }
  885. while (start + avail_so_far < offset + len &&
  886. it != sparse_ranges_.end() &&
  887. it->second.offset == start + avail_so_far) {
  888. avail_so_far += it->second.length;
  889. ++it;
  890. }
  891. int64_t len_from_start = len - (start - offset);
  892. *out_result = RangeResult(
  893. start, static_cast<int>(std::min(avail_so_far, len_from_start)));
  894. }
  895. int SimpleSynchronousEntry::CheckEOFRecord(
  896. BackendFileOperations* file_operations,
  897. base::File* file,
  898. int stream_index,
  899. const SimpleEntryStat& entry_stat,
  900. uint32_t expected_crc32) {
  901. DCHECK(initialized_);
  902. SimpleFileEOF eof_record;
  903. int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
  904. int file_index = GetFileIndexFromStreamIndex(stream_index);
  905. int rv =
  906. GetEOFRecordData(file, nullptr, file_index, file_offset, &eof_record);
  907. if (rv != net::OK) {
  908. DoomInternal(file_operations);
  909. return rv;
  910. }
  911. if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
  912. eof_record.data_crc32 != expected_crc32) {
  913. DVLOG(1) << "EOF record had bad crc.";
  914. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
  915. DoomInternal(file_operations);
  916. return net::ERR_CACHE_CHECKSUM_MISMATCH;
  917. }
  918. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
  919. return net::OK;
  920. }
  921. int SimpleSynchronousEntry::PreReadStreamPayload(
  922. base::File* file,
  923. PrefetchData* prefetch_data,
  924. int stream_index,
  925. int extra_size,
  926. const SimpleEntryStat& entry_stat,
  927. const SimpleFileEOF& eof_record,
  928. SimpleStreamPrefetchData* out) {
  929. DCHECK(stream_index == 0 || stream_index == 1);
  930. int stream_size = entry_stat.data_size(stream_index);
  931. int read_size = stream_size + extra_size;
  932. out->data = base::MakeRefCounted<net::GrowableIOBuffer>();
  933. out->data->SetCapacity(read_size);
  934. int file_offset = entry_stat.GetOffsetInFile(key_.size(), 0, stream_index);
  935. if (!ReadFromFileOrPrefetched(file, prefetch_data, 0, file_offset, read_size,
  936. out->data->data()))
  937. return net::ERR_FAILED;
  938. // Check the CRC32.
  939. uint32_t expected_crc32 = simple_util::Crc32(out->data->data(), stream_size);
  940. if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
  941. eof_record.data_crc32 != expected_crc32) {
  942. DVLOG(1) << "EOF record had bad crc.";
  943. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
  944. return net::ERR_CACHE_CHECKSUM_MISMATCH;
  945. }
  946. out->stream_crc32 = expected_crc32;
  947. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
  948. return net::OK;
  949. }
  950. void SimpleSynchronousEntry::Close(
  951. const SimpleEntryStat& entry_stat,
  952. std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write,
  953. net::GrowableIOBuffer* stream_0_data,
  954. SimpleEntryCloseResults* out_results) {
  955. // As we delete `this`, we cannot use ScopedFileOperationsBinding here.
  956. std::unique_ptr<BackendFileOperations> file_operations =
  957. unbound_file_operations_->Bind(base::SequencedTaskRunnerHandle::Get());
  958. unbound_file_operations_ = nullptr;
  959. base::ElapsedTimer close_time;
  960. DCHECK(stream_0_data);
  961. for (auto& crc_record : *crc32s_to_write) {
  962. const int stream_index = crc_record.index;
  963. const int file_index = GetFileIndexFromStreamIndex(stream_index);
  964. if (empty_file_omitted_[file_index])
  965. continue;
  966. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  967. file_operations.get(), this, SubFileForFileIndex(file_index));
  968. if (!file.IsOK()) {
  969. RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
  970. DoomInternal(file_operations.get());
  971. break;
  972. }
  973. if (stream_index == 0) {
  974. // Write stream 0 data.
  975. int stream_0_offset = entry_stat.GetOffsetInFile(key_.size(), 0, 0);
  976. if (file->Write(stream_0_offset, stream_0_data->data(),
  977. entry_stat.data_size(0)) != entry_stat.data_size(0)) {
  978. RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
  979. DVLOG(1) << "Could not write stream 0 data.";
  980. DoomInternal(file_operations.get());
  981. }
  982. net::SHA256HashValue hash_value;
  983. CalculateSHA256OfKey(key_, &hash_value);
  984. if (file->Write(stream_0_offset + entry_stat.data_size(0),
  985. reinterpret_cast<char*>(hash_value.data),
  986. sizeof(hash_value)) != sizeof(hash_value)) {
  987. RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
  988. DVLOG(1) << "Could not write stream 0 data.";
  989. DoomInternal(file_operations.get());
  990. }
  991. // Re-compute stream 0 CRC if the data got changed (we may be here even
  992. // if it didn't change if stream 0's position on disk got changed due to
  993. // stream 1 write).
  994. if (!crc_record.has_crc32) {
  995. crc_record.data_crc32 =
  996. simple_util::Crc32(stream_0_data->data(), entry_stat.data_size(0));
  997. crc_record.has_crc32 = true;
  998. }
  999. out_results->estimated_trailer_prefetch_size =
  1000. entry_stat.data_size(0) + sizeof(hash_value) + sizeof(SimpleFileEOF);
  1001. }
  1002. SimpleFileEOF eof_record;
  1003. eof_record.stream_size = entry_stat.data_size(stream_index);
  1004. eof_record.final_magic_number = kSimpleFinalMagicNumber;
  1005. eof_record.flags = 0;
  1006. if (crc_record.has_crc32)
  1007. eof_record.flags |= SimpleFileEOF::FLAG_HAS_CRC32;
  1008. if (stream_index == 0)
  1009. eof_record.flags |= SimpleFileEOF::FLAG_HAS_KEY_SHA256;
  1010. eof_record.data_crc32 = crc_record.data_crc32;
  1011. int eof_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
  1012. // If stream 0 changed size, the file needs to be resized, otherwise the
  1013. // next open will yield wrong stream sizes. On stream 1 and stream 2 proper
  1014. // resizing of the file is handled in SimpleSynchronousEntry::WriteData().
  1015. if (stream_index == 0 && !file->SetLength(eof_offset)) {
  1016. RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
  1017. DVLOG(1) << "Could not truncate stream 0 file.";
  1018. DoomInternal(file_operations.get());
  1019. break;
  1020. }
  1021. if (file->Write(eof_offset, reinterpret_cast<const char*>(&eof_record),
  1022. sizeof(eof_record)) != sizeof(eof_record)) {
  1023. RecordCloseResult(cache_type_, CLOSE_RESULT_WRITE_FAILURE);
  1024. DVLOG(1) << "Could not write eof record.";
  1025. DoomInternal(file_operations.get());
  1026. break;
  1027. }
  1028. }
  1029. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1030. if (empty_file_omitted_[i])
  1031. continue;
  1032. if (header_and_key_check_needed_[i]) {
  1033. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  1034. file_operations.get(), this, SubFileForFileIndex(i));
  1035. if (!file.IsOK() || !CheckHeaderAndKey(file.get(), i))
  1036. DoomInternal(file_operations.get());
  1037. }
  1038. CloseFile(file_operations.get(), i);
  1039. }
  1040. if (sparse_file_open()) {
  1041. CloseSparseFile(file_operations.get());
  1042. }
  1043. SIMPLE_CACHE_UMA(TIMES, "DiskCloseLatency", cache_type_,
  1044. close_time.Elapsed());
  1045. RecordCloseResult(cache_type_, CLOSE_RESULT_SUCCESS);
  1046. have_open_files_ = false;
  1047. delete this;
  1048. }
  1049. SimpleSynchronousEntry::SimpleSynchronousEntry(
  1050. net::CacheType cache_type,
  1051. const FilePath& path,
  1052. const std::string& key,
  1053. const uint64_t entry_hash,
  1054. SimpleFileTracker* file_tracker,
  1055. std::unique_ptr<UnboundBackendFileOperations> unbound_file_operations,
  1056. int32_t trailer_prefetch_size)
  1057. : cache_type_(cache_type),
  1058. path_(path),
  1059. entry_file_key_(entry_hash),
  1060. key_(key),
  1061. file_tracker_(file_tracker),
  1062. unbound_file_operations_(std::move(unbound_file_operations)),
  1063. trailer_prefetch_size_(trailer_prefetch_size) {
  1064. for (bool& empty_file_omitted : empty_file_omitted_) {
  1065. empty_file_omitted = false;
  1066. }
  1067. }
  1068. SimpleSynchronousEntry::~SimpleSynchronousEntry() {
  1069. DCHECK(!have_open_files_);
  1070. }
  1071. bool SimpleSynchronousEntry::MaybeOpenFile(
  1072. BackendFileOperations* file_operations,
  1073. int file_index,
  1074. base::File::Error* out_error) {
  1075. DCHECK(out_error);
  1076. FilePath filename = GetFilenameFromFileIndex(file_index);
  1077. int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
  1078. base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
  1079. auto file = std::make_unique<base::File>();
  1080. *file = file_operations->OpenFile(filename, flags);
  1081. *out_error = file->error_details();
  1082. if (CanOmitEmptyFile(file_index) && !file->IsValid() &&
  1083. *out_error == base::File::FILE_ERROR_NOT_FOUND) {
  1084. empty_file_omitted_[file_index] = true;
  1085. return true;
  1086. }
  1087. if (file->IsValid()) {
  1088. file_tracker_->Register(this, SubFileForFileIndex(file_index),
  1089. std::move(file));
  1090. return true;
  1091. }
  1092. return false;
  1093. }
  1094. bool SimpleSynchronousEntry::MaybeCreateFile(
  1095. BackendFileOperations* file_operations,
  1096. int file_index,
  1097. FileRequired file_required,
  1098. base::File::Error* out_error) {
  1099. DCHECK(out_error);
  1100. if (CanOmitEmptyFile(file_index) && file_required == FILE_NOT_REQUIRED) {
  1101. empty_file_omitted_[file_index] = true;
  1102. return true;
  1103. }
  1104. FilePath filename = GetFilenameFromFileIndex(file_index);
  1105. int flags = base::File::FLAG_CREATE | base::File::FLAG_READ |
  1106. base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
  1107. auto file =
  1108. std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
  1109. // It's possible that the creation failed because someone deleted the
  1110. // directory (e.g. because someone pressed "clear cache" on Android).
  1111. // If so, we would keep failing for a while until periodic index snapshot
  1112. // re-creates the cache dir, so try to recover from it quickly here.
  1113. //
  1114. // This previously also checked whether the directory was missing, but that
  1115. // races against other entry creations attempting the same recovery.
  1116. if (!file->IsValid() &&
  1117. file->error_details() == base::File::FILE_ERROR_NOT_FOUND) {
  1118. file_operations->CreateDirectory(path_);
  1119. *file = file_operations->OpenFile(filename, flags);
  1120. }
  1121. *out_error = file->error_details();
  1122. if (file->IsValid()) {
  1123. file_tracker_->Register(this, SubFileForFileIndex(file_index),
  1124. std::move(file));
  1125. empty_file_omitted_[file_index] = false;
  1126. return true;
  1127. }
  1128. return false;
  1129. }
  1130. bool SimpleSynchronousEntry::OpenFiles(BackendFileOperations* file_operations,
  1131. SimpleEntryStat* out_entry_stat) {
  1132. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1133. base::File::Error error;
  1134. if (!MaybeOpenFile(file_operations, i, &error)) {
  1135. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_PLATFORM_FILE_ERROR);
  1136. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncOpenPlatformFileError", cache_type_,
  1137. -error, -base::File::FILE_ERROR_MAX);
  1138. while (--i >= 0)
  1139. CloseFile(file_operations, i);
  1140. return false;
  1141. }
  1142. }
  1143. have_open_files_ = true;
  1144. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1145. if (empty_file_omitted_[i]) {
  1146. out_entry_stat->set_data_size(i + 1, 0);
  1147. continue;
  1148. }
  1149. base::File::Info file_info;
  1150. SimpleFileTracker::FileHandle file =
  1151. file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(i));
  1152. bool success = file.IsOK() && file->GetInfo(&file_info);
  1153. if (!success) {
  1154. DLOG(WARNING) << "Could not get platform file info.";
  1155. continue;
  1156. }
  1157. out_entry_stat->set_last_used(file_info.last_accessed);
  1158. out_entry_stat->set_last_modified(file_info.last_modified);
  1159. // Two things prevent from knowing the right values for |data_size|:
  1160. // 1) The key might not be known, hence its length might be unknown.
  1161. // 2) Stream 0 and stream 1 are in the same file, and the exact size for
  1162. // each will only be known when reading the EOF record for stream 0.
  1163. //
  1164. // The size for file 0 and 1 is temporarily kept in
  1165. // |data_size(1)| and |data_size(2)| respectively. Reading the key in
  1166. // InitializeForOpen yields the data size for each file. In the case of
  1167. // file hash_1, this is the total size of stream 2, and is assigned to
  1168. // data_size(2). In the case of file 0, it is the combined size of stream
  1169. // 0, stream 1 and one EOF record. The exact distribution of sizes between
  1170. // stream 1 and stream 0 is only determined after reading the EOF record
  1171. // for stream 0 in ReadAndValidateStream0AndMaybe1.
  1172. if (!base::IsValueInRangeForNumericType<int>(file_info.size)) {
  1173. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_INVALID_FILE_LENGTH);
  1174. return false;
  1175. }
  1176. out_entry_stat->set_data_size(i + 1, static_cast<int>(file_info.size));
  1177. }
  1178. return true;
  1179. }
  1180. bool SimpleSynchronousEntry::CreateFiles(BackendFileOperations* file_operations,
  1181. SimpleEntryStat* out_entry_stat) {
  1182. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1183. base::File::Error error;
  1184. if (!MaybeCreateFile(file_operations, i, FILE_NOT_REQUIRED, &error)) {
  1185. SIMPLE_CACHE_LOCAL(ENUMERATION, "SyncCreatePlatformFileError",
  1186. cache_type_, -error, -base::File::FILE_ERROR_MAX);
  1187. while (--i >= 0)
  1188. CloseFile(file_operations, i);
  1189. return false;
  1190. }
  1191. }
  1192. have_open_files_ = true;
  1193. base::Time creation_time = Time::Now();
  1194. out_entry_stat->set_last_modified(creation_time);
  1195. out_entry_stat->set_last_used(creation_time);
  1196. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i)
  1197. out_entry_stat->set_data_size(i, 0);
  1198. return true;
  1199. }
  1200. void SimpleSynchronousEntry::CloseFile(BackendFileOperations* file_operations,
  1201. int index) {
  1202. if (empty_file_omitted_[index]) {
  1203. empty_file_omitted_[index] = false;
  1204. } else {
  1205. // We want to delete files that were renamed for doom here; and we should do
  1206. // this before calling SimpleFileTracker::Close, since that would make the
  1207. // name available to other threads.
  1208. if (entry_file_key_.doom_generation != 0u) {
  1209. file_operations->DeleteFile(path_.AppendASCII(
  1210. GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, index)));
  1211. }
  1212. file_tracker_->Close(this, SubFileForFileIndex(index));
  1213. }
  1214. }
  1215. void SimpleSynchronousEntry::CloseFiles() {
  1216. if (!have_open_files_) {
  1217. return;
  1218. }
  1219. BackendFileOperations* file_operations = nullptr;
  1220. ScopedFileOperationsBinding binding(this, &file_operations);
  1221. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i)
  1222. CloseFile(file_operations, i);
  1223. if (sparse_file_open())
  1224. CloseSparseFile(file_operations);
  1225. have_open_files_ = false;
  1226. }
  1227. bool SimpleSynchronousEntry::CheckHeaderAndKey(base::File* file,
  1228. int file_index) {
  1229. std::vector<char> header_data(key_.empty() ? kInitialHeaderRead
  1230. : GetHeaderSize(key_.size()));
  1231. int bytes_read = file->Read(0, header_data.data(), header_data.size());
  1232. const SimpleFileHeader* header =
  1233. reinterpret_cast<const SimpleFileHeader*>(header_data.data());
  1234. if (bytes_read == -1 || static_cast<size_t>(bytes_read) < sizeof(*header)) {
  1235. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_HEADER);
  1236. return false;
  1237. }
  1238. // This resize will not invalidate iterators since it does not enlarge the
  1239. // header_data.
  1240. DCHECK_LE(static_cast<size_t>(bytes_read), header_data.size());
  1241. header_data.resize(bytes_read);
  1242. if (header->initial_magic_number != kSimpleInitialMagicNumber) {
  1243. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_MAGIC_NUMBER);
  1244. return false;
  1245. }
  1246. if (header->version != kSimpleEntryVersionOnDisk) {
  1247. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_BAD_VERSION);
  1248. return false;
  1249. }
  1250. size_t expected_header_size = GetHeaderSize(header->key_length);
  1251. if (header_data.size() < expected_header_size) {
  1252. size_t old_size = header_data.size();
  1253. int bytes_to_read = expected_header_size - old_size;
  1254. // This resize will invalidate iterators, since it is enlarging header_data.
  1255. header_data.resize(expected_header_size);
  1256. int read_result =
  1257. file->Read(old_size, header_data.data() + old_size, bytes_to_read);
  1258. if (read_result != bytes_to_read) {
  1259. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_CANT_READ_KEY);
  1260. return false;
  1261. }
  1262. header = reinterpret_cast<const SimpleFileHeader*>(header_data.data());
  1263. }
  1264. char* key_data = header_data.data() + sizeof(*header);
  1265. if (base::PersistentHash(key_data, header->key_length) != header->key_hash) {
  1266. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_HASH_MISMATCH);
  1267. return false;
  1268. }
  1269. std::string key_from_header(key_data, header->key_length);
  1270. if (key_.empty()) {
  1271. key_.swap(key_from_header);
  1272. } else {
  1273. if (key_ != key_from_header) {
  1274. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_KEY_MISMATCH);
  1275. return false;
  1276. }
  1277. }
  1278. header_and_key_check_needed_[file_index] = false;
  1279. return true;
  1280. }
  1281. int SimpleSynchronousEntry::InitializeForOpen(
  1282. BackendFileOperations* file_operations,
  1283. SimpleEntryStat* out_entry_stat,
  1284. SimpleStreamPrefetchData stream_prefetch_data[2]) {
  1285. DCHECK(!initialized_);
  1286. if (!OpenFiles(file_operations, out_entry_stat)) {
  1287. DLOG(WARNING) << "Could not open platform files for entry.";
  1288. return net::ERR_FAILED;
  1289. }
  1290. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1291. if (empty_file_omitted_[i])
  1292. continue;
  1293. if (key_.empty()) {
  1294. SimpleFileTracker::FileHandle file =
  1295. file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(i));
  1296. // If |key_| is empty, we were opened via the iterator interface, without
  1297. // knowing what our key is. We must therefore read the header immediately
  1298. // to discover it, so SimpleEntryImpl can make it available to
  1299. // disk_cache::Entry::GetKey().
  1300. if (!file.IsOK() || !CheckHeaderAndKey(file.get(), i))
  1301. return net::ERR_FAILED;
  1302. } else {
  1303. // If we do know which key were are looking for, we still need to
  1304. // check that the file actually has it (rather than just being a hash
  1305. // collision or some sort of file system accident), but that can be put
  1306. // off until opportune time: either the read of the footer, or when we
  1307. // start reading in the data, depending on stream # and format revision.
  1308. header_and_key_check_needed_[i] = true;
  1309. }
  1310. if (i == 0) {
  1311. // File size for stream 0 has been stored temporarily in data_size[1].
  1312. int ret_value_stream_0 = ReadAndValidateStream0AndMaybe1(
  1313. file_operations, out_entry_stat->data_size(1), out_entry_stat,
  1314. stream_prefetch_data);
  1315. if (ret_value_stream_0 != net::OK)
  1316. return ret_value_stream_0;
  1317. } else {
  1318. out_entry_stat->set_data_size(
  1319. 2,
  1320. GetDataSizeFromFileSize(key_.size(), out_entry_stat->data_size(2)));
  1321. const int32_t data_size_2 = out_entry_stat->data_size(2);
  1322. int ret_value_stream_2 = net::OK;
  1323. if (data_size_2 < 0) {
  1324. DLOG(WARNING) << "Stream 2 file is too small.";
  1325. ret_value_stream_2 = net::ERR_FAILED;
  1326. } else if (data_size_2 > 0) {
  1327. // Validate non empty stream 2.
  1328. SimpleFileEOF eof_record;
  1329. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  1330. file_operations, this, SubFileForFileIndex(i));
  1331. int file_offset =
  1332. out_entry_stat->GetEOFOffsetInFile(key_.size(), 2 /*stream index*/);
  1333. ret_value_stream_2 =
  1334. GetEOFRecordData(file.get(), nullptr, i, file_offset, &eof_record);
  1335. }
  1336. if (ret_value_stream_2 != net::OK) {
  1337. DCHECK_EQ(i, GetFileIndexFromStreamIndex(2));
  1338. DCHECK(CanOmitEmptyFile(GetFileIndexFromStreamIndex(2)));
  1339. // Stream 2 is broken, set its size to zero to have it automatically
  1340. // deleted further down in this function. For V8 this preserves the
  1341. // cached source when only the code cache was corrupted.
  1342. out_entry_stat->set_data_size(2, 0);
  1343. }
  1344. }
  1345. }
  1346. int32_t sparse_data_size = 0;
  1347. if (!OpenSparseFileIfExists(file_operations, &sparse_data_size)) {
  1348. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SPARSE_OPEN_FAILED);
  1349. return net::ERR_FAILED;
  1350. }
  1351. out_entry_stat->set_sparse_data_size(sparse_data_size);
  1352. const int stream2_file_index = GetFileIndexFromStreamIndex(2);
  1353. DCHECK(CanOmitEmptyFile(stream2_file_index));
  1354. if (!empty_file_omitted_[stream2_file_index] &&
  1355. out_entry_stat->data_size(2) == 0) {
  1356. CloseFile(file_operations, stream2_file_index);
  1357. DeleteFileForEntryHash(path_, entry_file_key_.entry_hash,
  1358. stream2_file_index, file_operations);
  1359. empty_file_omitted_[stream2_file_index] = true;
  1360. }
  1361. RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SUCCESS);
  1362. initialized_ = true;
  1363. return net::OK;
  1364. }
  1365. bool SimpleSynchronousEntry::InitializeCreatedFile(
  1366. BackendFileOperations* file_operations,
  1367. int file_index) {
  1368. SimpleFileTracker::FileHandle file = file_tracker_->Acquire(
  1369. file_operations, this, SubFileForFileIndex(file_index));
  1370. if (!file.IsOK())
  1371. return false;
  1372. SimpleFileHeader header;
  1373. header.initial_magic_number = kSimpleInitialMagicNumber;
  1374. header.version = kSimpleEntryVersionOnDisk;
  1375. header.key_length = key_.size();
  1376. header.key_hash = base::PersistentHash(key_);
  1377. int bytes_written =
  1378. file->Write(0, reinterpret_cast<char*>(&header), sizeof(header));
  1379. if (bytes_written != sizeof(header))
  1380. return false;
  1381. bytes_written = file->Write(sizeof(header), key_.data(), key_.size());
  1382. if (bytes_written != base::checked_cast<int>(key_.size()))
  1383. return false;
  1384. return true;
  1385. }
  1386. int SimpleSynchronousEntry::InitializeForCreate(
  1387. BackendFileOperations* file_operations,
  1388. SimpleEntryStat* out_entry_stat) {
  1389. DCHECK(!initialized_);
  1390. if (!CreateFiles(file_operations, out_entry_stat)) {
  1391. DLOG(WARNING) << "Could not create platform files.";
  1392. return net::ERR_FILE_EXISTS;
  1393. }
  1394. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1395. if (empty_file_omitted_[i])
  1396. continue;
  1397. if (!InitializeCreatedFile(file_operations, i))
  1398. return net::ERR_FAILED;
  1399. }
  1400. initialized_ = true;
  1401. return net::OK;
  1402. }
  1403. int SimpleSynchronousEntry::ReadAndValidateStream0AndMaybe1(
  1404. BackendFileOperations* file_operations,
  1405. int file_size,
  1406. SimpleEntryStat* out_entry_stat,
  1407. SimpleStreamPrefetchData stream_prefetch_data[2]) {
  1408. SimpleFileTracker::FileHandle file =
  1409. file_tracker_->Acquire(file_operations, this, SubFileForFileIndex(0));
  1410. if (!file.IsOK())
  1411. return net::ERR_FAILED;
  1412. // We may prefetch data from file in a couple cases:
  1413. // 1) If the file is small enough we may prefetch it entirely.
  1414. // 2) We may also prefetch a block of trailer bytes from the end of
  1415. // the file.
  1416. // In these cases the PrefetchData object is used to store the
  1417. // bytes read from the file. The PrefetchData object also keeps track
  1418. // of what range within the file has been prefetched. It will only
  1419. // allow reads wholely within this range to be accessed via its
  1420. // ReadData() method.
  1421. PrefetchData prefetch_data(file_size);
  1422. // Determine a threshold for fully prefetching the entire entry file. If
  1423. // the entry file is less than or equal to this number of bytes it will
  1424. // be fully prefetched.
  1425. int full_prefetch_size = GetSimpleCacheFullPrefetchSize();
  1426. // Determine how much trailer data to prefetch. If the full file prefetch
  1427. // does not trigger then this is the number of bytes to read from the end
  1428. // of the file in a single file operation. Ideally the trailer prefetch
  1429. // will contain at least stream 0 and its EOF record.
  1430. int trailer_prefetch_size =
  1431. GetSimpleCacheTrailerPrefetchSize(trailer_prefetch_size_);
  1432. OpenPrefetchMode prefetch_mode = OPEN_PREFETCH_NONE;
  1433. if (file_size <= full_prefetch_size || file_size <= trailer_prefetch_size) {
  1434. // Prefetch the entire file.
  1435. prefetch_mode = OPEN_PREFETCH_FULL;
  1436. RecordOpenPrefetchMode(cache_type_, prefetch_mode);
  1437. if (!prefetch_data.PrefetchFromFile(&file, 0, file_size))
  1438. return net::ERR_FAILED;
  1439. } else if (trailer_prefetch_size > 0) {
  1440. // Prefetch trailer data from the end of the file.
  1441. prefetch_mode = OPEN_PREFETCH_TRAILER;
  1442. RecordOpenPrefetchMode(cache_type_, prefetch_mode);
  1443. size_t length = std::min(trailer_prefetch_size, file_size);
  1444. size_t offset = file_size - length;
  1445. if (!prefetch_data.PrefetchFromFile(&file, offset, length))
  1446. return net::ERR_FAILED;
  1447. } else {
  1448. // Do no prefetching.
  1449. RecordOpenPrefetchMode(cache_type_, prefetch_mode);
  1450. }
  1451. // Read stream 0 footer first --- it has size/feature info required to figure
  1452. // out file 0's layout.
  1453. SimpleFileEOF stream_0_eof;
  1454. int rv = GetEOFRecordData(
  1455. file.get(), &prefetch_data, /* file_index = */ 0,
  1456. /* file_offset = */ file_size - sizeof(SimpleFileEOF), &stream_0_eof);
  1457. if (rv != net::OK)
  1458. return rv;
  1459. int32_t stream_0_size = stream_0_eof.stream_size;
  1460. if (stream_0_size < 0 || stream_0_size > file_size)
  1461. return net::ERR_FAILED;
  1462. out_entry_stat->set_data_size(0, stream_0_size);
  1463. // Calculate size for stream 1, now we know stream 0's.
  1464. // See comments in simple_entry_format.h for background.
  1465. bool has_key_sha256 =
  1466. (stream_0_eof.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
  1467. SimpleFileEOF::FLAG_HAS_KEY_SHA256;
  1468. int extra_post_stream_0_read = 0;
  1469. if (has_key_sha256)
  1470. extra_post_stream_0_read += sizeof(net::SHA256HashValue);
  1471. int32_t stream1_size = file_size - 2 * sizeof(SimpleFileEOF) - stream_0_size -
  1472. sizeof(SimpleFileHeader) - key_.size() -
  1473. extra_post_stream_0_read;
  1474. if (stream1_size < 0 || stream1_size > file_size)
  1475. return net::ERR_FAILED;
  1476. out_entry_stat->set_data_size(1, stream1_size);
  1477. // Put stream 0 data in memory --- plus maybe the sha256(key) footer.
  1478. rv = PreReadStreamPayload(file.get(), &prefetch_data, /* stream_index = */ 0,
  1479. extra_post_stream_0_read, *out_entry_stat,
  1480. stream_0_eof, &stream_prefetch_data[0]);
  1481. if (rv != net::OK)
  1482. return rv;
  1483. // Note the exact range needed in order to read the EOF record and stream 0.
  1484. // In APP_CACHE mode this will be stored directly in the index so we can
  1485. // know exactly how much to read next time.
  1486. computed_trailer_prefetch_size_ =
  1487. prefetch_data.GetDesiredTrailerPrefetchSize();
  1488. // If prefetch buffer is available, and we have sha256(key) (so we don't need
  1489. // to look at the header), extract out stream 1 info as well.
  1490. int stream_1_offset = out_entry_stat->GetOffsetInFile(
  1491. key_.size(), /* offset= */ 0, /* stream_index = */ 1);
  1492. int stream_1_read_size =
  1493. sizeof(SimpleFileEOF) + out_entry_stat->data_size(/* stream_index = */ 1);
  1494. if (has_key_sha256 &&
  1495. prefetch_data.HasData(stream_1_offset, stream_1_read_size)) {
  1496. SimpleFileEOF stream_1_eof;
  1497. int stream_1_eof_offset =
  1498. out_entry_stat->GetEOFOffsetInFile(key_.size(), /* stream_index = */ 1);
  1499. rv = GetEOFRecordData(file.get(), &prefetch_data, /* file_index = */ 0,
  1500. stream_1_eof_offset, &stream_1_eof);
  1501. if (rv != net::OK)
  1502. return rv;
  1503. rv = PreReadStreamPayload(file.get(), &prefetch_data,
  1504. /* stream_index = */ 1,
  1505. /* extra_size = */ 0, *out_entry_stat,
  1506. stream_1_eof, &stream_prefetch_data[1]);
  1507. if (rv != net::OK)
  1508. return rv;
  1509. }
  1510. // If present, check the key SHA256.
  1511. if (has_key_sha256) {
  1512. net::SHA256HashValue hash_value;
  1513. CalculateSHA256OfKey(key_, &hash_value);
  1514. bool matched =
  1515. std::memcmp(&hash_value,
  1516. stream_prefetch_data[0].data->data() + stream_0_size,
  1517. sizeof(hash_value)) == 0;
  1518. if (!matched)
  1519. return net::ERR_FAILED;
  1520. // Elide header check if we verified sha256(key) via footer.
  1521. header_and_key_check_needed_[0] = false;
  1522. }
  1523. // Ensure the key is validated before completion.
  1524. if (!has_key_sha256 && header_and_key_check_needed_[0])
  1525. CheckHeaderAndKey(file.get(), 0);
  1526. return net::OK;
  1527. }
  1528. bool SimpleSynchronousEntry::ReadFromFileOrPrefetched(
  1529. base::File* file,
  1530. PrefetchData* prefetch_data,
  1531. int file_index,
  1532. int offset,
  1533. int size,
  1534. char* dest) {
  1535. if (offset < 0 || size < 0)
  1536. return false;
  1537. if (size == 0)
  1538. return true;
  1539. base::CheckedNumeric<size_t> start(offset);
  1540. size_t start_numeric;
  1541. if (!start.AssignIfValid(&start_numeric))
  1542. return false;
  1543. base::CheckedNumeric<size_t> length(size);
  1544. size_t length_numeric;
  1545. if (!length.AssignIfValid(&length_numeric))
  1546. return false;
  1547. // First try to extract the desired range from the PrefetchData.
  1548. if (file_index == 0 && prefetch_data &&
  1549. prefetch_data->ReadData(start_numeric, length_numeric, dest)) {
  1550. return true;
  1551. }
  1552. // If we have not prefetched the range then we must read it from disk.
  1553. return file->Read(start_numeric, dest, length_numeric) == size;
  1554. }
  1555. int SimpleSynchronousEntry::GetEOFRecordData(base::File* file,
  1556. PrefetchData* prefetch_data,
  1557. int file_index,
  1558. int file_offset,
  1559. SimpleFileEOF* eof_record) {
  1560. if (!ReadFromFileOrPrefetched(file, prefetch_data, file_index, file_offset,
  1561. sizeof(SimpleFileEOF),
  1562. reinterpret_cast<char*>(eof_record))) {
  1563. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE);
  1564. return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
  1565. }
  1566. if (eof_record->final_magic_number != kSimpleFinalMagicNumber) {
  1567. RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH);
  1568. DVLOG(1) << "EOF record had bad magic number.";
  1569. return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
  1570. }
  1571. if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size))
  1572. return net::ERR_FAILED;
  1573. return net::OK;
  1574. }
  1575. // static
  1576. bool SimpleSynchronousEntry::DeleteFileForEntryHash(
  1577. const FilePath& path,
  1578. const uint64_t entry_hash,
  1579. const int file_index,
  1580. BackendFileOperations* file_operations) {
  1581. FilePath to_delete = path.AppendASCII(GetFilenameFromEntryFileKeyAndFileIndex(
  1582. SimpleFileTracker::EntryFileKey(entry_hash), file_index));
  1583. return file_operations->DeleteFile(to_delete);
  1584. }
  1585. // static
  1586. bool SimpleSynchronousEntry::DeleteFilesForEntryHash(
  1587. const FilePath& path,
  1588. const uint64_t entry_hash,
  1589. BackendFileOperations* file_operations) {
  1590. bool result = true;
  1591. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1592. if (!DeleteFileForEntryHash(path, entry_hash, i, file_operations) &&
  1593. !CanOmitEmptyFile(i)) {
  1594. result = false;
  1595. }
  1596. }
  1597. FilePath to_delete = path.AppendASCII(GetSparseFilenameFromEntryFileKey(
  1598. SimpleFileTracker::EntryFileKey(entry_hash)));
  1599. file_operations->DeleteFile(
  1600. to_delete,
  1601. BackendFileOperations::DeleteFileMode::kEnsureImmediateAvailability);
  1602. return result;
  1603. }
  1604. // static
  1605. bool SimpleSynchronousEntry::TruncateFilesForEntryHash(
  1606. const FilePath& path,
  1607. const uint64_t entry_hash,
  1608. BackendFileOperations* file_operations) {
  1609. SimpleFileTracker::EntryFileKey file_key(entry_hash);
  1610. bool result = true;
  1611. for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) {
  1612. FilePath filename_to_truncate =
  1613. path.AppendASCII(GetFilenameFromEntryFileKeyAndFileIndex(file_key, i));
  1614. if (!TruncatePath(filename_to_truncate, file_operations))
  1615. result = false;
  1616. }
  1617. FilePath to_delete =
  1618. path.AppendASCII(GetSparseFilenameFromEntryFileKey(file_key));
  1619. TruncatePath(to_delete, file_operations);
  1620. return result;
  1621. }
  1622. FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex(
  1623. int file_index) const {
  1624. return path_.AppendASCII(
  1625. GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, file_index));
  1626. }
  1627. base::FilePath SimpleSynchronousEntry::GetFilenameForSubfile(
  1628. SimpleFileTracker::SubFile sub_file) const {
  1629. if (sub_file == SimpleFileTracker::SubFile::FILE_SPARSE)
  1630. return path_.AppendASCII(
  1631. GetSparseFilenameFromEntryFileKey(entry_file_key_));
  1632. else
  1633. return GetFilenameFromFileIndex(FileIndexForSubFile(sub_file));
  1634. }
  1635. bool SimpleSynchronousEntry::OpenSparseFileIfExists(
  1636. BackendFileOperations* file_operations,
  1637. int32_t* out_sparse_data_size) {
  1638. DCHECK(!sparse_file_open());
  1639. FilePath filename =
  1640. path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
  1641. int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
  1642. base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
  1643. auto sparse_file =
  1644. std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
  1645. if (!sparse_file->IsValid()) {
  1646. // No file -> OK, file open error -> 'trouble.
  1647. return sparse_file->error_details() == base::File::FILE_ERROR_NOT_FOUND;
  1648. }
  1649. if (!ScanSparseFile(sparse_file.get(), out_sparse_data_size))
  1650. return false;
  1651. file_tracker_->Register(this, SimpleFileTracker::SubFile::FILE_SPARSE,
  1652. std::move(sparse_file));
  1653. sparse_file_open_ = true;
  1654. return true;
  1655. }
  1656. bool SimpleSynchronousEntry::CreateSparseFile(
  1657. BackendFileOperations* file_operations) {
  1658. DCHECK(!sparse_file_open());
  1659. FilePath filename =
  1660. path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_));
  1661. int flags = base::File::FLAG_CREATE | base::File::FLAG_READ |
  1662. base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE;
  1663. std::unique_ptr<base::File> sparse_file =
  1664. std::make_unique<base::File>(file_operations->OpenFile(filename, flags));
  1665. if (!sparse_file->IsValid())
  1666. return false;
  1667. if (!InitializeSparseFile(sparse_file.get()))
  1668. return false;
  1669. file_tracker_->Register(this, SimpleFileTracker::SubFile::FILE_SPARSE,
  1670. std::move(sparse_file));
  1671. sparse_file_open_ = true;
  1672. return true;
  1673. }
  1674. void SimpleSynchronousEntry::CloseSparseFile(
  1675. BackendFileOperations* file_operations) {
  1676. DCHECK(sparse_file_open());
  1677. if (entry_file_key_.doom_generation != 0u) {
  1678. file_operations->DeleteFile(
  1679. path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_)));
  1680. }
  1681. file_tracker_->Close(this, SimpleFileTracker::SubFile::FILE_SPARSE);
  1682. sparse_file_open_ = false;
  1683. }
  1684. bool SimpleSynchronousEntry::TruncateSparseFile(base::File* sparse_file) {
  1685. DCHECK(sparse_file_open());
  1686. int64_t header_and_key_length = sizeof(SimpleFileHeader) + key_.size();
  1687. if (!sparse_file->SetLength(header_and_key_length)) {
  1688. DLOG(WARNING) << "Could not truncate sparse file";
  1689. return false;
  1690. }
  1691. sparse_ranges_.clear();
  1692. sparse_tail_offset_ = header_and_key_length;
  1693. return true;
  1694. }
  1695. bool SimpleSynchronousEntry::InitializeSparseFile(base::File* sparse_file) {
  1696. SimpleFileHeader header;
  1697. header.initial_magic_number = kSimpleInitialMagicNumber;
  1698. header.version = kSimpleVersion;
  1699. header.key_length = key_.size();
  1700. header.key_hash = base::PersistentHash(key_);
  1701. int header_write_result =
  1702. sparse_file->Write(0, reinterpret_cast<char*>(&header), sizeof(header));
  1703. if (header_write_result != sizeof(header)) {
  1704. DLOG(WARNING) << "Could not write sparse file header";
  1705. return false;
  1706. }
  1707. int key_write_result =
  1708. sparse_file->Write(sizeof(header), key_.data(), key_.size());
  1709. if (key_write_result != base::checked_cast<int>(key_.size())) {
  1710. DLOG(WARNING) << "Could not write sparse file key";
  1711. return false;
  1712. }
  1713. sparse_ranges_.clear();
  1714. sparse_tail_offset_ = sizeof(header) + key_.size();
  1715. return true;
  1716. }
  1717. bool SimpleSynchronousEntry::ScanSparseFile(base::File* sparse_file,
  1718. int32_t* out_sparse_data_size) {
  1719. int64_t sparse_data_size = 0;
  1720. SimpleFileHeader header;
  1721. int header_read_result =
  1722. sparse_file->Read(0, reinterpret_cast<char*>(&header), sizeof(header));
  1723. if (header_read_result != sizeof(header)) {
  1724. DLOG(WARNING) << "Could not read header from sparse file.";
  1725. return false;
  1726. }
  1727. if (header.initial_magic_number != kSimpleInitialMagicNumber) {
  1728. DLOG(WARNING) << "Sparse file magic number did not match.";
  1729. return false;
  1730. }
  1731. if (header.version < kLastCompatSparseVersion ||
  1732. header.version > kSimpleVersion) {
  1733. DLOG(WARNING) << "Sparse file unreadable version.";
  1734. return false;
  1735. }
  1736. sparse_ranges_.clear();
  1737. int64_t range_header_offset = sizeof(header) + key_.size();
  1738. while (true) {
  1739. SimpleFileSparseRangeHeader range_header;
  1740. int range_header_read_result = sparse_file->Read(
  1741. range_header_offset, reinterpret_cast<char*>(&range_header),
  1742. sizeof(range_header));
  1743. if (range_header_read_result == 0)
  1744. break;
  1745. if (range_header_read_result != sizeof(range_header)) {
  1746. DLOG(WARNING) << "Could not read sparse range header.";
  1747. return false;
  1748. }
  1749. if (range_header.sparse_range_magic_number !=
  1750. kSimpleSparseRangeMagicNumber) {
  1751. DLOG(WARNING) << "Invalid sparse range header magic number.";
  1752. return false;
  1753. }
  1754. SparseRange range;
  1755. range.offset = range_header.offset;
  1756. range.length = range_header.length;
  1757. range.data_crc32 = range_header.data_crc32;
  1758. range.file_offset = range_header_offset + sizeof(range_header);
  1759. sparse_ranges_.insert(std::make_pair(range.offset, range));
  1760. range_header_offset += sizeof(range_header) + range.length;
  1761. DCHECK_GE(sparse_data_size + range.length, sparse_data_size);
  1762. sparse_data_size += range.length;
  1763. }
  1764. *out_sparse_data_size = static_cast<int32_t>(sparse_data_size);
  1765. sparse_tail_offset_ = range_header_offset;
  1766. return true;
  1767. }
  1768. bool SimpleSynchronousEntry::ReadSparseRange(base::File* sparse_file,
  1769. const SparseRange* range,
  1770. int offset,
  1771. int len,
  1772. char* buf) {
  1773. DCHECK(range);
  1774. DCHECK(buf);
  1775. DCHECK_LE(offset, range->length);
  1776. DCHECK_LE(offset + len, range->length);
  1777. int bytes_read = sparse_file->Read(range->file_offset + offset, buf, len);
  1778. if (bytes_read < len) {
  1779. DLOG(WARNING) << "Could not read sparse range.";
  1780. return false;
  1781. }
  1782. // If we read the whole range and we have a crc32, check it.
  1783. if (offset == 0 && len == range->length && range->data_crc32 != 0) {
  1784. if (simple_util::Crc32(buf, len) != range->data_crc32) {
  1785. DLOG(WARNING) << "Sparse range crc32 mismatch.";
  1786. return false;
  1787. }
  1788. }
  1789. // TODO(morlovich): Incremental crc32 calculation?
  1790. return true;
  1791. }
  1792. bool SimpleSynchronousEntry::WriteSparseRange(base::File* sparse_file,
  1793. SparseRange* range,
  1794. int offset,
  1795. int len,
  1796. const char* buf) {
  1797. DCHECK(range);
  1798. DCHECK(buf);
  1799. DCHECK_LE(offset, range->length);
  1800. DCHECK_LE(offset + len, range->length);
  1801. uint32_t new_crc32 = 0;
  1802. if (offset == 0 && len == range->length) {
  1803. new_crc32 = simple_util::Crc32(buf, len);
  1804. }
  1805. if (new_crc32 != range->data_crc32) {
  1806. range->data_crc32 = new_crc32;
  1807. SimpleFileSparseRangeHeader header;
  1808. header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber;
  1809. header.offset = range->offset;
  1810. header.length = range->length;
  1811. header.data_crc32 = range->data_crc32;
  1812. int bytes_written =
  1813. sparse_file->Write(range->file_offset - sizeof(header),
  1814. reinterpret_cast<char*>(&header), sizeof(header));
  1815. if (bytes_written != base::checked_cast<int>(sizeof(header))) {
  1816. DLOG(WARNING) << "Could not rewrite sparse range header.";
  1817. return false;
  1818. }
  1819. }
  1820. int bytes_written = sparse_file->Write(range->file_offset + offset, buf, len);
  1821. if (bytes_written < len) {
  1822. DLOG(WARNING) << "Could not write sparse range.";
  1823. return false;
  1824. }
  1825. return true;
  1826. }
  1827. bool SimpleSynchronousEntry::AppendSparseRange(base::File* sparse_file,
  1828. int64_t offset,
  1829. int len,
  1830. const char* buf) {
  1831. DCHECK_GE(offset, 0);
  1832. DCHECK_GT(len, 0);
  1833. DCHECK(buf);
  1834. uint32_t data_crc32 = simple_util::Crc32(buf, len);
  1835. SimpleFileSparseRangeHeader header;
  1836. header.sparse_range_magic_number = kSimpleSparseRangeMagicNumber;
  1837. header.offset = offset;
  1838. header.length = len;
  1839. header.data_crc32 = data_crc32;
  1840. int bytes_written = sparse_file->Write(
  1841. sparse_tail_offset_, reinterpret_cast<char*>(&header), sizeof(header));
  1842. if (bytes_written != base::checked_cast<int>(sizeof(header))) {
  1843. DLOG(WARNING) << "Could not append sparse range header.";
  1844. return false;
  1845. }
  1846. sparse_tail_offset_ += bytes_written;
  1847. bytes_written = sparse_file->Write(sparse_tail_offset_, buf, len);
  1848. if (bytes_written < len) {
  1849. DLOG(WARNING) << "Could not append sparse range data.";
  1850. return false;
  1851. }
  1852. int64_t data_file_offset = sparse_tail_offset_;
  1853. sparse_tail_offset_ += bytes_written;
  1854. SparseRange range;
  1855. range.offset = offset;
  1856. range.length = len;
  1857. range.data_crc32 = data_crc32;
  1858. range.file_offset = data_file_offset;
  1859. sparse_ranges_.insert(std::make_pair(offset, range));
  1860. return true;
  1861. }
  1862. } // namespace disk_cache