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

added GDALCacheFlushHelperHandler #4852

Closed
wants to merge 10 commits into from
20 changes: 20 additions & 0 deletions gcore/gdal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,26 @@ GDALAbstractBandBlockCache* GDALHashSetBandBlockCacheCreate(GDALRasterBand* poBa

//! @endcond

/* ******************************************************************** */
/* GDALCacheFlushHelperHandler */
/* ******************************************************************** */

//! By default, when a dataset being processed needs to allocate a new cache block
// and the global cache is already full, it is not allowed to flush the cache of
// other datasets to make room in the global cache, in order to prevent problems
// in multithreading scenarios. This callback asks the user whether it is safe to
// flush some dataset or not, in order to give a chance to do so and free some
// cache blocks. By doing so, the pressure on the cache might be released and avoid
// I/O congestion. It is up to the user to ensure that by answering "yes" in a
// multithreading scenario, flushing another dataset will not induce unexpected results.
// This callback cannot be installed on different thread local storages, since its
// purpose is to get a global answer regarding the user's known current thread states

typedef bool (CPL_STDCALL *GDALCacheFlushHelperHandler)(const GDALDataset* currentDataset, const GDALDataset* datasetThatCouldBeFlushed, void* cacheManager, void* pUserData);

GDALCacheFlushHelperHandler CPL_DLL CPL_STDCALL GDALSetCacheFlushHelperHandler(GDALCacheFlushHelperHandler, void* cacheManager, void* pUserData);
bool CPL_DLL CPL_STDCALL ApplyCacheHelperFlushHandler( const GDALDataset* currentDataset, const GDALDataset* datasetThatCouldBeFlushed, void* cacheManager);

/* ******************************************************************** */
/* GDALRasterBand */
/* ******************************************************************** */
Expand Down
48 changes: 48 additions & 0 deletions gcore/gdalabstractbandblockcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,54 @@ CPL_CVSID("$Id$")
static int nAllBandsKeptAlivedBlocks = 0;
#endif

static CPLMutex *hCacheHelperMutex = nullptr;
static GDALCacheFlushHelperHandler pfnCacheFlushHelperHandler = nullptr;
static void *pCacheFlushHelperHandlerUserData = nullptr;

/**
* Calls the current GDALCacheFlushHelperHandler
*
* @param currentDataset Dataset being processed and requiring a new cache block
* @param datasetThatCouldBeFlushed Dataset containing the oldest cache block that could be flushed
* @param cacheManager unused for now, just in case in the future a cache redesign could allow several cache block pools
*/
bool CPL_STDCALL
ApplyCacheHelperFlushHandler( const GDALDataset* currentDataset, const GDALDataset* datasetThatCouldBeFlushed, void* cacheManager)
{
bool result = false;
volatile GDALCacheFlushHelperHandler* pPfnCacheFlushHelperHandler = &pfnCacheFlushHelperHandler;//to avoid compiler warning about "inner-if" always true
if(pPfnCacheFlushHelperHandler != nullptr ) //quick test to avoid locking
{
CPLMutexHolderD( &hCacheHelperMutex );
GDALCacheFlushHelperHandler _pfnCacheFlushHelperHandler = *pPfnCacheFlushHelperHandler;
if( _pfnCacheFlushHelperHandler != nullptr )
result = _pfnCacheFlushHelperHandler(currentDataset, datasetThatCouldBeFlushed, cacheManager, pCacheFlushHelperHandlerUserData);
}
return result;
}

/**
* Installs a new GDALCacheFlushHelperHandler
*
* @param pfnCacheHelperHandlerNew new GDALCacheFlushHelperHandler, can be 0 to set none
* @param cacheManager unused for now, just in case in the future a cache redesign could allow several cache block pools
* @param pUserData custom user data, that must remain valid until the handler is uninstalled
* @return the previous GDALCacheFlushHelperHandler
*/

GDALCacheFlushHelperHandler CPL_STDCALL
GDALSetCacheFlushHelperHandler(GDALCacheFlushHelperHandler pfnCacheHelperHandlerNew, void* CPL_UNUSED cacheManager, void* pUserData)
{
(void)cacheManager;//unused
GDALCacheFlushHelperHandler pfnOldHandler = nullptr;
CPLMutexHolderD( &hCacheHelperMutex );
pfnOldHandler = pfnCacheFlushHelperHandler;
pfnCacheFlushHelperHandler = pfnCacheHelperHandlerNew;
pCacheFlushHelperHandlerUserData = pUserData;
return pfnOldHandler;
}
//end GDALSetCacheFlushHelperHandler()

/************************************************************************/
/* GDALArrayBandBlockCache() */
/************************************************************************/
Expand Down
5 changes: 4 additions & 1 deletion gcore/gdalrasterblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,10 @@ CPLErr GDALRasterBlock::Internalize()
}
else if (nDisableDirtyBlockFlushCounter == 0)
{
if( poTarget->poBand->GetDataset() == poThisDS )
GDALDataset* targetDataset = poTarget->poBand->GetDataset();
const bool isSameDataset = (targetDataset == poThisDS);
const bool canFlushTargetDataset = isSameDataset || ApplyCacheHelperFlushHandler(poThisDS, targetDataset, nullptr);
if( canFlushTargetDataset )
{
if( CPLAtomicCompareAndExchange(
&(poTarget->nLockCount), 0, -1) )
Expand Down