LCOV - code coverage report
Current view: top level - gcore - gdalrasterblock.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 279 315 88.6 %
Date: 2024-11-21 22:18:42 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        4762 : static CPLLockType GetLockType()
      52             : {
      53             :     static int nLockType = -1;
      54        4762 :     if (nLockType < 0)
      55             :     {
      56             :         const char *pszLockType =
      57         546 :             CPLGetConfigOption("GDAL_RB_LOCK_TYPE", "ADAPTIVE");
      58         546 :         if (EQUAL(pszLockType, "ADAPTIVE"))
      59         544 :             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         546 :         bDebugContention = CPLTestBool(
      73             :             CPLGetConfigOption("GDAL_RB_LOCK_DEBUG_CONTENTION", "NO"));
      74             :     }
      75        4762 :     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             :         static bool bHasWarned = false;
     188           0 :         if (!bHasWarned)
     189             :         {
     190           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     191             :                      "Cache max value doesn't fit on a 32 bit integer. "
     192             :                      "Call GDALGetCacheMax64() instead");
     193           0 :             bHasWarned = true;
     194             :         }
     195           0 :         nRes = INT_MAX;
     196             :     }
     197           1 :     return static_cast<int>(nRes);
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                         GDALGetCacheMax64()                          */
     202             : /************************************************************************/
     203             : 
     204             : /**
     205             :  * \brief Get maximum cache memory.
     206             :  *
     207             :  * Gets the maximum amount of memory available to the GDALRasterBlock
     208             :  * caching system for caching GDAL read/write imagery.
     209             :  *
     210             :  * The first time this function is called, it will read the GDAL_CACHEMAX
     211             :  * configuration option to initialize the maximum cache memory.
     212             :  * Starting with GDAL 2.1, the value can be expressed as x% of the usable
     213             :  * physical RAM (which may potentially be used by other processes). Starting
     214             :  * with GDAL 3.11, the value can include units of memory. If not units are
     215             :  * provided the value is assumed to be in MB.
     216             :  *
     217             :  * @return maximum in bytes.
     218             :  *
     219             :  * @since GDAL 1.8.0
     220             :  */
     221             : 
     222     3827720 : GIntBig CPL_STDCALL GDALGetCacheMax64()
     223             : {
     224             :     static std::once_flag flagSetupGDALGetCacheMax64;
     225     3827720 :     std::call_once(
     226             :         flagSetupGDALGetCacheMax64,
     227         546 :         []()
     228             :         {
     229             :             {
     230         546 :                 INITIALIZE_LOCK;
     231             :             }
     232         546 :             bSleepsForBockCacheDebug =
     233         546 :                 CPLTestBool(CPLGetConfigOption("GDAL_DEBUG_BLOCK_CACHE", "NO"));
     234             : 
     235         546 :             const char *pszCacheMax = CPLGetConfigOption("GDAL_CACHEMAX", "5%");
     236             :             GIntBig nNewCacheMax;
     237         546 :             bool bUnitSpecified = false;
     238             : 
     239         546 :             if (CPLParseMemorySize(pszCacheMax, &nNewCacheMax,
     240         546 :                                    &bUnitSpecified) != CE_None)
     241             :             {
     242           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     243             :                          "Invalid value for GDAL_CACHEMAX. "
     244             :                          "Using default value.");
     245           0 :                 if (CPLParseMemorySize("5%", &nNewCacheMax, &bUnitSpecified) !=
     246             :                     CE_None)
     247             :                 {
     248             :                     // This means that usable physical RAM could not be determined.
     249           0 :                     nNewCacheMax = nCacheMax;
     250             :                 }
     251             :             }
     252             : 
     253         546 :             if (!bUnitSpecified && nNewCacheMax < 100000)
     254             :             {
     255             :                 // Assume MB
     256           5 :                 nNewCacheMax *= (1024 * 1024);
     257             :             }
     258             : 
     259         546 :             nCacheMax = nNewCacheMax;
     260         546 :             CPLDebug("GDAL", "GDAL_CACHEMAX = " CPL_FRMT_GIB " MB",
     261             :                      nCacheMax / (1024 * 1024));
     262         546 :         });
     263             : 
     264             :     // coverity[overflow_sink]
     265     3827610 :     return nCacheMax;
     266             : }
     267             : 
     268             : /************************************************************************/
     269             : /*                          GDALGetCacheUsed()                          */
     270             : /************************************************************************/
     271             : 
     272             : /**
     273             :  * \brief Get cache memory used.
     274             :  *
     275             :  * @return the number of bytes of memory currently in use by the
     276             :  * GDALRasterBlock memory caching.
     277             :  */
     278             : 
     279           0 : int CPL_STDCALL GDALGetCacheUsed()
     280             : {
     281           0 :     if (nCacheUsed > INT_MAX)
     282             :     {
     283             :         static bool bHasWarned = false;
     284           0 :         if (!bHasWarned)
     285             :         {
     286           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     287             :                      "Cache used value doesn't fit on a 32 bit integer. "
     288             :                      "Call GDALGetCacheUsed64() instead");
     289           0 :             bHasWarned = true;
     290             :         }
     291           0 :         return INT_MAX;
     292             :     }
     293           0 :     return static_cast<int>(nCacheUsed);
     294             : }
     295             : 
     296             : /************************************************************************/
     297             : /*                        GDALGetCacheUsed64()                          */
     298             : /************************************************************************/
     299             : 
     300             : /**
     301             :  * \brief Get cache memory used.
     302             :  *
     303             :  * @return the number of bytes of memory currently in use by the
     304             :  * GDALRasterBlock memory caching.
     305             :  *
     306             :  * @since GDAL 1.8.0
     307             :  */
     308             : 
     309          17 : GIntBig CPL_STDCALL GDALGetCacheUsed64()
     310             : {
     311          17 :     return nCacheUsed;
     312             : }
     313             : 
     314             : /************************************************************************/
     315             : /*                        GDALFlushCacheBlock()                         */
     316             : /*                                                                      */
     317             : /*      The workhorse of cache management!                              */
     318             : /************************************************************************/
     319             : 
     320             : /**
     321             :  * \brief Try to flush one cached raster block
     322             :  *
     323             :  * This function will search the first unlocked raster block and will
     324             :  * flush it to release the associated memory.
     325             :  *
     326             :  * @return TRUE if one block was flushed, FALSE if there are no cached blocks
     327             :  *         or if they are currently locked.
     328             :  */
     329        4211 : int CPL_STDCALL GDALFlushCacheBlock()
     330             : 
     331             : {
     332        4211 :     return GDALRasterBlock::FlushCacheBlock();
     333             : }
     334             : 
     335             : /************************************************************************/
     336             : /* ==================================================================== */
     337             : /*                           GDALRasterBlock                            */
     338             : /* ==================================================================== */
     339             : /************************************************************************/
     340             : 
     341             : /**
     342             :  * \class GDALRasterBlock "gdal_priv.h"
     343             :  *
     344             :  * GDALRasterBlock objects hold one block of raster data for one band
     345             :  * that is currently stored in the GDAL raster cache.  The cache holds
     346             :  * some blocks of raster data for zero or more GDALRasterBand objects
     347             :  * across zero or more GDALDataset objects in a global raster cache with
     348             :  * a least recently used (LRU) list and an upper cache limit (see
     349             :  * GDALSetCacheMax()) under which the cache size is normally kept.
     350             :  *
     351             :  * Some blocks in the cache may be modified relative to the state on disk
     352             :  * (they are marked "Dirty") and must be flushed to disk before they can
     353             :  * be discarded.  Other (Clean) blocks may just be discarded if their memory
     354             :  * needs to be recovered.
     355             :  *
     356             :  * In normal situations applications do not interact directly with the
     357             :  * GDALRasterBlock - instead it it utilized by the RasterIO() interfaces
     358             :  * to implement caching.
     359             :  *
     360             :  * Some driver classes are implemented in a fashion that completely avoids
     361             :  * use of the GDAL raster cache (and GDALRasterBlock) though this is not very
     362             :  * common.
     363             :  */
     364             : 
     365             : /************************************************************************/
     366             : /*                          FlushCacheBlock()                           */
     367             : /*                                                                      */
     368             : /*      Note, if we have a lot of blocks locked for a long time, this    */
     369             : /*      method is going to get slow because it will have to traverse    */
     370             : /*      the linked list a long ways looking for a flushing              */
     371             : /*      candidate.   It might help to re-touch locked blocks to push    */
     372             : /*      them to the top of the list.                                    */
     373             : /************************************************************************/
     374             : 
     375             : /**
     376             :  * \brief Attempt to flush at least one block from the cache.
     377             :  *
     378             :  * This static method is normally used to recover memory when a request
     379             :  * for a new cache block would put cache memory use over the established
     380             :  * limit.
     381             :  *
     382             :  * C++ analog to the C function GDALFlushCacheBlock().
     383             :  *
     384             :  * @param bDirtyBlocksOnly Only flushes dirty blocks.
     385             :  * @return TRUE if successful or FALSE if no flushable block is found.
     386             :  */
     387             : 
     388        4216 : int GDALRasterBlock::FlushCacheBlock(int bDirtyBlocksOnly)
     389             : 
     390             : {
     391             :     GDALRasterBlock *poTarget;
     392             : 
     393             :     {
     394        4216 :         INITIALIZE_LOCK;
     395        4216 :         poTarget = poOldest;
     396             : 
     397        4226 :         while (poTarget != nullptr)
     398             :         {
     399        4229 :             if (!bDirtyBlocksOnly ||
     400           9 :                 (poTarget->GetDirty() && nDisableDirtyBlockFlushCounter == 0))
     401             :             {
     402        4211 :                 if (CPLAtomicCompareAndExchange(&(poTarget->nLockCount), 0, -1))
     403        4210 :                     break;
     404             :             }
     405          10 :             poTarget = poTarget->poPrevious;
     406             :         }
     407             : 
     408        4216 :         if (poTarget == nullptr)
     409           6 :             return FALSE;
     410        4210 :         if (bSleepsForBockCacheDebug)
     411             :         {
     412             :             // coverity[tainted_data]
     413           6 :             const double dfDelay = CPLAtof(CPLGetConfigOption(
     414             :                 "GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_DROP_LOCK", "0"));
     415           6 :             if (dfDelay > 0)
     416           3 :                 CPLSleep(dfDelay);
     417             :         }
     418             : 
     419        4210 :         poTarget->Detach_unlocked();
     420        4210 :         poTarget->GetBand()->UnreferenceBlock(poTarget);
     421             :     }
     422             : 
     423        4210 :     if (bSleepsForBockCacheDebug)
     424             :     {
     425             :         // coverity[tainted_data]
     426           6 :         const double dfDelay = CPLAtof(
     427             :             CPLGetConfigOption("GDAL_RB_FLUSHBLOCK_SLEEP_AFTER_RB_LOCK", "0"));
     428           6 :         if (dfDelay > 0)
     429           1 :             CPLSleep(dfDelay);
     430             :     }
     431             : 
     432        4210 :     if (poTarget->GetDirty())
     433             :     {
     434          30 :         const CPLErr eErr = poTarget->Write();
     435          30 :         if (eErr != CE_None)
     436             :         {
     437             :             // Save the error for later reporting.
     438           0 :             poTarget->GetBand()->SetFlushBlockErr(eErr);
     439             :         }
     440             :     }
     441             : 
     442        4210 :     VSIFreeAligned(poTarget->pData);
     443        4210 :     poTarget->pData = nullptr;
     444        4210 :     poTarget->GetBand()->AddBlockToFreeList(poTarget);
     445             : 
     446        4210 :     return TRUE;
     447             : }
     448             : 
     449             : /************************************************************************/
     450             : /*                          FlushDirtyBlocks()                          */
     451             : /************************************************************************/
     452             : 
     453             : /**
     454             :  * \brief Flush all dirty blocks from cache.
     455             :  *
     456             :  * This static method is normally used to recover memory and is especially
     457             :  * useful when doing multi-threaded code that can trigger the block cache.
     458             :  *
     459             :  * Due to the current design of the block cache, dirty blocks belonging to a
     460             :  * same dataset could be pushed simultaneously to the IWriteBlock() method of
     461             :  * that dataset from different threads, causing races.
     462             :  *
     463             :  * Calling this method before that code can help workarounding that issue,
     464             :  * in a multiple readers, one writer scenario.
     465             :  *
     466             :  * @since GDAL 2.0
     467             :  */
     468             : 
     469           5 : void GDALRasterBlock::FlushDirtyBlocks()
     470             : 
     471             : {
     472           5 :     while (FlushCacheBlock(TRUE))
     473             :     {
     474             :         /* go on */
     475             :     }
     476           5 : }
     477             : 
     478             : /************************************************************************/
     479             : /*                      EnterDisableDirtyBlockFlush()                   */
     480             : /************************************************************************/
     481             : 
     482             : /**
     483             :  * \brief Starts preventing dirty blocks from being flushed
     484             :  *
     485             :  * This static method is used to prevent dirty blocks from being flushed.
     486             :  * This might be useful when in a IWriteBlock() method, whose implementation
     487             :  * can directly/indirectly cause the block cache to evict new blocks, to
     488             :  * be recursively called on the same dataset.
     489             :  *
     490             :  * This method implements a reference counter and is thread-safe.
     491             :  *
     492             :  * This call must be paired with a corresponding LeaveDisableDirtyBlockFlush().
     493             :  *
     494             :  * @since GDAL 2.2.2
     495             :  */
     496             : 
     497       13774 : void GDALRasterBlock::EnterDisableDirtyBlockFlush()
     498             : {
     499       13774 :     CPLAtomicInc(&nDisableDirtyBlockFlushCounter);
     500       13774 : }
     501             : 
     502             : /************************************************************************/
     503             : /*                      LeaveDisableDirtyBlockFlush()                   */
     504             : /************************************************************************/
     505             : 
     506             : /**
     507             :  * \brief Ends preventing dirty blocks from being flushed.
     508             :  *
     509             :  * Undoes the effect of EnterDisableDirtyBlockFlush().
     510             :  *
     511             :  * @since GDAL 2.2.2
     512             :  */
     513             : 
     514       13774 : void GDALRasterBlock::LeaveDisableDirtyBlockFlush()
     515             : {
     516       13774 :     CPLAtomicDec(&nDisableDirtyBlockFlushCounter);
     517       13774 : }
     518             : 
     519             : /************************************************************************/
     520             : /*                          GDALRasterBlock()                           */
     521             : /************************************************************************/
     522             : 
     523             : /**
     524             :  * @brief GDALRasterBlock Constructor
     525             :  *
     526             :  * Normally only called from GDALRasterBand::GetLockedBlockRef().
     527             :  *
     528             :  * @param poBandIn the raster band used as source of raster block
     529             :  * being constructed.
     530             :  *
     531             :  * @param nXOffIn the horizontal block offset, with zero indicating
     532             :  * the left most block, 1 the next block and so forth.
     533             :  *
     534             :  * @param nYOffIn the vertical block offset, with zero indicating
     535             :  * the top most block, 1 the next block and so forth.
     536             :  */
     537             : 
     538     3118850 : GDALRasterBlock::GDALRasterBlock(GDALRasterBand *poBandIn, int nXOffIn,
     539     3118850 :                                  int nYOffIn)
     540     6237630 :     : eType(poBandIn->GetRasterDataType()), bDirty(false), nLockCount(0),
     541             :       nXOff(nXOffIn), nYOff(nYOffIn), nXSize(0), nYSize(0), pData(nullptr),
     542     3118850 :       poBand(poBandIn), poNext(nullptr), poPrevious(nullptr), bMustDetach(true)
     543             : {
     544     3118780 :     CPLAssert(poBandIn != nullptr);
     545     3118780 :     poBand->GetBlockSize(&nXSize, &nYSize);
     546     3118720 : }
     547             : 
     548             : /************************************************************************/
     549             : /*                          GDALRasterBlock()                           */
     550             : /************************************************************************/
     551             : 
     552             : /**
     553             :  * @brief GDALRasterBlock Constructor (for GDALHashSetBandBlockAccess purpose)
     554             :  *
     555             :  * Normally only called from GDALHashSetBandBlockAccess class. Such a block
     556             :  * is completely non functional and only meant as being used to do a look-up
     557             :  * in the hash set of GDALHashSetBandBlockAccess
     558             :  *
     559             :  * @param nXOffIn the horizontal block offset, with zero indicating
     560             :  * the left most block, 1 the next block and so forth.
     561             :  *
     562             :  * @param nYOffIn the vertical block offset, with zero indicating
     563             :  * the top most block, 1 the next block and so forth.
     564             :  */
     565             : 
     566     2960300 : GDALRasterBlock::GDALRasterBlock(int nXOffIn, int nYOffIn)
     567             :     : eType(GDT_Unknown), bDirty(false), nLockCount(0), nXOff(nXOffIn),
     568             :       nYOff(nYOffIn), nXSize(0), nYSize(0), pData(nullptr), poBand(nullptr),
     569     2960300 :       poNext(nullptr), poPrevious(nullptr), bMustDetach(false)
     570             : {
     571     2960300 : }
     572             : 
     573             : /************************************************************************/
     574             : /*                                  RecycleFor()                        */
     575             : /************************************************************************/
     576             : 
     577             : /**
     578             :  * Recycle an existing block (of the same band)
     579             :  *
     580             :  * Normally called from GDALAbstractBandBlockCache::CreateBlock().
     581             :  */
     582             : 
     583       10362 : void GDALRasterBlock::RecycleFor(int nXOffIn, int nYOffIn)
     584             : {
     585       10362 :     CPLAssert(pData == nullptr);
     586       10362 :     pData = nullptr;
     587       10362 :     bDirty = false;
     588       10362 :     nLockCount = 0;
     589             : 
     590       10362 :     poNext = nullptr;
     591       10362 :     poPrevious = nullptr;
     592             : 
     593       10362 :     nXOff = nXOffIn;
     594       10362 :     nYOff = nYOffIn;
     595       10362 :     bMustDetach = true;
     596       10362 : }
     597             : 
     598             : /************************************************************************/
     599             : /*                          ~GDALRasterBlock()                          */
     600             : /************************************************************************/
     601             : 
     602             : /**
     603             :  * Block destructor.
     604             :  *
     605             :  * Normally called from GDALRasterBand::FlushBlock().
     606             :  */
     607             : 
     608    15277330 : GDALRasterBlock::~GDALRasterBlock()
     609             : 
     610             : {
     611     6079220 :     Detach();
     612             : 
     613     6079220 :     if (pData != nullptr)
     614             :     {
     615     3099700 :         VSIFreeAligned(pData);
     616             :     }
     617             : 
     618     6079230 :     CPLAssert(nLockCount <= 0);
     619             : 
     620             : #ifdef ENABLE_DEBUG
     621             :     Verify();
     622             : #endif
     623     9198160 : }
     624             : 
     625             : /************************************************************************/
     626             : /*                        GetEffectiveBlockSize()                       */
     627             : /************************************************************************/
     628             : 
     629     6258590 : static size_t GetEffectiveBlockSize(GPtrDiff_t nBlockSize)
     630             : {
     631             :     // The real cost of a block allocation is more than just nBlockSize
     632             :     // As we allocate with 64-byte alignment, use 64 as a multiple.
     633             :     // We arbitrarily add 2 * sizeof(GDALRasterBlock) to account for that
     634             :     return static_cast<size_t>(
     635    12517200 :         std::min(static_cast<GUIntBig>(UINT_MAX),
     636     6258590 :                  static_cast<GUIntBig>(DIV_ROUND_UP(nBlockSize, 64)) * 64 +
     637     6258590 :                      2 * sizeof(GDALRasterBlock)));
     638             : }
     639             : 
     640             : /************************************************************************/
     641             : /*                               Detach()                               */
     642             : /************************************************************************/
     643             : 
     644             : /**
     645             :  * Remove block from cache.
     646             :  *
     647             :  * This method removes the current block from the linked list used to keep
     648             :  * track of all cached blocks in order of age.  It does not affect whether
     649             :  * the block is referenced by a GDALRasterBand nor does it destroy or flush
     650             :  * the block.
     651             :  */
     652             : 
     653     7162830 : void GDALRasterBlock::Detach()
     654             : 
     655             : {
     656     7162830 :     if (bMustDetach)
     657             :     {
     658     6199400 :         TAKE_LOCK;
     659     3099700 :         Detach_unlocked();
     660             :     }
     661     7162830 : }
     662             : 
     663     3129290 : void GDALRasterBlock::Detach_unlocked()
     664             : {
     665     3129290 :     if (poOldest == this)
     666     2548390 :         poOldest = poPrevious;
     667             : 
     668     3129290 :     if (poNewest == this)
     669             :     {
     670       25163 :         poNewest = poNext;
     671             :     }
     672             : 
     673     3129290 :     if (poPrevious != nullptr)
     674     3104130 :         poPrevious->poNext = poNext;
     675             : 
     676     3129290 :     if (poNext != nullptr)
     677      580903 :         poNext->poPrevious = poPrevious;
     678             : 
     679     3129290 :     poPrevious = nullptr;
     680     3129290 :     poNext = nullptr;
     681     3129290 :     bMustDetach = false;
     682             : 
     683     3129290 :     if (pData)
     684     3129290 :         nCacheUsed -= GetEffectiveBlockSize(GetBlockSize());
     685             : 
     686             : #ifdef ENABLE_DEBUG
     687             :     Verify();
     688             : #endif
     689     3129290 : }
     690             : 
     691             : /************************************************************************/
     692             : /*                               Verify()                               */
     693             : /************************************************************************/
     694             : 
     695             : /**
     696             :  * Confirms (via assertions) that the block cache linked list is in a
     697             :  * consistent state.
     698             :  */
     699             : 
     700             : #ifdef ENABLE_DEBUG
     701             : void GDALRasterBlock::Verify()
     702             : 
     703             : {
     704             :     TAKE_LOCK;
     705             : 
     706             :     CPLAssert((poNewest == nullptr && poOldest == nullptr) ||
     707             :               (poNewest != nullptr && poOldest != nullptr));
     708             : 
     709             :     if (poNewest != nullptr)
     710             :     {
     711             :         CPLAssert(poNewest->poPrevious == nullptr);
     712             :         CPLAssert(poOldest->poNext == nullptr);
     713             : 
     714             :         GDALRasterBlock *poLast = nullptr;
     715             :         for (GDALRasterBlock *poBlock = poNewest; poBlock != nullptr;
     716             :              poBlock = poBlock->poNext)
     717             :         {
     718             :             CPLAssert(poBlock->poPrevious == poLast);
     719             : 
     720             :             poLast = poBlock;
     721             :         }
     722             : 
     723             :         CPLAssert(poOldest == poLast);
     724             :     }
     725             : }
     726             : 
     727             : #else
     728           0 : void GDALRasterBlock::Verify()
     729             : {
     730           0 : }
     731             : #endif
     732             : 
     733             : #ifdef notdef
     734             : void GDALRasterBlock::CheckNonOrphanedBlocks(GDALRasterBand *poBand)
     735             : {
     736             :     TAKE_LOCK;
     737             :     for (GDALRasterBlock *poBlock = poNewest; poBlock != nullptr;
     738             :          poBlock = poBlock->poNext)
     739             :     {
     740             :         if (poBlock->GetBand() == poBand)
     741             :         {
     742             :             printf("Cache has still blocks of band %p\n", poBand); /*ok*/
     743             :             printf("Band : %d\n", poBand->GetBand());              /*ok*/
     744             :             printf("nRasterXSize = %d\n", poBand->GetXSize());     /*ok*/
     745             :             printf("nRasterYSize = %d\n", poBand->GetYSize());     /*ok*/
     746             :             int nBlockXSize, nBlockYSize;
     747             :             poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     748             :             printf("nBlockXSize = %d\n", nBlockXSize);      /*ok*/
     749             :             printf("nBlockYSize = %d\n", nBlockYSize);      /*ok*/
     750             :             printf("Dataset : %p\n", poBand->GetDataset()); /*ok*/
     751             :             if (poBand->GetDataset())
     752             :                 printf("Dataset : %s\n", /*ok*/
     753             :                        poBand->GetDataset()->GetDescription());
     754             :         }
     755             :     }
     756             : }
     757             : #endif
     758             : 
     759             : /************************************************************************/
     760             : /*                               Write()                                */
     761             : /************************************************************************/
     762             : 
     763             : /**
     764             :  * Force writing of the current block, if dirty.
     765             :  *
     766             :  * The block is written using GDALRasterBand::IWriteBlock() on its
     767             :  * corresponding band object.  Even if the write fails the block will
     768             :  * be marked clean.
     769             :  *
     770             :  * @return CE_None otherwise the error returned by IWriteBlock().
     771             :  */
     772             : 
     773      177200 : CPLErr GDALRasterBlock::Write()
     774             : 
     775             : {
     776      177200 :     if (!GetDirty())
     777           0 :         return CE_None;
     778             : 
     779      177201 :     if (poBand == nullptr)
     780           0 :         return CE_Failure;
     781             : 
     782      177201 :     MarkClean();
     783             : 
     784      177202 :     if (poBand->eFlushBlockErr == CE_None)
     785             :     {
     786      177202 :         int bCallLeaveReadWrite = poBand->EnterReadWrite(GF_Write);
     787      177202 :         CPLErr eErr = poBand->IWriteBlock(nXOff, nYOff, pData);
     788      177202 :         if (bCallLeaveReadWrite)
     789      109189 :             poBand->LeaveReadWrite();
     790      177196 :         return eErr;
     791             :     }
     792             :     else
     793           0 :         return poBand->eFlushBlockErr;
     794             : }
     795             : 
     796             : /************************************************************************/
     797             : /*                               Touch()                                */
     798             : /************************************************************************/
     799             : 
     800             : /**
     801             :  * Push block to top of LRU (least-recently used) list.
     802             :  *
     803             :  * This method is normally called when a block is used to keep track
     804             :  * that it has been recently used.
     805             :  */
     806             : 
     807     6682200 : void GDALRasterBlock::Touch()
     808             : 
     809             : {
     810             :     // Can be safely tested outside the lock
     811     6682200 :     if (poNewest == this)
     812      343346 :         return;
     813             : 
     814    12679800 :     TAKE_LOCK;
     815     6340940 :     Touch_unlocked();
     816             : }
     817             : 
     818     9470230 : void GDALRasterBlock::Touch_unlocked()
     819             : 
     820             : {
     821             :     // Could happen even if tested in Touch() before taking the lock
     822             :     // Scenario would be :
     823             :     // 0. this is the second block (the one pointed by poNewest->poNext)
     824             :     // 1. Thread 1 calls Touch() and poNewest != this at that point
     825             :     // 2. Thread 2 detaches poNewest
     826             :     // 3. Thread 1 arrives here
     827     9470230 :     if (poNewest == this)
     828           0 :         return;
     829             : 
     830             :     // We should not try to touch a block that has been detached.
     831             :     // If that happen, corruption has already occurred.
     832     9470230 :     CPLAssert(bMustDetach);
     833             : 
     834     9470230 :     if (poOldest == this)
     835     1442090 :         poOldest = this->poPrevious;
     836             : 
     837     9470230 :     if (poPrevious != nullptr)
     838     6340940 :         poPrevious->poNext = poNext;
     839             : 
     840     9470230 :     if (poNext != nullptr)
     841     4898840 :         poNext->poPrevious = poPrevious;
     842             : 
     843     9470230 :     poPrevious = nullptr;
     844     9470230 :     poNext = poNewest;
     845             : 
     846     9470230 :     if (poNewest != nullptr)
     847             :     {
     848     9450960 :         CPLAssert(poNewest->poPrevious == nullptr);
     849     9450960 :         poNewest->poPrevious = this;
     850             :     }
     851     9470230 :     poNewest = this;
     852             : 
     853     9470230 :     if (poOldest == nullptr)
     854             :     {
     855       19266 :         CPLAssert(poPrevious == nullptr && poNext == nullptr);
     856       19266 :         poOldest = this;
     857             :     }
     858             : #ifdef ENABLE_DEBUG
     859             :     Verify();
     860             : #endif
     861             : }
     862             : 
     863             : /************************************************************************/
     864             : /*                            Internalize()                             */
     865             : /************************************************************************/
     866             : 
     867             : /**
     868             :  * Allocate memory for block.
     869             :  *
     870             :  * This method allocates memory for the block, and attempts to flush other
     871             :  * blocks, if necessary, to bring the total cache size back within the limits.
     872             :  * The newly allocated block is touched and will be considered most recently
     873             :  * used in the LRU list.
     874             :  *
     875             :  * @return CE_None on success or CE_Failure if memory allocation fails.
     876             :  */
     877             : 
     878     3129130 : CPLErr GDALRasterBlock::Internalize()
     879             : 
     880             : {
     881     3129130 :     CPLAssert(pData == nullptr);
     882             : 
     883     3129130 :     void *pNewData = nullptr;
     884             : 
     885             :     // This call will initialize the hRBLock mutex. Other call places can
     886             :     // only be called if we have go through there.
     887     3129130 :     const GIntBig nCurCacheMax = GDALGetCacheMax64();
     888             : 
     889             :     // No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo().
     890     3129090 :     const auto nSizeInBytes = GetBlockSize();
     891             : 
     892             :     /* -------------------------------------------------------------------- */
     893             :     /*      Flush old blocks if we are nearing our memory limit.            */
     894             :     /* -------------------------------------------------------------------- */
     895     3129070 :     bool bFirstIter = true;
     896     3129070 :     bool bLoopAgain = false;
     897     3129070 :     GDALDataset *poThisDS = poBand->GetDataset();
     898     3129330 :     do
     899             :     {
     900     3129100 :         bLoopAgain = false;
     901     3129100 :         GDALRasterBlock *apoBlocksToFree[64] = {nullptr};
     902     3129100 :         int nBlocksToFree = 0;
     903             :         {
     904     6258430 :             TAKE_LOCK;
     905             : 
     906     3129330 :             if (bFirstIter)
     907     3129290 :                 nCacheUsed += GetEffectiveBlockSize(nSizeInBytes);
     908     3129330 :             GDALRasterBlock *poTarget = poOldest;
     909     3147580 :             while (nCacheUsed > nCurCacheMax)
     910             :             {
     911       36035 :                 GDALRasterBlock *poDirtyBlockOtherDataset = nullptr;
     912             :                 // In this first pass, only discard dirty blocks of this
     913             :                 // dataset. We do this to decrease significantly the likelihood
     914             :                 // of the following weakness of the block cache design:
     915             :                 // 1. Thread 1 fills block B with ones
     916             :                 // 2. Thread 2 evicts this dirty block, while thread 1 almost
     917             :                 //    at the same time (but slightly after) tries to reacquire
     918             :                 //    this block. As it has been removed from the block cache
     919             :                 //    array/set, thread 1 now tries to read block B from disk,
     920             :                 //    so gets the old value.
     921      105898 :                 while (poTarget != nullptr)
     922             :                 {
     923       95237 :                     if (!poTarget->GetDirty())
     924             :                     {
     925       23364 :                         if (CPLAtomicCompareAndExchange(&(poTarget->nLockCount),
     926       23364 :                                                         0, -1))
     927       18256 :                             break;
     928             :                     }
     929       71873 :                     else if (nDisableDirtyBlockFlushCounter == 0)
     930             :                     {
     931       71873 :                         if (poTarget->poBand->GetDataset() == poThisDS)
     932             :                         {
     933        7118 :                             if (CPLAtomicCompareAndExchange(
     934        7118 :                                     &(poTarget->nLockCount), 0, -1))
     935        7118 :                                 break;
     936             :                         }
     937       64755 :                         else if (poDirtyBlockOtherDataset == nullptr)
     938             :                         {
     939        5752 :                             poDirtyBlockOtherDataset = poTarget;
     940             :                         }
     941             :                     }
     942       69863 :                     poTarget = poTarget->poPrevious;
     943             :                 }
     944       36035 :                 if (poTarget == nullptr && poDirtyBlockOtherDataset)
     945             :                 {
     946           6 :                     if (CPLAtomicCompareAndExchange(
     947           6 :                             &(poDirtyBlockOtherDataset->nLockCount), 0, -1))
     948             :                     {
     949           6 :                         CPLDebug("GDAL",
     950             :                                  "Evicting dirty block of another dataset");
     951           6 :                         poTarget = poDirtyBlockOtherDataset;
     952             :                     }
     953             :                     else
     954             :                     {
     955           0 :                         poTarget = poOldest;
     956           0 :                         while (poTarget != nullptr)
     957             :                         {
     958           0 :                             if (CPLAtomicCompareAndExchange(
     959           0 :                                     &(poTarget->nLockCount), 0, -1))
     960             :                             {
     961           0 :                                 CPLDebug(
     962             :                                     "GDAL",
     963             :                                     "Evicting dirty block of another dataset");
     964           0 :                                 break;
     965             :                             }
     966           0 :                             poTarget = poTarget->poPrevious;
     967             :                         }
     968             :                     }
     969             :                 }
     970             : 
     971       36035 :                 if (poTarget != nullptr)
     972             :                 {
     973       25380 :                     if (bSleepsForBockCacheDebug)
     974             :                     {
     975             :                         // coverity[tainted_data]
     976           3 :                         const double dfDelay = CPLAtof(CPLGetConfigOption(
     977             :                             "GDAL_RB_INTERNALIZE_SLEEP_AFTER_DROP_LOCK", "0"));
     978           3 :                         if (dfDelay > 0)
     979           1 :                             CPLSleep(dfDelay);
     980             :                     }
     981             : 
     982       25380 :                     GDALRasterBlock *_poPrevious = poTarget->poPrevious;
     983             : 
     984       25380 :                     poTarget->Detach_unlocked();
     985       25380 :                     poTarget->GetBand()->UnreferenceBlock(poTarget);
     986             : 
     987       25380 :                     apoBlocksToFree[nBlocksToFree++] = poTarget;
     988       25380 :                     if (poTarget->GetDirty())
     989             :                     {
     990             :                         // Only free one dirty block at a time so that
     991             :                         // other dirty blocks of other bands with the same
     992             :                         // coordinates can be found with TryGetLockedBlock()
     993        7124 :                         bLoopAgain = nCacheUsed > nCurCacheMax;
     994        7124 :                         break;
     995             :                     }
     996       18256 :                     if (nBlocksToFree == 64)
     997             :                     {
     998           0 :                         bLoopAgain = (nCacheUsed > nCurCacheMax);
     999           0 :                         break;
    1000             :                     }
    1001             : 
    1002       18256 :                     poTarget = _poPrevious;
    1003             :                 }
    1004             :                 else
    1005             :                 {
    1006       10655 :                     break;
    1007             :                 }
    1008             :             }
    1009             : 
    1010             :             /* ------------------------------------------------------------------
    1011             :              */
    1012             :             /*      Add this block to the list. */
    1013             :             /* ------------------------------------------------------------------
    1014             :              */
    1015     3129330 :             if (!bLoopAgain)
    1016     3129290 :                 Touch_unlocked();
    1017             :         }
    1018             : 
    1019     3129330 :         bFirstIter = false;
    1020             : 
    1021             :         // Now free blocks we have detached and removed from their band.
    1022     3154710 :         for (int i = 0; i < nBlocksToFree; ++i)
    1023             :         {
    1024       25380 :             GDALRasterBlock *const poBlock = apoBlocksToFree[i];
    1025             : 
    1026       25380 :             if (poBlock->GetDirty())
    1027             :             {
    1028        7124 :                 if (bSleepsForBockCacheDebug)
    1029             :                 {
    1030             :                     // coverity[tainted_data]
    1031           1 :                     const double dfDelay = CPLAtof(CPLGetConfigOption(
    1032             :                         "GDAL_RB_INTERNALIZE_SLEEP_AFTER_DETACH_BEFORE_WRITE",
    1033             :                         "0"));
    1034           1 :                     if (dfDelay > 0)
    1035           1 :                         CPLSleep(dfDelay);
    1036             :                 }
    1037             : 
    1038        7124 :                 CPLErr eErr = poBlock->Write();
    1039        7124 :                 if (eErr != CE_None)
    1040             :                 {
    1041             :                     // Save the error for later reporting.
    1042           0 :                     poBlock->GetBand()->SetFlushBlockErr(eErr);
    1043             :                 }
    1044             :             }
    1045             : 
    1046             :             // Try to recycle the data of an existing block.
    1047       25380 :             void *pDataBlock = poBlock->pData;
    1048       50224 :             if (pNewData == nullptr && pDataBlock != nullptr &&
    1049       24844 :                 poBlock->GetBlockSize() == nSizeInBytes)
    1050             :             {
    1051       24741 :                 pNewData = pDataBlock;
    1052             :             }
    1053             :             else
    1054             :             {
    1055         639 :                 VSIFreeAligned(poBlock->pData);
    1056             :             }
    1057       25380 :             poBlock->pData = nullptr;
    1058             : 
    1059       25380 :             poBlock->GetBand()->AddBlockToFreeList(poBlock);
    1060             :         }
    1061             :     } while (bLoopAgain);
    1062             : 
    1063     3129290 :     if (pNewData == nullptr)
    1064             :     {
    1065     3104550 :         pNewData = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nSizeInBytes);
    1066     3104520 :         if (pNewData == nullptr)
    1067             :         {
    1068           0 :             return (CE_Failure);
    1069             :         }
    1070             :     }
    1071             : 
    1072     3129260 :     pData = pNewData;
    1073             : 
    1074     3129260 :     return CE_None;
    1075             : }
    1076             : 
    1077             : /************************************************************************/
    1078             : /*                             MarkDirty()                              */
    1079             : /************************************************************************/
    1080             : 
    1081             : /**
    1082             :  * Mark the block as modified.
    1083             :  *
    1084             :  * A dirty block is one that has been modified and will need to be written
    1085             :  * to disk before it can be flushed.
    1086             :  */
    1087             : 
    1088     3633040 : void GDALRasterBlock::MarkDirty()
    1089             : {
    1090     3633040 :     if (poBand)
    1091             :     {
    1092     3633040 :         poBand->InitRWLock();
    1093     3633040 :         if (!bDirty)
    1094      248080 :             poBand->IncDirtyBlocks(1);
    1095             :     }
    1096     3633040 :     bDirty = true;
    1097     3633040 : }
    1098             : 
    1099             : /************************************************************************/
    1100             : /*                             MarkClean()                              */
    1101             : /************************************************************************/
    1102             : 
    1103             : /**
    1104             :  * Mark the block as unmodified.
    1105             :  *
    1106             :  * A dirty block is one that has been modified and will need to be written
    1107             :  * to disk before it can be flushed.
    1108             :  */
    1109             : 
    1110      246839 : void GDALRasterBlock::MarkClean()
    1111             : {
    1112      246839 :     if (bDirty && poBand)
    1113      246809 :         poBand->IncDirtyBlocks(-1);
    1114      246840 :     bDirty = false;
    1115      246840 : }
    1116             : 
    1117             : /************************************************************************/
    1118             : /*                          DestroyRBMutex()                           */
    1119             : /************************************************************************/
    1120             : 
    1121             : /*! @cond Doxygen_Suppress */
    1122         933 : void GDALRasterBlock::DestroyRBMutex()
    1123             : {
    1124         933 :     if (hRBLock != nullptr)
    1125         413 :         DESTROY_LOCK;
    1126         933 :     hRBLock = nullptr;
    1127         933 : }
    1128             : 
    1129             : /*! @endcond */
    1130             : 
    1131             : /************************************************************************/
    1132             : /*                              TakeLock()                              */
    1133             : /************************************************************************/
    1134             : 
    1135             : /**
    1136             :  * Take a lock and Touch().
    1137             :  *
    1138             :  * Should only be used by GDALArrayBandBlockCache::TryGetLockedBlockRef()
    1139             :  * and GDALHashSetBandBlockCache::TryGetLockedBlockRef()
    1140             :  *
    1141             :  * @return TRUE if the lock has been successfully acquired. If FALSE, the
    1142             :  *         block is being evicted by another thread, and so should be
    1143             :  *         considered as invalid.
    1144             :  */
    1145             : 
    1146     6683790 : int GDALRasterBlock::TakeLock()
    1147             : {
    1148     6683790 :     const int nLockVal = AddLock();
    1149     6682660 :     CPLAssert(nLockVal >= 0);
    1150     6682660 :     if (bSleepsForBockCacheDebug)
    1151             :     {
    1152             :         // coverity[tainted_data]
    1153           4 :         const double dfDelay = CPLAtof(
    1154             :             CPLGetConfigOption("GDAL_RB_TRYGET_SLEEP_AFTER_TAKE_LOCK", "0"));
    1155           4 :         if (dfDelay > 0)
    1156           1 :             CPLSleep(dfDelay);
    1157             :     }
    1158     6681570 :     if (nLockVal == 0)
    1159             :     {
    1160             :         // The block is being evicted by GDALRasterBlock::Internalize()
    1161             :         // or FlushCacheBlock()
    1162             : 
    1163             : #ifdef DEBUG
    1164           4 :         CPLDebug(
    1165             :             "GDAL",
    1166             :             "TakeLock(%p): Block(%d,%d,%p) is being evicted while trying to "
    1167             :             "reacquire it.",
    1168           2 :             reinterpret_cast<void *>(CPLGetPID()), nXOff, nYOff, poBand);
    1169             : #endif
    1170           2 :         DropLock();
    1171             : 
    1172           2 :         return FALSE;
    1173             :     }
    1174     6681560 :     Touch();
    1175     6684240 :     return TRUE;
    1176             : }
    1177             : 
    1178             : /************************************************************************/
    1179             : /*                      DropLockForRemovalFromStorage()                 */
    1180             : /************************************************************************/
    1181             : 
    1182             : /**
    1183             :  * Drop a lock before removing the block from the band storage.
    1184             :  *
    1185             :  * Should only be used by GDALArrayBandBlockCache::FlushBlock()
    1186             :  * and GDALHashSetBandBlockCache::FlushBlock()
    1187             :  *
    1188             :  * @return TRUE if the lock has been successfully dropped.
    1189             :  */
    1190             : 
    1191     3099700 : int GDALRasterBlock::DropLockForRemovalFromStorage()
    1192             : {
    1193             :     // Detect potential conflict with GDALRasterBlock::Internalize()
    1194             :     // or FlushCacheBlock()
    1195     3099700 :     if (CPLAtomicCompareAndExchange(&nLockCount, 0, -1))
    1196     3099700 :         return TRUE;
    1197             : #ifdef DEBUG
    1198           6 :     CPLDebug("GDAL",
    1199             :              "DropLockForRemovalFromStorage(%p): Block(%d,%d,%p) was attempted "
    1200             :              "to be flushed from band but it is flushed by global cache.",
    1201           3 :              reinterpret_cast<void *>(CPLGetPID()), nXOff, nYOff, poBand);
    1202             : #endif
    1203             : 
    1204             :     // Wait for the block for having been unreferenced.
    1205           3 :     TAKE_LOCK;
    1206             : 
    1207           3 :     return FALSE;
    1208             : }
    1209             : 
    1210             : #if 0
    1211             : void GDALRasterBlock::DumpAll()
    1212             : {
    1213             :     int iBlock = 0;
    1214             :     for( GDALRasterBlock *poBlock = poNewest;
    1215             :          poBlock != nullptr;
    1216             :          poBlock = poBlock->poNext )
    1217             :     {
    1218             :         printf("Block %d\n", iBlock);/*ok*/
    1219             :         poBlock->DumpBlock();
    1220             :         printf("\n");/*ok*/
    1221             :         iBlock++;
    1222             :     }
    1223             : }
    1224             : 
    1225             : void GDALRasterBlock::DumpBlock()
    1226             : {
    1227             :     printf("  Lock count = %d\n", nLockCount);/*ok*/
    1228             :     printf("  bDirty = %d\n", static_cast<int>(bDirty));/*ok*/
    1229             :     printf("  nXOff = %d\n", nXOff);/*ok*/
    1230             :     printf("  nYOff = %d\n", nYOff);/*ok*/
    1231             :     printf("  nXSize = %d\n", nXSize);/*ok*/
    1232             :     printf("  nYSize = %d\n", nYSize);/*ok*/
    1233             :     printf("  eType = %d\n", eType);/*ok*/
    1234             :     printf("  Band %p\n", GetBand());/*ok*/
    1235             :     printf("  Band %d\n", GetBand()->GetBand());/*ok*/
    1236             :     if( GetBand()->GetDataset() )
    1237             :         printf("  Dataset = %s\n",/*ok*/
    1238             :                GetBand()->GetDataset()->GetDescription());
    1239             : }
    1240             : #endif  // if 0

Generated by: LCOV version 1.14