LCOV - code coverage report
Current view: top level - gcore - gdalabstractbandblockcache.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 93 93 100.0 %
Date: 2025-10-15 23:46:56 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Store cached blocks
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot org>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot org>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "gdal_priv.h"
      15             : 
      16             : #include <algorithm>
      17             : #include <cstddef>
      18             : #include <new>
      19             : 
      20             : #include "cpl_atomic_ops.h"
      21             : #include "cpl_error.h"
      22             : #include "cpl_multiproc.h"
      23             : 
      24             : #include "gdal_abstractbandblockcache.h"
      25             : 
      26             : //! @cond Doxygen_Suppress
      27             : 
      28             : #ifdef DEBUG_VERBOSE_ABBC
      29             : static int nAllBandsKeptAlivedBlocks = 0;
      30             : #endif
      31             : 
      32             : /************************************************************************/
      33             : /*                       GDALArrayBandBlockCache()                      */
      34             : /************************************************************************/
      35             : 
      36      238505 : GDALAbstractBandBlockCache::GDALAbstractBandBlockCache(GDALRasterBand *poBandIn)
      37      715446 :     : hSpinLock(CPLCreateLock(LOCK_SPIN)), hCond(CPLCreateCond()),
      38      238505 :       hCondMutex(CPLCreateMutex()), poBand(poBandIn)
      39             : {
      40      238508 :     if (hCondMutex)
      41      238507 :         CPLReleaseMutex(hCondMutex);
      42      238510 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                      ~GDALAbstractBandBlockCache()                   */
      46             : /************************************************************************/
      47             : 
      48      477019 : GDALAbstractBandBlockCache::~GDALAbstractBandBlockCache()
      49             : {
      50      238509 :     CPLAssert(nKeepAliveCounter == 0);
      51      238509 :     FreeDanglingBlocks();
      52      238507 :     if (hSpinLock)
      53      238507 :         CPLDestroyLock(hSpinLock);
      54      238510 :     if (hCondMutex)
      55      238510 :         CPLDestroyMutex(hCondMutex);
      56      238510 :     if (hCond)
      57      238510 :         CPLDestroyCond(hCond);
      58      238510 : }
      59             : 
      60             : /************************************************************************/
      61             : /*                            UnreferenceBlockBase()                    */
      62             : /*                                                                      */
      63             : /*      This is called by GDALRasterBlock::Internalize() and            */
      64             : /*      FlushCacheBlock() when they remove a block from the linked list */
      65             : /*      but haven't yet flushed it to disk or recovered its pData member*/
      66             : /*      We must be aware that they are blocks in that state, since the  */
      67             : /*      band must be kept alive while AddBlockToFreeList() hasn't been  */
      68             : /*      called (in case a block is being flushed while the final        */
      69             : /*      FlushCache() of the main thread of the dataset is running).     */
      70             : /************************************************************************/
      71             : 
      72       29635 : void GDALAbstractBandBlockCache::UnreferenceBlockBase()
      73             : {
      74       29635 :     CPLAtomicInc(&nKeepAliveCounter);
      75       29635 : }
      76             : 
      77             : /************************************************************************/
      78             : /*                          AddBlockToFreeList()                        */
      79             : /*                                                                      */
      80             : /*      This is called by GDALRasterBlock::Internalize() and            */
      81             : /*      FlushCacheBlock() after they have been finished with a block.   */
      82             : /************************************************************************/
      83             : 
      84       29634 : void GDALAbstractBandBlockCache::AddBlockToFreeList(GDALRasterBlock *poBlock)
      85             : {
      86       29634 :     CPLAssert(poBlock->poPrevious == nullptr);
      87       29634 :     CPLAssert(poBlock->poNext == nullptr);
      88             :     {
      89             : #ifdef DEBUG_VERBOSE_ABBC
      90             :         CPLAtomicInc(&nAllBandsKeptAlivedBlocks);
      91             :         fprintf(/*ok*/ stderr,
      92             :                 "AddBlockToFreeList(): nAllBandsKeptAlivedBlocks=%d\n",
      93             :                 nAllBandsKeptAlivedBlocks);
      94             : #endif
      95       29634 :         CPLLockHolderOptionalLockD(hSpinLock);
      96       29634 :         poBlock->poNext = psListBlocksToFree;
      97       29634 :         psListBlocksToFree = poBlock;
      98             :     }
      99             : 
     100             :     // If no more blocks in transient state, then warn
     101             :     // WaitCompletionPendingTasks()
     102       29633 :     CPLAcquireMutex(hCondMutex, 1000);
     103       29634 :     if (CPLAtomicDec(&nKeepAliveCounter) == 0)
     104             :     {
     105       29426 :         CPLCondSignal(hCond);
     106             :     }
     107       29633 :     CPLReleaseMutex(hCondMutex);
     108       29634 : }
     109             : 
     110             : /************************************************************************/
     111             : /*                      WaitCompletionPendingTasks()                    */
     112             : /************************************************************************/
     113             : 
     114     1816220 : void GDALAbstractBandBlockCache::WaitCompletionPendingTasks()
     115             : {
     116             : #ifdef DEBUG_VERBOSE
     117             :     CPLDebug("GDAL", "WaitCompletionPendingTasks()");
     118             : #endif
     119             : 
     120     1816220 :     CPLAcquireMutex(hCondMutex, 1000);
     121     1816230 :     while (nKeepAliveCounter != 0)
     122             :     {
     123           4 :         CPLDebug("GDAL", "Waiting for other thread to finish working with our "
     124             :                          "blocks");
     125           4 :         CPLCondWait(hCond, hCondMutex);
     126             :     }
     127     1816220 :     CPLReleaseMutex(hCondMutex);
     128     1816230 : }
     129             : 
     130             : /************************************************************************/
     131             : /*                           FreeDanglingBlocks()                       */
     132             : /************************************************************************/
     133             : 
     134     4606070 : void GDALAbstractBandBlockCache::FreeDanglingBlocks()
     135             : {
     136             :     GDALRasterBlock *poList;
     137             :     {
     138     4606070 :         CPLLockHolderOptionalLockD(hSpinLock);
     139     4606140 :         poList = psListBlocksToFree;
     140     4606140 :         psListBlocksToFree = nullptr;
     141             :     }
     142     4624240 :     while (poList)
     143             :     {
     144             : #ifdef DEBUG_VERBOSE_ABBC
     145             :         CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     146             :         fprintf(/*ok*/ stderr,
     147             :                 "FreeDanglingBlocks(): nAllBandsKeptAlivedBlocks=%d\n",
     148             :                 nAllBandsKeptAlivedBlocks);
     149             : #endif
     150       18169 :         GDALRasterBlock *poNext = poList->poNext;
     151       18169 :         poList->poNext = nullptr;
     152       18169 :         delete poList;
     153       18118 :         poList = poNext;
     154             :     }
     155     4606080 : }
     156             : 
     157             : /************************************************************************/
     158             : /*                            CreateBlock()                             */
     159             : /************************************************************************/
     160             : 
     161     3368500 : GDALRasterBlock *GDALAbstractBandBlockCache::CreateBlock(int nXBlockOff,
     162             :                                                          int nYBlockOff)
     163             : {
     164             :     GDALRasterBlock *poBlock;
     165             :     {
     166     6736950 :         CPLLockHolderOptionalLockD(hSpinLock);
     167     3368450 :         poBlock = psListBlocksToFree;
     168     3368450 :         if (poBlock)
     169             :         {
     170             : #ifdef DEBUG_VERBOSE_ABBC
     171             :             CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     172             :             fprintf(/*ok*/ stderr,
     173             :                     "CreateBlock(): nAllBandsKeptAlivedBlocks=%d\n",
     174             :                     nAllBandsKeptAlivedBlocks);
     175             : #endif
     176       11466 :             psListBlocksToFree = poBlock->poNext;
     177             :         }
     178             :     }
     179     3368420 :     if (poBlock)
     180       11466 :         poBlock->RecycleFor(nXBlockOff, nYBlockOff);
     181             :     else
     182     3357010 :         poBlock =
     183     3356960 :             new (std::nothrow) GDALRasterBlock(poBand, nXBlockOff, nYBlockOff);
     184     3368430 :     return poBlock;
     185             : }
     186             : 
     187             : /************************************************************************/
     188             : /*                         IncDirtyBlocks()                             */
     189             : /************************************************************************/
     190             : 
     191             : /**
     192             :  * \brief Increment/decrement the number of dirty blocks
     193             :  */
     194             : 
     195      796480 : void GDALAbstractBandBlockCache::IncDirtyBlocks(int nInc)
     196             : {
     197      796480 :     CPLAtomicAdd(&m_nDirtyBlocks, nInc);
     198      796482 : }
     199             : 
     200             : /************************************************************************/
     201             : /*                      StartDirtyBlockFlushingLog()                    */
     202             : /************************************************************************/
     203             : 
     204      999147 : void GDALAbstractBandBlockCache::StartDirtyBlockFlushingLog()
     205             : {
     206      999147 :     m_nInitialDirtyBlocksInFlushCache = 0;
     207      999147 :     if (m_nDirtyBlocks > 0 && CPLIsDefaultErrorHandlerAndCatchDebug())
     208             :     {
     209        2437 :         if (CPLIsDebugEnabled() &&
     210           4 :             CPLGetConfigOption("GDAL_REPORT_DIRTY_BLOCK_FLUSHING", nullptr) ==
     211             :                 nullptr)
     212             :         {
     213           4 :             m_nInitialDirtyBlocksInFlushCache = m_nDirtyBlocks;
     214           4 :             m_nLastTick = -1;
     215             :         }
     216             :     }
     217      999147 : }
     218             : 
     219             : /************************************************************************/
     220             : /*                      UpdateDirtyBlockFlushingLog()                   */
     221             : /************************************************************************/
     222             : 
     223      217363 : void GDALAbstractBandBlockCache::UpdateDirtyBlockFlushingLog()
     224             : {
     225             :     // Poor man progress report for console applications
     226      217363 :     if (m_nInitialDirtyBlocksInFlushCache)
     227             :     {
     228        1600 :         const auto nRemainingDirtyBlocks = m_nDirtyBlocks;
     229        1600 :         const auto nFlushedBlocks =
     230        1600 :             m_nInitialDirtyBlocksInFlushCache - nRemainingDirtyBlocks + 1;
     231        1600 :         const double dfComplete =
     232        1600 :             double(nFlushedBlocks) / m_nInitialDirtyBlocksInFlushCache;
     233             :         const int nThisTick =
     234        1600 :             std::min(40, std::max(0, static_cast<int>(dfComplete * 40.0)));
     235        1600 :         if (nThisTick > m_nLastTick)
     236             :         {
     237         164 :             if (m_nLastTick < 0)
     238             :             {
     239           4 :                 fprintf(stderr, "GDAL: Flushing dirty blocks: "); /*ok*/
     240           4 :                 fflush(stderr);                                   /*ok*/
     241             :             }
     242         328 :             while (nThisTick > m_nLastTick)
     243             :             {
     244         164 :                 ++m_nLastTick;
     245         164 :                 if (m_nLastTick % 4 == 0)
     246          44 :                     fprintf(stderr, "%d", (m_nLastTick / 4) * 10); /*ok*/
     247             :                 else
     248         120 :                     fprintf(stderr, "."); /*ok*/
     249             :             }
     250             : 
     251         164 :             if (nThisTick == 40)
     252           4 :                 fprintf(stderr, " - done.\n"); /*ok*/
     253             :             else
     254         160 :                 fflush(stderr); /*ok*/
     255             :         }
     256             :     }
     257      217363 : }
     258             : 
     259             : /************************************************************************/
     260             : /*                       EndDirtyBlockFlushingLog()                     */
     261             : /************************************************************************/
     262             : 
     263      999151 : void GDALAbstractBandBlockCache::EndDirtyBlockFlushingLog()
     264             : {
     265      999151 :     m_nInitialDirtyBlocksInFlushCache = 0;
     266      999151 :     m_nLastTick = -1;
     267      999151 : }
     268             : 
     269             : //! @endcond

Generated by: LCOV version 1.14