LCOV - code coverage report
Current view: top level - gcore - gdalproxypool.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 575 681 84.4 %
Date: 2024-11-21 22:18:42 Functions: 63 75 84.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  A dataset and raster band classes that differ the opening of the
       5             :  *           underlying dataset in a limited pool of opened datasets.
       6             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal_proxy.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cstdio>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_hash_set.h"
      25             : #include "cpl_multiproc.h"
      26             : #include "cpl_string.h"
      27             : #include "gdal.h"
      28             : #include "gdal_priv.h"
      29             : 
      30             : //! @cond Doxygen_Suppress
      31             : 
      32             : /* We *must* share the same mutex as the gdaldataset.cpp file, as we are */
      33             : /* doing GDALOpen() calls that can indirectly call GDALOpenShared() on */
      34             : /* an auxiliary dataset ... */
      35             : /* Then we could get dead-locks in multi-threaded use case */
      36             : 
      37             : /* ******************************************************************** */
      38             : /*                         GDALDatasetPool                              */
      39             : /* ******************************************************************** */
      40             : 
      41             : /* This class is a singleton that maintains a pool of opened datasets */
      42             : /* The cache uses a LRU strategy */
      43             : 
      44             : class GDALDatasetPool;
      45             : static GDALDatasetPool *singleton = nullptr;
      46             : 
      47           0 : void GDALNullifyProxyPoolSingleton()
      48             : {
      49           0 :     singleton = nullptr;
      50           0 : }
      51             : 
      52             : struct _GDALProxyPoolCacheEntry
      53             : {
      54             :     GIntBig responsiblePID;
      55             :     char *pszFileNameAndOpenOptions;
      56             :     char *pszOwner;
      57             :     GDALDataset *poDS;
      58             :     GIntBig nRAMUsage;
      59             : 
      60             :     /* Ref count of the cached dataset */
      61             :     int refCount;
      62             : 
      63             :     GDALProxyPoolCacheEntry *prev;
      64             :     GDALProxyPoolCacheEntry *next;
      65             : };
      66             : 
      67             : // This variable prevents a dataset that is going to be opened in
      68             : // GDALDatasetPool::_RefDataset from increasing refCount if, during its
      69             : // opening, it creates a GDALProxyPoolDataset.
      70             : // We increment it before opening or closing a cached dataset and decrement
      71             : // it afterwards
      72             : // The typical use case is a VRT made of simple sources that are VRT
      73             : // We don't want the "inner" VRT to take a reference on the pool, otherwise
      74             : // there is a high chance that this reference will not be dropped and the pool
      75             : // remain ghost.
      76             : static thread_local int refCountOfDisabledRefCount = 0;
      77             : 
      78             : class GDALDatasetPool
      79             : {
      80             :   private:
      81             :     bool bInDestruction = false;
      82             : 
      83             :     /* Ref count of the pool singleton */
      84             :     /* Taken by "toplevel" GDALProxyPoolDataset in its constructor and released
      85             :      */
      86             :     /* in its destructor. See also refCountOfDisabledRefCount for the difference
      87             :      */
      88             :     /* between toplevel and inner GDALProxyPoolDataset */
      89             :     int refCount = 0;
      90             : 
      91             :     int maxSize = 0;
      92             :     int currentSize = 0;
      93             :     int64_t nMaxRAMUsage = 0;
      94             :     int64_t nRAMUsage = 0;
      95             :     GDALProxyPoolCacheEntry *firstEntry = nullptr;
      96             :     GDALProxyPoolCacheEntry *lastEntry = nullptr;
      97             : 
      98             :     /* Caution : to be sure that we don't run out of entries, size must be at */
      99             :     /* least greater or equal than the maximum number of threads */
     100             :     explicit GDALDatasetPool(int maxSize, int64_t nMaxRAMUsage);
     101             :     ~GDALDatasetPool();
     102             :     GDALProxyPoolCacheEntry *_RefDataset(const char *pszFileName,
     103             :                                          GDALAccess eAccess,
     104             :                                          CSLConstList papszOpenOptions,
     105             :                                          int bShared, bool bForceOpen,
     106             :                                          const char *pszOwner);
     107             :     void _CloseDatasetIfZeroRefCount(const char *pszFileName,
     108             :                                      CSLConstList papszOpenOptions,
     109             :                                      GDALAccess eAccess, const char *pszOwner);
     110             : 
     111             : #ifdef DEBUG_PROXY_POOL
     112             :     // cppcheck-suppress unusedPrivateFunction
     113             :     void ShowContent();
     114             :     void CheckLinks();
     115             : #endif
     116             : 
     117             :     CPL_DISALLOW_COPY_ASSIGN(GDALDatasetPool)
     118             : 
     119             :   public:
     120             :     static void Ref();
     121             :     static void Unref();
     122             :     static GDALProxyPoolCacheEntry *RefDataset(const char *pszFileName,
     123             :                                                GDALAccess eAccess,
     124             :                                                char **papszOpenOptions,
     125             :                                                int bShared, bool bForceOpen,
     126             :                                                const char *pszOwner);
     127             :     static void UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry);
     128             :     static void CloseDatasetIfZeroRefCount(const char *pszFileName,
     129             :                                            CSLConstList papszOpenOptions,
     130             :                                            GDALAccess eAccess,
     131             :                                            const char *pszOwner);
     132             : 
     133             :     static void PreventDestroy();
     134             :     static void ForceDestroy();
     135             : };
     136             : 
     137             : /************************************************************************/
     138             : /*                         GDALDatasetPool()                            */
     139             : /************************************************************************/
     140             : 
     141         342 : GDALDatasetPool::GDALDatasetPool(int maxSizeIn, int64_t nMaxRAMUsageIn)
     142         342 :     : maxSize(maxSizeIn), nMaxRAMUsage(nMaxRAMUsageIn)
     143             : {
     144         342 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                        ~GDALDatasetPool()                            */
     148             : /************************************************************************/
     149             : 
     150         678 : GDALDatasetPool::~GDALDatasetPool()
     151             : {
     152         339 :     bInDestruction = true;
     153         339 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     154         339 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     155         667 :     while (cur)
     156             :     {
     157         328 :         GDALProxyPoolCacheEntry *next = cur->next;
     158         328 :         CPLFree(cur->pszFileNameAndOpenOptions);
     159         328 :         CPLFree(cur->pszOwner);
     160         328 :         CPLAssert(cur->refCount == 0);
     161         328 :         if (cur->poDS)
     162             :         {
     163           0 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     164           0 :             GDALClose(cur->poDS);
     165             :         }
     166         328 :         CPLFree(cur);
     167         328 :         cur = next;
     168             :     }
     169         339 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     170         339 : }
     171             : 
     172             : #ifdef DEBUG_PROXY_POOL
     173             : /************************************************************************/
     174             : /*                            ShowContent()                             */
     175             : /************************************************************************/
     176             : 
     177             : void GDALDatasetPool::ShowContent()
     178             : {
     179             :     GDALProxyPoolCacheEntry *cur = firstEntry;
     180             :     int i = 0;
     181             :     while (cur)
     182             :     {
     183             :         printf("[%d] pszFileName=%s, owner=%s, refCount=%d, " /*ok*/
     184             :                "responsiblePID=%d\n",
     185             :                i,
     186             :                cur->pszFileNameAndOpenOptions ? cur->pszFileNameAndOpenOptions
     187             :                                               : "(null)",
     188             :                cur->pszOwner ? cur->pszOwner : "(null)", cur->refCount,
     189             :                (int)cur->responsiblePID);
     190             :         i++;
     191             :         cur = cur->next;
     192             :     }
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                             CheckLinks()                             */
     197             : /************************************************************************/
     198             : 
     199             : void GDALDatasetPool::CheckLinks()
     200             : {
     201             :     GDALProxyPoolCacheEntry *cur = firstEntry;
     202             :     int i = 0;
     203             :     while (cur)
     204             :     {
     205             :         CPLAssert(cur == firstEntry || cur->prev->next == cur);
     206             :         CPLAssert(cur == lastEntry || cur->next->prev == cur);
     207             :         ++i;
     208             :         CPLAssert(cur->next != nullptr || cur == lastEntry);
     209             :         cur = cur->next;
     210             :     }
     211             :     (void)i;
     212             :     CPLAssert(i == currentSize);
     213             : }
     214             : #endif
     215             : 
     216             : /************************************************************************/
     217             : /*                       GetFilenameAndOpenOptions()                    */
     218             : /************************************************************************/
     219             : 
     220       27990 : static std::string GetFilenameAndOpenOptions(const char *pszFileName,
     221             :                                              CSLConstList papszOpenOptions)
     222             : {
     223       27990 :     std::string osFilenameAndOO(pszFileName);
     224       28028 :     for (int i = 0; papszOpenOptions && papszOpenOptions[i]; ++i)
     225             :     {
     226          38 :         osFilenameAndOO += "||";
     227          38 :         osFilenameAndOO += papszOpenOptions[i];
     228             :     }
     229       27990 :     return osFilenameAndOO;
     230             : }
     231             : 
     232             : /************************************************************************/
     233             : /*                            _RefDataset()                             */
     234             : /************************************************************************/
     235             : 
     236             : GDALProxyPoolCacheEntry *
     237       25520 : GDALDatasetPool::_RefDataset(const char *pszFileName, GDALAccess eAccess,
     238             :                              CSLConstList papszOpenOptions, int bShared,
     239             :                              bool bForceOpen, const char *pszOwner)
     240             : {
     241       25520 :     CPLMutex **pMutex = GDALGetphDLMutex();
     242       51039 :     CPLMutexHolderD(pMutex);
     243             : 
     244       25523 :     if (bInDestruction)
     245           0 :         return nullptr;
     246             : 
     247       25523 :     const GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     248             : 
     249             :     const auto EvictEntryWithZeroRefCount =
     250        4760 :         [this, responsiblePID](bool evictEntryWithOpenedDataset)
     251             :     {
     252         793 :         GDALProxyPoolCacheEntry *cur = firstEntry;
     253         793 :         GDALProxyPoolCacheEntry *candidate = nullptr;
     254       79899 :         while (cur)
     255             :         {
     256       79106 :             GDALProxyPoolCacheEntry *next = cur->next;
     257             : 
     258       79106 :             if (cur->refCount == 0 &&
     259       78213 :                 (!evictEntryWithOpenedDataset || cur->nRAMUsage > 0))
     260             :             {
     261       78213 :                 candidate = cur;
     262             :             }
     263             : 
     264       79106 :             cur = next;
     265             :         }
     266         793 :         if (candidate == nullptr)
     267           0 :             return false;
     268             : 
     269         793 :         nRAMUsage -= candidate->nRAMUsage;
     270         793 :         candidate->nRAMUsage = 0;
     271             : 
     272         793 :         CPLFree(candidate->pszFileNameAndOpenOptions);
     273         793 :         candidate->pszFileNameAndOpenOptions = nullptr;
     274             : 
     275         793 :         if (candidate->poDS)
     276             :         {
     277             :             /* Close by pretending we are the thread that GDALOpen'ed this */
     278             :             /* dataset */
     279           2 :             GDALSetResponsiblePIDForCurrentThread(candidate->responsiblePID);
     280             : 
     281           2 :             refCountOfDisabledRefCount++;
     282           2 :             GDALClose(candidate->poDS);
     283           2 :             refCountOfDisabledRefCount--;
     284             : 
     285           2 :             candidate->poDS = nullptr;
     286           2 :             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     287             :         }
     288         793 :         CPLFree(candidate->pszOwner);
     289         793 :         candidate->pszOwner = nullptr;
     290             : 
     291         793 :         if (!evictEntryWithOpenedDataset && candidate != firstEntry)
     292             :         {
     293             :             /* Recycle this entry for the to-be-opened dataset and */
     294             :             /* moves it to the top of the list */
     295         793 :             if (candidate->prev)
     296         793 :                 candidate->prev->next = candidate->next;
     297             : 
     298         793 :             if (candidate->next)
     299           0 :                 candidate->next->prev = candidate->prev;
     300             :             else
     301             :             {
     302         793 :                 CPLAssert(candidate == lastEntry);
     303         793 :                 lastEntry->prev->next = nullptr;
     304         793 :                 lastEntry = lastEntry->prev;
     305             :             }
     306         793 :             candidate->prev = nullptr;
     307         793 :             candidate->next = firstEntry;
     308         793 :             firstEntry->prev = candidate;
     309         793 :             firstEntry = candidate;
     310             : 
     311             : #ifdef DEBUG_PROXY_POOL
     312             :             CheckLinks();
     313             : #endif
     314             :         }
     315             : 
     316         793 :         return true;
     317       25523 :     };
     318             : 
     319       25523 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     320             : 
     321             :     const std::string osFilenameAndOO =
     322       51046 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     323             : 
     324      315511 :     while (cur)
     325             :     {
     326      312006 :         GDALProxyPoolCacheEntry *next = cur->next;
     327             : 
     328      389834 :         if (cur->refCount >= 0 && cur->pszFileNameAndOpenOptions &&
     329      723895 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     330       21956 :             ((bShared && cur->responsiblePID == responsiblePID &&
     331       21949 :               ((cur->pszOwner == nullptr && pszOwner == nullptr) ||
     332       21258 :                (cur->pszOwner != nullptr && pszOwner != nullptr &&
     333       21364 :                 strcmp(cur->pszOwner, pszOwner) == 0))) ||
     334          99 :              (!bShared && cur->refCount == 0)))
     335             :         {
     336       22018 :             if (cur != firstEntry)
     337             :             {
     338             :                 /* Move to begin */
     339        1475 :                 if (cur->next)
     340        1303 :                     cur->next->prev = cur->prev;
     341             :                 else
     342         172 :                     lastEntry = cur->prev;
     343        1475 :                 cur->prev->next = cur->next;
     344        1475 :                 cur->prev = nullptr;
     345        1475 :                 firstEntry->prev = cur;
     346        1475 :                 cur->next = firstEntry;
     347        1475 :                 firstEntry = cur;
     348             : 
     349             : #ifdef DEBUG_PROXY_POOL
     350             :                 CheckLinks();
     351             : #endif
     352             :             }
     353             : 
     354       22018 :             cur->refCount++;
     355       22018 :             return cur;
     356             :         }
     357             : 
     358      289988 :         cur = next;
     359             :     }
     360             : 
     361        3505 :     if (!bForceOpen)
     362        2123 :         return nullptr;
     363             : 
     364        1382 :     if (currentSize == maxSize)
     365             :     {
     366         793 :         if (!EvictEntryWithZeroRefCount(false))
     367             :         {
     368           0 :             CPLError(
     369             :                 CE_Failure, CPLE_AppDefined,
     370             :                 "Too many threads are running for the current value of the "
     371             :                 "dataset pool size (%d).\n"
     372             :                 "or too many proxy datasets are opened in a cascaded way.\n"
     373             :                 "Try increasing GDAL_MAX_DATASET_POOL_SIZE.",
     374             :                 maxSize);
     375           0 :             return nullptr;
     376             :         }
     377             : 
     378         793 :         CPLAssert(firstEntry);
     379         793 :         cur = firstEntry;
     380             :     }
     381             :     else
     382             :     {
     383             :         /* Prepend */
     384             :         cur = static_cast<GDALProxyPoolCacheEntry *>(
     385         589 :             CPLCalloc(1, sizeof(GDALProxyPoolCacheEntry)));
     386         589 :         if (lastEntry == nullptr)
     387         294 :             lastEntry = cur;
     388         589 :         cur->prev = nullptr;
     389         589 :         cur->next = firstEntry;
     390         589 :         if (firstEntry)
     391         295 :             firstEntry->prev = cur;
     392         589 :         firstEntry = cur;
     393         589 :         currentSize++;
     394             : #ifdef DEBUG_PROXY_POOL
     395             :         CheckLinks();
     396             : #endif
     397             :     }
     398             : 
     399        1382 :     cur->pszFileNameAndOpenOptions = CPLStrdup(osFilenameAndOO.c_str());
     400        1382 :     cur->pszOwner = (pszOwner) ? CPLStrdup(pszOwner) : nullptr;
     401        1382 :     cur->responsiblePID = responsiblePID;
     402        1382 :     cur->refCount = -1;  // to mark loading of dataset in progress
     403        1382 :     cur->nRAMUsage = 0;
     404             : 
     405        1382 :     refCountOfDisabledRefCount++;
     406        1382 :     const int nFlag =
     407             :         ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) |
     408        1382 :         GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
     409        1382 :     CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
     410             : 
     411             :     // Release mutex while opening dataset to avoid lock contention.
     412        1382 :     CPLReleaseMutex(*pMutex);
     413        1382 :     auto poDS = GDALDataset::Open(pszFileName, nFlag, nullptr, papszOpenOptions,
     414             :                                   nullptr);
     415        1382 :     CPLAcquireMutex(*pMutex, 1000.0);
     416             : 
     417        1382 :     cur->poDS = poDS;
     418        1382 :     cur->refCount = 1;
     419             : 
     420        1382 :     refCountOfDisabledRefCount--;
     421             : 
     422        1382 :     if (cur->poDS)
     423             :     {
     424        1172 :         cur->nRAMUsage =
     425        1172 :             std::max<GIntBig>(0, cur->poDS->GetEstimatedRAMUsage());
     426        1172 :         nRAMUsage += cur->nRAMUsage;
     427             :     }
     428             : 
     429        1382 :     if (nMaxRAMUsage > 0 && cur->nRAMUsage > 0)
     430             :     {
     431         100 :         while (nRAMUsage > nMaxRAMUsage && nRAMUsage != cur->nRAMUsage &&
     432           0 :                EvictEntryWithZeroRefCount(true))
     433             :         {
     434             :             // ok
     435             :         }
     436             :     }
     437             : 
     438        1382 :     return cur;
     439             : }
     440             : 
     441             : /************************************************************************/
     442             : /*                   _CloseDatasetIfZeroRefCount()                      */
     443             : /************************************************************************/
     444             : 
     445        2467 : void GDALDatasetPool::_CloseDatasetIfZeroRefCount(const char *pszFileName,
     446             :                                                   CSLConstList papszOpenOptions,
     447             :                                                   GDALAccess /* eAccess */,
     448             :                                                   const char *pszOwner)
     449             : {
     450             :     // May fix https://github.com/OSGeo/gdal/issues/4318
     451        2467 :     if (bInDestruction)
     452           0 :         return;
     453             : 
     454        2467 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     455        2467 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     456             : 
     457             :     const std::string osFilenameAndOO =
     458        4934 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     459             : 
     460       77664 :     while (cur)
     461             :     {
     462       76367 :         GDALProxyPoolCacheEntry *next = cur->next;
     463             : 
     464       93491 :         if (cur->refCount == 0 && cur->pszFileNameAndOpenOptions &&
     465       18519 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     466        1391 :             ((pszOwner == nullptr && cur->pszOwner == nullptr) ||
     467        1239 :              (pszOwner != nullptr && cur->pszOwner != nullptr &&
     468      153968 :               strcmp(cur->pszOwner, pszOwner) == 0)) &&
     469        1385 :             cur->poDS != nullptr)
     470             :         {
     471             :             /* Close by pretending we are the thread that GDALOpen'ed this */
     472             :             /* dataset */
     473        1170 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     474             : 
     475        1170 :             GDALDataset *poDS = cur->poDS;
     476             : 
     477        1170 :             nRAMUsage -= cur->nRAMUsage;
     478        1170 :             cur->nRAMUsage = 0;
     479             : 
     480        1170 :             cur->poDS = nullptr;
     481        1170 :             CPLFree(cur->pszFileNameAndOpenOptions);
     482        1170 :             cur->pszFileNameAndOpenOptions = nullptr;
     483        1170 :             CPLFree(cur->pszOwner);
     484        1170 :             cur->pszOwner = nullptr;
     485             : 
     486        1170 :             refCountOfDisabledRefCount++;
     487        1170 :             GDALClose(poDS);
     488        1170 :             refCountOfDisabledRefCount--;
     489             : 
     490        1170 :             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     491        1170 :             break;
     492             :         }
     493             : 
     494       75197 :         cur = next;
     495             :     }
     496             : }
     497             : 
     498             : /************************************************************************/
     499             : /*                       GDALGetMaxDatasetPoolSize()                    */
     500             : /************************************************************************/
     501             : 
     502             : /** Return the maximum number of datasets simultaneously opened in the
     503             :  * dataset pool.
     504             :  */
     505         379 : int GDALGetMaxDatasetPoolSize()
     506             : {
     507         379 :     int nSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
     508         379 :     if (nSize < 2)
     509           0 :         nSize = 2;
     510         379 :     else if (nSize > 1000)
     511           0 :         nSize = 1000;
     512         379 :     return nSize;
     513             : }
     514             : 
     515             : /************************************************************************/
     516             : /*                                 Ref()                                */
     517             : /************************************************************************/
     518             : 
     519        2467 : void GDALDatasetPool::Ref()
     520             : {
     521        4934 :     CPLMutexHolderD(GDALGetphDLMutex());
     522        2467 :     if (singleton == nullptr)
     523             :     {
     524             : 
     525             :         // Try to not consume more than 25% of the usable RAM
     526             :         GIntBig l_nMaxRAMUsage =
     527         342 :             (CPLGetUsablePhysicalRAM() - GDALGetCacheMax64()) / 4;
     528             :         const char *pszMaxRAMUsage =
     529         342 :             CPLGetConfigOption("GDAL_MAX_DATASET_POOL_RAM_USAGE", nullptr);
     530         342 :         if (pszMaxRAMUsage)
     531             :         {
     532           0 :             l_nMaxRAMUsage = std::strtoll(pszMaxRAMUsage, nullptr, 10);
     533           0 :             if (strstr(pszMaxRAMUsage, "MB"))
     534           0 :                 l_nMaxRAMUsage *= 1024 * 1024;
     535           0 :             else if (strstr(pszMaxRAMUsage, "GB"))
     536           0 :                 l_nMaxRAMUsage *= 1024 * 1024 * 1024;
     537             :         }
     538             : 
     539         342 :         singleton =
     540         342 :             new GDALDatasetPool(GDALGetMaxDatasetPoolSize(), l_nMaxRAMUsage);
     541             :     }
     542        2467 :     if (refCountOfDisabledRefCount == 0)
     543        2467 :         singleton->refCount++;
     544        2467 : }
     545             : 
     546             : /* keep that in sync with gdaldrivermanager.cpp */
     547         933 : void GDALDatasetPool::PreventDestroy()
     548             : {
     549         933 :     CPLMutexHolderD(GDALGetphDLMutex());
     550         933 :     if (!singleton)
     551         930 :         return;
     552           3 :     refCountOfDisabledRefCount++;
     553             : }
     554             : 
     555             : /* keep that in sync with gdaldrivermanager.cpp */
     556             : extern void GDALDatasetPoolPreventDestroy();
     557             : 
     558         933 : void GDALDatasetPoolPreventDestroy()
     559             : {
     560         933 :     GDALDatasetPool::PreventDestroy();
     561         933 : }
     562             : 
     563             : /************************************************************************/
     564             : /*                               Unref()                                */
     565             : /************************************************************************/
     566             : 
     567        2467 : void GDALDatasetPool::Unref()
     568             : {
     569        2467 :     CPLMutexHolderD(GDALGetphDLMutex());
     570        2467 :     if (!singleton)
     571             :     {
     572           0 :         CPLAssert(false);
     573             :         return;
     574             :     }
     575        2467 :     if (refCountOfDisabledRefCount == 0)
     576             :     {
     577        2437 :         singleton->refCount--;
     578        2437 :         if (singleton->refCount == 0)
     579             :         {
     580         336 :             delete singleton;
     581         336 :             singleton = nullptr;
     582             :         }
     583             :     }
     584             : }
     585             : 
     586             : /* keep that in sync with gdaldrivermanager.cpp */
     587         933 : void GDALDatasetPool::ForceDestroy()
     588             : {
     589         933 :     CPLMutexHolderD(GDALGetphDLMutex());
     590         933 :     if (!singleton)
     591         930 :         return;
     592           3 :     refCountOfDisabledRefCount--;
     593           3 :     CPLAssert(refCountOfDisabledRefCount == 0);
     594           3 :     singleton->refCount = 0;
     595           3 :     delete singleton;
     596           3 :     singleton = nullptr;
     597             : }
     598             : 
     599             : /* keep that in sync with gdaldrivermanager.cpp */
     600             : extern void GDALDatasetPoolForceDestroy();
     601             : 
     602         933 : void GDALDatasetPoolForceDestroy()
     603             : {
     604         933 :     GDALDatasetPool::ForceDestroy();
     605         933 : }
     606             : 
     607             : /************************************************************************/
     608             : /*                           RefDataset()                               */
     609             : /************************************************************************/
     610             : 
     611             : GDALProxyPoolCacheEntry *
     612       25522 : GDALDatasetPool::RefDataset(const char *pszFileName, GDALAccess eAccess,
     613             :                             char **papszOpenOptions, int bShared,
     614             :                             bool bForceOpen, const char *pszOwner)
     615             : {
     616       25522 :     return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions,
     617       25523 :                                   bShared, bForceOpen, pszOwner);
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                       UnrefDataset()                                 */
     622             : /************************************************************************/
     623             : 
     624       23399 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry)
     625             : {
     626       23399 :     CPLMutexHolderD(GDALGetphDLMutex());
     627       23400 :     cacheEntry->refCount--;
     628       23400 : }
     629             : 
     630             : /************************************************************************/
     631             : /*                   CloseDatasetIfZeroRefCount()                       */
     632             : /************************************************************************/
     633             : 
     634        2467 : void GDALDatasetPool::CloseDatasetIfZeroRefCount(const char *pszFileName,
     635             :                                                  CSLConstList papszOpenOptions,
     636             :                                                  GDALAccess eAccess,
     637             :                                                  const char *pszOwner)
     638             : {
     639        4934 :     CPLMutexHolderD(GDALGetphDLMutex());
     640        2467 :     singleton->_CloseDatasetIfZeroRefCount(pszFileName, papszOpenOptions,
     641             :                                            eAccess, pszOwner);
     642        2467 : }
     643             : 
     644             : struct GetMetadataElt
     645             : {
     646             :     char *pszDomain;
     647             :     char **papszMetadata;
     648             : };
     649             : 
     650          42 : static unsigned long hash_func_get_metadata(const void *_elt)
     651             : {
     652          42 :     const GetMetadataElt *elt = static_cast<const GetMetadataElt *>(_elt);
     653          42 :     return CPLHashSetHashStr(elt->pszDomain);
     654             : }
     655             : 
     656           8 : static int equal_func_get_metadata(const void *_elt1, const void *_elt2)
     657             : {
     658           8 :     const GetMetadataElt *elt1 = static_cast<const GetMetadataElt *>(_elt1);
     659           8 :     const GetMetadataElt *elt2 = static_cast<const GetMetadataElt *>(_elt2);
     660           8 :     return CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
     661             : }
     662             : 
     663          24 : static void free_func_get_metadata(void *_elt)
     664             : {
     665          24 :     GetMetadataElt *elt = static_cast<GetMetadataElt *>(_elt);
     666          24 :     CPLFree(elt->pszDomain);
     667          24 :     CSLDestroy(elt->papszMetadata);
     668          24 :     CPLFree(elt);
     669          24 : }
     670             : 
     671             : struct GetMetadataItemElt
     672             : {
     673             :     char *pszName;
     674             :     char *pszDomain;
     675             :     char *pszMetadataItem;
     676             : };
     677             : 
     678          68 : static unsigned long hash_func_get_metadata_item(const void *_elt)
     679             : {
     680          68 :     const GetMetadataItemElt *elt =
     681             :         static_cast<const GetMetadataItemElt *>(_elt);
     682          68 :     return CPLHashSetHashStr(elt->pszName) ^ CPLHashSetHashStr(elt->pszDomain);
     683             : }
     684             : 
     685          18 : static int equal_func_get_metadata_item(const void *_elt1, const void *_elt2)
     686             : {
     687          18 :     const GetMetadataItemElt *elt1 =
     688             :         static_cast<const GetMetadataItemElt *>(_elt1);
     689          18 :     const GetMetadataItemElt *elt2 =
     690             :         static_cast<const GetMetadataItemElt *>(_elt2);
     691          36 :     return CPLHashSetEqualStr(elt1->pszName, elt2->pszName) &&
     692          36 :            CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
     693             : }
     694             : 
     695          43 : static void free_func_get_metadata_item(void *_elt)
     696             : {
     697          43 :     GetMetadataItemElt *elt = static_cast<GetMetadataItemElt *>(_elt);
     698          43 :     CPLFree(elt->pszName);
     699          43 :     CPLFree(elt->pszDomain);
     700          43 :     CPLFree(elt->pszMetadataItem);
     701          43 :     CPLFree(elt);
     702          43 : }
     703             : 
     704             : /* ******************************************************************** */
     705             : /*                     GDALProxyPoolDataset                             */
     706             : /* ******************************************************************** */
     707             : 
     708             : /* Note : the bShared parameter must be used with caution. You can */
     709             : /* set it to TRUE  for being used as a VRT source : in that case, */
     710             : /* VRTSimpleSource will take care of destroying it when there are no */
     711             : /* reference to it (in VRTSimpleSource::~VRTSimpleSource()) */
     712             : /* However this will not be registered as a genuine shared dataset, like it */
     713             : /* would have been with MarkAsShared(). But MarkAsShared() is not usable for */
     714             : /* GDALProxyPoolDataset objects, as they share the same description as their */
     715             : /* underlying dataset. So *NEVER* call MarkAsShared() on a GDALProxyPoolDataset
     716             :  */
     717             : /* object */
     718             : 
     719             : /* pszOwner is only honoured in the bShared case, and restrict the scope */
     720             : /* of the sharing. Only calls to _RefDataset() with the same value of */
     721             : /* pszOwner can effectively use the same dataset. The use case is */
     722             : /* to avoid 2 VRTs (potentially the same one) opened by a single thread,
     723             :  * pointing to */
     724             : /* the same source datasets. In that case, they would use the same dataset */
     725             : /* So even if the VRT handles themselves are used from different threads, since
     726             :  */
     727             : /* the underlying sources are shared, that might cause crashes (#6939). */
     728             : /* But we want to allow a same VRT referencing the same source dataset,*/
     729             : /* for example if it has multiple bands. So in practice the value of pszOwner */
     730             : /* is the serialized value (%p formatting) of the VRT dataset handle. */
     731             : 
     732        1219 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     733             :     const char *pszSourceDatasetDescription, int nRasterXSizeIn,
     734             :     int nRasterYSizeIn, GDALAccess eAccessIn, int bSharedIn,
     735             :     const char *pszProjectionRefIn, double *padfGeoTransform,
     736        1219 :     const char *pszOwner)
     737        2438 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread()),
     738        1219 :       pszProjectionRef(pszProjectionRefIn ? CPLStrdup(pszProjectionRefIn)
     739        1219 :                                           : nullptr)
     740             : {
     741        1219 :     GDALDatasetPool::Ref();
     742             : 
     743        1219 :     SetDescription(pszSourceDatasetDescription);
     744             : 
     745        1219 :     nRasterXSize = nRasterXSizeIn;
     746        1219 :     nRasterYSize = nRasterYSizeIn;
     747        1219 :     eAccess = eAccessIn;
     748             : 
     749        1219 :     bShared = CPL_TO_BOOL(bSharedIn);
     750        1219 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     751             : 
     752        1219 :     if (padfGeoTransform)
     753             :     {
     754        1170 :         memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
     755        1170 :         bHasSrcGeoTransform = true;
     756             :     }
     757             :     else
     758             :     {
     759          49 :         adfGeoTransform[0] = 0;
     760          49 :         adfGeoTransform[1] = 1;
     761          49 :         adfGeoTransform[2] = 0;
     762          49 :         adfGeoTransform[3] = 0;
     763          49 :         adfGeoTransform[4] = 0;
     764          49 :         adfGeoTransform[5] = 1;
     765          49 :         bHasSrcGeoTransform = false;
     766             :     }
     767             : 
     768        1219 :     if (pszProjectionRefIn)
     769             :     {
     770        1180 :         m_poSRS = new OGRSpatialReference();
     771        1180 :         m_poSRS->importFromWkt(pszProjectionRefIn);
     772        1180 :         m_bHasSrcSRS = true;
     773             :     }
     774        1219 : }
     775             : 
     776             : /* Constructor where the parameters (raster size, etc.) are obtained
     777             :  * by opening the underlying dataset.
     778             :  */
     779        1248 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     780             :     const char *pszSourceDatasetDescription, GDALAccess eAccessIn,
     781        1248 :     int bSharedIn, const char *pszOwner)
     782        1248 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread())
     783             : {
     784        1248 :     GDALDatasetPool::Ref();
     785             : 
     786        1248 :     SetDescription(pszSourceDatasetDescription);
     787             : 
     788        1248 :     eAccess = eAccessIn;
     789             : 
     790        1248 :     bShared = CPL_TO_BOOL(bSharedIn);
     791        1248 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     792        1248 : }
     793             : 
     794             : /************************************************************************/
     795             : /*                              Create()                                */
     796             : /************************************************************************/
     797             : 
     798             : /* Instantiate a GDALProxyPoolDataset where the parameters (raster size, etc.)
     799             :  * are obtained by opening the underlying dataset.
     800             :  * Its bands are also instantiated.
     801             :  */
     802        1248 : GDALProxyPoolDataset *GDALProxyPoolDataset::Create(
     803             :     const char *pszSourceDatasetDescription, CSLConstList papszOpenOptionsIn,
     804             :     GDALAccess eAccessIn, int bSharedIn, const char *pszOwner)
     805             : {
     806             :     std::unique_ptr<GDALProxyPoolDataset> poSelf(new GDALProxyPoolDataset(
     807        2496 :         pszSourceDatasetDescription, eAccessIn, bSharedIn, pszOwner));
     808        1248 :     poSelf->SetOpenOptions(papszOpenOptionsIn);
     809        1248 :     GDALDataset *poUnderlyingDS = poSelf->RefUnderlyingDataset();
     810        1248 :     if (!poUnderlyingDS)
     811         215 :         return nullptr;
     812        1033 :     poSelf->nRasterXSize = poUnderlyingDS->GetRasterXSize();
     813        1033 :     poSelf->nRasterYSize = poUnderlyingDS->GetRasterYSize();
     814        1033 :     if (poUnderlyingDS->GetGeoTransform(poSelf->adfGeoTransform) == CE_None)
     815         873 :         poSelf->bHasSrcGeoTransform = true;
     816        1032 :     const auto poSRS = poUnderlyingDS->GetSpatialRef();
     817        1033 :     if (poSRS)
     818             :     {
     819         798 :         poSelf->m_poSRS = poSRS->Clone();
     820         797 :         poSelf->m_bHasSrcSRS = true;
     821             :     }
     822        3132 :     for (int i = 1; i <= poUnderlyingDS->GetRasterCount(); ++i)
     823             :     {
     824        2099 :         auto poSrcBand = poUnderlyingDS->GetRasterBand(i);
     825        2100 :         if (!poSrcBand)
     826             :         {
     827           0 :             poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     828           0 :             return nullptr;
     829             :         }
     830             :         int nSrcBlockXSize, nSrcBlockYSize;
     831        2100 :         poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
     832        2099 :         poSelf->AddSrcBandDescription(poSrcBand->GetRasterDataType(),
     833             :                                       nSrcBlockXSize, nSrcBlockYSize);
     834             :     }
     835        1033 :     poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     836        1033 :     return poSelf.release();
     837             : }
     838             : 
     839             : /************************************************************************/
     840             : /*                    ~GDALProxyPoolDataset()                           */
     841             : /************************************************************************/
     842             : 
     843        4924 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
     844             : {
     845        2467 :     GDALDatasetPool::CloseDatasetIfZeroRefCount(
     846        2467 :         GetDescription(), papszOpenOptions, eAccess, m_pszOwner);
     847             : 
     848             :     /* See comment in constructor */
     849             :     /* It is not really a genuine shared dataset, so we don't */
     850             :     /* want ~GDALDataset() to try to release it from its */
     851             :     /* shared dataset hashset. This will save a */
     852             :     /* "Should not happen. Cannot find %s, this=%p in phSharedDatasetSet" debug
     853             :      * message */
     854        2467 :     bShared = false;
     855             : 
     856        2467 :     CPLFree(pszProjectionRef);
     857        2467 :     CPLFree(pszGCPProjection);
     858        2467 :     if (nGCPCount)
     859             :     {
     860           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     861           0 :         CPLFree(pasGCPList);
     862             :     }
     863        2467 :     if (metadataSet)
     864           4 :         CPLHashSetDestroy(metadataSet);
     865        2467 :     if (metadataItemSet)
     866           2 :         CPLHashSetDestroy(metadataItemSet);
     867        2467 :     CPLFree(m_pszOwner);
     868        2467 :     if (m_poSRS)
     869        1978 :         m_poSRS->Release();
     870        2467 :     if (m_poGCPSRS)
     871           0 :         m_poGCPSRS->Release();
     872             : 
     873        2467 :     GDALDatasetPool::Unref();
     874        4924 : }
     875             : 
     876             : /************************************************************************/
     877             : /*                        SetOpenOptions()                              */
     878             : /************************************************************************/
     879             : 
     880        2418 : void GDALProxyPoolDataset::SetOpenOptions(CSLConstList papszOpenOptionsIn)
     881             : {
     882        2418 :     CPLAssert(papszOpenOptions == nullptr);
     883        2418 :     papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
     884        2418 : }
     885             : 
     886             : /************************************************************************/
     887             : /*                    AddSrcBandDescription()                           */
     888             : /************************************************************************/
     889             : 
     890        4393 : void GDALProxyPoolDataset::AddSrcBandDescription(GDALDataType eDataType,
     891             :                                                  int nBlockXSize,
     892             :                                                  int nBlockYSize)
     893             : {
     894        4393 :     SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType,
     895        4393 :                                                     nBlockXSize, nBlockYSize));
     896        4393 : }
     897             : 
     898             : /************************************************************************/
     899             : /*                    AddSrcBand()                                      */
     900             : /************************************************************************/
     901             : 
     902           0 : void GDALProxyPoolDataset::AddSrcBand(int nBand, GDALDataType eDataType,
     903             :                                       int nBlockXSize, int nBlockYSize)
     904             : {
     905           0 :     SetBand(nBand, new GDALProxyPoolRasterBand(this, nBand, eDataType,
     906           0 :                                                nBlockXSize, nBlockYSize));
     907           0 : }
     908             : 
     909             : /************************************************************************/
     910             : /*                    RefUnderlyingDataset()                            */
     911             : /************************************************************************/
     912             : 
     913        2511 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset() const
     914             : {
     915        2511 :     return RefUnderlyingDataset(true);
     916             : }
     917             : 
     918       25522 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset(bool bForceOpen) const
     919             : {
     920             :     /* We pretend that the current thread is responsiblePID, that is */
     921             :     /* to say the thread that created that GDALProxyPoolDataset object. */
     922             :     /* This is for the case when a GDALProxyPoolDataset is created by a */
     923             :     /* thread and used by other threads. These other threads, when doing actual
     924             :      */
     925             :     /* IO, will come there and potentially open the underlying dataset. */
     926             :     /* By doing this, they can indirectly call GDALOpenShared() on .aux file */
     927             :     /* for example. So this call to GDALOpenShared() must occur as if it */
     928             :     /* was done by the creating thread, otherwise it will not be correctly
     929             :      * closed afterwards... */
     930             :     /* To make a long story short : this is necessary when warping with
     931             :      * ChunkAndWarpMulti */
     932             :     /* a VRT of GeoTIFFs that have associated .aux files */
     933       25522 :     GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
     934       25523 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     935       25523 :     cacheEntry =
     936       25521 :         GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
     937       25523 :                                     GetShared(), bForceOpen, m_pszOwner);
     938       25523 :     GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
     939       25523 :     if (cacheEntry != nullptr)
     940             :     {
     941       23400 :         if (cacheEntry->poDS != nullptr)
     942       23185 :             return cacheEntry->poDS;
     943             :         else
     944         215 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     945             :     }
     946        2338 :     return nullptr;
     947             : }
     948             : 
     949             : /************************************************************************/
     950             : /*                    UnrefUnderlyingDataset()                        */
     951             : /************************************************************************/
     952             : 
     953       23185 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(
     954             :     CPL_UNUSED GDALDataset *poUnderlyingDataset) const
     955             : {
     956       23185 :     if (cacheEntry != nullptr)
     957             :     {
     958       23185 :         CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
     959       23185 :         if (cacheEntry->poDS != nullptr)
     960       23184 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     961             :     }
     962       23186 : }
     963             : 
     964             : /************************************************************************/
     965             : /*                         FlushCache()                                 */
     966             : /************************************************************************/
     967             : 
     968           0 : CPLErr GDALProxyPoolDataset::FlushCache(bool bAtClosing)
     969             : {
     970           0 :     CPLErr eErr = CE_None;
     971           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset(false);
     972           0 :     if (poUnderlyingDataset)
     973             :     {
     974           0 :         eErr = poUnderlyingDataset->FlushCache(bAtClosing);
     975           0 :         UnrefUnderlyingDataset(poUnderlyingDataset);
     976             :     }
     977           0 :     return eErr;
     978             : }
     979             : 
     980             : /************************************************************************/
     981             : /*                        SetSpatialRef()                               */
     982             : /************************************************************************/
     983             : 
     984           0 : CPLErr GDALProxyPoolDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     985             : {
     986           0 :     m_bHasSrcSRS = false;
     987           0 :     return GDALProxyDataset::SetSpatialRef(poSRS);
     988             : }
     989             : 
     990             : /************************************************************************/
     991             : /*                        GetSpatialRef()                               */
     992             : /************************************************************************/
     993             : 
     994         200 : const OGRSpatialReference *GDALProxyPoolDataset::GetSpatialRef() const
     995             : {
     996         200 :     if (m_bHasSrcSRS)
     997         198 :         return m_poSRS;
     998             :     else
     999             :     {
    1000           2 :         if (m_poSRS)
    1001           0 :             m_poSRS->Release();
    1002           2 :         m_poSRS = nullptr;
    1003           2 :         auto poSRS = GDALProxyDataset::GetSpatialRef();
    1004           2 :         if (poSRS)
    1005           0 :             m_poSRS = poSRS->Clone();
    1006           2 :         return m_poSRS;
    1007             :     }
    1008             : }
    1009             : 
    1010             : /************************************************************************/
    1011             : /*                        SetGeoTransform()                             */
    1012             : /************************************************************************/
    1013             : 
    1014           0 : CPLErr GDALProxyPoolDataset::SetGeoTransform(double *padfGeoTransform)
    1015             : {
    1016           0 :     bHasSrcGeoTransform = false;
    1017           0 :     return GDALProxyDataset::SetGeoTransform(padfGeoTransform);
    1018             : }
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                        GetGeoTransform()                             */
    1022             : /************************************************************************/
    1023             : 
    1024         565 : CPLErr GDALProxyPoolDataset::GetGeoTransform(double *padfGeoTransform)
    1025             : {
    1026         565 :     if (bHasSrcGeoTransform)
    1027             :     {
    1028         565 :         memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
    1029         565 :         return CE_None;
    1030             :     }
    1031             :     else
    1032             :     {
    1033           0 :         return GDALProxyDataset::GetGeoTransform(padfGeoTransform);
    1034             :     }
    1035             : }
    1036             : 
    1037             : /************************************************************************/
    1038             : /*                            GetMetadata()                             */
    1039             : /************************************************************************/
    1040             : 
    1041          22 : char **GDALProxyPoolDataset::GetMetadata(const char *pszDomain)
    1042             : {
    1043          22 :     if (metadataSet == nullptr)
    1044           4 :         metadataSet =
    1045           4 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1046             :                           free_func_get_metadata);
    1047             : 
    1048          22 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1049          22 :     if (poUnderlyingDataset == nullptr)
    1050           0 :         return nullptr;
    1051             : 
    1052             :     char **papszUnderlyingMetadata =
    1053          22 :         poUnderlyingDataset->GetMetadata(pszDomain);
    1054             : 
    1055             :     GetMetadataElt *pElt =
    1056          22 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1057          22 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1058          22 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1059          22 :     CPLHashSetInsert(metadataSet, pElt);
    1060             : 
    1061          22 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1062             : 
    1063          22 :     return pElt->papszMetadata;
    1064             : }
    1065             : 
    1066             : /************************************************************************/
    1067             : /*                        GetMetadataItem()                             */
    1068             : /************************************************************************/
    1069             : 
    1070           4 : const char *GDALProxyPoolDataset::GetMetadataItem(const char *pszName,
    1071             :                                                   const char *pszDomain)
    1072             : {
    1073           4 :     if (metadataItemSet == nullptr)
    1074           2 :         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
    1075             :                                         equal_func_get_metadata_item,
    1076             :                                         free_func_get_metadata_item);
    1077             : 
    1078           4 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1079           4 :     if (poUnderlyingDataset == nullptr)
    1080           0 :         return nullptr;
    1081             : 
    1082             :     const char *pszUnderlyingMetadataItem =
    1083           4 :         poUnderlyingDataset->GetMetadataItem(pszName, pszDomain);
    1084             : 
    1085             :     GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
    1086           4 :         CPLMalloc(sizeof(GetMetadataItemElt)));
    1087           4 :     pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
    1088           4 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1089           4 :     pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
    1090           4 :                                 ? CPLStrdup(pszUnderlyingMetadataItem)
    1091             :                                 : nullptr;
    1092           4 :     CPLHashSetInsert(metadataItemSet, pElt);
    1093             : 
    1094           4 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1095             : 
    1096           4 :     return pElt->pszMetadataItem;
    1097             : }
    1098             : 
    1099             : /************************************************************************/
    1100             : /*                      GetInternalHandle()                             */
    1101             : /************************************************************************/
    1102             : 
    1103           0 : void *GDALProxyPoolDataset::GetInternalHandle(const char *pszRequest)
    1104             : {
    1105           0 :     CPLError(
    1106             :         CE_Warning, CPLE_AppDefined,
    1107             :         "GetInternalHandle() cannot be safely called on a proxy pool dataset\n"
    1108             :         "as the returned value may be invalidated at any time.\n");
    1109           0 :     return GDALProxyDataset::GetInternalHandle(pszRequest);
    1110             : }
    1111             : 
    1112             : /************************************************************************/
    1113             : /*                     GetGCPSpatialRef()                               */
    1114             : /************************************************************************/
    1115             : 
    1116           0 : const OGRSpatialReference *GDALProxyPoolDataset::GetGCPSpatialRef() const
    1117             : {
    1118           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1119           0 :     if (poUnderlyingDataset == nullptr)
    1120           0 :         return nullptr;
    1121             : 
    1122           0 :     m_poGCPSRS->Release();
    1123           0 :     m_poGCPSRS = nullptr;
    1124             : 
    1125           0 :     const auto poUnderlyingGCPSRS = poUnderlyingDataset->GetGCPSpatialRef();
    1126           0 :     if (poUnderlyingGCPSRS)
    1127           0 :         m_poGCPSRS = poUnderlyingGCPSRS->Clone();
    1128             : 
    1129           0 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1130             : 
    1131           0 :     return m_poGCPSRS;
    1132             : }
    1133             : 
    1134             : /************************************************************************/
    1135             : /*                            GetGCPs()                                 */
    1136             : /************************************************************************/
    1137             : 
    1138           0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
    1139             : {
    1140           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1141           0 :     if (poUnderlyingDataset == nullptr)
    1142           0 :         return nullptr;
    1143             : 
    1144           0 :     if (nGCPCount)
    1145             :     {
    1146           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
    1147           0 :         CPLFree(pasGCPList);
    1148           0 :         pasGCPList = nullptr;
    1149             :     }
    1150             : 
    1151           0 :     const GDAL_GCP *pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
    1152           0 :     nGCPCount = poUnderlyingDataset->GetGCPCount();
    1153           0 :     if (nGCPCount)
    1154           0 :         pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList);
    1155             : 
    1156           0 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1157             : 
    1158           0 :     return pasGCPList;
    1159             : }
    1160             : 
    1161             : /************************************************************************/
    1162             : /*                     GDALProxyPoolDatasetCreate()                     */
    1163             : /************************************************************************/
    1164             : 
    1165        1170 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(
    1166             :     const char *pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize,
    1167             :     GDALAccess eAccess, int bShared, const char *pszProjectionRef,
    1168             :     double *padfGeoTransform)
    1169             : {
    1170             :     return reinterpret_cast<GDALProxyPoolDatasetH>(new GDALProxyPoolDataset(
    1171             :         pszSourceDatasetDescription, nRasterXSize, nRasterYSize, eAccess,
    1172        1170 :         bShared, pszProjectionRef, padfGeoTransform));
    1173             : }
    1174             : 
    1175             : /************************************************************************/
    1176             : /*                       GDALProxyPoolDatasetDelete()                   */
    1177             : /************************************************************************/
    1178             : 
    1179           0 : void GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
    1180             : {
    1181           0 :     delete reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset);
    1182           0 : }
    1183             : 
    1184             : /************************************************************************/
    1185             : /*              GDALProxyPoolDatasetAddSrcBandDescription()             */
    1186             : /************************************************************************/
    1187             : 
    1188        2253 : void GDALProxyPoolDatasetAddSrcBandDescription(
    1189             :     GDALProxyPoolDatasetH hProxyPoolDataset, GDALDataType eDataType,
    1190             :     int nBlockXSize, int nBlockYSize)
    1191             : {
    1192             :     reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset)
    1193        2253 :         ->AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
    1194        2253 : }
    1195             : 
    1196             : /* ******************************************************************** */
    1197             : /*                    GDALProxyPoolRasterBand()                         */
    1198             : /* ******************************************************************** */
    1199             : 
    1200        4410 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset *poDSIn,
    1201             :                                                  int nBandIn,
    1202             :                                                  GDALDataType eDataTypeIn,
    1203             :                                                  int nBlockXSizeIn,
    1204        4410 :                                                  int nBlockYSizeIn)
    1205             : {
    1206        4410 :     poDS = poDSIn;
    1207        4410 :     nBand = nBandIn;
    1208        4410 :     eDataType = eDataTypeIn;
    1209        4410 :     nRasterXSize = poDSIn->GetRasterXSize();
    1210        4409 :     nRasterYSize = poDSIn->GetRasterYSize();
    1211        4410 :     nBlockXSize = nBlockXSizeIn;
    1212        4410 :     nBlockYSize = nBlockYSizeIn;
    1213        4410 : }
    1214             : 
    1215             : /* ******************************************************************** */
    1216             : /*                    GDALProxyPoolRasterBand()                         */
    1217             : /* ******************************************************************** */
    1218             : 
    1219          52 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(
    1220          52 :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingRasterBand)
    1221             : {
    1222          52 :     poDS = poDSIn;
    1223          52 :     nBand = poUnderlyingRasterBand->GetBand();
    1224          52 :     eDataType = poUnderlyingRasterBand->GetRasterDataType();
    1225          52 :     nRasterXSize = poUnderlyingRasterBand->GetXSize();
    1226          52 :     nRasterYSize = poUnderlyingRasterBand->GetYSize();
    1227          52 :     poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    1228          52 : }
    1229             : 
    1230             : /* ******************************************************************** */
    1231             : /*                   ~GDALProxyPoolRasterBand()                         */
    1232             : /* ******************************************************************** */
    1233        8855 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
    1234             : {
    1235        4462 :     if (metadataSet)
    1236           2 :         CPLHashSetDestroy(metadataSet);
    1237        4462 :     if (metadataItemSet)
    1238          19 :         CPLHashSetDestroy(metadataItemSet);
    1239        4462 :     CPLFree(pszUnitType);
    1240        4462 :     CSLDestroy(papszCategoryNames);
    1241        4462 :     if (poColorTable)
    1242           6 :         delete poColorTable;
    1243             : 
    1244        4486 :     for (int i = 0; i < nSizeProxyOverviewRasterBand; i++)
    1245             :     {
    1246          24 :         if (papoProxyOverviewRasterBand[i])
    1247          24 :             delete papoProxyOverviewRasterBand[i];
    1248             :     }
    1249        4462 :     CPLFree(papoProxyOverviewRasterBand);
    1250        4462 :     if (poProxyMaskBand)
    1251          45 :         delete poProxyMaskBand;
    1252        8855 : }
    1253             : 
    1254             : /************************************************************************/
    1255             : /*                AddSrcMaskBandDescriptionFromUnderlying()             */
    1256             : /************************************************************************/
    1257             : 
    1258          11 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescriptionFromUnderlying()
    1259             : {
    1260          11 :     if (poProxyMaskBand != nullptr)
    1261           2 :         return;
    1262           9 :     GDALRasterBand *poUnderlyingBand = RefUnderlyingRasterBand();
    1263           9 :     if (poUnderlyingBand == nullptr)
    1264           0 :         return;
    1265           9 :     auto poSrcMaskBand = poUnderlyingBand->GetMaskBand();
    1266             :     int nSrcBlockXSize, nSrcBlockYSize;
    1267           9 :     poSrcMaskBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1268           9 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1269           9 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this,
    1270           9 :         poSrcMaskBand->GetRasterDataType(), nSrcBlockXSize, nSrcBlockYSize);
    1271           9 :     UnrefUnderlyingRasterBand(poUnderlyingBand);
    1272             : }
    1273             : 
    1274             : /************************************************************************/
    1275             : /*                 AddSrcMaskBandDescription()                          */
    1276             : /************************************************************************/
    1277             : 
    1278           8 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescription(
    1279             :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1280             : {
    1281           8 :     CPLAssert(poProxyMaskBand == nullptr);
    1282           8 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1283           8 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this, eDataTypeIn,
    1284           8 :         nBlockXSizeIn, nBlockYSizeIn);
    1285           8 : }
    1286             : 
    1287             : /************************************************************************/
    1288             : /*                  RefUnderlyingRasterBand()                           */
    1289             : /************************************************************************/
    1290             : 
    1291             : GDALRasterBand *
    1292       23012 : GDALProxyPoolRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1293             : {
    1294             :     GDALDataset *poUnderlyingDataset =
    1295       23012 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1296       23012 :             ->RefUnderlyingDataset(bForceOpen);
    1297       23012 :     if (poUnderlyingDataset == nullptr)
    1298        2123 :         return nullptr;
    1299             : 
    1300       20889 :     GDALRasterBand *poBand = poUnderlyingDataset->GetRasterBand(nBand);
    1301       20889 :     if (poBand == nullptr)
    1302             :     {
    1303           0 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1304           0 :             ->UnrefUnderlyingDataset(poUnderlyingDataset);
    1305             :     }
    1306       20889 :     else if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1307             :     {
    1308             :         // Here we try to load nBlockXSize&nBlockYSize from underlying band
    1309             :         // but we must guarantee that we will not access directly to
    1310             :         // nBlockXSize/nBlockYSize before RefUnderlyingRasterBand() is called
    1311             :         int nSrcBlockXSize, nSrcBlockYSize;
    1312          10 :         poBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1313          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockXSize =
    1314             :             nSrcBlockXSize;
    1315          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockYSize =
    1316             :             nSrcBlockYSize;
    1317             :     }
    1318             : 
    1319       20889 :     return poBand;
    1320             : }
    1321             : 
    1322             : /************************************************************************/
    1323             : /*                  UnrefUnderlyingRasterBand()                       */
    1324             : /************************************************************************/
    1325             : 
    1326       20889 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(
    1327             :     GDALRasterBand *poUnderlyingRasterBand) const
    1328             : {
    1329       20889 :     if (poUnderlyingRasterBand)
    1330       20889 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1331       20889 :             ->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
    1332       20889 : }
    1333             : 
    1334             : /************************************************************************/
    1335             : /*                             FlushCache()                             */
    1336             : /************************************************************************/
    1337             : 
    1338        3366 : CPLErr GDALProxyPoolRasterBand::FlushCache(bool bAtClosing)
    1339             : {
    1340        3366 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand(false);
    1341        3366 :     if (poUnderlyingRasterBand)
    1342             :     {
    1343        1243 :         CPLErr eErr = poUnderlyingRasterBand->FlushCache(bAtClosing);
    1344        1243 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1345        1243 :         return eErr;
    1346             :     }
    1347        2123 :     return CE_None;
    1348             : }
    1349             : 
    1350             : /************************************************************************/
    1351             : /*                            GetMetadata()                             */
    1352             : /************************************************************************/
    1353             : 
    1354           2 : char **GDALProxyPoolRasterBand::GetMetadata(const char *pszDomain)
    1355             : {
    1356           2 :     if (metadataSet == nullptr)
    1357           2 :         metadataSet =
    1358           2 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1359             :                           free_func_get_metadata);
    1360             : 
    1361           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1362           2 :     if (poUnderlyingRasterBand == nullptr)
    1363           0 :         return nullptr;
    1364             : 
    1365             :     char **papszUnderlyingMetadata =
    1366           2 :         poUnderlyingRasterBand->GetMetadata(pszDomain);
    1367             : 
    1368             :     GetMetadataElt *pElt =
    1369           2 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1370           2 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1371           2 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1372           2 :     CPLHashSetInsert(metadataSet, pElt);
    1373             : 
    1374           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1375             : 
    1376           2 :     return pElt->papszMetadata;
    1377             : }
    1378             : 
    1379             : /************************************************************************/
    1380             : /*                        GetMetadataItem()                             */
    1381             : /************************************************************************/
    1382             : 
    1383          39 : const char *GDALProxyPoolRasterBand::GetMetadataItem(const char *pszName,
    1384             :                                                      const char *pszDomain)
    1385             : {
    1386          39 :     if (metadataItemSet == nullptr)
    1387          19 :         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
    1388             :                                         equal_func_get_metadata_item,
    1389             :                                         free_func_get_metadata_item);
    1390             : 
    1391          39 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1392          39 :     if (poUnderlyingRasterBand == nullptr)
    1393           0 :         return nullptr;
    1394             : 
    1395             :     const char *pszUnderlyingMetadataItem =
    1396          39 :         poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
    1397             : 
    1398             :     GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
    1399          39 :         CPLMalloc(sizeof(GetMetadataItemElt)));
    1400          39 :     pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
    1401          39 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1402          39 :     pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
    1403          39 :                                 ? CPLStrdup(pszUnderlyingMetadataItem)
    1404             :                                 : nullptr;
    1405          39 :     CPLHashSetInsert(metadataItemSet, pElt);
    1406             : 
    1407          39 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1408             : 
    1409          39 :     return pElt->pszMetadataItem;
    1410             : }
    1411             : 
    1412             : /* ******************************************************************** */
    1413             : /*                       GetCategoryNames()                             */
    1414             : /* ******************************************************************** */
    1415             : 
    1416           2 : char **GDALProxyPoolRasterBand::GetCategoryNames()
    1417             : {
    1418           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1419           2 :     if (poUnderlyingRasterBand == nullptr)
    1420           0 :         return nullptr;
    1421             : 
    1422           2 :     CSLDestroy(papszCategoryNames);
    1423           2 :     papszCategoryNames = nullptr;
    1424             : 
    1425             :     char **papszUnderlyingCategoryNames =
    1426           2 :         poUnderlyingRasterBand->GetCategoryNames();
    1427           2 :     if (papszUnderlyingCategoryNames)
    1428           0 :         papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
    1429             : 
    1430           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1431             : 
    1432           2 :     return papszCategoryNames;
    1433             : }
    1434             : 
    1435             : /* ******************************************************************** */
    1436             : /*                           GetUnitType()                              */
    1437             : /* ******************************************************************** */
    1438             : 
    1439           2 : const char *GDALProxyPoolRasterBand::GetUnitType()
    1440             : {
    1441           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1442           2 :     if (poUnderlyingRasterBand == nullptr)
    1443           0 :         return nullptr;
    1444             : 
    1445           2 :     CPLFree(pszUnitType);
    1446           2 :     pszUnitType = nullptr;
    1447             : 
    1448           2 :     const char *pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
    1449           2 :     if (pszUnderlyingUnitType)
    1450           2 :         pszUnitType = CPLStrdup(pszUnderlyingUnitType);
    1451             : 
    1452           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1453             : 
    1454           2 :     return pszUnitType;
    1455             : }
    1456             : 
    1457             : /* ******************************************************************** */
    1458             : /*                          GetColorTable()                             */
    1459             : /* ******************************************************************** */
    1460             : 
    1461         432 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
    1462             : {
    1463         432 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1464         432 :     if (poUnderlyingRasterBand == nullptr)
    1465           0 :         return nullptr;
    1466             : 
    1467         432 :     if (poColorTable)
    1468          31 :         delete poColorTable;
    1469         432 :     poColorTable = nullptr;
    1470             : 
    1471             :     GDALColorTable *poUnderlyingColorTable =
    1472         432 :         poUnderlyingRasterBand->GetColorTable();
    1473         432 :     if (poUnderlyingColorTable)
    1474          37 :         poColorTable = poUnderlyingColorTable->Clone();
    1475             : 
    1476         432 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1477             : 
    1478         432 :     return poColorTable;
    1479             : }
    1480             : 
    1481             : /* ******************************************************************** */
    1482             : /*                           GetOverview()                              */
    1483             : /* ******************************************************************** */
    1484             : 
    1485          36 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
    1486             : {
    1487          36 :     if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
    1488             :     {
    1489          12 :         if (papoProxyOverviewRasterBand[nOverviewBand])
    1490          12 :             return papoProxyOverviewRasterBand[nOverviewBand];
    1491             :     }
    1492             : 
    1493          24 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1494          24 :     if (poUnderlyingRasterBand == nullptr)
    1495           0 :         return nullptr;
    1496             : 
    1497             :     GDALRasterBand *poOverviewRasterBand =
    1498          24 :         poUnderlyingRasterBand->GetOverview(nOverviewBand);
    1499          24 :     if (poOverviewRasterBand == nullptr)
    1500             :     {
    1501           0 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1502           0 :         return nullptr;
    1503             :     }
    1504             : 
    1505          24 :     if (nOverviewBand >= nSizeProxyOverviewRasterBand)
    1506             :     {
    1507          24 :         papoProxyOverviewRasterBand =
    1508             :             static_cast<GDALProxyPoolOverviewRasterBand **>(
    1509          48 :                 CPLRealloc(papoProxyOverviewRasterBand,
    1510             :                            sizeof(GDALProxyPoolOverviewRasterBand *) *
    1511          24 :                                (nOverviewBand + 1)));
    1512          48 :         for (int i = nSizeProxyOverviewRasterBand; i < nOverviewBand + 1; i++)
    1513          24 :             papoProxyOverviewRasterBand[i] = nullptr;
    1514          24 :         nSizeProxyOverviewRasterBand = nOverviewBand + 1;
    1515             :     }
    1516             : 
    1517          24 :     papoProxyOverviewRasterBand[nOverviewBand] =
    1518             :         new GDALProxyPoolOverviewRasterBand(
    1519          24 :             cpl::down_cast<GDALProxyPoolDataset *>(poDS), poOverviewRasterBand,
    1520          24 :             this, nOverviewBand);
    1521             : 
    1522          24 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1523             : 
    1524          24 :     return papoProxyOverviewRasterBand[nOverviewBand];
    1525             : }
    1526             : 
    1527             : /* ******************************************************************** */
    1528             : /*                     GetRasterSampleOverview()                        */
    1529             : /* ******************************************************************** */
    1530             : 
    1531             : GDALRasterBand *
    1532           0 : GDALProxyPoolRasterBand::GetRasterSampleOverview(GUIntBig /* nDesiredSamples */)
    1533             : {
    1534           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    1535             :              "GDALProxyPoolRasterBand::GetRasterSampleOverview : not "
    1536             :              "implemented yet");
    1537           0 :     return nullptr;
    1538             : }
    1539             : 
    1540             : /* ******************************************************************** */
    1541             : /*                           GetMaskBand()                              */
    1542             : /* ******************************************************************** */
    1543             : 
    1544          69 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
    1545             : {
    1546          69 :     if (poProxyMaskBand)
    1547          41 :         return poProxyMaskBand;
    1548             : 
    1549          28 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1550          28 :     if (poUnderlyingRasterBand == nullptr)
    1551           0 :         return nullptr;
    1552             : 
    1553          28 :     GDALRasterBand *poMaskBand = poUnderlyingRasterBand->GetMaskBand();
    1554             : 
    1555          28 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1556          28 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), poMaskBand, this);
    1557             : 
    1558          28 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1559             : 
    1560          28 :     return poProxyMaskBand;
    1561             : }
    1562             : 
    1563             : /* ******************************************************************** */
    1564             : /*             GDALProxyPoolOverviewRasterBand()                        */
    1565             : /* ******************************************************************** */
    1566             : 
    1567          24 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(
    1568             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingOverviewBand,
    1569          24 :     GDALProxyPoolRasterBand *poMainBandIn, int nOverviewBandIn)
    1570             :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingOverviewBand),
    1571          24 :       poMainBand(poMainBandIn), nOverviewBand(nOverviewBandIn)
    1572             : {
    1573          24 : }
    1574             : 
    1575             : /* ******************************************************************** */
    1576             : /*                  ~GDALProxyPoolOverviewRasterBand()                  */
    1577             : /* ******************************************************************** */
    1578             : 
    1579          48 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
    1580             : {
    1581          24 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1582          48 : }
    1583             : 
    1584             : /* ******************************************************************** */
    1585             : /*                    RefUnderlyingRasterBand()                         */
    1586             : /* ******************************************************************** */
    1587             : 
    1588             : GDALRasterBand *
    1589           0 : GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1590             : {
    1591           0 :     poUnderlyingMainRasterBand =
    1592           0 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1593           0 :     if (poUnderlyingMainRasterBand == nullptr)
    1594           0 :         return nullptr;
    1595             : 
    1596           0 :     nRefCountUnderlyingMainRasterBand++;
    1597           0 :     return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
    1598             : }
    1599             : 
    1600             : /* ******************************************************************** */
    1601             : /*                  UnrefUnderlyingRasterBand()                         */
    1602             : /* ******************************************************************** */
    1603             : 
    1604           0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(
    1605             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1606             : {
    1607           0 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1608           0 :     nRefCountUnderlyingMainRasterBand--;
    1609           0 : }
    1610             : 
    1611             : /* ******************************************************************** */
    1612             : /*                     GDALProxyPoolMaskBand()                          */
    1613             : /* ******************************************************************** */
    1614             : 
    1615          28 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1616             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingMaskBand,
    1617          28 :     GDALProxyPoolRasterBand *poMainBandIn)
    1618          28 :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingMaskBand)
    1619             : {
    1620          28 :     poMainBand = poMainBandIn;
    1621             : 
    1622          28 :     poUnderlyingMainRasterBand = nullptr;
    1623          28 :     nRefCountUnderlyingMainRasterBand = 0;
    1624          28 : }
    1625             : 
    1626             : /* ******************************************************************** */
    1627             : /*                     GDALProxyPoolMaskBand()                          */
    1628             : /* ******************************************************************** */
    1629             : 
    1630          17 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1631             :     GDALProxyPoolDataset *poDSIn, GDALProxyPoolRasterBand *poMainBandIn,
    1632          17 :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1633             :     : GDALProxyPoolRasterBand(poDSIn, 1, eDataTypeIn, nBlockXSizeIn,
    1634             :                               nBlockYSizeIn),
    1635          17 :       poMainBand(poMainBandIn)
    1636             : {
    1637          17 : }
    1638             : 
    1639             : /* ******************************************************************** */
    1640             : /*                          ~GDALProxyPoolMaskBand()                    */
    1641             : /* ******************************************************************** */
    1642             : 
    1643          90 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
    1644             : {
    1645          45 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1646          90 : }
    1647             : 
    1648             : /* ******************************************************************** */
    1649             : /*                    RefUnderlyingRasterBand()                         */
    1650             : /* ******************************************************************** */
    1651             : 
    1652             : GDALRasterBand *
    1653         163 : GDALProxyPoolMaskBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1654             : {
    1655         163 :     poUnderlyingMainRasterBand =
    1656         163 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1657         163 :     if (poUnderlyingMainRasterBand == nullptr)
    1658           0 :         return nullptr;
    1659             : 
    1660         163 :     nRefCountUnderlyingMainRasterBand++;
    1661         163 :     return poUnderlyingMainRasterBand->GetMaskBand();
    1662             : }
    1663             : 
    1664             : /* ******************************************************************** */
    1665             : /*                  UnrefUnderlyingRasterBand()                         */
    1666             : /* ******************************************************************** */
    1667             : 
    1668         163 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(
    1669             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1670             : {
    1671         163 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1672         163 :     nRefCountUnderlyingMainRasterBand--;
    1673         163 : }
    1674             : 
    1675             : //! @endcond

Generated by: LCOV version 1.14