mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
CachingFileLoader: don't cache blocks the backend failed to fully read
SaveIntoCache() discarded backend_->ReadAt()'s return value entirely and unconditionally marked the requested block(s) as cached. A short or failed read from the backend (e.g. a Remote ISO connection dropping mid-file, now that LocalFileLoader/RetryingFileLoader correctly report failures as 0 rather than a huge count) would still get stored as a "valid" cached block, permanently serving its uninitialized tail as if it were real file data on every later read, with no retry. Only insert a block once we've confirmed the backend actually delivered the full BLOCK_SIZE for it.
This commit is contained in:
1 parent
1671814be1
commit
7e64052914
1 file changed
+13
-4
@@ -174,13 +174,21 @@ void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, Flags flags, bool r
|
||||
blocksMutex_.unlock();
|
||||
|
||||
u8 *buf = new u8[BLOCK_SIZE];
|
||||
backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, BLOCK_SIZE, buf, flags);
|
||||
size_t readBytes = backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, BLOCK_SIZE, buf, flags);
|
||||
|
||||
blocksMutex_.lock();
|
||||
// While blocksMutex_ was unlocked, another thread may have read.
|
||||
// If so, free the one we just read.
|
||||
if (blocks_.find(cacheStartPos) == blocks_.end()) {
|
||||
blocks_[cacheStartPos] = BlockInfo{buf};
|
||||
// Only cache a block we actually fully read - a short/failed read (e.g. a
|
||||
// dropped connection on a Remote ISO) must not be cached as if valid, or
|
||||
// every later read of this block would silently return the uninitialized
|
||||
// tail of `buf` as if it were real file data.
|
||||
if (readBytes == BLOCK_SIZE) {
|
||||
blocks_[cacheStartPos] = BlockInfo{buf};
|
||||
} else {
|
||||
delete [] buf;
|
||||
}
|
||||
} else {
|
||||
delete [] buf;
|
||||
}
|
||||
@@ -188,10 +196,11 @@ void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, Flags flags, bool r
|
||||
blocksMutex_.unlock();
|
||||
|
||||
u8 *wholeRead = new u8[blocksToRead << BLOCK_SHIFT];
|
||||
backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, blocksToRead << BLOCK_SHIFT, wholeRead, flags);
|
||||
size_t readBytes = backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, blocksToRead << BLOCK_SHIFT, wholeRead, flags);
|
||||
size_t wholeBlocksRead = readBytes >> BLOCK_SHIFT;
|
||||
|
||||
blocksMutex_.lock();
|
||||
for (size_t i = 0; i < blocksToRead; ++i) {
|
||||
for (size_t i = 0; i < wholeBlocksRead; ++i) {
|
||||
if (blocks_.find(cacheStartPos + i) != blocks_.end()) {
|
||||
// Written while we were busy, just skip it. Keep the existing block.
|
||||
continue;
|
||||
|
||||
Reference in new issue
Block a user