int GDALRasterBlock::FlushCacheBlock(int bDirtyBlocksOnly) { GDALRasterBlock *poTarget; { INITIALIZE_LOCK; poTarget = poOldest; while( poTarget != NULL && (poTarget->GetLockCount() > 0 || (bDirtyBlocksOnly && !poTarget->GetDirty())) ) poTarget = poTarget->poPrevious; if( poTarget == NULL ) return FALSE; poTarget->Detach_unlocked(); poTarget->GetBand()->UnreferenceBlock(poTarget->GetXOff(),poTarget->GetYOff()); } if( poTarget->GetDirty() ) { CPLErr eErr = poTarget->Write(); if( eErr != CE_None ) { /* Save the error for later reporting */ poTarget->GetBand()->SetFlushBlockErr(eErr); } } delete poTarget; return TRUE; }
int GDALRasterBlock::FlushCacheBlock( int bDirtyBlocksOnly ) { GDALRasterBlock *poTarget; { INITIALIZE_LOCK; poTarget = poOldest; while( poTarget != NULL ) { if( !bDirtyBlocksOnly || poTarget->GetDirty() ) { if( CPLAtomicCompareAndExchange( &(poTarget->nLockCount), 0, -1) ) break; } poTarget = poTarget->poPrevious; } if( poTarget == NULL ) return FALSE; if( bSleepsForBockCacheDebug ) CPLSleep(CPLAtof( CPLGetConfigOption( "GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_DROP_LOCK", "0"))); poTarget->Detach_unlocked(); poTarget->GetBand()->UnreferenceBlock(poTarget); } if( bSleepsForBockCacheDebug ) CPLSleep(CPLAtof( CPLGetConfigOption("GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_RB_LOCK", "0"))); if( poTarget->GetDirty() ) { const CPLErr eErr = poTarget->Write(); if( eErr != CE_None ) { // Save the error for later reporting. poTarget->GetBand()->SetFlushBlockErr(eErr); } } VSIFree(poTarget->pData); poTarget->pData = NULL; poTarget->GetBand()->AddBlockToFreeList(poTarget); return TRUE; }
CPLErr GDALHashSetBandBlockCache::FlushBlock( int nXBlockOff, int nYBlockOff, int bWriteDirtyBlock ) { GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff); GDALRasterBlock* poBlock = nullptr; { CPLLockHolderOptionalLockD( hLock ); auto oIter = m_oSet.find(&oBlockForLookup); if( oIter == m_oSet.end() ) return CE_None; poBlock = *oIter; m_oSet.erase(oIter); } if( !poBlock->DropLockForRemovalFromStorage() ) return CE_None; CPLErr eErr = CE_None; if( bWriteDirtyBlock && poBlock->GetDirty() ) eErr = poBlock->Write(); delete poBlock; return eErr; }
CPLErr GDALArrayBandBlockCache::FlushBlock( int nXBlockOff, int nYBlockOff, int bWriteDirtyBlock ) { int nBlockIndex; GDALRasterBlock *poBlock = NULL; /* -------------------------------------------------------------------- */ /* Simple case for single level caches. */ /* -------------------------------------------------------------------- */ if( !bSubBlockingActive ) { nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow; poBlock = u.papoBlocks[nBlockIndex]; u.papoBlocks[nBlockIndex] = NULL; } /* -------------------------------------------------------------------- */ /* Identify our subblock. */ /* -------------------------------------------------------------------- */ else { int nSubBlock = TO_SUBBLOCK(nXBlockOff) + TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow; /* -------------------------------------------------------------------- */ /* Check within subblock. */ /* -------------------------------------------------------------------- */ GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock]; if( papoSubBlockGrid == NULL ) return CE_None; int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff) + WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE; poBlock = papoSubBlockGrid[nBlockInSubBlock]; papoSubBlockGrid[nBlockInSubBlock] = NULL; } if( poBlock == NULL ) return CE_None; if( !poBlock->DropLockForRemovalFromStorage() ) return CE_None; /* -------------------------------------------------------------------- */ /* Is the target block dirty? If so we need to write it. */ /* -------------------------------------------------------------------- */ CPLErr eErr = CE_None; poBlock->Detach(); if( bWriteDirtyBlock && poBlock->GetDirty() ) eErr = poBlock->Write(); /* -------------------------------------------------------------------- */ /* Deallocate the block; */ /* -------------------------------------------------------------------- */ delete poBlock; return eErr; }
CPLErr GDALRasterBlock::Internalize() { void *pNewData = NULL; int nSizeInBytes; CPLAssert( pData == NULL ); // This call will initialize the hRBLock mutex. Other call places can // only be called if we have go through there. GIntBig nCurCacheMax = GDALGetCacheMax64(); /* No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo() */ nSizeInBytes = GetBlockSize(); /* -------------------------------------------------------------------- */ /* Flush old blocks if we are nearing our memory limit. */ /* -------------------------------------------------------------------- */ int bFirstIter = TRUE; int bLoopAgain; do { bLoopAgain = FALSE; GDALRasterBlock* apoBlocksToFree[64]; int nBlocksToFree = 0; { TAKE_LOCK; if( bFirstIter ) nCacheUsed += nSizeInBytes; GDALRasterBlock *poTarget = poOldest; while( nCacheUsed > nCurCacheMax ) { while( poTarget != NULL && poTarget->GetLockCount() > 0 ) poTarget = poTarget->poPrevious; if( poTarget != NULL ) { GDALRasterBlock* _poPrevious = poTarget->poPrevious; poTarget->Detach_unlocked(); poTarget->GetBand()->UnreferenceBlock(poTarget->GetXOff(),poTarget->GetYOff()); apoBlocksToFree[nBlocksToFree++] = poTarget; if( poTarget->GetDirty() ) { // Only free one dirty block at a time so that // other dirty blocks of other bands with the same coordinates // can be found with TryGetLockedBlock() bLoopAgain = ( nCacheUsed > nCurCacheMax ); break; } if( nBlocksToFree == 64 ) { CPLDebug("GDAL", "More than 64 blocks are flagged to be flushed. Not trying more"); break; } poTarget = _poPrevious; } else break; } /* -------------------------------------------------------------------- */ /* Add this block to the list. */ /* -------------------------------------------------------------------- */ if( !bLoopAgain ) Touch_unlocked(); } bFirstIter = FALSE; /* Now free blocks we have detached and removed from their band */ for(int i=0; i<nBlocksToFree; i++) { GDALRasterBlock *poBlock = apoBlocksToFree[i]; if( poBlock->GetDirty() ) { CPLErr eErr = poBlock->Write(); if( eErr != CE_None ) { /* Save the error for later reporting */ poBlock->GetBand()->SetFlushBlockErr(eErr); } } /* Try to recycle the data of an existing block */ void* pDataBlock = poBlock->pData; if( pNewData == NULL && pDataBlock != NULL && poBlock->GetBlockSize() >= nSizeInBytes ) { pNewData = pDataBlock; poBlock->pData = NULL; } delete poBlock; } } while(bLoopAgain); if( pNewData == NULL ) { pNewData = VSIMalloc( nSizeInBytes ); if( pNewData == NULL ) { CPLError( CE_Failure, CPLE_OutOfMemory, "GDALRasterBlock::Internalize : Out of memory allocating %d bytes.", nSizeInBytes); return( CE_Failure ); } } pData = pNewData; return( CE_None ); }
CPLErr GDALRasterBlock::Internalize() { CPLAssert( pData == NULL ); void *pNewData = NULL; // This call will initialize the hRBLock mutex. Other call places can // only be called if we have go through there. const GIntBig nCurCacheMax = GDALGetCacheMax64(); // No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo(). const int nSizeInBytes = GetBlockSize(); /* -------------------------------------------------------------------- */ /* Flush old blocks if we are nearing our memory limit. */ /* -------------------------------------------------------------------- */ bool bFirstIter = true; bool bLoopAgain = false; do { bLoopAgain = false; GDALRasterBlock* apoBlocksToFree[64] = { NULL }; int nBlocksToFree = 0; { TAKE_LOCK; if( bFirstIter ) nCacheUsed += nSizeInBytes; GDALRasterBlock *poTarget = poOldest; while( nCacheUsed > nCurCacheMax ) { while( poTarget != NULL ) { if( CPLAtomicCompareAndExchange( &(poTarget->nLockCount), 0, -1) ) break; poTarget = poTarget->poPrevious; } if( poTarget != NULL ) { if( bSleepsForBockCacheDebug ) CPLSleep(CPLAtof( CPLGetConfigOption( "GDAL_RB_INTERNALIZE_SLEEP_AFTER_DROP_LOCK", "0"))); GDALRasterBlock* _poPrevious = poTarget->poPrevious; poTarget->Detach_unlocked(); poTarget->GetBand()->UnreferenceBlock(poTarget); apoBlocksToFree[nBlocksToFree++] = poTarget; if( poTarget->GetDirty() ) { // Only free one dirty block at a time so that // other dirty blocks of other bands with the same // coordinates can be found with TryGetLockedBlock() bLoopAgain = nCacheUsed > nCurCacheMax; break; } if( nBlocksToFree == 64 ) { bLoopAgain = ( nCacheUsed > nCurCacheMax ); break; } poTarget = _poPrevious; } else { break; } } /* ------------------------------------------------------------------ */ /* Add this block to the list. */ /* ------------------------------------------------------------------ */ if( !bLoopAgain ) Touch_unlocked(); } bFirstIter = false; // Now free blocks we have detached and removed from their band. for( int i = 0; i < nBlocksToFree; ++i) { GDALRasterBlock * const poBlock = apoBlocksToFree[i]; if( poBlock->GetDirty() ) { CPLErr eErr = poBlock->Write(); if( eErr != CE_None ) { // Save the error for later reporting. poBlock->GetBand()->SetFlushBlockErr(eErr); } } // Try to recycle the data of an existing block. void* pDataBlock = poBlock->pData; if( pNewData == NULL && pDataBlock != NULL && poBlock->GetBlockSize() == nSizeInBytes ) { pNewData = pDataBlock; } else { VSIFree(poBlock->pData); } poBlock->pData = NULL; poBlock->GetBand()->AddBlockToFreeList(poBlock); } } while(bLoopAgain); if( pNewData == NULL ) { pNewData = VSI_MALLOC_VERBOSE( nSizeInBytes ); if( pNewData == NULL ) { return( CE_Failure ); } } pData = pNewData; return CE_None; }