Merge branch 'dont-ask-the-disk-for-things-we-already-know' into 'master'

Avoid IO in resolveParentFileIndices

See merge request OpenMW/openmw!4627
This commit is contained in:
Alexei Kotov 2025-04-14 13:11:57 +03:00
commit 271ab2e109
4 changed files with 77 additions and 3 deletions

View file

@ -88,4 +88,31 @@ namespace
EXPECT_EQ(reader->getFileOffset(), sInitialOffset);
}
}
TEST_F(ESM3ReadersCacheWithContentFile, CachedSizeAndName)
{
ESM::ReadersCache readers(2);
{
readers.get(0)->openRaw(std::make_unique<std::istringstream>("123"), "closed0.omwaddon");
readers.get(1)->openRaw(std::make_unique<std::istringstream>("12345"), "closed1.omwaddon");
readers.get(2)->openRaw(std::make_unique<std::istringstream>("1234567"), "free.omwaddon");
}
auto busy = readers.get(3);
busy->openRaw(std::make_unique<std::istringstream>("123456789"), "busy.omwaddon");
EXPECT_EQ(readers.getFileSize(0), 3);
EXPECT_EQ(readers.getName(0), "closed0.omwaddon");
EXPECT_EQ(readers.getFileSize(1), 5);
EXPECT_EQ(readers.getName(1), "closed1.omwaddon");
EXPECT_EQ(readers.getFileSize(2), 7);
EXPECT_EQ(readers.getName(2), "free.omwaddon");
EXPECT_EQ(readers.getFileSize(3), 9);
EXPECT_EQ(readers.getName(3), "busy.omwaddon");
// not-yet-seen indices give zero for their size
EXPECT_EQ(readers.getFileSize(4), 0);
}
}

View file

@ -73,10 +73,10 @@ namespace ESM
int index = getIndex();
for (int i = 0; i < getIndex(); i++)
{
const ESM::ReadersCache::BusyItem reader = readers.get(static_cast<std::size_t>(i));
if (reader->getFileSize() == 0)
if (readers.getFileSize(static_cast<std::size_t>(i)) == 0)
continue; // Content file in non-ESM format
const auto fnamecandidate = Files::pathToUnicodeString(reader->getName().filename());
const auto fnamecandidate
= Files::pathToUnicodeString(readers.getName(static_cast<std::size_t>(i)).filename());
if (Misc::StringUtils::ciEqual(fname, fnamecandidate))
{
index = i;

View file

@ -47,6 +47,7 @@ namespace ESM
{
it->mReader.open(*it->mName);
it->mName.reset();
it->mFileSize.reset();
}
mBusyItems.splice(mBusyItems.end(), mClosedItems, it);
break;
@ -57,6 +58,46 @@ namespace ESM
return BusyItem(*this, it);
}
const std::filesystem::path& ReadersCache::getName(std::size_t index) const
{
const auto indexIt = mIndex.find(index);
if (indexIt == mIndex.end())
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been created yet");
switch (indexIt->second->mState)
{
case State::Busy:
case State::Free:
return indexIt->second->mReader.getName();
case State::Closed:
if (indexIt->second->mName)
return *indexIt->second->mName;
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its filename");
default:
throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state");
}
}
std::size_t ReadersCache::getFileSize(std::size_t index)
{
const auto indexIt = mIndex.find(index);
if (indexIt == mIndex.end())
return 0;
switch (indexIt->second->mState)
{
case State::Busy:
case State::Free:
if (!indexIt->second->mReader.getName().empty())
return indexIt->second->mReader.getFileSize();
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been opened yet");
case State::Closed:
if (indexIt->second->mFileSize)
return *indexIt->second->mFileSize;
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its file size");
default:
throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state");
}
}
void ReadersCache::closeExtraReaders()
{
while (!mFreeItems.empty() && mBusyItems.size() + mFreeItems.size() + 1 > mCapacity)
@ -65,6 +106,7 @@ namespace ESM
if (it->mReader.isOpen())
{
it->mName = it->mReader.getName();
it->mFileSize = it->mReader.getFileSize();
it->mReader.close();
}
mClosedItems.splice(mClosedItems.end(), mFreeItems, it);

View file

@ -26,6 +26,7 @@ namespace ESM
State mState = State::Busy;
ESMReader mReader;
std::optional<std::filesystem::path> mName;
std::optional<std::size_t> mFileSize;
Item() = default;
};
@ -55,6 +56,10 @@ namespace ESM
BusyItem get(std::size_t index);
const std::filesystem::path& getName(std::size_t index) const;
std::size_t getFileSize(std::size_t index);
void clear();
private: