LCOV - code coverage report
Current view: top level - gcore - gdalarraybandblockcache.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 150 163 92.0 %
Date: 2024-11-21 22:18:42 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Store cached blocks in a array or a two-level array
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot org>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot org>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal_priv.h"
      16             : 
      17             : #include <cassert>
      18             : #include <climits>
      19             : #include <cstddef>
      20             : #include <new>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_multiproc.h"
      25             : #include "cpl_vsi.h"
      26             : 
      27             : //! @cond Doxygen_Suppress
      28             : 
      29             : constexpr int SUBBLOCK_SIZE = 64;
      30             : #define TO_SUBBLOCK(x) ((x) >> 6)
      31             : #define WITHIN_SUBBLOCK(x) ((x)&0x3f)
      32             : 
      33             : /* ******************************************************************** */
      34             : /*                        GDALArrayBandBlockCache                       */
      35             : /* ******************************************************************** */
      36             : 
      37             : class GDALArrayBandBlockCache final : public GDALAbstractBandBlockCache
      38             : {
      39             :     bool bSubBlockingActive = false;
      40             :     int nSubBlocksPerRow = 0;
      41             :     int nSubBlocksPerColumn = 0;
      42             : 
      43             :     union u
      44             :     {
      45             :         GDALRasterBlock **papoBlocks;
      46             :         GDALRasterBlock ***papapoBlocks;
      47             : 
      48       32953 :         u() : papoBlocks(nullptr)
      49             :         {
      50       32953 :         }
      51             :     } u{};
      52             : 
      53             :     CPL_DISALLOW_COPY_ASSIGN(GDALArrayBandBlockCache)
      54             : 
      55             :   public:
      56             :     explicit GDALArrayBandBlockCache(GDALRasterBand *poBand);
      57             :     ~GDALArrayBandBlockCache() override;
      58             : 
      59             :     bool Init() override;
      60             :     bool IsInitOK() override;
      61             :     CPLErr FlushCache() override;
      62             :     CPLErr AdoptBlock(GDALRasterBlock *) override;
      63             :     GDALRasterBlock *TryGetLockedBlockRef(int nXBlockOff,
      64             :                                           int nYBlockYOff) override;
      65             :     CPLErr UnreferenceBlock(GDALRasterBlock *poBlock) override;
      66             :     CPLErr FlushBlock(int nXBlockOff, int nYBlockOff,
      67             :                       int bWriteDirtyBlock) override;
      68             : };
      69             : 
      70             : /************************************************************************/
      71             : /*                     GDALArrayBandBlockCacheCreate()                 */
      72             : /************************************************************************/
      73             : 
      74             : GDALAbstractBandBlockCache *
      75       32953 : GDALArrayBandBlockCacheCreate(GDALRasterBand *poBand)
      76             : {
      77       32953 :     return new (std::nothrow) GDALArrayBandBlockCache(poBand);
      78             : }
      79             : 
      80             : /************************************************************************/
      81             : /*                       GDALArrayBandBlockCache()                      */
      82             : /************************************************************************/
      83             : 
      84       32953 : GDALArrayBandBlockCache::GDALArrayBandBlockCache(GDALRasterBand *poBandIn)
      85       32953 :     : GDALAbstractBandBlockCache(poBandIn)
      86             : {
      87       32953 : }
      88             : 
      89             : /************************************************************************/
      90             : /*                      ~GDALArrayBandBlockCache()                     */
      91             : /************************************************************************/
      92             : 
      93       65905 : GDALArrayBandBlockCache::~GDALArrayBandBlockCache()
      94             : {
      95       32952 :     GDALArrayBandBlockCache::FlushCache();
      96             : 
      97       32950 :     if (!bSubBlockingActive)
      98       32825 :         CPLFree(u.papoBlocks);
      99             :     else
     100         125 :         CPLFree(u.papapoBlocks);
     101       65905 : }
     102             : 
     103             : /************************************************************************/
     104             : /*                                  Init()                              */
     105             : /************************************************************************/
     106             : 
     107       32953 : bool GDALArrayBandBlockCache::Init()
     108             : {
     109       32953 :     if (poBand->nBlocksPerRow < SUBBLOCK_SIZE / 2)
     110             :     {
     111       32828 :         bSubBlockingActive = false;
     112             : 
     113       32828 :         if (poBand->nBlocksPerRow < INT_MAX / poBand->nBlocksPerColumn)
     114             :         {
     115       32828 :             u.papoBlocks = static_cast<GDALRasterBlock **>(VSICalloc(
     116       32828 :                 sizeof(void *), cpl::fits_on<int>(poBand->nBlocksPerRow *
     117       32828 :                                                   poBand->nBlocksPerColumn)));
     118       32828 :             if (u.papoBlocks == nullptr)
     119             :             {
     120           0 :                 poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
     121             :                                     "Out of memory in InitBlockInfo().");
     122           0 :                 return false;
     123             :             }
     124             :         }
     125             :         else
     126             :         {
     127           0 :             poBand->ReportError(
     128             :                 CE_Failure, CPLE_NotSupported, "Too many blocks : %d x %d",
     129           0 :                 poBand->nBlocksPerRow, poBand->nBlocksPerColumn);
     130           0 :             return false;
     131             :         }
     132             :     }
     133             :     else
     134             :     {
     135         125 :         bSubBlockingActive = true;
     136             : 
     137         125 :         nSubBlocksPerRow = DIV_ROUND_UP(poBand->nBlocksPerRow, SUBBLOCK_SIZE);
     138         125 :         nSubBlocksPerColumn =
     139         125 :             DIV_ROUND_UP(poBand->nBlocksPerColumn, SUBBLOCK_SIZE);
     140             : 
     141         125 :         if (nSubBlocksPerRow < INT_MAX / nSubBlocksPerColumn)
     142             :         {
     143         125 :             u.papapoBlocks = static_cast<GDALRasterBlock ***>(VSICalloc(
     144             :                 sizeof(void *),
     145         125 :                 cpl::fits_on<int>(nSubBlocksPerRow * nSubBlocksPerColumn)));
     146         125 :             if (u.papapoBlocks == nullptr)
     147             :             {
     148           0 :                 poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
     149             :                                     "Out of memory in InitBlockInfo().");
     150           0 :                 return false;
     151             :             }
     152             :         }
     153             :         else
     154             :         {
     155           0 :             poBand->ReportError(CE_Failure, CPLE_NotSupported,
     156             :                                 "Too many subblocks : %d x %d",
     157             :                                 nSubBlocksPerRow, nSubBlocksPerColumn);
     158           0 :             return false;
     159             :         }
     160             :     }
     161             : 
     162       32953 :     return true;
     163             : }
     164             : 
     165             : /************************************************************************/
     166             : /*                             IsInitOK()                               */
     167             : /************************************************************************/
     168             : 
     169     8368720 : bool GDALArrayBandBlockCache::IsInitOK()
     170             : {
     171     8368720 :     return (!bSubBlockingActive) ? u.papoBlocks != nullptr
     172     8368720 :                                  : u.papapoBlocks != nullptr;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                            AdoptBlock()                              */
     177             : /************************************************************************/
     178             : 
     179     1113160 : CPLErr GDALArrayBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
     180             : 
     181             : {
     182     1113160 :     const int nXBlockOff = poBlock->GetXOff();
     183     1113150 :     const int nYBlockOff = poBlock->GetYOff();
     184             : 
     185     1113150 :     FreeDanglingBlocks();
     186             : 
     187             :     /* -------------------------------------------------------------------- */
     188             :     /*      Simple case without subblocking.                                */
     189             :     /* -------------------------------------------------------------------- */
     190             : 
     191     1113120 :     if (!bSubBlockingActive)
     192             :     {
     193     1055370 :         const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
     194             : 
     195     1055370 :         CPLAssert(u.papoBlocks[nBlockIndex] == nullptr);
     196     1055370 :         u.papoBlocks[nBlockIndex] = poBlock;
     197             :     }
     198             :     else
     199             :     {
     200             :         /* --------------------------------------------------------------------
     201             :          */
     202             :         /*      Identify the subblock in which our target occurs, and create */
     203             :         /*      it if necessary. */
     204             :         /* --------------------------------------------------------------------
     205             :          */
     206       57743 :         const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
     207       57743 :                               TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
     208             : 
     209       57743 :         if (u.papapoBlocks[nSubBlock] == nullptr)
     210             :         {
     211         169 :             const int nSubGridSize =
     212             :                 sizeof(GDALRasterBlock *) * SUBBLOCK_SIZE * SUBBLOCK_SIZE;
     213             : 
     214         338 :             u.papapoBlocks[nSubBlock] =
     215         169 :                 static_cast<GDALRasterBlock **>(VSICalloc(1, nSubGridSize));
     216         169 :             if (u.papapoBlocks[nSubBlock] == nullptr)
     217             :             {
     218           0 :                 poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
     219             :                                     "Out of memory in AdoptBlock().");
     220           0 :                 return CE_Failure;
     221             :             }
     222             :         }
     223             : 
     224             :         /* --------------------------------------------------------------------
     225             :          */
     226             :         /*      Check within subblock. */
     227             :         /* --------------------------------------------------------------------
     228             :          */
     229       57743 :         GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
     230             : 
     231       57743 :         const int nBlockInSubBlock =
     232       57743 :             WITHIN_SUBBLOCK(nXBlockOff) +
     233       57743 :             WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
     234             : 
     235       57743 :         CPLAssert(papoSubBlockGrid[nBlockInSubBlock] == nullptr);
     236       57743 :         papoSubBlockGrid[nBlockInSubBlock] = poBlock;
     237             :     }
     238             : 
     239     1113120 :     return CE_None;
     240             : }
     241             : 
     242             : /************************************************************************/
     243             : /*                            FlushCache()                              */
     244             : /************************************************************************/
     245             : 
     246      179677 : CPLErr GDALArrayBandBlockCache::FlushCache()
     247             : {
     248      179677 :     FreeDanglingBlocks();
     249             : 
     250      179674 :     CPLErr eGlobalErr = poBand->eFlushBlockErr;
     251             : 
     252      179674 :     StartDirtyBlockFlushingLog();
     253             : 
     254             :     /* -------------------------------------------------------------------- */
     255             :     /*      Flush all blocks in memory ... this case is without subblocking.*/
     256             :     /* -------------------------------------------------------------------- */
     257      179671 :     if (!bSubBlockingActive && u.papoBlocks != nullptr)
     258             :     {
     259      179247 :         const int nBlocksPerColumn = poBand->nBlocksPerColumn;
     260      179247 :         const int nBlocksPerRow = poBand->nBlocksPerRow;
     261    87883100 :         for (int iY = 0; iY < nBlocksPerColumn; iY++)
     262             :         {
     263   175729000 :             for (int iX = 0; iX < nBlocksPerRow; iX++)
     264             :             {
     265    88025200 :                 if (u.papoBlocks[iX + iY * nBlocksPerRow] != nullptr)
     266             :                 {
     267     1025960 :                     CPLErr eErr = FlushBlock(iX, iY, eGlobalErr == CE_None);
     268             : 
     269     1025960 :                     if (eErr != CE_None)
     270           5 :                         eGlobalErr = eErr;
     271             :                 }
     272             :             }
     273      179248 :         }
     274             :     }
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      With subblocking.  We can short circuit missing subblocks.      */
     278             :     /* -------------------------------------------------------------------- */
     279         424 :     else if (u.papapoBlocks != nullptr)
     280             :     {
     281         906 :         for (int iSBY = 0; iSBY < nSubBlocksPerColumn; iSBY++)
     282             :         {
     283        1522 :             for (int iSBX = 0; iSBX < nSubBlocksPerRow; iSBX++)
     284             :             {
     285        1039 :                 const int nSubBlock = iSBX + iSBY * nSubBlocksPerRow;
     286             : 
     287        1039 :                 GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
     288             : 
     289        1039 :                 if (papoSubBlockGrid == nullptr)
     290         870 :                     continue;
     291             : 
     292       10985 :                 for (int iY = 0; iY < SUBBLOCK_SIZE; iY++)
     293             :                 {
     294      703040 :                     for (int iX = 0; iX < SUBBLOCK_SIZE; iX++)
     295             :                     {
     296      692224 :                         if (papoSubBlockGrid[iX + iY * SUBBLOCK_SIZE] !=
     297             :                             nullptr)
     298             :                         {
     299      112128 :                             CPLErr eErr = FlushBlock(iX + iSBX * SUBBLOCK_SIZE,
     300       56064 :                                                      iY + iSBY * SUBBLOCK_SIZE,
     301             :                                                      eGlobalErr == CE_None);
     302       56064 :                             if (eErr != CE_None)
     303           2 :                                 eGlobalErr = eErr;
     304             :                         }
     305             :                     }
     306             :                 }
     307             : 
     308             :                 // We might as well get rid of this grid chunk since we know
     309             :                 // it is now empty.
     310         169 :                 u.papapoBlocks[nSubBlock] = nullptr;
     311         169 :                 CPLFree(papoSubBlockGrid);
     312             :             }
     313             :         }
     314             :     }
     315             : 
     316      179672 :     EndDirtyBlockFlushingLog();
     317             : 
     318      179673 :     WaitCompletionPendingTasks();
     319             : 
     320      179672 :     return (eGlobalErr);
     321             : }
     322             : 
     323             : /************************************************************************/
     324             : /*                        UnreferenceBlock()                            */
     325             : /************************************************************************/
     326             : 
     327       29590 : CPLErr GDALArrayBandBlockCache::UnreferenceBlock(GDALRasterBlock *poBlock)
     328             : {
     329       29590 :     const int nXBlockOff = poBlock->GetXOff();
     330       29590 :     const int nYBlockOff = poBlock->GetYOff();
     331             : 
     332       29590 :     UnreferenceBlockBase();
     333             : 
     334             :     /* -------------------------------------------------------------------- */
     335             :     /*      Simple case for single level caches.                            */
     336             :     /* -------------------------------------------------------------------- */
     337       29590 :     if (!bSubBlockingActive)
     338             :     {
     339       27913 :         const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
     340             : 
     341       27913 :         u.papoBlocks[nBlockIndex] = nullptr;
     342             :     }
     343             : 
     344             :     /* -------------------------------------------------------------------- */
     345             :     /*      Identify our subblock.                                          */
     346             :     /* -------------------------------------------------------------------- */
     347             :     else
     348             :     {
     349        1677 :         const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
     350        1677 :                               TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
     351             : 
     352             :         /* --------------------------------------------------------------------
     353             :          */
     354             :         /*      Check within subblock. */
     355             :         /* --------------------------------------------------------------------
     356             :          */
     357        1677 :         GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
     358        1677 :         if (papoSubBlockGrid == nullptr)
     359           0 :             return CE_None;
     360             : 
     361        1677 :         const int nBlockInSubBlock =
     362        1677 :             WITHIN_SUBBLOCK(nXBlockOff) +
     363        1677 :             WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
     364             : 
     365        1677 :         papoSubBlockGrid[nBlockInSubBlock] = nullptr;
     366             :     }
     367             : 
     368       29590 :     return CE_None;
     369             : }
     370             : 
     371             : /************************************************************************/
     372             : /*                            FlushBlock()                              */
     373             : /************************************************************************/
     374             : 
     375     1084320 : CPLErr GDALArrayBandBlockCache::FlushBlock(int nXBlockOff, int nYBlockOff,
     376             :                                            int bWriteDirtyBlock)
     377             : 
     378             : {
     379     1084320 :     GDALRasterBlock *poBlock = nullptr;
     380             : 
     381             :     /* -------------------------------------------------------------------- */
     382             :     /*      Simple case for single level caches.                            */
     383             :     /* -------------------------------------------------------------------- */
     384     1084320 :     if (!bSubBlockingActive)
     385             :     {
     386     1028250 :         const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
     387             : 
     388     1028250 :         assert(u.papoBlocks);
     389     1028250 :         poBlock = u.papoBlocks[nBlockIndex];
     390     1028250 :         u.papoBlocks[nBlockIndex] = nullptr;
     391             :     }
     392             : 
     393             :     /* -------------------------------------------------------------------- */
     394             :     /*      Identify our subblock.                                          */
     395             :     /* -------------------------------------------------------------------- */
     396             :     else
     397             :     {
     398       56066 :         const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
     399       56066 :                               TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
     400             : 
     401             :         /* --------------------------------------------------------------------
     402             :          */
     403             :         /*      Check within subblock. */
     404             :         /* --------------------------------------------------------------------
     405             :          */
     406       56066 :         GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
     407       56066 :         if (papoSubBlockGrid == nullptr)
     408           0 :             return CE_None;
     409             : 
     410       56066 :         const int nBlockInSubBlock =
     411       56066 :             WITHIN_SUBBLOCK(nXBlockOff) +
     412       56066 :             WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
     413             : 
     414       56066 :         poBlock = papoSubBlockGrid[nBlockInSubBlock];
     415       56066 :         papoSubBlockGrid[nBlockInSubBlock] = nullptr;
     416             :     }
     417             : 
     418     1084320 :     if (poBlock == nullptr)
     419         701 :         return CE_None;
     420             : 
     421     1083620 :     if (!poBlock->DropLockForRemovalFromStorage())
     422           3 :         return CE_None;
     423             : 
     424             :     /* -------------------------------------------------------------------- */
     425             :     /*      Is the target block dirty?  If so we need to write it.          */
     426             :     /* -------------------------------------------------------------------- */
     427     1083610 :     poBlock->Detach();
     428             : 
     429     1083620 :     CPLErr eErr = CE_None;
     430             : 
     431     1083620 :     if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
     432             :     {
     433      165033 :         UpdateDirtyBlockFlushingLog();
     434             : 
     435      165032 :         eErr = poBlock->Write();
     436             :     }
     437             : 
     438             :     /* -------------------------------------------------------------------- */
     439             :     /*      Deallocate the block;                                           */
     440             :     /* -------------------------------------------------------------------- */
     441     1083620 :     delete poBlock;
     442             : 
     443     1083620 :     return eErr;
     444             : }
     445             : 
     446             : /************************************************************************/
     447             : /*                        TryGetLockedBlockRef()                        */
     448             : /************************************************************************/
     449             : 
     450     6904360 : GDALRasterBlock *GDALArrayBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
     451             :                                                                int nYBlockOff)
     452             : 
     453             : {
     454             :     /* -------------------------------------------------------------------- */
     455             :     /*      Simple case for single level caches.                            */
     456             :     /* -------------------------------------------------------------------- */
     457     6904360 :     if (!bSubBlockingActive)
     458             :     {
     459     6121070 :         const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
     460             : 
     461     6121070 :         GDALRasterBlock *poBlock = u.papoBlocks[nBlockIndex];
     462     6121070 :         if (poBlock == nullptr || !poBlock->TakeLock())
     463     1107050 :             return nullptr;
     464     5015690 :         return poBlock;
     465             :     }
     466             :     else
     467             :     {
     468             :         /* --------------------------------------------------------------------
     469             :          */
     470             :         /*      Identify our subblock. */
     471             :         /* --------------------------------------------------------------------
     472             :          */
     473      783291 :         const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
     474      783291 :                               TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
     475             : 
     476             :         /* --------------------------------------------------------------------
     477             :          */
     478             :         /*      Check within subblock. */
     479             :         /* --------------------------------------------------------------------
     480             :          */
     481      783291 :         GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
     482      783291 :         if (papoSubBlockGrid == nullptr)
     483          52 :             return nullptr;
     484             : 
     485      783239 :         const int nBlockInSubBlock =
     486      783239 :             WITHIN_SUBBLOCK(nXBlockOff) +
     487      783239 :             WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
     488             : 
     489      783239 :         GDALRasterBlock *poBlock = papoSubBlockGrid[nBlockInSubBlock];
     490      783239 :         if (poBlock == nullptr || !poBlock->TakeLock())
     491       57581 :             return nullptr;
     492      725658 :         return poBlock;
     493             :     }
     494             : }
     495             : 
     496             : //! @endcond

Generated by: LCOV version 1.14