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-05-03 15:49:35 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "gdal_priv.h"
      31             : 
      32             : #include <algorithm>
      33             : #include <cstddef>
      34             : #include <new>
      35             : 
      36             : #include "cpl_atomic_ops.h"
      37             : #include "cpl_error.h"
      38             : #include "cpl_multiproc.h"
      39             : 
      40             : //! @cond Doxygen_Suppress
      41             : 
      42             : #ifdef DEBUG_VERBOSE_ABBC
      43             : static int nAllBandsKeptAlivedBlocks = 0;
      44             : #endif
      45             : 
      46             : /************************************************************************/
      47             : /*                       GDALArrayBandBlockCache()                      */
      48             : /************************************************************************/
      49             : 
      50       29059 : GDALAbstractBandBlockCache::GDALAbstractBandBlockCache(GDALRasterBand *poBandIn)
      51       87177 :     : hSpinLock(CPLCreateLock(LOCK_SPIN)), hCond(CPLCreateCond()),
      52       29059 :       hCondMutex(CPLCreateMutex()), poBand(poBandIn)
      53             : {
      54       29059 :     if (hCondMutex)
      55       29059 :         CPLReleaseMutex(hCondMutex);
      56       29059 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                      ~GDALAbstractBandBlockCache()                   */
      60             : /************************************************************************/
      61             : 
      62       58119 : GDALAbstractBandBlockCache::~GDALAbstractBandBlockCache()
      63             : {
      64       29059 :     CPLAssert(nKeepAliveCounter == 0);
      65       29059 :     FreeDanglingBlocks();
      66       29059 :     if (hSpinLock)
      67       29058 :         CPLDestroyLock(hSpinLock);
      68       29060 :     if (hCondMutex)
      69       29059 :         CPLDestroyMutex(hCondMutex);
      70       29060 :     if (hCond)
      71       29059 :         CPLDestroyCond(hCond);
      72       29060 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                            UnreferenceBlockBase()                    */
      76             : /*                                                                      */
      77             : /*      This is called by GDALRasterBlock::Internalize() and            */
      78             : /*      FlushCacheBlock() when they remove a block from the linked list */
      79             : /*      but haven't yet flushed it to disk or recovered its pData member*/
      80             : /*      We must be aware that they are blocks in that state, since the  */
      81             : /*      band must be kept alive while AddBlockToFreeList() hasn't been  */
      82             : /*      called (in case a block is being flushed while the final        */
      83             : /*      FlushCache() of the main thread of the dataset is running).     */
      84             : /************************************************************************/
      85             : 
      86       29608 : void GDALAbstractBandBlockCache::UnreferenceBlockBase()
      87             : {
      88       29608 :     CPLAtomicInc(&nKeepAliveCounter);
      89       29608 : }
      90             : 
      91             : /************************************************************************/
      92             : /*                          AddBlockToFreeList()                        */
      93             : /*                                                                      */
      94             : /*      This is called by GDALRasterBlock::Internalize() and            */
      95             : /*      FlushCacheBlock() after they have been finished with a block.   */
      96             : /************************************************************************/
      97             : 
      98       29608 : void GDALAbstractBandBlockCache::AddBlockToFreeList(GDALRasterBlock *poBlock)
      99             : {
     100       29608 :     CPLAssert(poBlock->poPrevious == nullptr);
     101       29608 :     CPLAssert(poBlock->poNext == nullptr);
     102             :     {
     103             : #ifdef DEBUG_VERBOSE_ABBC
     104             :         CPLAtomicInc(&nAllBandsKeptAlivedBlocks);
     105             :         fprintf(/*ok*/ stderr,
     106             :                 "AddBlockToFreeList(): nAllBandsKeptAlivedBlocks=%d\n",
     107             :                 nAllBandsKeptAlivedBlocks);
     108             : #endif
     109       29608 :         CPLLockHolderOptionalLockD(hSpinLock);
     110       29608 :         poBlock->poNext = psListBlocksToFree;
     111       29608 :         psListBlocksToFree = poBlock;
     112             :     }
     113             : 
     114             :     // If no more blocks in transient state, then warn
     115             :     // WaitCompletionPendingTasks()
     116       29608 :     CPLAcquireMutex(hCondMutex, 1000);
     117       29608 :     if (CPLAtomicDec(&nKeepAliveCounter) == 0)
     118             :     {
     119       29562 :         CPLCondSignal(hCond);
     120             :     }
     121       29607 :     CPLReleaseMutex(hCondMutex);
     122       29608 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                      WaitCompletionPendingTasks()                    */
     126             : /************************************************************************/
     127             : 
     128      582303 : void GDALAbstractBandBlockCache::WaitCompletionPendingTasks()
     129             : {
     130             : #ifdef DEBUG_VERBOSE
     131             :     CPLDebug("GDAL", "WaitCompletionPendingTasks()");
     132             : #endif
     133             : 
     134      582303 :     CPLAcquireMutex(hCondMutex, 1000);
     135      582305 :     while (nKeepAliveCounter != 0)
     136             :     {
     137           2 :         CPLDebug("GDAL", "Waiting for other thread to finish working with our "
     138             :                          "blocks");
     139           2 :         CPLCondWait(hCond, hCondMutex);
     140             :     }
     141      582303 :     CPLReleaseMutex(hCondMutex);
     142      582304 : }
     143             : 
     144             : /************************************************************************/
     145             : /*                           FreeDanglingBlocks()                       */
     146             : /************************************************************************/
     147             : 
     148     3164340 : void GDALAbstractBandBlockCache::FreeDanglingBlocks()
     149             : {
     150             :     GDALRasterBlock *poList;
     151             :     {
     152     3164340 :         CPLLockHolderOptionalLockD(hSpinLock);
     153     3164350 :         poList = psListBlocksToFree;
     154     3164350 :         psListBlocksToFree = nullptr;
     155             :     }
     156     3182550 :     while (poList)
     157             :     {
     158             : #ifdef DEBUG_VERBOSE_ABBC
     159             :         CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     160             :         fprintf(/*ok*/ stderr,
     161             :                 "FreeDanglingBlocks(): nAllBandsKeptAlivedBlocks=%d\n",
     162             :                 nAllBandsKeptAlivedBlocks);
     163             : #endif
     164       18206 :         GDALRasterBlock *poNext = poList->poNext;
     165       18206 :         poList->poNext = nullptr;
     166       18206 :         delete poList;
     167       18202 :         poList = poNext;
     168             :     }
     169     3164340 : }
     170             : 
     171             : /************************************************************************/
     172             : /*                            CreateBlock()                             */
     173             : /************************************************************************/
     174             : 
     175     2967590 : GDALRasterBlock *GDALAbstractBandBlockCache::CreateBlock(int nXBlockOff,
     176             :                                                          int nYBlockOff)
     177             : {
     178             :     GDALRasterBlock *poBlock;
     179             :     {
     180     5935190 :         CPLLockHolderOptionalLockD(hSpinLock);
     181     2967600 :         poBlock = psListBlocksToFree;
     182     2967600 :         if (poBlock)
     183             :         {
     184             : #ifdef DEBUG_VERBOSE_ABBC
     185             :             CPLAtomicDec(&nAllBandsKeptAlivedBlocks);
     186             :             fprintf(/*ok*/ stderr,
     187             :                     "CreateBlock(): nAllBandsKeptAlivedBlocks=%d\n",
     188             :                     nAllBandsKeptAlivedBlocks);
     189             : #endif
     190       11402 :             psListBlocksToFree = poBlock->poNext;
     191             :         }
     192             :     }
     193     2967600 :     if (poBlock)
     194       11402 :         poBlock->RecycleFor(nXBlockOff, nYBlockOff);
     195             :     else
     196     2956190 :         poBlock =
     197     2956190 :             new (std::nothrow) GDALRasterBlock(poBand, nXBlockOff, nYBlockOff);
     198     2967590 :     return poBlock;
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                         IncDirtyBlocks()                             */
     203             : /************************************************************************/
     204             : 
     205             : /**
     206             :  * \brief Increment/decrement the number of dirty blocks
     207             :  */
     208             : 
     209      488711 : void GDALAbstractBandBlockCache::IncDirtyBlocks(int nInc)
     210             : {
     211      488711 :     CPLAtomicAdd(&m_nDirtyBlocks, nInc);
     212      488711 : }
     213             : 
     214             : /************************************************************************/
     215             : /*                      StartDirtyBlockFlushingLog()                    */
     216             : /************************************************************************/
     217             : 
     218      167689 : void GDALAbstractBandBlockCache::StartDirtyBlockFlushingLog()
     219             : {
     220      167689 :     m_nInitialDirtyBlocksInFlushCache = 0;
     221      167689 :     if (m_nDirtyBlocks > 0 && CPLIsDefaultErrorHandlerAndCatchDebug())
     222             :     {
     223        1775 :         const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
     224        1776 :         if (pszDebug && (EQUAL(pszDebug, "ON") || EQUAL(pszDebug, "GDAL")) &&
     225           1 :             CPLGetConfigOption("GDAL_REPORT_DIRTY_BLOCK_FLUSHING", nullptr) ==
     226             :                 nullptr)
     227             :         {
     228           1 :             m_nInitialDirtyBlocksInFlushCache = m_nDirtyBlocks;
     229           1 :             m_nLastTick = -1;
     230             :         }
     231             :     }
     232      167689 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                      UpdateDirtyBlockFlushingLog()                   */
     236             : /************************************************************************/
     237             : 
     238      162819 : void GDALAbstractBandBlockCache::UpdateDirtyBlockFlushingLog()
     239             : {
     240             :     // Poor man progress report for console applications
     241      162819 :     if (m_nInitialDirtyBlocksInFlushCache)
     242             :     {
     243           1 :         const auto nRemainingDirtyBlocks = m_nDirtyBlocks;
     244           1 :         const auto nFlushedBlocks =
     245           1 :             m_nInitialDirtyBlocksInFlushCache - nRemainingDirtyBlocks + 1;
     246           1 :         const double dfComplete =
     247           1 :             double(nFlushedBlocks) / m_nInitialDirtyBlocksInFlushCache;
     248             :         const int nThisTick =
     249           1 :             std::min(40, std::max(0, static_cast<int>(dfComplete * 40.0)));
     250           1 :         if (nThisTick > m_nLastTick)
     251             :         {
     252           1 :             if (m_nLastTick < 0)
     253             :             {
     254           1 :                 fprintf(stderr, "GDAL: Flushing dirty blocks: "); /*ok*/
     255           1 :                 fflush(stderr);                                   /*ok*/
     256             :             }
     257          42 :             while (nThisTick > m_nLastTick)
     258             :             {
     259          41 :                 ++m_nLastTick;
     260          41 :                 if (m_nLastTick % 4 == 0)
     261          11 :                     fprintf(stderr, "%d", (m_nLastTick / 4) * 10); /*ok*/
     262             :                 else
     263          30 :                     fprintf(stderr, "."); /*ok*/
     264             :             }
     265             : 
     266           1 :             if (nThisTick == 40)
     267           1 :                 fprintf(stderr, " - done.\n"); /*ok*/
     268             :             else
     269           0 :                 fflush(stderr); /*ok*/
     270             :         }
     271             :     }
     272      162819 : }
     273             : 
     274             : /************************************************************************/
     275             : /*                       EndDirtyBlockFlushingLog()                     */
     276             : /************************************************************************/
     277             : 
     278      167690 : void GDALAbstractBandBlockCache::EndDirtyBlockFlushingLog()
     279             : {
     280      167690 :     m_nInitialDirtyBlocksInFlushCache = 0;
     281      167690 :     m_nLastTick = -1;
     282      167690 : }
     283             : 
     284             : //! @endcond

Generated by: LCOV version 1.14