void GDALRasterBlock::Touch() { TAKE_LOCK; Touch_unlocked(); }
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; }