Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.8 fix] VRTComplexSource: fix excessive RAM usage with many sources (fixes #8967, 3.8.0 regression) #8970

Merged
merged 1 commit into from
Dec 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions frmts/vrt/vrtsources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2533,6 +2533,21 @@ static inline bool hasZeroByte(uint32_t v)
/* RasterIOProcessNoData() */
/************************************************************************/

namespace
{
template <class T> struct VRTWorkBufferReleaser
{
std::vector<T> &m_oVector;
explicit VRTWorkBufferReleaser(std::vector<T> &oVector) : m_oVector(oVector)
{
}
~VRTWorkBufferReleaser()
{
std::vector<T>().swap(m_oVector);
}
};
} // namespace

// This method is an optimization of the generic RasterIOInternal()
// that deals with a VRTComplexSource with only a NODATA value in it, and
// no other processing flags.
Expand All @@ -2549,6 +2564,12 @@ CPLErr VRTComplexSource::RasterIOProcessNoData(
CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
CPLAssert(GDALIsValueInRange<SourceDT>(m_dfNoDataValue));

// WARNING: we need to make sure to clear that buffer in all exit
// paths otherwise when using many sources, we can easily exhaust RAM.
// That buffer should be at the dataset level, not the source, but we
// can't fix that in 3.8 branch without breaking ABI...
VRTWorkBufferReleaser<NoInitByte> oWrkBufferReleaser(m_abyWrkBuffer);

/* -------------------------------------------------------------------- */
/* Read into a temporary buffer. */
/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -2733,6 +2754,14 @@ CPLErr VRTComplexSource::RasterIOInternal(
const int nWordSize = GDALGetDataTypeSizeBytes(eWrkDataType);
assert(nWordSize != 0);

// WARNING: we need to make sure to clear those buffers in all exit
// paths otherwise when using many sources, we can easily exhaust RAM.
// Those buffers should be at the dataset level, not the source, but we
// can't fix that in 3.8 branch without breaking ABI...
VRTWorkBufferReleaser<NoInitByte> oWrkBufferReleaser(m_abyWrkBuffer);
VRTWorkBufferReleaser<NoInitByte> oWrkBufferMaskReleaser(
m_abyWrkBufferMask);

// If no explicit <NODATA> is set, but UseMaskBand is set, and the band
// has a nodata value, then use it as if it was set as <NODATA>
int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
Expand Down
Loading