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-01-18 12:42:00 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             : //! @cond Doxygen_Suppress
      25             : 
      26             : #ifdef DEBUG_VERBOSE_ABBC
      27             : static int nAllBandsKeptAlivedBlocks = 0;
      28             : #endif
      29             : 
      30             : /************************************************************************/
      31             : /*                       GDALArrayBandBlockCache()                      */
      32             : /************************************************************************/
      33             : 
      34       33763 : GDALAbstractBandBlockCache::GDALAbstractBandBlockCache(GDALRasterBand *poBandIn)
      35      101263 :     : hSpinLock(CPLCreateLock(LOCK_SPIN)), hCond(CPLCreateCond()),
      36       33763 :       hCondMutex(CPLCreateMutex()), poBand(poBandIn)
      37             : {
      38       33764 :     if (hCondMutex)
      39       33764 :         CPLReleaseMutex(hCondMutex);
      40       33764 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                      ~GDALAbstractBandBlockCache()                   */
      44             : /************************************************************************/
      45             : 
      46       67526 : GDALAbstractBandBlockCache::~GDALAbstractBandBlockCache()
      47             : {
      48       33762 :     CPLAssert(nKeepAliveCounter == 0);
      49       33762 :     FreeDanglingBlocks();
      50       33764 :     if (hSpinLock)
      51       33764 :         CPLDestroyLock(hSpinLock);
      52       33764 :     if (hCondMutex)
      53       33764 :         CPLDestroyMutex(hCondMutex);
      54       33764 :     if (hCond)
      55       33764 :         CPLDestroyCond(hCond);
      56       33764 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                            UnreferenceBlockBase()                    */
      60             : /*                                                                      */
      61             : /*      This is called by GDALRasterBlock::Internalize() and            */
      62             : /*      FlushCacheBlock() when they remove a block from the linked list */
      63             : /*      but haven't yet flushed it to disk or recovered its pData member*/
      64             : /*      We must be aware that they are blocks in that state, since the  */
      65             : /*      band must be kept alive while AddBlockToFreeList() hasn't been  */
      66             : /*      called (in case a block is being flushed while the final        */
      67             : /*      FlushCache() of the main thread of the dataset is running).     */
      68             : /************************************************************************/
      69             : 
      70       29595 : void GDALAbstractBandBlockCache::UnreferenceBlockBase()
      71             : {
      72       29595 :     CPLAtomicInc(&nKeepAliveCounter);
      73       29595 : }
      74             : 
      75             : /************************************************************************/
      76             : /*                          AddBlockToFreeList()                        */
      77             : /*                                                                      */
      78             : /*      This is called by GDALRasterBlock::Internalize() and            */
      79             : /*      FlushCacheBlock() after they have been finished with a block.   */
      80             : /************************************************************************/
      81             : 
      82       29595 : void GDALAbstractBandBlockCache::AddBlockToFreeList(GDALRasterBlock *poBlock)
      83             : {
      84       29595 :     CPLAssert(poBlock->poPrevious == nullptr);
      85       29595 :     CPLAssert(poBlock->poNext == nullptr);
      86             :     {
      87             : #ifdef DEBUG_VERBOSE_ABBC
      88             :         CPLAtomicInc(&nAllBandsKeptAlivedBlocks);
      89             :         fprintf(/*ok*/ stderr,
      90             :                 "AddBlockToFreeList(): nAllBandsKeptAlivedBlocks=%d\n",
      91             :                 nAllBandsKeptAlivedBlocks);
      92             : #endif
      93       29595 :         CPLLockHolderOptionalLockD(hSpinLock);
      94       29595 :         poBlock->poNext = psListBlocksToFree;
      95       29595 :         psListBlocksToFree = poBlock;
      96             :     }
      97             : 
      98             :     // If no more blocks in transient state, then warn
      99             :     // WaitCompletionPendingTasks()
     100       29595 :     CPLAcquireMutex(hCondMutex, 1000);
     101       29595 :     if (CPLAtomicDec(&nKeepAliveCounter) == 0)
     102             :     {
     103       29550 :         CPLCondSignal(hCond);
     104             :     }
     105       29595 :     CPLReleaseMutex(hCondMutex);
     106       29595 : }
     107             : 
     108             : /************************************************************************/
     109             : /*                      WaitCompletionPendingTasks()                    */
     110             : /************************************************************************/
     111             : 
     112      671792 : void GDALAbstractBandBlockCache::WaitCompletionPendingTasks()
     113             : {
     114             : #ifdef DEBUG_VERBOSE
     115             :     CPLDebug("GDAL", "WaitCompletionPendingTasks()");
     116             : #endif
     117             : 
     118      671792 :     CPLAcquireMutex(hCondMutex, 1000);
     119      671793 :     while (nKeepAliveCounter != 0)
     120             :     {
     121           3 :         CPLDebug("GDAL", "Waiting for other thread to finish working with our "
     122             :                          "blocks");
     123           3 :         CPLCondWait(hCond, hCondMutex);
     124             :     }
     125      671790 :     CPLReleaseMutex(hCondMutex);
     126      671792 : }
     127             : 
     128             : /************************************************************************/
     129             : /*                           FreeDanglingBlocks()                       */
     130             : /************************************************************************/
     131             : 
     132     3364720 : void GDALAbstractBandBlockCache::FreeDanglingBlocks()
     133             : {
     134             :     GDALRasterBlock *poList;
     135             :     {
     136     3364720 :         CPLLockHolderOptionalLockD(hSpinLock);
     137     3364720 :         poList = psListBlocksToFree;
     138     3364720 :         psListBlocksToFree = nullptr;
     139             :     }
     140     3383920 :     while (poList)
     141             :     {
     142             : #ifdef DEBUG_VERBOSE_ABBC
     143             :         CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     144             :         fprintf(/*ok*/ stderr,
     145             :                 "FreeDanglingBlocks(): nAllBandsKeptAlivedBlocks=%d\n",
     146             :                 nAllBandsKeptAlivedBlocks);
     147             : #endif
     148       19222 :         GDALRasterBlock *poNext = poList->poNext;
     149       19222 :         poList->poNext = nullptr;
     150       19222 :         delete poList;
     151       19213 :         poList = poNext;
     152             :     }
     153     3364700 : }
     154             : 
     155             : /************************************************************************/
     156             : /*                            CreateBlock()                             */
     157             : /************************************************************************/
     158             : 
     159     3148170 : GDALRasterBlock *GDALAbstractBandBlockCache::CreateBlock(int nXBlockOff,
     160             :                                                          int nYBlockOff)
     161             : {
     162             :     GDALRasterBlock *poBlock;
     163             :     {
     164     6296430 :         CPLLockHolderOptionalLockD(hSpinLock);
     165     3148250 :         poBlock = psListBlocksToFree;
     166     3148250 :         if (poBlock)
     167             :         {
     168             : #ifdef DEBUG_VERBOSE_ABBC
     169             :             CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     170             :             fprintf(/*ok*/ stderr,
     171             :                     "CreateBlock(): nAllBandsKeptAlivedBlocks=%d\n",
     172             :                     nAllBandsKeptAlivedBlocks);
     173             : #endif
     174       10373 :             psListBlocksToFree = poBlock->poNext;
     175             :         }
     176             :     }
     177     3148330 :     if (poBlock)
     178       10373 :         poBlock->RecycleFor(nXBlockOff, nYBlockOff);
     179             :     else
     180     3137920 :         poBlock =
     181     3137960 :             new (std::nothrow) GDALRasterBlock(poBand, nXBlockOff, nYBlockOff);
     182     3148280 :     return poBlock;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                         IncDirtyBlocks()                             */
     187             : /************************************************************************/
     188             : 
     189             : /**
     190             :  * \brief Increment/decrement the number of dirty blocks
     191             :  */
     192             : 
     193      515146 : void GDALAbstractBandBlockCache::IncDirtyBlocks(int nInc)
     194             : {
     195      515146 :     CPLAtomicAdd(&m_nDirtyBlocks, nInc);
     196      515145 : }
     197             : 
     198             : /************************************************************************/
     199             : /*                      StartDirtyBlockFlushingLog()                    */
     200             : /************************************************************************/
     201             : 
     202      182500 : void GDALAbstractBandBlockCache::StartDirtyBlockFlushingLog()
     203             : {
     204      182500 :     m_nInitialDirtyBlocksInFlushCache = 0;
     205      182500 :     if (m_nDirtyBlocks > 0 && CPLIsDefaultErrorHandlerAndCatchDebug())
     206             :     {
     207        1865 :         if (CPLIsDebugEnabled() &&
     208           5 :             CPLGetConfigOption("GDAL_REPORT_DIRTY_BLOCK_FLUSHING", nullptr) ==
     209             :                 nullptr)
     210             :         {
     211           5 :             m_nInitialDirtyBlocksInFlushCache = m_nDirtyBlocks;
     212           5 :             m_nLastTick = -1;
     213             :         }
     214             :     }
     215      182500 : }
     216             : 
     217             : /************************************************************************/
     218             : /*                      UpdateDirtyBlockFlushingLog()                   */
     219             : /************************************************************************/
     220             : 
     221      175939 : void GDALAbstractBandBlockCache::UpdateDirtyBlockFlushingLog()
     222             : {
     223             :     // Poor man progress report for console applications
     224      175939 :     if (m_nInitialDirtyBlocksInFlushCache)
     225             :     {
     226        1601 :         const auto nRemainingDirtyBlocks = m_nDirtyBlocks;
     227        1601 :         const auto nFlushedBlocks =
     228        1601 :             m_nInitialDirtyBlocksInFlushCache - nRemainingDirtyBlocks + 1;
     229        1601 :         const double dfComplete =
     230        1601 :             double(nFlushedBlocks) / m_nInitialDirtyBlocksInFlushCache;
     231             :         const int nThisTick =
     232        1601 :             std::min(40, std::max(0, static_cast<int>(dfComplete * 40.0)));
     233        1601 :         if (nThisTick > m_nLastTick)
     234             :         {
     235         165 :             if (m_nLastTick < 0)
     236             :             {
     237           5 :                 fprintf(stderr, "GDAL: Flushing dirty blocks: "); /*ok*/
     238           5 :                 fflush(stderr);                                   /*ok*/
     239             :             }
     240         370 :             while (nThisTick > m_nLastTick)
     241             :             {
     242         205 :                 ++m_nLastTick;
     243         205 :                 if (m_nLastTick % 4 == 0)
     244          55 :                     fprintf(stderr, "%d", (m_nLastTick / 4) * 10); /*ok*/
     245             :                 else
     246         150 :                     fprintf(stderr, "."); /*ok*/
     247             :             }
     248             : 
     249         165 :             if (nThisTick == 40)
     250           5 :                 fprintf(stderr, " - done.\n"); /*ok*/
     251             :             else
     252         160 :                 fflush(stderr); /*ok*/
     253             :         }
     254             :     }
     255      175939 : }
     256             : 
     257             : /************************************************************************/
     258             : /*                       EndDirtyBlockFlushingLog()                     */
     259             : /************************************************************************/
     260             : 
     261      182500 : void GDALAbstractBandBlockCache::EndDirtyBlockFlushingLog()
     262             : {
     263      182500 :     m_nInitialDirtyBlocksInFlushCache = 0;
     264      182500 :     m_nLastTick = -1;
     265      182500 : }
     266             : 
     267             : //! @endcond

Generated by: LCOV version 1.14