diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index 73d5a37b53..1d047d2876 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -117,6 +117,7 @@ void DiskCachingFileLoaderCache::InitCache(const std::string &path) { cacheSize_ = 0; indexCount_ = 0; oldestGeneration_ = 0; + maxBlocks_ = MAX_BLOCKS_LOWER_BOUND; generation_ = 0; const std::string cacheFilePath = MakeCacheFilePath(path); @@ -248,7 +249,7 @@ size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, s } bool DiskCachingFileLoaderCache::MakeCacheSpaceFor(size_t blocks) { - size_t goal = MAX_BLOCKS_CACHED - blocks; + size_t goal = (size_t)maxBlocks_ - blocks; while (cacheSize_ > goal) { u16 minGeneration = generation_; @@ -414,6 +415,9 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const std::string &path) { valid = false; } else if (header.filesize != filesize_) { valid = false; + } else if (header.maxBlocks < MAX_BLOCKS_LOWER_BOUND || header.maxBlocks > MAX_BLOCKS_UPPER_BOUND) { + // This means it's not in our safety bounds, reject. + valid = false; } // If it's valid, retain the file pointer. @@ -427,6 +431,7 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const std::string &path) { // Now let's load the index. blockSize_ = header.blockSize; + maxBlocks_ = header.maxBlocks; LoadCacheIndex(); } else { ERROR_LOG(LOADER, "Disk cache file header did not match, recreating cache file"); @@ -446,8 +451,8 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() { indexCount_ = (filesize_ + blockSize_ - 1) / blockSize_; index_.resize(indexCount_); - blockIndexLookup_.resize(MAX_BLOCKS_CACHED); - memset(&blockIndexLookup_[0], INVALID_INDEX, MAX_BLOCKS_CACHED * sizeof(blockIndexLookup_[0])); + blockIndexLookup_.resize(maxBlocks_); + memset(&blockIndexLookup_[0], INVALID_INDEX, maxBlocks_ * sizeof(blockIndexLookup_[0])); if (fread(&index_[0], sizeof(BlockInfo), indexCount_, f_) != indexCount_) { fclose(f_); @@ -462,7 +467,7 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() { cacheSize_ = 0; for (size_t i = 0; i < index_.size(); ++i) { - if (index_[i].block > MAX_BLOCKS_CACHED) { + if (index_[i].block > maxBlocks_) { index_[i].block = INVALID_BLOCK; } if (index_[i].block == INVALID_BLOCK) { @@ -482,6 +487,14 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() { } void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) { + maxBlocks_ = DetermineMaxBlocks(); + if (maxBlocks_ < MAX_BLOCKS_LOWER_BOUND) { + // There's not enough free space to cache, disable. + f_ = nullptr; + ERROR_LOG(LOADER, "Not enough free space; disabling disk cache"); + return; + } + f_ = File::OpenCFile(path, "wb+"); if (!f_) { ERROR_LOG(LOADER, "Could not create disk cache file"); @@ -499,6 +512,7 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) { header.version = CACHE_VERSION; header.blockSize = blockSize_; header.filesize = filesize_; + header.maxBlocks = maxBlocks_; if (fwrite(&header, sizeof(header), 1, f_) != 1) { fclose(f_); @@ -509,8 +523,8 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) { indexCount_ = (filesize_ + blockSize_ - 1) / blockSize_; index_.resize(indexCount_); - blockIndexLookup_.resize(MAX_BLOCKS_CACHED); - memset(&blockIndexLookup_[0], INVALID_INDEX, MAX_BLOCKS_CACHED * sizeof(blockIndexLookup_[0])); + blockIndexLookup_.resize(maxBlocks_); + memset(&blockIndexLookup_[0], INVALID_INDEX, maxBlocks_ * sizeof(blockIndexLookup_[0])); if (fwrite(&index_[0], sizeof(BlockInfo), indexCount_, f_) != indexCount_) { fclose(f_); @@ -519,3 +533,8 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) { return; } } + +u32 DiskCachingFileLoaderCache::DetermineMaxBlocks() { + // TODO (don't forget to clamp UPPER) + return 4096; +} diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index f175470a83..abec752683 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -104,24 +104,27 @@ private: void LoadCacheIndex(); void CreateCacheFile(const std::string &path); + u32 DetermineMaxBlocks(); + // File format: // 64 magic // 32 version // 32 blockSize // 64 filesize + // 32 maxBlocks // index[filesize / blockSize] <-- ~500 KB for 4GB // 32 (fileoffset - headersize) / blockSize -> -1=not present // 16 generation? // 16 hits? - // blocks[MAX_BLOCKS] + // blocks[up to maxBlocks] // 8 * blockSize enum { - CACHE_VERSION = 1, + CACHE_VERSION = 2, DEFAULT_BLOCK_SIZE = 65536, MAX_BLOCKS_PER_READ = 16, - // TODO: Dynamic. - MAX_BLOCKS_CACHED = 4096, // 256 MB + MAX_BLOCKS_LOWER_BOUND = 256, // 16 MB + MAX_BLOCKS_UPPER_BOUND = 8192, // 512 MB INVALID_BLOCK = 0xFFFFFFFF, INVALID_INDEX = 0xFFFFFFFF, }; @@ -131,6 +134,7 @@ private: u32 blockSize_; u16 generation_; u16 oldestGeneration_; + u32 maxBlocks_; size_t cacheSize_; size_t indexCount_; recursive_mutex lock_; @@ -140,6 +144,7 @@ private: u32_le version; u32_le blockSize; s64_le filesize; + s32_le maxBlocks; }; struct BlockInfo {