LCOV - code coverage report
Current view: top level - gcore - gdalrasterblock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 281 313 89.8 %
Date: 2025-07-01 22:47:05 Functions: 29 31 93.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of GDALRasterBlock class and related global
       5             :  *           raster block cache management.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  **********************************************************************
       9             :  * Copyright (c) 1998, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "gdal.h"
      17             : #include "gdal_priv.h"
      18             : 
      19             : #include <algorithm>
      20             : #include <climits>
      21             : #include <cstring>
      22             : #include <mutex>
      23             : 
      24             : #include "cpl_atomic_ops.h"
      25             : #include "cpl_conv.h"
      26             : #include "cpl_error.h"
      27             : #include "cpl_multiproc.h"
      28             : #include "cpl_string.h"
      29             : #include "cpl_vsi.h"
      30             : 
      31             : // Will later be overridden by the default 5% if GDAL_CACHEMAX not defined.
      32             : static GIntBig nCacheMax = 40 * 1024 * 1024;
      33             : static GIntBig nCacheUsed = 0;
      34             : 
      35             : static GDALRasterBlock *poOldest = nullptr;  // Tail.
      36             : static GDALRasterBlock *poNewest = nullptr;  // Head.
      37             : 
      38             : static int nDisableDirtyBlockFlushCounter = 0;
      39             : 
      40             : #if 0
      41             : static CPLMutex *hRBLock = nullptr;
      42             : #define INITIALIZE_LOCK CPLMutexHolderD(&hRBLock)
      43             : #define TAKE_LOCK CPLMutexHolderOptionalLockD(hRBLock)
      44             : #define DESTROY_LOCK CPLDestroyMutex(hRBLock)
      45             : #else
      46             : 
      47             : static CPLLock *hRBLock = nullptr;
      48             : static bool bDebugContention = false;
      49             : static bool bSleepsForBockCacheDebug = false;
      50             : 
      51        4994 : static CPLLockType GetLockType()
      52             : {
      53             :     static int nLockType = -1;
      54        4994 :     if (nLockType < 0)
      55             :     {
      56             :         const char *pszLockType =
      57         513 :             CPLGetConfigOption("GDAL_RB_LOCK_TYPE", "ADAPTIVE");
      58         513 :         if (EQUAL(pszLockType, "ADAPTIVE"))
      59         511 :             nLockType = LOCK_ADAPTIVE_MUTEX;
      60           2 :         else if (EQUAL(pszLockType, "RECURSIVE"))
      61           0 :             nLockType = LOCK_RECURSIVE_MUTEX;
      62           2 :         else if (EQUAL(pszLockType, "SPIN"))
      63           2 :             nLockType = LOCK_SPIN;
      64             :         else
      65             :         {
      66           0 :             CPLError(
      67             :                 CE_Warning, CPLE_NotSupported,
      68             :                 "GDAL_RB_LOCK_TYPE=%s not supported. Falling back to ADAPTIVE",
      69             :                 pszLockType);
      70           0 :             nLockType = LOCK_ADAPTIVE_MUTEX;
      71             :         }
      72         513 :         bDebugContention = CPLTestBool(
      73             :             CPLGetConfigOption("GDAL_RB_LOCK_DEBUG_CONTENTION", "NO"));
      74             :     }
      75        4994 :     return static_cast<CPLLockType>(nLockType);
      76             : }
      77             : 
      78             : #define INITIALIZE_LOCK                                                        \
      79             :     CPLLockHolderD(&hRBLock, GetLockType());                                   \
      80             :     CPLLockSetDebugPerf(hRBLock, bDebugContention)
      81             : #define TAKE_LOCK CPLLockHolderOptionalLockD(hRBLock)
      82             : #define DESTROY_LOCK CPLDestroyLock(hRBLock)
      83             : 
      84             : #endif
      85             : 
      86             : // #define ENABLE_DEBUG
      87             : 
      88             : /************************************************************************/
      89             : /*                          GDALSetCacheMax()                           */
      90             : /************************************************************************/
      91             : 
      92             : /**
      93             :  * \brief Set maximum cache memory.
      94             :  *
      95             :  * This function sets the maximum amount of memory that GDAL is permitted
      96             :  * to use for GDALRasterBlock caching. The unit of the value is bytes.
      97             :  *
      98             :  * The maximum value is 2GB, due to the use of a signed 32 bit integer.
      99             :  * Use GDALSetCacheMax64() to be able to set a higher value.
     100             :  *
     101             :  * @param nNewSizeInBytes the maximum number of bytes for caching.
     102             :  */
     103             : 
     104          15 : void CPL_STDCALL GDALSetCacheMax(int nNewSizeInBytes)
     105             : 
     106             : {
     107          15 :     GDALSetCacheMax64(nNewSizeInBytes);
     108          15 : }
     109             : 
     110             : /************************************************************************/
     111             : /*                        GDALSetCacheMax64()                           */
     112             : /************************************************************************/
     113             : 
     114             : /**
     115             :  * \brief Set maximum cache memory.
     116             :  *
     117             :  * This function sets the maximum amount of memory that GDAL is permitted
     118             :  * to use for GDALRasterBlock caching. The unit of the value is bytes.
     119             :  *
     120             :  * Note: On 32 bit platforms, the maximum amount of memory that can be addressed
     121             :  * by a process might be 2 GB or 3 GB, depending on the operating system
     122             :  * capabilities. This function will not make any attempt to check the
     123             :  * consistency of the passed value with the effective capabilities of the OS.
     124             :  *
     125             :  * @param nNewSizeInBytes the maximum number of bytes for caching.
     126             :  *
     127             :  * @since GDAL 1.8.0
     128             :  */
     129             : 
     130          91 : void CPL_STDCALL GDALSetCacheMax64(GIntBig nNewSizeInBytes)
     131             : 
     132             : {
     133             : #if 0
     134             :     if( nNewSizeInBytes == 12346789 )
     135             :     {
     136             :         GDALRasterBlock::DumpAll();
     137             :         return;
     138             :     }
     139             : #endif
     140             : 
     141             :     // To force one-time initialization of nCacheMax if not already done
     142          91 :     GDALGetCacheMax64();
     143          91 :     nCacheMax = nNewSizeInBytes;
     144             : 
     145             :     /* -------------------------------------------------------------------- */
     146             :     /*      Flush blocks till we are under the new limit or till we         */
     147             :     /*      can't seem to flush anymore.                                    */
     148             :     /* -------------------------------------------------------------------- */
     149        4295 :     while (nCacheUsed > nCacheMax)
     150             :     {
     151        4204 :         const GIntBig nOldCacheUsed = nCacheUsed;
     152             : 
     153        4204 :         GDALFlushCacheBlock();
     154             : 
     155        4204 :         if (nCacheUsed == nOldCacheUsed)
     156           0 :             break;
     157             :     }
     158          91 : }
     159             : 
     160             : /************************************************************************/
     161             : /*                          GDALGetCacheMax()                           */
     162             : /************************************************************************/
     163             : 
     164             : /**
     165             :  * \brief Get maximum cache memory.
     166             :  *
     167             :  * Gets the maximum amount of memory available to the GDALRasterBlock
     168             :  * caching system for caching GDAL read/write imagery.
     169             :  *
     170             :  * The first type this function is called, it will read the GDAL_CACHEMAX
     171             :  * configuration option to initialize the maximum cache memory.
     172             :  * Starting with GDAL 2.1, the value can be expressed as x% of the usable
     173             :  * physical RAM (which may potentially be used by other processes). Otherwise
     174             :  * it is expected to be a value in MB.
     175             :  *
     176             :  * This function cannot return a value higher than 2 GB. Use
     177             :  * GDALGetCacheMax64() to get a non-truncated value.
     178             :  *
     179             :  * @return maximum in bytes.
     180             :  */
     181             : 
     182           1 : int CPL_STDCALL GDALGetCacheMax()
     183             : {
     184           1 :     GIntBig nRes = GDALGetCacheMax64();
     185           1 :     if (nRes > INT_MAX)
     186             :     {
     187           0 :         CPLErrorOnce(CE_Warning, CPLE_AppDefined,
     188             :                      "Cache max value doesn't fit on a 32 bit integer. "
     189             :                      "Call GDALGetCacheMax64() instead");
     190           0 :         nRes = INT_MAX;
     191             :     }
     192           1 :     return static_cast<int>(nRes);
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                         GDALGetCacheMax64()                          */
     197             : /************************************************************************/
     198             : 
     199             : /**
     200             :  * \brief Get maximum cache memory.
     201             :  *
     202             :  * Gets the maximum amount of memory available to the GDALRasterBlock
     203             :  * caching system for caching GDAL read/write imagery.
     204             :  *
     205             :  * The first time this function is called, it will read the GDAL_CACHEMAX
     206             :  * configuration option to initialize the maximum cache memory.
     207             :  * Starting with GDAL 2.1, the value can be expressed as x% of the usable
     208             :  * physical RAM (which may potentially be used by other processes). Starting
     209             :  * with GDAL 3.11, the value can include units of memory. If not units are
     210             :  * provided the value is assumed to be in MB.
     211             :  *
     212             :  * @return maximum in bytes.
     213             :  *
     214             :  * @since GDAL 1.8.0
     215             :  */
     216             : 
     217     4093800 : GIntBig CPL_STDCALL GDALGetCacheMax64()
     218             : {
     219             :     static std::once_flag flagSetupGDALGetCacheMax64;
     220     4093800 :     std::call_once(
     221             :         flagSetupGDALGetCacheMax64,
     222         513 :         []()
     223             :         {
     224             :             {
     225         513 :                 INITIALIZE_LOCK;
     226             :             }
     227         513 :             bSleepsForBockCacheDebug =
     228         513 :                 CPLTestBool(CPLGetConfigOption("GDAL_DEBUG_BLOCK_CACHE", "NO"));
     229             : 
     230         513 :             const char *pszCacheMax = CPLGetConfigOption("GDAL_CACHEMAX", "5%");
     231             :             GIntBig nNewCacheMax;
     232         513 :             bool bUnitSpecified = false;
     233             : 
     234         513 :             if (CPLParseMemorySize(pszCacheMax, &nNewCacheMax,
     235         513 :                                    &bUnitSpecified) != CE_None)
     236             :             {
     237           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     238             :                          "Invalid value for GDAL_CACHEMAX. "
     239             :                          "Using default value.");
     240           0 :                 if (CPLParseMemorySize("5%", &nNewCacheMax, &bUnitSpecified) !=
     241             :                     CE_None)
     242             :                 {
     243             :                     // This means that usable physical RAM could not be determined.
     244           0 :                     nNewCacheMax = nCacheMax;
     245             :                 }
     246             :             }
     247             : 
     248         513 :             if (!bUnitSpecified && nNewCacheMax < 100000)
     249             :             {
     250             :                 // Assume MB
     251           5 :                 nNewCacheMax *= (1024 * 1024);
     252             :             }
     253             : 
     254         513 :             nCacheMax = nNewCacheMax;
     255         513 :             CPLDebug("GDAL", "GDAL_CACHEMAX = " CPL_FRMT_GIB " MB",
     256             :                      nCacheMax / (1024 * 1024));
     257         513 :         });
     258             : 
     259     4091210 :     return nCacheMax;
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                          GDALGetCacheUsed()                          */
     264             : /************************************************************************/
     265             : 
     266             : /**
     267             :  * \brief Get cache memory used.
     268             :  *
     269             :  * @return the number of bytes of memory currently in use by the
     270             :  * GDALRasterBlock memory caching.
     271             :  */
     272             : 
     273           0 : int CPL_STDCALL GDALGetCacheUsed()
     274             : {
     275           0 :     if (nCacheUsed > INT_MAX)
     276             :     {
     277           0 :         CPLErrorOnce(CE_Warning, CPLE_AppDefined,
     278             :                      "Cache used value doesn't fit on a 32 bit integer. "
     279             :                      "Call GDALGetCacheUsed64() instead");
     280           0 :         return INT_MAX;
     281             :     }
     282           0 :     return static_cast<int>(nCacheUsed);
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                        GDALGetCacheUsed64()                          */
     287             : /************************************************************************/
     288             : 
     289             : /**
     290             :  * \brief Get cache memory used.
     291             :  *
     292             :  * @return the number of bytes of memory currently in use by the
     293             :  * GDALRasterBlock memory caching.
     294             :  *
     295             :  * @since GDAL 1.8.0
     296             :  */
     297             : 
     298          17 : GIntBig CPL_STDCALL GDALGetCacheUsed64()
     299             : {
     300          17 :     return nCacheUsed;
     301             : }
     302             : 
     303             : /************************************************************************/
     304             : /*                        GDALFlushCacheBlock()                         */
     305             : /*                                                                      */
     306             : /*      The workhorse of cache management!                              */
     307             : /************************************************************************/
     308             : 
     309             : /**
     310             :  * \brief Try to flush one cached raster block
     311             :  *
     312             :  * This function will search the first unlocked raster block and will
     313             :  * flush it to release the associated memory.
     314             :  *
     315             :  * @return TRUE if one block was flushed, FALSE if there are no cached blocks
     316             :  *         or if they are currently locked.
     317             :  */
     318        4211 : int CPL_STDCALL GDALFlushCacheBlock()
     319             : 
     320             : {
     321        4211 :     return GDALRasterBlock::FlushCacheBlock();
     322             : }
     323             : 
     324             : /************************************************************************/
     325             : /* ==================================================================== */
     326             : /*                           GDALRasterBlock                            */
     327             : /* ==================================================================== */
     328             : /************************************************************************/
     329             : 
     330             : /**
     331             :  * \class GDALRasterBlock "gdal_priv.h"
     332             :  *
     333             :  * GDALRasterBlock objects hold one block of raster data for one band
     334             :  * that is currently stored in the GDAL raster cache.  The cache holds
     335             :  * some blocks of raster data for zero or more GDALRasterBand objects
     336             :  * across zero or more GDALDataset objects in a global raster cache with
     337             :  * a least recently used (LRU) list and an upper cache limit (see
     338             :  * GDALSetCacheMax()) under which the cache size is normally kept.
     339             :  *
     340             :  * Some blocks in the cache may be modified relative to the state on disk
     341             :  * (they are marked "Dirty") and must be flushed to disk before they can
     342             :  * be discarded.  Other (Clean) blocks may just be discarded if their memory
     343             :  * needs to be recovered.
     344             :  *
     345             :  * In normal situations applications do not interact directly with the
     346             :  * GDALRasterBlock - instead it it utilized by the RasterIO() interfaces
     347             :  * to implement caching.
     348             :  *
     349             :  * Some driver classes are implemented in a fashion that completely avoids
     350             :  * use of the GDAL raster cache (and GDALRasterBlock) though this is not very
     351             :  * common.
     352             :  */
     353             : 
     354             : /************************************************************************/
     355             : /*                          FlushCacheBlock()                           */
     356             : /*                                                                      */
     357             : /*      Note, if we have a lot of blocks locked for a long time, this    */
     358             : /*      method is going to get slow because it will have to traverse    */
     359             : /*      the linked list a long ways looking for a flushing              */
     360             : /*      candidate.   It might help to re-touch locked blocks to push    */
     361             : /*      them to the top of the list.                                    */
     362             : /************************************************************************/
     363             : 
     364             : /**
     365             :  * \brief Attempt to flush at least one block from the cache.
     366             :  *
     367             :  * This static method is normally used to recover memory when a request
     368             :  * for a new cache block would put cache memory use over the established
     369             :  * limit.
     370             :  *
     371             :  * C++ analog to the C function GDALFlushCacheBlock().
     372             :  *
     373             :  * @param bDirtyBlocksOnly Only flushes dirty blocks.
     374             :  * @return TRUE if successful or FALSE if no flushable block is found.
     375             :  */
     376             : 
     377        4216 : int GDALRasterBlock::FlushCacheBlock(int bDirtyBlocksOnly)
     378             : 
     379             : {
     380             :     GDALRasterBlock *poTarget;
     381             : 
     382             :     {
     383        4216 :         INITIALIZE_LOCK;
     384        4216 :         poTarget = poOldest;
     385             : 
     386        4226 :         while (poTarget != nullptr)
     387             :         {
     388        4229 :             if (!bDirtyBlocksOnly ||
     389           9 :                 (poTarget->GetDirty() && nDisableDirtyBlockFlushCounter == 0))
     390             :             {
     391        4211 :                 if (CPLAtomicCompareAndExchange(&(poTarget->nLockCount), 0, -1))
     392        4210 :                     break;
     393             :             }
     394          10 :             poTarget = poTarget->poPrevious;
     395             :         }
     396             : 
     397        4216 :         if (poTarget == nullptr)
     398           6 :             return FALSE;
     399             : #ifndef __COVERITY__
     400             :         // Disabled to avoid complains about sleeping under locks, that
     401             :         // are only true for debug/testing code
     402        4210 :         if (bSleepsForBockCacheDebug)
     403             :         {
     404           6 :             const double dfDelay = CPLAtof(CPLGetConfigOption(
     405             :                 "GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_DROP_LOCK", "0"));
     406           6 :             if (dfDelay > 0)
     407           3 :                 CPLSleep(dfDelay);
     408             :         }
     409             : #endif
     410             : 
     411        4210 :         poTarget->Detach_unlocked();
     412        4210 :         poTarget->GetBand()->UnreferenceBlock(poTarget);
     413             :     }
     414             : 
     415             : #ifndef __COVERITY__
     416             :     // Disabled to avoid complains about sleeping under locks, that
     417             :     // are only true for debug/testing code
     418        4210 :     if (bSleepsForBockCacheDebug)
     419             :     {
     420           6 :         const double dfDelay = CPLAtof(
     421             :             CPLGetConfigOption("GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_RB_LOCK", "0"));
     422           6 :         if (dfDelay > 0)
     423           1 :             CPLSleep(dfDelay);
     424             :     }
     425             : #endif
     426             : 
     427        4210 :     if (poTarget->GetDirty())
     428             :     {
     429          30 :         const CPLErr eErr = poTarget->Write();
     430          30 :         if (eErr != CE_None)
     431             :         {
     432             :             // Save the error for later reporting.
     433           0 :             poTarget->GetBand()->SetFlushBlockErr(eErr);
     434             :         }
     435             :     }
     436             : 
     437        4210 :     VSIFreeAligned(poTarget->pData);
     438        4210 :     poTarget->pData = nullptr;
     439        4210 :     poTarget->GetBand()->AddBlockToFreeList(poTarget);
     440             : 
     441        4210 :     return TRUE;
     442             : }
     443             : 
     444             : /************************************************************************/
     445             : /*                          FlushDirtyBlocks()                          */
     446             : /************************************************************************/
     447             : 
     448             : /**
     449             :  * \brief Flush all dirty blocks from cache.
     450             :  *
     451             :  * This static method is normally used to recover memory and is especially
     452             :  * useful when doing multi-threaded code that can trigger the block cache.
     453             :  *
     454             :  * Due to the current design of the block cache, dirty blocks belonging to a
     455             :  * same dataset could be pushed simultaneously to the IWriteBlock() method of
     456             :  * that dataset from different threads, causing races.
     457             :  *
     458             :  * Calling this method before that code can help workarounding that issue,
     459             :  * in a multiple readers, one writer scenario.
     460             :  *
     461             :  * @since GDAL 2.0
     462             :  */
     463             : 
     464           5 : void GDALRasterBlock::FlushDirtyBlocks()
     465             : 
     466             : {
     467           5 :     while (FlushCacheBlock(TRUE))
     468             :     {
     469             :         /* go on */
     470             :     }
     471           5 : }
     472             : 
     473             : /************************************************************************/
     474             : /*                      EnterDisableDirtyBlockFlush()                   */
     475             : /************************************************************************/
     476             : 
     477             : /**
     478             :  * \brief Starts preventing dirty blocks from being flushed
     479             :  *
     480             :  * This static method is used to prevent dirty blocks from being flushed.
     481             :  * This might be useful when in a IWriteBlock() method, whose implementation
     482             :  * can directly/indirectly cause the block cache to evict new blocks, to
     483             :  * be recursively called on the same dataset.
     484             :  *
     485             :  * This method implements a reference counter and is thread-safe.
     486             :  *
     487             :  * This call must be paired with a corresponding LeaveDisableDirtyBlockFlush().
     488             :  *
     489             :  * @since GDAL 2.2.2
     490             :  */
     491             : 
     492       14015 : void GDALRasterBlock::EnterDisableDirtyBlockFlush()
     493             : {
     494       14015 :     CPLAtomicInc(&nDisableDirtyBlockFlushCounter);
     495       14015 : }
     496             : 
     497             : /************************************************************************/
     498             : /*                      LeaveDisableDirtyBlockFlush()                   */
     499             : /************************************************************************/
     500             : 
     501             : /**
     502             :  * \brief Ends preventing dirty blocks from being flushed.
     503             :  *
     504             :  * Undoes the effect of EnterDisableDirtyBlockFlush().
     505             :  *
     506             :  * @since GDAL 2.2.2
     507             :  */
     508             : 
     509       14015 : void GDALRasterBlock::LeaveDisableDirtyBlockFlush()
     510             : {
     511       14015 :     CPLAtomicDec(&nDisableDirtyBlockFlushCounter);
     512       14015 : }
     513             : 
     514             : /************************************************************************/
     515             : /*                          GDALRasterBlock()                           */
     516             : /************************************************************************/
     517             : 
     518             : /**
     519             :  * @brief GDALRasterBlock Constructor
     520             :  *
     521             :  * Normally only called from GDALRasterBand::GetLockedBlockRef().
     522             :  *
     523             :  * @param poBandIn the raster band used as source of raster block
     524             :  * being constructed.
     525             :  *
     526             :  * @param nXOffIn the horizontal block offset, with zero indicating
     527             :  * the left most block, 1 the next block and so forth.
     528             :  *
     529             :  * @param nYOffIn the vertical block offset, with zero indicating
     530             :  * the top most block, 1 the next block and so forth.
     531             :  */
     532             : 
     533     3351210 : GDALRasterBlock::GDALRasterBlock(GDALRasterBand *poBandIn, int nXOffIn,
     534     3351210 :                                  int nYOffIn)
     535     6702350 :     : eType(poBandIn->GetRasterDataType()), bDirty(false), nLockCount(0),
     536             :       nXOff(nXOffIn), nYOff(nYOffIn), nXSize(0), nYSize(0), pData(nullptr),
     537     3351210 :       poBand(poBandIn), poNext(nullptr), poPrevious(nullptr), bMustDetach(true)
     538             : {
     539     3351140 :     if (!hRBLock)
     540             :     {
     541             :         // Needed for scenarios where GDALAllRegister() is called after
     542             :         // GDALDestroyDriverManager()
     543         341 :         INITIALIZE_LOCK;
     544             :     }
     545             : 
     546     3351060 :     CPLAssert(poBandIn != nullptr);
     547     3351060 :     poBand->GetBlockSize(&nXSize, &nYSize);
     548     3351120 : }
     549             : 
     550             : /************************************************************************/
     551             : /*                          GDALRasterBlock()                           */
     552             : /************************************************************************/
     553             : 
     554             : /**
     555             :  * @brief GDALRasterBlock Constructor (for GDALHashSetBandBlockAccess purpose)
     556             :  *
     557             :  * Normally only called from GDALHashSetBandBlockAccess class. Such a block
     558             :  * is completely non functional and only meant as being used to do a look-up
     559             :  * in the hash set of GDALHashSetBandBlockAccess
     560             :  *
     561             :  * @param nXOffIn the horizontal block offset, with zero indicating
     562             :  * the left most block, 1 the next block and so forth.
     563             :  *
     564             :  * @param nYOffIn the vertical block offset, with zero indicating
     565             :  * the top most block, 1 the next block and so forth.
     566             :  */
     567             : 
     568     2960300 : GDALRasterBlock::GDALRasterBlock(int nXOffIn, int nYOffIn)
     569             :     : eType(GDT_Unknown), bDirty(false), nLockCount(0), nXOff(nXOffIn),
     570             :       nYOff(nYOffIn), nXSize(0), nYSize(0), pData(nullptr), poBand(nullptr),
     571     2960300 :       poNext(nullptr), poPrevious(nullptr), bMustDetach(false)
     572             : {
     573     2960300 : }
     574             : 
     575             : /************************************************************************/
     576             : /*                                  RecycleFor()                        */
     577             : /************************************************************************/
     578             : 
     579             : /**
     580             :  * Recycle an existing block (of the same band)
     581             :  *
     582             :  * Normally called from GDALAbstractBandBlockCache::CreateBlock().
     583             :  */
     584             : 
     585       10295 : void GDALRasterBlock::RecycleFor(int nXOffIn, int nYOffIn)
     586             : {
     587       10295 :     CPLAssert(pData == nullptr);
     588       10295 :     pData = nullptr;
     589       10295 :     bDirty = false;
     590       10295 :     nLockCount = 0;
     591             : 
     592       10295 :     poNext = nullptr;
     593       10295 :     poPrevious = nullptr;
     594             : 
     595       10295 :     nXOff = nXOffIn;
     596       10295 :     nYOff = nYOffIn;
     597       10295 :     bMustDetach = true;
     598       10295 : }
     599             : 
     600             : /************************************************************************/
     601             : /*                          ~GDALRasterBlock()                          */
     602             : /************************************************************************/
     603             : 
     604             : /**
     605             :  * Block destructor.
     606             :  *
     607             :  * Normally called from GDALRasterBand::FlushBlock().
     608             :  */
     609             : 
     610    15974340 : GDALRasterBlock::~GDALRasterBlock()
     611             : 
     612             : {
     613     6311540 :     Detach();
     614             : 
     615     6311540 :     if (pData != nullptr)
     616             :     {
     617     3331920 :         VSIFreeAligned(pData);
     618             :     }
     619             : 
     620     6311540 :     CPLAssert(nLockCount <= 0);
     621             : 
     622             : #ifdef ENABLE_DEBUG
     623             :     Verify();
     624             : #endif
     625     9662780 : }
     626             : 
     627             : /************************************************************************/
     628             : /*                        GetEffectiveBlockSize()                       */
     629             : /************************************************************************/
     630             : 
     631     6723070 : static size_t GetEffectiveBlockSize(GPtrDiff_t nBlockSize)
     632             : {
     633             :     // The real cost of a block allocation is more than just nBlockSize
     634             :     // As we allocate with 64-byte alignment, use 64 as a multiple.
     635             :     // We arbitrarily add 2 * sizeof(GDALRasterBlock) to account for that
     636             :     return static_cast<size_t>(
     637    13446100 :         std::min(static_cast<GUIntBig>(UINT_MAX),
     638     6723070 :                  static_cast<GUIntBig>(DIV_ROUND_UP(nBlockSize, 64)) * 64 +
     639     6723070 :                      2 * sizeof(GDALRasterBlock)));
     640             : }
     641             : 
     642             : /************************************************************************/
     643             : /*                               Detach()                               */
     644             : /************************************************************************/
     645             : 
     646             : /**
     647             :  * Remove block from cache.
     648             :  *
     649             :  * This method removes the current block from the linked list used to keep
     650             :  * track of all cached blocks in order of age.  It does not affect whether
     651             :  * the block is referenced by a GDALRasterBand nor does it destroy or flush
     652             :  * the block.
     653             :  */
     654             : 
     655     7627360 : void GDALRasterBlock::Detach()
     656             : 
     657             : {
     658     7627360 :     if (bMustDetach)
     659             :     {
     660     6663840 :         TAKE_LOCK;
     661     3331920 :         Detach_unlocked();
     662             :     }
     663     7627360 : }
     664             : 
     665     3361540 : void GDALRasterBlock::Detach_unlocked()
     666             : {
     667     3361540 :     if (poOldest == this)
     668     2774700 :         poOldest = poPrevious;
     669             : 
     670     3361540 :     if (poNewest == this)
     671             :     {
     672       27335 :         poNewest = poNext;
     673             :     }
     674             : 
     675     3361540 :     if (poPrevious != nullptr)
     676     3334200 :         poPrevious->poNext = poNext;
     677             : 
     678     3361540 :     if (poNext != nullptr)
     679      586835 :         poNext->poPrevious = poPrevious;
     680             : 
     681     3361540 :     poPrevious = nullptr;
     682     3361540 :     poNext = nullptr;
     683     3361540 :     bMustDetach = false;
     684             : 
     685     3361540 :     if (pData)
     686     3361540 :         nCacheUsed -= GetEffectiveBlockSize(GetBlockSize());
     687             : 
     688             : #ifdef ENABLE_DEBUG
     689             :     Verify();
     690             : #endif
     691     3361540 : }
     692             : 
     693             : /************************************************************************/
     694             : /*                               Verify()                               */
     695             : /************************************************************************/
     696             : 
     697             : /**
     698             :  * Confirms (via assertions) that the block cache linked list is in a
     699             :  * consistent state.
     700             :  */
     701             : 
     702             : #ifdef ENABLE_DEBUG
     703             : void GDALRasterBlock::Verify()
     704             : 
     705             : {
     706             :     TAKE_LOCK;
     707             : 
     708             :     CPLAssert((poNewest == nullptr && poOldest == nullptr) ||
     709             :               (poNewest != nullptr && poOldest != nullptr));
     710             : 
     711             :     if (poNewest != nullptr)
     712             :     {
     713             :         CPLAssert(poNewest->poPrevious == nullptr);
     714             :         CPLAssert(poOldest->poNext == nullptr);
     715             : 
     716             :         GDALRasterBlock *poLast = nullptr;
     717             :         for (GDALRasterBlock *poBlock = poNewest; poBlock != nullptr;
     718             :              poBlock = poBlock->poNext)
     719             :         {
     720             :             CPLAssert(poBlock->poPrevious == poLast);
     721             : 
     722             :             poLast = poBlock;
     723             :         }
     724             : 
     725             :         CPLAssert(poOldest == poLast);
     726             :     }
     727             : }
     728             : 
     729             : #else
     730           0 : void GDALRasterBlock::Verify()
     731             : {
     732           0 : }
     733             : #endif
     734             : 
     735             : #ifdef notdef
     736             : void GDALRasterBlock::CheckNonOrphanedBlocks(GDALRasterBand *poBand)
     737             : {
     738             :     TAKE_LOCK;
     739             :     for (GDALRasterBlock *poBlock = poNewest; poBlock != nullptr;
     740             :          poBlock = poBlock->poNext)
     741             :     {
     742             :         if (poBlock->GetBand() == poBand)
     743             :         {
     744             :             printf("Cache has still blocks of band %p\n", poBand); /*ok*/
     745             :             printf("Band : %d\n", poBand->GetBand());              /*ok*/
     746             :             printf("nRasterXSize = %d\n", poBand->GetXSize());     /*ok*/
     747             :             printf("nRasterYSize = %d\n", poBand->GetYSize());     /*ok*/
     748             :             int nBlockXSize, nBlockYSize;
     749             :             poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     750             :             printf("nBlockXSize = %d\n", nBlockXSize);      /*ok*/
     751             :             printf("nBlockYSize = %d\n", nBlockYSize);      /*ok*/
     752             :             printf("Dataset : %p\n", poBand->GetDataset()); /*ok*/
     753             :             if (poBand->GetDataset())
     754             :                 printf("Dataset : %s\n", /*ok*/
     755             :                        poBand->GetDataset()->GetDescription());
     756             :         }
     757             :     }
     758             : }
     759             : #endif
     760             : 
     761             : /************************************************************************/
     762             : /*                               Write()                                */
     763             : /************************************************************************/
     764             : 
     765             : /**
     766             :  * Force writing of the current block, if dirty.
     767             :  *
     768             :  * The block is written using GDALRasterBand::IWriteBlock() on its
     769             :  * corresponding band object.  Even if the write fails the block will
     770             :  * be marked clean.
     771             :  *
     772             :  * @return CE_None otherwise the error returned by IWriteBlock().
     773             :  */
     774             : 
     775      205503 : CPLErr GDALRasterBlock::Write()
     776             : 
     777             : {
     778      205503 :     if (!GetDirty())
     779           0 :         return CE_None;
     780             : 
     781      205503 :     if (poBand == nullptr)
     782           0 :         return CE_Failure;
     783             : 
     784      205503 :     MarkClean();
     785             : 
     786      205503 :     if (poBand->eFlushBlockErr == CE_None)
     787             :     {
     788      205503 :         int bCallLeaveReadWrite = poBand->EnterReadWrite(GF_Write);
     789      205503 :         CPLErr eErr = poBand->IWriteBlock(nXOff, nYOff, pData);
     790      205503 :         if (bCallLeaveReadWrite)
     791      125254 :             poBand->LeaveReadWrite();
     792      205500 :         return eErr;
     793             :     }
     794             :     else
     795           0 :         return poBand->eFlushBlockErr;
     796             : }
     797             : 
     798             : /************************************************************************/
     799             : /*                               Touch()                                */
     800             : /************************************************************************/
     801             : 
     802             : /**
     803             :  * Push block to top of LRU (least-recently used) list.
     804             :  *
     805             :  * This method is normally called when a block is used to keep track
     806             :  * that it has been recently used.
     807             :  */
     808             : 
     809     7146840 : void GDALRasterBlock::Touch()
     810             : 
     811             : {
     812             :     // Can be safely tested outside the lock
     813     7146840 :     if (poNewest == this)
     814      335509 :         return;
     815             : 
     816    13623800 :     TAKE_LOCK;
     817     6812470 :     Touch_unlocked();
     818             : }
     819             : 
     820    10174000 : void GDALRasterBlock::Touch_unlocked()
     821             : 
     822             : {
     823             :     // Could happen even if tested in Touch() before taking the lock
     824             :     // Scenario would be :
     825             :     // 0. this is the second block (the one pointed by poNewest->poNext)
     826             :     // 1. Thread 1 calls Touch() and poNewest != this at that point
     827             :     // 2. Thread 2 detaches poNewest
     828             :     // 3. Thread 1 arrives here
     829    10174000 :     if (poNewest == this)
     830           0 :         return;
     831             : 
     832             :     // We should not try to touch a block that has been detached.
     833             :     // If that happen, corruption has already occurred.
     834    10174000 :     CPLAssert(bMustDetach);
     835             : 
     836    10174000 :     if (poOldest == this)
     837     1543010 :         poOldest = this->poPrevious;
     838             : 
     839    10174000 :     if (poPrevious != nullptr)
     840     6812470 :         poPrevious->poNext = poNext;
     841             : 
     842    10174000 :     if (poNext != nullptr)
     843     5269450 :         poNext->poPrevious = poPrevious;
     844             : 
     845    10174000 :     poPrevious = nullptr;
     846    10174000 :     poNext = poNewest;
     847             : 
     848    10174000 :     if (poNewest != nullptr)
     849             :     {
     850    10152200 :         CPLAssert(poNewest->poPrevious == nullptr);
     851    10152200 :         poNewest->poPrevious = this;
     852             :     }
     853    10174000 :     poNewest = this;
     854             : 
     855    10174000 :     if (poOldest == nullptr)
     856             :     {
     857       21826 :         CPLAssert(poPrevious == nullptr && poNext == nullptr);
     858       21826 :         poOldest = this;
     859             :     }
     860             : #ifdef ENABLE_DEBUG
     861             :     Verify();
     862             : #endif
     863             : }
     864             : 
     865             : /************************************************************************/
     866             : /*                            Internalize()                             */
     867             : /************************************************************************/
     868             : 
     869             : /**
     870             :  * Allocate memory for block.
     871             :  *
     872             :  * This method allocates memory for the block, and attempts to flush other
     873             :  * blocks, if necessary, to bring the total cache size back within the limits.
     874             :  * The newly allocated block is touched and will be considered most recently
     875             :  * used in the LRU list.
     876             :  *
     877             :  * @return CE_None on success or CE_Failure if memory allocation fails.
     878             :  */
     879             : 
     880     3361430 : CPLErr GDALRasterBlock::Internalize()
     881             : 
     882             : {
     883     3361430 :     CPLAssert(pData == nullptr);
     884             : 
     885     3361430 :     void *pNewData = nullptr;
     886             : 
     887             :     // This call will initialize the hRBLock mutex. Other call places can
     888             :     // only be called if we have go through there.
     889     3361430 :     const GIntBig nCurCacheMax = GDALGetCacheMax64();
     890             : 
     891             :     // No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo().
     892     3361380 :     const auto nSizeInBytes = GetBlockSize();
     893             : 
     894             :     /* -------------------------------------------------------------------- */
     895             :     /*      Flush old blocks if we are nearing our memory limit.            */
     896             :     /* -------------------------------------------------------------------- */
     897     3361370 :     bool bFirstIter = true;
     898     3361370 :     bool bLoopAgain = false;
     899     3361370 :     GDALDataset *poThisDS = poBand->GetDataset();
     900     3361570 :     do
     901             :     {
     902     3361390 :         bLoopAgain = false;
     903     3361390 :         GDALRasterBlock *apoBlocksToFree[64] = {nullptr};
     904     3361390 :         int nBlocksToFree = 0;
     905             :         {
     906     6722960 :             TAKE_LOCK;
     907             : 
     908     3361570 :             if (bFirstIter)
     909     3361540 :                 nCacheUsed += GetEffectiveBlockSize(nSizeInBytes);
     910     3361570 :             GDALRasterBlock *poTarget = poOldest;
     911     3379850 :             while (nCacheUsed > nCurCacheMax)
     912             :             {
     913       36059 :                 GDALRasterBlock *poDirtyBlockOtherDataset = nullptr;
     914             :                 // In this first pass, only discard dirty blocks of this
     915             :                 // dataset. We do this to decrease significantly the likelihood
     916             :                 // of the following weakness of the block cache design:
     917             :                 // 1. Thread 1 fills block B with ones
     918             :                 // 2. Thread 2 evicts this dirty block, while thread 1 almost
     919             :                 //    at the same time (but slightly after) tries to reacquire
     920             :                 //    this block. As it has been removed from the block cache
     921             :                 //    array/set, thread 1 now tries to read block B from disk,
     922             :                 //    so gets the old value.
     923      170450 :                 while (poTarget != nullptr)
     924             :                 {
     925      159787 :                     if (!poTarget->GetDirty())
     926             :                     {
     927       29513 :                         if (CPLAtomicCompareAndExchange(&(poTarget->nLockCount),
     928       29513 :                                                         0, -1))
     929       18279 :                             break;
     930             :                     }
     931      130274 :                     else if (nDisableDirtyBlockFlushCounter == 0)
     932             :                     {
     933      130274 :                         if (poTarget->poBand->GetDataset() == poThisDS)
     934             :                         {
     935        7117 :                             if (CPLAtomicCompareAndExchange(
     936        7117 :                                     &(poTarget->nLockCount), 0, -1))
     937        7117 :                                 break;
     938             :                         }
     939      123157 :                         else if (poDirtyBlockOtherDataset == nullptr)
     940             :                         {
     941        8390 :                             poDirtyBlockOtherDataset = poTarget;
     942             :                         }
     943             :                     }
     944      134391 :                     poTarget = poTarget->poPrevious;
     945             :                 }
     946       36059 :                 if (poTarget == nullptr && poDirtyBlockOtherDataset)
     947             :                 {
     948           6 :                     if (CPLAtomicCompareAndExchange(
     949           6 :                             &(poDirtyBlockOtherDataset->nLockCount), 0, -1))
     950             :                     {
     951           6 :                         CPLDebug("GDAL",
     952             :                                  "Evicting dirty block of another dataset");
     953           6 :                         poTarget = poDirtyBlockOtherDataset;
     954             :                     }
     955             :                     else
     956             :                     {
     957           0 :                         poTarget = poOldest;
     958           0 :                         while (poTarget != nullptr)
     959             :                         {
     960           0 :                             if (CPLAtomicCompareAndExchange(
     961           0 :                                     &(poTarget->nLockCount), 0, -1))
     962             :                             {
     963           0 :                                 CPLDebug(
     964             :                                     "GDAL",
     965             :                                     "Evicting dirty block of another dataset");
     966           0 :                                 break;
     967             :                             }
     968           0 :                             poTarget = poTarget->poPrevious;
     969             :                         }
     970             :                     }
     971             :                 }
     972             : 
     973       36059 :                 if (poTarget != nullptr)
     974             :                 {
     975             : #ifndef __COVERITY__
     976             :                     // Disabled to avoid complains about sleeping under locks,
     977             :                     // that are only true for debug/testing code
     978       25402 :                     if (bSleepsForBockCacheDebug)
     979             :                     {
     980           2 :                         const double dfDelay = CPLAtof(CPLGetConfigOption(
     981             :                             "GDAL_RB_INTERNALIZE_SLEEP_AFTER_DROP_LOCK", "0"));
     982           2 :                         if (dfDelay > 0)
     983           1 :                             CPLSleep(dfDelay);
     984             :                     }
     985             : #endif
     986             : 
     987       25402 :                     GDALRasterBlock *_poPrevious = poTarget->poPrevious;
     988             : 
     989       25402 :                     poTarget->Detach_unlocked();
     990       25402 :                     poTarget->GetBand()->UnreferenceBlock(poTarget);
     991             : 
     992       25402 :                     apoBlocksToFree[nBlocksToFree++] = poTarget;
     993       25402 :                     if (poTarget->GetDirty())
     994             :                     {
     995             :                         // Only free one dirty block at a time so that
     996             :                         // other dirty blocks of other bands with the same
     997             :                         // coordinates can be found with TryGetLockedBlock()
     998        7123 :                         bLoopAgain = nCacheUsed > nCurCacheMax;
     999        7123 :                         break;
    1000             :                     }
    1001       18279 :                     if (nBlocksToFree == 64)
    1002             :                     {
    1003           0 :                         bLoopAgain = (nCacheUsed > nCurCacheMax);
    1004           0 :                         break;
    1005             :                     }
    1006             : 
    1007       18279 :                     poTarget = _poPrevious;
    1008             :                 }
    1009             :                 else
    1010             :                 {
    1011       10657 :                     break;
    1012             :                 }
    1013             :             }
    1014             : 
    1015             :             /* ------------------------------------------------------------------
    1016             :              */
    1017             :             /*      Add this block to the list. */
    1018             :             /* ------------------------------------------------------------------
    1019             :              */
    1020     3361570 :             if (!bLoopAgain)
    1021     3361540 :                 Touch_unlocked();
    1022             :         }
    1023             : 
    1024     3361570 :         bFirstIter = false;
    1025             : 
    1026             :         // Now free blocks we have detached and removed from their band.
    1027     3386970 :         for (int i = 0; i < nBlocksToFree; ++i)
    1028             :         {
    1029       25402 :             GDALRasterBlock *const poBlock = apoBlocksToFree[i];
    1030             : 
    1031       25402 :             if (poBlock->GetDirty())
    1032             :             {
    1033             : #ifndef __COVERITY__
    1034             :                 // Disabled to avoid complains about sleeping under locks, that
    1035             :                 // are only true for debug/testing code
    1036        7123 :                 if (bSleepsForBockCacheDebug)
    1037             :                 {
    1038           1 :                     const double dfDelay = CPLAtof(CPLGetConfigOption(
    1039             :                         "GDAL_RB_INTERNALIZE_SLEEP_AFTER_DETACH_BEFORE_WRITE",
    1040             :                         "0"));
    1041           1 :                     if (dfDelay > 0)
    1042           1 :                         CPLSleep(dfDelay);
    1043             :                 }
    1044             : #endif
    1045             : 
    1046        7123 :                 CPLErr eErr = poBlock->Write();
    1047        7123 :                 if (eErr != CE_None)
    1048             :                 {
    1049             :                     // Save the error for later reporting.
    1050           0 :                     poBlock->GetBand()->SetFlushBlockErr(eErr);
    1051             :                 }
    1052             :             }
    1053             : 
    1054             :             // Try to recycle the data of an existing block.
    1055       25402 :             void *pDataBlock = poBlock->pData;
    1056       50268 :             if (pNewData == nullptr && pDataBlock != nullptr &&
    1057       24866 :                 poBlock->GetBlockSize() == nSizeInBytes)
    1058             :             {
    1059       24764 :                 pNewData = pDataBlock;
    1060             :             }
    1061             :             else
    1062             :             {
    1063         638 :                 VSIFreeAligned(poBlock->pData);
    1064             :             }
    1065       25402 :             poBlock->pData = nullptr;
    1066             : 
    1067       25402 :             poBlock->GetBand()->AddBlockToFreeList(poBlock);
    1068             :         }
    1069             :     } while (bLoopAgain);
    1070             : 
    1071     3361540 :     if (pNewData == nullptr)
    1072             :     {
    1073     3336770 :         pNewData = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nSizeInBytes);
    1074     3336640 :         if (pNewData == nullptr)
    1075             :         {
    1076           0 :             return (CE_Failure);
    1077             :         }
    1078             :     }
    1079             : 
    1080     3361400 :     pData = pNewData;
    1081             : 
    1082     3361400 :     return CE_None;
    1083             : }
    1084             : 
    1085             : /************************************************************************/
    1086             : /*                             MarkDirty()                              */
    1087             : /************************************************************************/
    1088             : 
    1089             : /**
    1090             :  * Mark the block as modified.
    1091             :  *
    1092             :  * A dirty block is one that has been modified and will need to be written
    1093             :  * to disk before it can be flushed.
    1094             :  */
    1095             : 
    1096     3954920 : void GDALRasterBlock::MarkDirty()
    1097             : {
    1098     3954920 :     if (poBand)
    1099             :     {
    1100     3954920 :         poBand->InitRWLock();
    1101     3954920 :         if (!bDirty)
    1102      376092 :             poBand->IncDirtyBlocks(1);
    1103             :     }
    1104     3954920 :     bDirty = true;
    1105     3954920 : }
    1106             : 
    1107             : /************************************************************************/
    1108             : /*                             MarkClean()                              */
    1109             : /************************************************************************/
    1110             : 
    1111             : /**
    1112             :  * Mark the block as unmodified.
    1113             :  *
    1114             :  * A dirty block is one that has been modified and will need to be written
    1115             :  * to disk before it can be flushed.
    1116             :  */
    1117             : 
    1118      373987 : void GDALRasterBlock::MarkClean()
    1119             : {
    1120      373987 :     if (bDirty && poBand)
    1121      373957 :         poBand->IncDirtyBlocks(-1);
    1122      373987 :     bDirty = false;
    1123      373987 : }
    1124             : 
    1125             : /************************************************************************/
    1126             : /*                          DestroyRBMutex()                           */
    1127             : /************************************************************************/
    1128             : 
    1129             : /*! @cond Doxygen_Suppress */
    1130        1113 : void GDALRasterBlock::DestroyRBMutex()
    1131             : {
    1132        1113 :     if (hRBLock != nullptr)
    1133         370 :         DESTROY_LOCK;
    1134        1113 :     hRBLock = nullptr;
    1135        1113 : }
    1136             : 
    1137             : /*! @endcond */
    1138             : 
    1139             : /************************************************************************/
    1140             : /*                              TakeLock()                              */
    1141             : /************************************************************************/
    1142             : 
    1143             : /**
    1144             :  * Take a lock and Touch().
    1145             :  *
    1146             :  * Should only be used by GDALArrayBandBlockCache::TryGetLockedBlockRef()
    1147             :  * and GDALHashSetBandBlockCache::TryGetLockedBlockRef()
    1148             :  *
    1149             :  * @return TRUE if the lock has been successfully acquired. If FALSE, the
    1150             :  *         block is being evicted by another thread, and so should be
    1151             :  *         considered as invalid.
    1152             :  */
    1153             : 
    1154     7145840 : int GDALRasterBlock::TakeLock()
    1155             : {
    1156     7145840 :     const int nLockVal = AddLock();
    1157     7146280 :     CPLAssert(nLockVal >= 0);
    1158             : #ifndef __COVERITY__
    1159             :     // Disabled to avoid complains about sleeping under locks, that
    1160             :     // are only true for debug/testing code
    1161     7146280 :     if (bSleepsForBockCacheDebug)
    1162             :     {
    1163           4 :         const double dfDelay = CPLAtof(
    1164             :             CPLGetConfigOption("GDAL_RB_TRYGET_SLEEP_AFTER_TAKE_LOCK", "0"));
    1165           4 :         if (dfDelay > 0)
    1166           1 :             CPLSleep(dfDelay);
    1167             :     }
    1168             : #endif
    1169             : 
    1170     7146310 :     if (nLockVal == 0)
    1171             :     {
    1172             :         // The block is being evicted by GDALRasterBlock::Internalize()
    1173             :         // or FlushCacheBlock()
    1174             : 
    1175             : #ifdef DEBUG
    1176           4 :         CPLDebug(
    1177             :             "GDAL",
    1178             :             "TakeLock(%p): Block(%d,%d,%p) is being evicted while trying to "
    1179             :             "reacquire it.",
    1180           2 :             reinterpret_cast<void *>(CPLGetPID()), nXOff, nYOff, poBand);
    1181             : #endif
    1182           2 :         DropLock();
    1183             : 
    1184           2 :         return FALSE;
    1185             :     }
    1186     7146300 :     Touch();
    1187     7147980 :     return TRUE;
    1188             : }
    1189             : 
    1190             : /************************************************************************/
    1191             : /*                      DropLockForRemovalFromStorage()                 */
    1192             : /************************************************************************/
    1193             : 
    1194             : /**
    1195             :  * Drop a lock before removing the block from the band storage.
    1196             :  *
    1197             :  * Should only be used by GDALArrayBandBlockCache::FlushBlock()
    1198             :  * and GDALHashSetBandBlockCache::FlushBlock()
    1199             :  *
    1200             :  * @return TRUE if the lock has been successfully dropped.
    1201             :  */
    1202             : 
    1203     3331920 : int GDALRasterBlock::DropLockForRemovalFromStorage()
    1204             : {
    1205             :     // Detect potential conflict with GDALRasterBlock::Internalize()
    1206             :     // or FlushCacheBlock()
    1207     3331920 :     if (CPLAtomicCompareAndExchange(&nLockCount, 0, -1))
    1208     3331920 :         return TRUE;
    1209             : #ifdef DEBUG
    1210           5 :     CPLDebug("GDAL",
    1211             :              "DropLockForRemovalFromStorage(%p): Block(%d,%d,%p) was attempted "
    1212             :              "to be flushed from band but it is flushed by global cache.",
    1213           3 :              reinterpret_cast<void *>(CPLGetPID()), nXOff, nYOff, poBand);
    1214             : #endif
    1215             : 
    1216             :     // Wait for the block for having been unreferenced.
    1217           2 :     TAKE_LOCK;
    1218             : 
    1219           2 :     return FALSE;
    1220             : }
    1221             : 
    1222             : #if 0
    1223             : void GDALRasterBlock::DumpAll()
    1224             : {
    1225             :     int iBlock = 0;
    1226             :     for( GDALRasterBlock *poBlock = poNewest;
    1227             :          poBlock != nullptr;
    1228             :          poBlock = poBlock->poNext )
    1229             :     {
    1230             :         printf("Block %d\n", iBlock);/*ok*/
    1231             :         poBlock->DumpBlock();
    1232             :         printf("\n");/*ok*/
    1233             :         iBlock++;
    1234             :     }
    1235             : }
    1236             : 
    1237             : void GDALRasterBlock::DumpBlock()
    1238             : {
    1239             :     printf("  Lock count = %d\n", nLockCount);/*ok*/
    1240             :     printf("  bDirty = %d\n", static_cast<int>(bDirty));/*ok*/
    1241             :     printf("  nXOff = %d\n", nXOff);/*ok*/
    1242             :     printf("  nYOff = %d\n", nYOff);/*ok*/
    1243             :     printf("  nXSize = %d\n", nXSize);/*ok*/
    1244             :     printf("  nYSize = %d\n", nYSize);/*ok*/
    1245             :     printf("  eType = %d\n", eType);/*ok*/
    1246             :     printf("  Band %p\n", GetBand());/*ok*/
    1247             :     printf("  Band %d\n", GetBand()->GetBand());/*ok*/
    1248             :     if( GetBand()->GetDataset() )
    1249             :         printf("  Dataset = %s\n",/*ok*/
    1250             :                GetBand()->GetDataset()->GetDescription());
    1251             : }
    1252             : #endif  // if 0

Generated by: LCOV version 1.14