CPLErr GDALHashSetBandBlockCache::AdoptBlock( GDALRasterBlock * poBlock )

{
    FreeDanglingBlocks();

    CPLLockHolderOptionalLockD( hLock );
    m_oSet.insert(poBlock);

    return CE_None;
}
GDALRasterBlock *GDALHashSetBandBlockCache::TryGetLockedBlockRef(
    int nXBlockOff, int nYBlockOff )

{
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
    GDALRasterBlock* poBlock;
    {
        CPLLockHolderOptionalLockD( hLock );
        auto oIter = m_oSet.find(&oBlockForLookup);
        if( oIter == m_oSet.end() )
            return nullptr;
        poBlock = *oIter;
    }
    if( !poBlock->TakeLock()  )
        return nullptr;
    return poBlock;
}
void GDALAbstractBandBlockCache::FreeDanglingBlocks()
{
    GDALRasterBlock* poList;
    {
        CPLLockHolderOptionalLockD(hSpinLock);
        poList = psListBlocksToFree;
        psListBlocksToFree = NULL;
    }
    while( poList )
    {
#ifdef DEBUG_VERBOSE_ABBC
        CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
        fprintf(stderr, "FreeDanglingBlocks(): nAllBandsKeptAlivedBlocks=%d\n", nAllBandsKeptAlivedBlocks);
#endif
        GDALRasterBlock* poNext = poList->poNext;
        poList->poNext = NULL;
        delete poList;
        poList = poNext;
    }
}
void GDALAbstractBandBlockCache::AddBlockToFreeList( GDALRasterBlock *poBlock )
{
    CPLAssert(poBlock->poPrevious == NULL);
    CPLAssert(poBlock->poNext == NULL);
    {
#ifdef DEBUG_VERBOSE_ABBC
        CPLAtomicInc(&nAllBandsKeptAlivedBlocks);
        fprintf(stderr, "AddBlockToFreeList(): nAllBandsKeptAlivedBlocks=%d\n", nAllBandsKeptAlivedBlocks);
#endif
        CPLLockHolderOptionalLockD(hSpinLock);
        poBlock->poNext = psListBlocksToFree;
        psListBlocksToFree = poBlock;
    }

    // If no more blocks in transient state, then warn WaitKeepAliveCounter()
    CPLAcquireMutex(hCondMutex, 1000);
    if( CPLAtomicDec(&nKeepAliveCounter) == 0 )
    {
        CPLCondSignal(hCond);
    }
    CPLReleaseMutex(hCondMutex);
}
GDALRasterBlock* GDALAbstractBandBlockCache::CreateBlock(int nXBlockOff,
                                                         int nYBlockOff)
{
    GDALRasterBlock* poBlock;
    {
        CPLLockHolderOptionalLockD(hSpinLock);
        poBlock = psListBlocksToFree;
        if( poBlock )
        {
#ifdef DEBUG_VERBOSE_ABBC
            CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
            fprintf(stderr, "CreateBlock(): nAllBandsKeptAlivedBlocks=%d\n", nAllBandsKeptAlivedBlocks);
#endif
            psListBlocksToFree = poBlock->poNext;
        }
    }
    if( poBlock )
        poBlock->RecycleFor(nXBlockOff, nYBlockOff);
    else
        poBlock = new (std::nothrow) GDALRasterBlock(
            poBand, nXBlockOff, nYBlockOff );
    return poBlock;
}
CPLErr GDALHashSetBandBlockCache::FlushCache()
{
    FreeDanglingBlocks();

    CPLErr eGlobalErr = poBand->eFlushBlockErr;

    std::set<GDALRasterBlock*, BlockComparator> oOldSet;
    {
        CPLLockHolderOptionalLockD( hLock );
        oOldSet = std::move(m_oSet);
    }

    StartDirtyBlockFlushingLog();
    for( auto& poBlock: oOldSet )
    {
        if( poBlock->DropLockForRemovalFromStorage() )
        {
            CPLErr eErr = CE_None;

            if( eGlobalErr == CE_None && poBlock->GetDirty() )
            {
                UpdateDirtyBlockFlushingLog();
                eErr = poBlock->Write();
            }

            delete poBlock;

            if( eErr != CE_None )
                eGlobalErr = eErr;
        }
    }
    EndDirtyBlockFlushingLog();

    WaitKeepAliveCounter();

    return( eGlobalErr );
}