LCOV - code coverage report
Current view: top level - gcore - gdalabstractbandblockcache.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 93 94 98.9 %
Date: 2024-11-21 22:18:42 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       33023 : GDALAbstractBandBlockCache::GDALAbstractBandBlockCache(GDALRasterBand *poBandIn)
      35       99067 :     : hSpinLock(CPLCreateLock(LOCK_SPIN)), hCond(CPLCreateCond()),
      36       33023 :       hCondMutex(CPLCreateMutex()), poBand(poBandIn)
      37             : {
      38       33023 :     if (hCondMutex)
      39       33023 :         CPLReleaseMutex(hCondMutex);
      40       33023 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                      ~GDALAbstractBandBlockCache()                   */
      44             : /************************************************************************/
      45             : 
      46       66045 : GDALAbstractBandBlockCache::~GDALAbstractBandBlockCache()
      47             : {
      48       33023 :     CPLAssert(nKeepAliveCounter == 0);
      49       33023 :     FreeDanglingBlocks();
      50       33023 :     if (hSpinLock)
      51       33023 :         CPLDestroyLock(hSpinLock);
      52       33023 :     if (hCondMutex)
      53       33023 :         CPLDestroyMutex(hCondMutex);
      54       33023 :     if (hCond)
      55       33023 :         CPLDestroyCond(hCond);
      56       33022 : }
      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       29590 : void GDALAbstractBandBlockCache::UnreferenceBlockBase()
      71             : {
      72       29590 :     CPLAtomicInc(&nKeepAliveCounter);
      73       29590 : }
      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       29590 : void GDALAbstractBandBlockCache::AddBlockToFreeList(GDALRasterBlock *poBlock)
      83             : {
      84       29590 :     CPLAssert(poBlock->poPrevious == nullptr);
      85       29590 :     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       29590 :         CPLLockHolderOptionalLockD(hSpinLock);
      94       29590 :         poBlock->poNext = psListBlocksToFree;
      95       29590 :         psListBlocksToFree = poBlock;
      96             :     }
      97             : 
      98             :     // If no more blocks in transient state, then warn
      99             :     // WaitCompletionPendingTasks()
     100       29147 :     CPLAcquireMutex(hCondMutex, 1000);
     101       29590 :     if (CPLAtomicDec(&nKeepAliveCounter) == 0)
     102             :     {
     103       28799 :         CPLCondSignal(hCond);
     104             :     }
     105       29590 :     CPLReleaseMutex(hCondMutex);
     106       29590 : }
     107             : 
     108             : /************************************************************************/
     109             : /*                      WaitCompletionPendingTasks()                    */
     110             : /************************************************************************/
     111             : 
     112      669150 : void GDALAbstractBandBlockCache::WaitCompletionPendingTasks()
     113             : {
     114             : #ifdef DEBUG_VERBOSE
     115             :     CPLDebug("GDAL", "WaitCompletionPendingTasks()");
     116             : #endif
     117             : 
     118      669150 :     CPLAcquireMutex(hCondMutex, 1000);
     119      669152 :     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      669149 :     CPLReleaseMutex(hCondMutex);
     126      669147 : }
     127             : 
     128             : /************************************************************************/
     129             : /*                           FreeDanglingBlocks()                       */
     130             : /************************************************************************/
     131             : 
     132     3342150 : void GDALAbstractBandBlockCache::FreeDanglingBlocks()
     133             : {
     134             :     GDALRasterBlock *poList;
     135             :     {
     136     3342150 :         CPLLockHolderOptionalLockD(hSpinLock);
     137     3342160 :         poList = psListBlocksToFree;
     138     3342160 :         psListBlocksToFree = nullptr;
     139             :     }
     140     3361350 :     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       19228 :         GDALRasterBlock *poNext = poList->poNext;
     149       19228 :         poList->poNext = nullptr;
     150       19228 :         delete poList;
     151       19228 :         poList = poNext;
     152             :     }
     153     3342120 : }
     154             : 
     155             : /************************************************************************/
     156             : /*                            CreateBlock()                             */
     157             : /************************************************************************/
     158             : 
     159     3129080 : GDALRasterBlock *GDALAbstractBandBlockCache::CreateBlock(int nXBlockOff,
     160             :                                                          int nYBlockOff)
     161             : {
     162             :     GDALRasterBlock *poBlock;
     163             :     {
     164     6258220 :         CPLLockHolderOptionalLockD(hSpinLock);
     165     3129140 :         poBlock = psListBlocksToFree;
     166     3129140 :         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       10362 :             psListBlocksToFree = poBlock->poNext;
     175             :         }
     176             :     }
     177     3129110 :     if (poBlock)
     178       10362 :         poBlock->RecycleFor(nXBlockOff, nYBlockOff);
     179             :     else
     180     3118710 :         poBlock =
     181     3118740 :             new (std::nothrow) GDALRasterBlock(poBand, nXBlockOff, nYBlockOff);
     182     3129080 :     return poBlock;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                         IncDirtyBlocks()                             */
     187             : /************************************************************************/
     188             : 
     189             : /**
     190             :  * \brief Increment/decrement the number of dirty blocks
     191             :  */
     192             : 
     193      494888 : void GDALAbstractBandBlockCache::IncDirtyBlocks(int nInc)
     194             : {
     195      494888 :     CPLAtomicAdd(&m_nDirtyBlocks, nInc);
     196      494890 : }
     197             : 
     198             : /************************************************************************/
     199             : /*                      StartDirtyBlockFlushingLog()                    */
     200             : /************************************************************************/
     201             : 
     202      179895 : void GDALAbstractBandBlockCache::StartDirtyBlockFlushingLog()
     203             : {
     204      179895 :     m_nInitialDirtyBlocksInFlushCache = 0;
     205      179895 :     if (m_nDirtyBlocks > 0 && CPLIsDefaultErrorHandlerAndCatchDebug())
     206             :     {
     207        1817 :         const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
     208        1818 :         if (pszDebug && (EQUAL(pszDebug, "ON") || EQUAL(pszDebug, "GDAL")) &&
     209           1 :             CPLGetConfigOption("GDAL_REPORT_DIRTY_BLOCK_FLUSHING", nullptr) ==
     210             :                 nullptr)
     211             :         {
     212           1 :             m_nInitialDirtyBlocksInFlushCache = m_nDirtyBlocks;
     213           1 :             m_nLastTick = -1;
     214             :         }
     215             :     }
     216      179895 : }
     217             : 
     218             : /************************************************************************/
     219             : /*                      UpdateDirtyBlockFlushingLog()                   */
     220             : /************************************************************************/
     221             : 
     222      165832 : void GDALAbstractBandBlockCache::UpdateDirtyBlockFlushingLog()
     223             : {
     224             :     // Poor man progress report for console applications
     225      165832 :     if (m_nInitialDirtyBlocksInFlushCache)
     226             :     {
     227           1 :         const auto nRemainingDirtyBlocks = m_nDirtyBlocks;
     228           1 :         const auto nFlushedBlocks =
     229           1 :             m_nInitialDirtyBlocksInFlushCache - nRemainingDirtyBlocks + 1;
     230           1 :         const double dfComplete =
     231           1 :             double(nFlushedBlocks) / m_nInitialDirtyBlocksInFlushCache;
     232             :         const int nThisTick =
     233           1 :             std::min(40, std::max(0, static_cast<int>(dfComplete * 40.0)));
     234           1 :         if (nThisTick > m_nLastTick)
     235             :         {
     236           1 :             if (m_nLastTick < 0)
     237             :             {
     238           1 :                 fprintf(stderr, "GDAL: Flushing dirty blocks: "); /*ok*/
     239           1 :                 fflush(stderr);                                   /*ok*/
     240             :             }
     241          42 :             while (nThisTick > m_nLastTick)
     242             :             {
     243          41 :                 ++m_nLastTick;
     244          41 :                 if (m_nLastTick % 4 == 0)
     245          11 :                     fprintf(stderr, "%d", (m_nLastTick / 4) * 10); /*ok*/
     246             :                 else
     247          30 :                     fprintf(stderr, "."); /*ok*/
     248             :             }
     249             : 
     250           1 :             if (nThisTick == 40)
     251           1 :                 fprintf(stderr, " - done.\n"); /*ok*/
     252             :             else
     253           0 :                 fflush(stderr); /*ok*/
     254             :         }
     255             :     }
     256      165832 : }
     257             : 
     258             : /************************************************************************/
     259             : /*                       EndDirtyBlockFlushingLog()                     */
     260             : /************************************************************************/
     261             : 
     262      179896 : void GDALAbstractBandBlockCache::EndDirtyBlockFlushingLog()
     263             : {
     264      179896 :     m_nInitialDirtyBlocksInFlushCache = 0;
     265      179896 :     m_nLastTick = -1;
     266      179896 : }
     267             : 
     268             : //! @endcond

Generated by: LCOV version 1.14