LCOV - code coverage report
Current view: top level - gcore - gdalproxypool.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 568 675 84.1 %
Date: 2025-07-01 22:47:05 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         402 : GDALDatasetPool::GDALDatasetPool(int maxSizeIn, int64_t nMaxRAMUsageIn)
     142         402 :     : maxSize(maxSizeIn), nMaxRAMUsage(nMaxRAMUsageIn)
     143             : {
     144         402 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                        ~GDALDatasetPool()                            */
     148             : /************************************************************************/
     149             : 
     150         798 : GDALDatasetPool::~GDALDatasetPool()
     151             : {
     152         399 :     bInDestruction = true;
     153         399 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     154         399 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     155         817 :     while (cur)
     156             :     {
     157         418 :         GDALProxyPoolCacheEntry *next = cur->next;
     158         418 :         CPLFree(cur->pszFileNameAndOpenOptions);
     159         418 :         CPLFree(cur->pszOwner);
     160         418 :         CPLAssert(cur->refCount == 0);
     161         418 :         if (cur->poDS)
     162             :         {
     163           0 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     164           0 :             GDALClose(cur->poDS);
     165             :         }
     166         418 :         CPLFree(cur);
     167         418 :         cur = next;
     168             :     }
     169         399 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     170         399 : }
     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      236711 : static std::string GetFilenameAndOpenOptions(const char *pszFileName,
     221             :                                              CSLConstList papszOpenOptions)
     222             : {
     223      236711 :     std::string osFilenameAndOO(pszFileName);
     224      236775 :     for (int i = 0; papszOpenOptions && papszOpenOptions[i]; ++i)
     225             :     {
     226          64 :         osFilenameAndOO += "||";
     227          64 :         osFilenameAndOO += papszOpenOptions[i];
     228             :     }
     229      236711 :     return osFilenameAndOO;
     230             : }
     231             : 
     232             : /************************************************************************/
     233             : /*                            _RefDataset()                             */
     234             : /************************************************************************/
     235             : 
     236             : GDALProxyPoolCacheEntry *
     237      232017 : GDALDatasetPool::_RefDataset(const char *pszFileName, GDALAccess eAccess,
     238             :                              CSLConstList papszOpenOptions, int bShared,
     239             :                              bool bForceOpen, const char *pszOwner)
     240             : {
     241      232017 :     CPLMutex **pMutex = GDALGetphDLMutex();
     242      464034 :     CPLMutexHolderD(pMutex);
     243             : 
     244      232019 :     if (bInDestruction)
     245           0 :         return nullptr;
     246             : 
     247      232019 :     const GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     248             : 
     249             :     const auto EvictEntryWithZeroRefCount =
     250       17324 :         [this, responsiblePID](bool evictEntryWithOpenedDataset)
     251             :     {
     252        2887 :         GDALProxyPoolCacheEntry *cur = firstEntry;
     253        2887 :         GDALProxyPoolCacheEntry *candidate = nullptr;
     254      291393 :         while (cur)
     255             :         {
     256      288506 :             GDALProxyPoolCacheEntry *next = cur->next;
     257             : 
     258      288506 :             if (cur->refCount == 0 &&
     259      284302 :                 (!evictEntryWithOpenedDataset || cur->nRAMUsage > 0))
     260             :             {
     261      284302 :                 candidate = cur;
     262             :             }
     263             : 
     264      288506 :             cur = next;
     265             :         }
     266        2887 :         if (candidate == nullptr)
     267           0 :             return false;
     268             : 
     269        2887 :         nRAMUsage -= candidate->nRAMUsage;
     270        2887 :         candidate->nRAMUsage = 0;
     271             : 
     272        2887 :         CPLFree(candidate->pszFileNameAndOpenOptions);
     273        2887 :         candidate->pszFileNameAndOpenOptions = nullptr;
     274             : 
     275        2887 :         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        2887 :         CPLFree(candidate->pszOwner);
     289        2887 :         candidate->pszOwner = nullptr;
     290             : 
     291        2887 :         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        2887 :             if (candidate->prev)
     296        2887 :                 candidate->prev->next = candidate->next;
     297             : 
     298        2887 :             if (candidate->next)
     299           0 :                 candidate->next->prev = candidate->prev;
     300             :             else
     301             :             {
     302        2887 :                 CPLAssert(candidate == lastEntry);
     303        2887 :                 lastEntry->prev->next = nullptr;
     304        2887 :                 lastEntry = lastEntry->prev;
     305             :             }
     306        2887 :             candidate->prev = nullptr;
     307        2887 :             candidate->next = firstEntry;
     308        2887 :             firstEntry->prev = candidate;
     309        2887 :             firstEntry = candidate;
     310             : 
     311             : #ifdef DEBUG_PROXY_POOL
     312             :             CheckLinks();
     313             : #endif
     314             :         }
     315             : 
     316        2887 :         return true;
     317      232019 :     };
     318             : 
     319      232019 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     320             : 
     321             :     const std::string osFilenameAndOO =
     322      464038 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     323             : 
     324      744988 :     while (cur)
     325             :     {
     326      739253 :         GDALProxyPoolCacheEntry *next = cur->next;
     327             : 
     328     1026110 :         if (cur->refCount >= 0 && cur->pszFileNameAndOpenOptions &&
     329     1991710 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     330      226247 :             ((bShared && cur->responsiblePID == responsiblePID &&
     331      226241 :               ((cur->pszOwner == nullptr && pszOwner == nullptr) ||
     332      225491 :                (cur->pszOwner != nullptr && pszOwner != nullptr &&
     333      225596 :                 strcmp(cur->pszOwner, pszOwner) == 0))) ||
     334          99 :              (!bShared && cur->refCount == 0)))
     335             :         {
     336      226284 :             if (cur != firstEntry)
     337             :             {
     338             :                 /* Move to begin */
     339        7479 :                 if (cur->next)
     340        7116 :                     cur->next->prev = cur->prev;
     341             :                 else
     342         363 :                     lastEntry = cur->prev;
     343        7479 :                 cur->prev->next = cur->next;
     344        7479 :                 cur->prev = nullptr;
     345        7479 :                 firstEntry->prev = cur;
     346        7479 :                 cur->next = firstEntry;
     347        7479 :                 firstEntry = cur;
     348             : 
     349             : #ifdef DEBUG_PROXY_POOL
     350             :                 CheckLinks();
     351             : #endif
     352             :             }
     353             : 
     354      226284 :             cur->refCount++;
     355      226284 :             return cur;
     356             :         }
     357             : 
     358      512969 :         cur = next;
     359             :     }
     360             : 
     361        5735 :     if (!bForceOpen)
     362        2163 :         return nullptr;
     363             : 
     364        3572 :     if (currentSize == maxSize)
     365             :     {
     366        2887 :         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        2887 :         CPLAssert(firstEntry);
     379        2887 :         cur = firstEntry;
     380             :     }
     381             :     else
     382             :     {
     383             :         /* Prepend */
     384             :         cur = static_cast<GDALProxyPoolCacheEntry *>(
     385         685 :             CPLCalloc(1, sizeof(GDALProxyPoolCacheEntry)));
     386         685 :         if (lastEntry == nullptr)
     387         352 :             lastEntry = cur;
     388         685 :         cur->prev = nullptr;
     389         685 :         cur->next = firstEntry;
     390         685 :         if (firstEntry)
     391         333 :             firstEntry->prev = cur;
     392         685 :         firstEntry = cur;
     393         685 :         currentSize++;
     394             : #ifdef DEBUG_PROXY_POOL
     395             :         CheckLinks();
     396             : #endif
     397             :     }
     398             : 
     399        3572 :     cur->pszFileNameAndOpenOptions = CPLStrdup(osFilenameAndOO.c_str());
     400        3572 :     cur->pszOwner = (pszOwner) ? CPLStrdup(pszOwner) : nullptr;
     401        3572 :     cur->responsiblePID = responsiblePID;
     402        3572 :     cur->refCount = -1;  // to mark loading of dataset in progress
     403        3572 :     cur->nRAMUsage = 0;
     404             : 
     405        3572 :     refCountOfDisabledRefCount++;
     406        3572 :     const int nFlag =
     407             :         ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) |
     408        3572 :         GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
     409        3572 :     CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
     410             : 
     411             :     // Release mutex while opening dataset to avoid lock contention.
     412        3572 :     CPLReleaseMutex(*pMutex);
     413        3572 :     auto poDS = GDALDataset::Open(pszFileName, nFlag, nullptr, papszOpenOptions,
     414             :                                   nullptr);
     415        3572 :     CPLAcquireMutex(*pMutex, 1000.0);
     416             : 
     417        3572 :     cur->poDS = poDS;
     418        3572 :     cur->refCount = 1;
     419             : 
     420        3572 :     refCountOfDisabledRefCount--;
     421             : 
     422        3572 :     if (cur->poDS)
     423             :     {
     424        3403 :         cur->nRAMUsage =
     425        3403 :             std::max<GIntBig>(0, cur->poDS->GetEstimatedRAMUsage());
     426        3403 :         nRAMUsage += cur->nRAMUsage;
     427             :     }
     428             : 
     429        3572 :     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        3572 :     return cur;
     439             : }
     440             : 
     441             : /************************************************************************/
     442             : /*                   _CloseDatasetIfZeroRefCount()                      */
     443             : /************************************************************************/
     444             : 
     445        4692 : 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        4692 :     if (bInDestruction)
     452           0 :         return;
     453             : 
     454        4692 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     455        4692 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     456             : 
     457             :     const std::string osFilenameAndOO =
     458        9384 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     459             : 
     460       82928 :     while (cur)
     461             :     {
     462       81637 :         GDALProxyPoolCacheEntry *next = cur->next;
     463             : 
     464      102124 :         if (cur->refCount == 0 && cur->pszFileNameAndOpenOptions &&
     465       24077 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     466        3586 :             ((pszOwner == nullptr && cur->pszOwner == nullptr) ||
     467        3401 :              (pszOwner != nullptr && cur->pszOwner != nullptr &&
     468      166670 :               strcmp(cur->pszOwner, pszOwner) == 0)) &&
     469        3576 :             cur->poDS != nullptr)
     470             :         {
     471             :             /* Close by pretending we are the thread that GDALOpen'ed this */
     472             :             /* dataset */
     473        3401 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     474             : 
     475        3401 :             GDALDataset *poDS = cur->poDS;
     476             : 
     477        3401 :             nRAMUsage -= cur->nRAMUsage;
     478        3401 :             cur->nRAMUsage = 0;
     479             : 
     480        3401 :             cur->poDS = nullptr;
     481        3401 :             CPLFree(cur->pszFileNameAndOpenOptions);
     482        3401 :             cur->pszFileNameAndOpenOptions = nullptr;
     483        3401 :             CPLFree(cur->pszOwner);
     484        3401 :             cur->pszOwner = nullptr;
     485             : 
     486        3401 :             refCountOfDisabledRefCount++;
     487        3401 :             GDALClose(poDS);
     488        3401 :             refCountOfDisabledRefCount--;
     489             : 
     490        3401 :             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     491        3401 :             break;
     492             :         }
     493             : 
     494       78236 :         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         439 : int GDALGetMaxDatasetPoolSize()
     506             : {
     507         439 :     int nSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
     508         439 :     if (nSize < 2)
     509           0 :         nSize = 2;
     510         439 :     else if (nSize > 1000)
     511           0 :         nSize = 1000;
     512         439 :     return nSize;
     513             : }
     514             : 
     515             : /************************************************************************/
     516             : /*                                 Ref()                                */
     517             : /************************************************************************/
     518             : 
     519        4691 : void GDALDatasetPool::Ref()
     520             : {
     521        9383 :     CPLMutexHolderD(GDALGetphDLMutex());
     522        4692 :     if (singleton == nullptr)
     523             :     {
     524             : 
     525             :         // Try to not consume more than 25% of the usable RAM
     526             :         GIntBig l_nMaxRAMUsage =
     527         402 :             (CPLGetUsablePhysicalRAM() - GDALGetCacheMax64()) / 4;
     528             :         const char *pszMaxRAMUsage =
     529         402 :             CPLGetConfigOption("GDAL_MAX_DATASET_POOL_RAM_USAGE", nullptr);
     530         402 :         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         402 :         singleton =
     540         402 :             new GDALDatasetPool(GDALGetMaxDatasetPoolSize(), l_nMaxRAMUsage);
     541             :     }
     542        4692 :     if (refCountOfDisabledRefCount == 0)
     543        4692 :         singleton->refCount++;
     544        4692 : }
     545             : 
     546             : /* keep that in sync with gdaldrivermanager.cpp */
     547        1113 : void GDALDatasetPool::PreventDestroy()
     548             : {
     549        1113 :     CPLMutexHolderD(GDALGetphDLMutex());
     550        1113 :     if (!singleton)
     551        1110 :         return;
     552           3 :     refCountOfDisabledRefCount++;
     553             : }
     554             : 
     555             : /* keep that in sync with gdaldrivermanager.cpp */
     556             : extern void GDALDatasetPoolPreventDestroy();
     557             : 
     558        1113 : void GDALDatasetPoolPreventDestroy()
     559             : {
     560        1113 :     GDALDatasetPool::PreventDestroy();
     561        1113 : }
     562             : 
     563             : /************************************************************************/
     564             : /*                               Unref()                                */
     565             : /************************************************************************/
     566             : 
     567        4692 : void GDALDatasetPool::Unref()
     568             : {
     569        4692 :     CPLMutexHolderD(GDALGetphDLMutex());
     570        4692 :     if (!singleton)
     571             :     {
     572           0 :         CPLAssert(false);
     573             :         return;
     574             :     }
     575        4692 :     if (refCountOfDisabledRefCount == 0)
     576             :     {
     577        4655 :         singleton->refCount--;
     578        4655 :         if (singleton->refCount == 0)
     579             :         {
     580         396 :             delete singleton;
     581         396 :             singleton = nullptr;
     582             :         }
     583             :     }
     584             : }
     585             : 
     586             : /* keep that in sync with gdaldrivermanager.cpp */
     587        1113 : void GDALDatasetPool::ForceDestroy()
     588             : {
     589        1113 :     CPLMutexHolderD(GDALGetphDLMutex());
     590        1113 :     if (!singleton)
     591        1110 :         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        1113 : void GDALDatasetPoolForceDestroy()
     603             : {
     604        1113 :     GDALDatasetPool::ForceDestroy();
     605        1113 : }
     606             : 
     607             : /************************************************************************/
     608             : /*                           RefDataset()                               */
     609             : /************************************************************************/
     610             : 
     611             : GDALProxyPoolCacheEntry *
     612      232016 : GDALDatasetPool::RefDataset(const char *pszFileName, GDALAccess eAccess,
     613             :                             char **papszOpenOptions, int bShared,
     614             :                             bool bForceOpen, const char *pszOwner)
     615             : {
     616      232016 :     return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions,
     617      232019 :                                   bShared, bForceOpen, pszOwner);
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                       UnrefDataset()                                 */
     622             : /************************************************************************/
     623             : 
     624      229856 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry)
     625             : {
     626      229856 :     CPLMutexHolderD(GDALGetphDLMutex());
     627      229856 :     cacheEntry->refCount--;
     628      229856 : }
     629             : 
     630             : /************************************************************************/
     631             : /*                   CloseDatasetIfZeroRefCount()                       */
     632             : /************************************************************************/
     633             : 
     634        4692 : void GDALDatasetPool::CloseDatasetIfZeroRefCount(const char *pszFileName,
     635             :                                                  CSLConstList papszOpenOptions,
     636             :                                                  GDALAccess eAccess,
     637             :                                                  const char *pszOwner)
     638             : {
     639        9384 :     CPLMutexHolderD(GDALGetphDLMutex());
     640        4692 :     singleton->_CloseDatasetIfZeroRefCount(pszFileName, papszOpenOptions,
     641             :                                            eAccess, pszOwner);
     642        4692 : }
     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          70 : static unsigned long hash_func_get_metadata_item(const void *_elt)
     679             : {
     680          70 :     const GetMetadataItemElt *elt =
     681             :         static_cast<const GetMetadataItemElt *>(_elt);
     682          70 :     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          44 : static void free_func_get_metadata_item(void *_elt)
     696             : {
     697          44 :     GetMetadataItemElt *elt = static_cast<GetMetadataItemElt *>(_elt);
     698          44 :     CPLFree(elt->pszName);
     699          44 :     CPLFree(elt->pszDomain);
     700          44 :     CPLFree(elt->pszMetadataItem);
     701          44 :     CPLFree(elt);
     702          44 : }
     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        1282 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     733             :     const char *pszSourceDatasetDescription, int nRasterXSizeIn,
     734             :     int nRasterYSizeIn, GDALAccess eAccessIn, int bSharedIn,
     735             :     const char *pszProjectionRefIn, const GDALGeoTransform *pGT,
     736        1282 :     const char *pszOwner)
     737        2564 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread()),
     738        1282 :       pszProjectionRef(pszProjectionRefIn ? CPLStrdup(pszProjectionRefIn)
     739        2564 :                                           : nullptr)
     740             : {
     741        1282 :     GDALDatasetPool::Ref();
     742             : 
     743        1282 :     SetDescription(pszSourceDatasetDescription);
     744             : 
     745        1282 :     nRasterXSize = nRasterXSizeIn;
     746        1282 :     nRasterYSize = nRasterYSizeIn;
     747        1282 :     eAccess = eAccessIn;
     748             : 
     749        1282 :     bShared = CPL_TO_BOOL(bSharedIn);
     750        1282 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     751             : 
     752        1282 :     if (pGT)
     753             :     {
     754        1233 :         m_gt = *pGT;
     755        1233 :         m_bHasSrcGeoTransform = true;
     756             :     }
     757             : 
     758        1282 :     if (pszProjectionRefIn)
     759             :     {
     760        1243 :         m_poSRS = new OGRSpatialReference();
     761        1243 :         m_poSRS->importFromWkt(pszProjectionRefIn);
     762        1243 :         m_bHasSrcSRS = true;
     763             :     }
     764        1282 : }
     765             : 
     766             : /* Constructor where the parameters (raster size, etc.) are obtained
     767             :  * by opening the underlying dataset.
     768             :  */
     769        3410 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     770             :     const char *pszSourceDatasetDescription, GDALAccess eAccessIn,
     771        3410 :     int bSharedIn, const char *pszOwner)
     772        3410 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread())
     773             : {
     774        3409 :     GDALDatasetPool::Ref();
     775             : 
     776        3410 :     SetDescription(pszSourceDatasetDescription);
     777             : 
     778        3409 :     eAccess = eAccessIn;
     779             : 
     780        3409 :     bShared = CPL_TO_BOOL(bSharedIn);
     781        3410 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     782        3410 : }
     783             : 
     784             : /************************************************************************/
     785             : /*                              Create()                                */
     786             : /************************************************************************/
     787             : 
     788             : /* Instantiate a GDALProxyPoolDataset where the parameters (raster size, etc.)
     789             :  * are obtained by opening the underlying dataset.
     790             :  * Its bands are also instantiated.
     791             :  */
     792        3410 : GDALProxyPoolDataset *GDALProxyPoolDataset::Create(
     793             :     const char *pszSourceDatasetDescription, CSLConstList papszOpenOptionsIn,
     794             :     GDALAccess eAccessIn, int bSharedIn, const char *pszOwner)
     795             : {
     796             :     std::unique_ptr<GDALProxyPoolDataset> poSelf(new GDALProxyPoolDataset(
     797        6820 :         pszSourceDatasetDescription, eAccessIn, bSharedIn, pszOwner));
     798        3407 :     poSelf->SetOpenOptions(papszOpenOptionsIn);
     799        3408 :     GDALDataset *poUnderlyingDS = poSelf->RefUnderlyingDataset();
     800        3410 :     if (!poUnderlyingDS)
     801         175 :         return nullptr;
     802        3235 :     poSelf->nRasterXSize = poUnderlyingDS->GetRasterXSize();
     803        3235 :     poSelf->nRasterYSize = poUnderlyingDS->GetRasterYSize();
     804        3235 :     if (poUnderlyingDS->GetGeoTransform(poSelf->m_gt) == CE_None)
     805         970 :         poSelf->m_bHasSrcGeoTransform = true;
     806        3235 :     const auto poSRS = poUnderlyingDS->GetSpatialRef();
     807        3235 :     if (poSRS)
     808             :     {
     809         878 :         poSelf->m_poSRS = poSRS->Clone();
     810         878 :         poSelf->m_bHasSrcSRS = true;
     811             :     }
     812      106326 :     for (int i = 1; i <= poUnderlyingDS->GetRasterCount(); ++i)
     813             :     {
     814      103091 :         auto poSrcBand = poUnderlyingDS->GetRasterBand(i);
     815      103091 :         if (!poSrcBand)
     816             :         {
     817           0 :             poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     818           0 :             return nullptr;
     819             :         }
     820             :         int nSrcBlockXSize, nSrcBlockYSize;
     821      103091 :         poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
     822      103091 :         poSelf->AddSrcBandDescription(poSrcBand->GetRasterDataType(),
     823             :                                       nSrcBlockXSize, nSrcBlockYSize);
     824             :     }
     825        3235 :     poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     826        3235 :     return poSelf.release();
     827             : }
     828             : 
     829             : /************************************************************************/
     830             : /*                    ~GDALProxyPoolDataset()                           */
     831             : /************************************************************************/
     832             : 
     833        9374 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
     834             : {
     835        4692 :     GDALDatasetPool::CloseDatasetIfZeroRefCount(
     836        4692 :         GetDescription(), papszOpenOptions, eAccess, m_pszOwner);
     837             : 
     838             :     /* See comment in constructor */
     839             :     /* It is not really a genuine shared dataset, so we don't */
     840             :     /* want ~GDALDataset() to try to release it from its */
     841             :     /* shared dataset hashset. This will save a */
     842             :     /* "Should not happen. Cannot find %s, this=%p in phSharedDatasetSet" debug
     843             :      * message */
     844        4692 :     bShared = false;
     845             : 
     846        4692 :     CPLFree(pszProjectionRef);
     847        4692 :     CPLFree(pszGCPProjection);
     848        4692 :     if (nGCPCount)
     849             :     {
     850           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     851           0 :         CPLFree(pasGCPList);
     852             :     }
     853        4692 :     if (metadataSet)
     854           4 :         CPLHashSetDestroy(metadataSet);
     855        4692 :     if (metadataItemSet)
     856           2 :         CPLHashSetDestroy(metadataItemSet);
     857        4692 :     CPLFree(m_pszOwner);
     858        4692 :     if (m_poSRS)
     859        2121 :         m_poSRS->Release();
     860        4692 :     if (m_poGCPSRS)
     861           0 :         m_poGCPSRS->Release();
     862             : 
     863        4692 :     GDALDatasetPool::Unref();
     864        9374 : }
     865             : 
     866             : /************************************************************************/
     867             : /*                        SetOpenOptions()                              */
     868             : /************************************************************************/
     869             : 
     870        4642 : void GDALProxyPoolDataset::SetOpenOptions(CSLConstList papszOpenOptionsIn)
     871             : {
     872        4642 :     CPLAssert(papszOpenOptions == nullptr);
     873        4642 :     papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
     874        4639 : }
     875             : 
     876             : /************************************************************************/
     877             : /*                    AddSrcBandDescription()                           */
     878             : /************************************************************************/
     879             : 
     880      105454 : void GDALProxyPoolDataset::AddSrcBandDescription(GDALDataType eDataType,
     881             :                                                  int nBlockXSize,
     882             :                                                  int nBlockYSize)
     883             : {
     884      105454 :     SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType,
     885      105454 :                                                     nBlockXSize, nBlockYSize));
     886      105454 : }
     887             : 
     888             : /************************************************************************/
     889             : /*                    AddSrcBand()                                      */
     890             : /************************************************************************/
     891             : 
     892           0 : void GDALProxyPoolDataset::AddSrcBand(int nBand, GDALDataType eDataType,
     893             :                                       int nBlockXSize, int nBlockYSize)
     894             : {
     895           0 :     SetBand(nBand, new GDALProxyPoolRasterBand(this, nBand, eDataType,
     896           0 :                                                nBlockXSize, nBlockYSize));
     897           0 : }
     898             : 
     899             : /************************************************************************/
     900             : /*                    RefUnderlyingDataset()                            */
     901             : /************************************************************************/
     902             : 
     903        4692 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset() const
     904             : {
     905        4692 :     return RefUnderlyingDataset(true);
     906             : }
     907             : 
     908      232015 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset(bool bForceOpen) const
     909             : {
     910             :     /* We pretend that the current thread is responsiblePID, that is */
     911             :     /* to say the thread that created that GDALProxyPoolDataset object. */
     912             :     /* This is for the case when a GDALProxyPoolDataset is created by a */
     913             :     /* thread and used by other threads. These other threads, when doing actual
     914             :      */
     915             :     /* IO, will come there and potentially open the underlying dataset. */
     916             :     /* By doing this, they can indirectly call GDALOpenShared() on .aux file */
     917             :     /* for example. So this call to GDALOpenShared() must occur as if it */
     918             :     /* was done by the creating thread, otherwise it will not be correctly
     919             :      * closed afterwards... */
     920             :     /* To make a long story short : this is necessary when warping with
     921             :      * ChunkAndWarpMulti */
     922             :     /* a VRT of GeoTIFFs that have associated .aux files */
     923      232015 :     GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
     924      232015 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     925      232019 :     cacheEntry =
     926      232014 :         GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
     927      232016 :                                     GetShared(), bForceOpen, m_pszOwner);
     928      232019 :     GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
     929      232019 :     if (cacheEntry != nullptr)
     930             :     {
     931      229856 :         if (cacheEntry->poDS != nullptr)
     932      229681 :             return cacheEntry->poDS;
     933             :         else
     934         175 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     935             :     }
     936        2338 :     return nullptr;
     937             : }
     938             : 
     939             : /************************************************************************/
     940             : /*                    UnrefUnderlyingDataset()                        */
     941             : /************************************************************************/
     942             : 
     943      229681 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(
     944             :     CPL_UNUSED GDALDataset *poUnderlyingDataset) const
     945             : {
     946      229681 :     if (cacheEntry != nullptr)
     947             :     {
     948      229681 :         CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
     949      229681 :         if (cacheEntry->poDS != nullptr)
     950      229681 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     951             :     }
     952      229681 : }
     953             : 
     954             : /************************************************************************/
     955             : /*                         FlushCache()                                 */
     956             : /************************************************************************/
     957             : 
     958           0 : CPLErr GDALProxyPoolDataset::FlushCache(bool bAtClosing)
     959             : {
     960           0 :     CPLErr eErr = CE_None;
     961           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset(false);
     962           0 :     if (poUnderlyingDataset)
     963             :     {
     964           0 :         eErr = poUnderlyingDataset->FlushCache(bAtClosing);
     965           0 :         UnrefUnderlyingDataset(poUnderlyingDataset);
     966             :     }
     967           0 :     return eErr;
     968             : }
     969             : 
     970             : /************************************************************************/
     971             : /*                        SetSpatialRef()                               */
     972             : /************************************************************************/
     973             : 
     974           0 : CPLErr GDALProxyPoolDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     975             : {
     976           0 :     m_bHasSrcSRS = false;
     977           0 :     return GDALProxyDataset::SetSpatialRef(poSRS);
     978             : }
     979             : 
     980             : /************************************************************************/
     981             : /*                        GetSpatialRef()                               */
     982             : /************************************************************************/
     983             : 
     984         204 : const OGRSpatialReference *GDALProxyPoolDataset::GetSpatialRef() const
     985             : {
     986         204 :     if (m_bHasSrcSRS)
     987         202 :         return m_poSRS;
     988             :     else
     989             :     {
     990           2 :         if (m_poSRS)
     991           0 :             m_poSRS->Release();
     992           2 :         m_poSRS = nullptr;
     993           2 :         auto poSRS = GDALProxyDataset::GetSpatialRef();
     994           2 :         if (poSRS)
     995           0 :             m_poSRS = poSRS->Clone();
     996           2 :         return m_poSRS;
     997             :     }
     998             : }
     999             : 
    1000             : /************************************************************************/
    1001             : /*                        SetGeoTransform()                             */
    1002             : /************************************************************************/
    1003             : 
    1004           0 : CPLErr GDALProxyPoolDataset::SetGeoTransform(const GDALGeoTransform &gt)
    1005             : {
    1006           0 :     m_gt = gt;
    1007           0 :     m_bHasSrcGeoTransform = false;
    1008           0 :     return GDALProxyDataset::SetGeoTransform(gt);
    1009             : }
    1010             : 
    1011             : /************************************************************************/
    1012             : /*                        GetGeoTransform()                             */
    1013             : /************************************************************************/
    1014             : 
    1015         573 : CPLErr GDALProxyPoolDataset::GetGeoTransform(GDALGeoTransform &gt) const
    1016             : {
    1017         573 :     if (m_bHasSrcGeoTransform)
    1018             :     {
    1019         573 :         gt = m_gt;
    1020         573 :         return CE_None;
    1021             :     }
    1022             :     else
    1023             :     {
    1024           0 :         return GDALProxyDataset::GetGeoTransform(gt);
    1025             :     }
    1026             : }
    1027             : 
    1028             : /************************************************************************/
    1029             : /*                            GetMetadata()                             */
    1030             : /************************************************************************/
    1031             : 
    1032          22 : char **GDALProxyPoolDataset::GetMetadata(const char *pszDomain)
    1033             : {
    1034          22 :     if (metadataSet == nullptr)
    1035           4 :         metadataSet =
    1036           4 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1037             :                           free_func_get_metadata);
    1038             : 
    1039          22 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1040          22 :     if (poUnderlyingDataset == nullptr)
    1041           0 :         return nullptr;
    1042             : 
    1043             :     char **papszUnderlyingMetadata =
    1044          22 :         poUnderlyingDataset->GetMetadata(pszDomain);
    1045             : 
    1046             :     GetMetadataElt *pElt =
    1047          22 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1048          22 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1049          22 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1050          22 :     CPLHashSetInsert(metadataSet, pElt);
    1051             : 
    1052          22 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1053             : 
    1054          22 :     return pElt->papszMetadata;
    1055             : }
    1056             : 
    1057             : /************************************************************************/
    1058             : /*                        GetMetadataItem()                             */
    1059             : /************************************************************************/
    1060             : 
    1061           4 : const char *GDALProxyPoolDataset::GetMetadataItem(const char *pszName,
    1062             :                                                   const char *pszDomain)
    1063             : {
    1064           4 :     if (metadataItemSet == nullptr)
    1065           2 :         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
    1066             :                                         equal_func_get_metadata_item,
    1067             :                                         free_func_get_metadata_item);
    1068             : 
    1069           4 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1070           4 :     if (poUnderlyingDataset == nullptr)
    1071           0 :         return nullptr;
    1072             : 
    1073             :     const char *pszUnderlyingMetadataItem =
    1074           4 :         poUnderlyingDataset->GetMetadataItem(pszName, pszDomain);
    1075             : 
    1076             :     GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
    1077           4 :         CPLMalloc(sizeof(GetMetadataItemElt)));
    1078           4 :     pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
    1079           4 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1080           4 :     pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
    1081           4 :                                 ? CPLStrdup(pszUnderlyingMetadataItem)
    1082             :                                 : nullptr;
    1083           4 :     CPLHashSetInsert(metadataItemSet, pElt);
    1084             : 
    1085           4 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1086             : 
    1087           4 :     return pElt->pszMetadataItem;
    1088             : }
    1089             : 
    1090             : /************************************************************************/
    1091             : /*                      GetInternalHandle()                             */
    1092             : /************************************************************************/
    1093             : 
    1094           0 : void *GDALProxyPoolDataset::GetInternalHandle(const char *pszRequest)
    1095             : {
    1096           0 :     CPLError(
    1097             :         CE_Warning, CPLE_AppDefined,
    1098             :         "GetInternalHandle() cannot be safely called on a proxy pool dataset\n"
    1099             :         "as the returned value may be invalidated at any time.\n");
    1100           0 :     return GDALProxyDataset::GetInternalHandle(pszRequest);
    1101             : }
    1102             : 
    1103             : /************************************************************************/
    1104             : /*                     GetGCPSpatialRef()                               */
    1105             : /************************************************************************/
    1106             : 
    1107           0 : const OGRSpatialReference *GDALProxyPoolDataset::GetGCPSpatialRef() const
    1108             : {
    1109           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1110           0 :     if (poUnderlyingDataset == nullptr)
    1111           0 :         return nullptr;
    1112             : 
    1113           0 :     m_poGCPSRS->Release();
    1114           0 :     m_poGCPSRS = nullptr;
    1115             : 
    1116           0 :     const auto poUnderlyingGCPSRS = poUnderlyingDataset->GetGCPSpatialRef();
    1117           0 :     if (poUnderlyingGCPSRS)
    1118           0 :         m_poGCPSRS = poUnderlyingGCPSRS->Clone();
    1119             : 
    1120           0 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1121             : 
    1122           0 :     return m_poGCPSRS;
    1123             : }
    1124             : 
    1125             : /************************************************************************/
    1126             : /*                            GetGCPs()                                 */
    1127             : /************************************************************************/
    1128             : 
    1129           0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
    1130             : {
    1131           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1132           0 :     if (poUnderlyingDataset == nullptr)
    1133           0 :         return nullptr;
    1134             : 
    1135           0 :     if (nGCPCount)
    1136             :     {
    1137           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
    1138           0 :         CPLFree(pasGCPList);
    1139           0 :         pasGCPList = nullptr;
    1140             :     }
    1141             : 
    1142           0 :     const GDAL_GCP *pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
    1143           0 :     nGCPCount = poUnderlyingDataset->GetGCPCount();
    1144           0 :     if (nGCPCount)
    1145           0 :         pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList);
    1146             : 
    1147           0 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1148             : 
    1149           0 :     return pasGCPList;
    1150             : }
    1151             : 
    1152             : /************************************************************************/
    1153             : /*                     GDALProxyPoolDatasetCreate()                     */
    1154             : /************************************************************************/
    1155             : 
    1156        1233 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(
    1157             :     const char *pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize,
    1158             :     GDALAccess eAccess, int bShared, const char *pszProjectionRef,
    1159             :     const double *padfGeoTransform)
    1160             : {
    1161             :     return reinterpret_cast<GDALProxyPoolDatasetH>(new GDALProxyPoolDataset(
    1162             :         pszSourceDatasetDescription, nRasterXSize, nRasterYSize, eAccess,
    1163             :         bShared, pszProjectionRef,
    1164        1233 :         reinterpret_cast<const GDALGeoTransform *>(padfGeoTransform)));
    1165             : }
    1166             : 
    1167             : /************************************************************************/
    1168             : /*                       GDALProxyPoolDatasetDelete()                   */
    1169             : /************************************************************************/
    1170             : 
    1171           0 : void GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
    1172             : {
    1173           0 :     delete reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset);
    1174           0 : }
    1175             : 
    1176             : /************************************************************************/
    1177             : /*              GDALProxyPoolDatasetAddSrcBandDescription()             */
    1178             : /************************************************************************/
    1179             : 
    1180        2324 : void GDALProxyPoolDatasetAddSrcBandDescription(
    1181             :     GDALProxyPoolDatasetH hProxyPoolDataset, GDALDataType eDataType,
    1182             :     int nBlockXSize, int nBlockYSize)
    1183             : {
    1184             :     reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset)
    1185        2324 :         ->AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
    1186        2324 : }
    1187             : 
    1188             : /* ******************************************************************** */
    1189             : /*                    GDALProxyPoolRasterBand()                         */
    1190             : /* ******************************************************************** */
    1191             : 
    1192      105476 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset *poDSIn,
    1193             :                                                  int nBandIn,
    1194             :                                                  GDALDataType eDataTypeIn,
    1195             :                                                  int nBlockXSizeIn,
    1196      105476 :                                                  int nBlockYSizeIn)
    1197             : {
    1198      105476 :     poDS = poDSIn;
    1199      105476 :     nBand = nBandIn;
    1200      105476 :     eDataType = eDataTypeIn;
    1201      105476 :     nRasterXSize = poDSIn->GetRasterXSize();
    1202      105476 :     nRasterYSize = poDSIn->GetRasterYSize();
    1203      105476 :     nBlockXSize = nBlockXSizeIn;
    1204      105476 :     nBlockYSize = nBlockYSizeIn;
    1205      105476 : }
    1206             : 
    1207             : /* ******************************************************************** */
    1208             : /*                    GDALProxyPoolRasterBand()                         */
    1209             : /* ******************************************************************** */
    1210             : 
    1211          62 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(
    1212          62 :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingRasterBand)
    1213             : {
    1214          62 :     poDS = poDSIn;
    1215          62 :     nBand = poUnderlyingRasterBand->GetBand();
    1216          62 :     eDataType = poUnderlyingRasterBand->GetRasterDataType();
    1217          62 :     nRasterXSize = poUnderlyingRasterBand->GetXSize();
    1218          62 :     nRasterYSize = poUnderlyingRasterBand->GetYSize();
    1219          62 :     poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    1220          62 : }
    1221             : 
    1222             : /* ******************************************************************** */
    1223             : /*                   ~GDALProxyPoolRasterBand()                         */
    1224             : /* ******************************************************************** */
    1225      210992 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
    1226             : {
    1227      105538 :     if (metadataSet)
    1228           2 :         CPLHashSetDestroy(metadataSet);
    1229      105538 :     if (metadataItemSet)
    1230          20 :         CPLHashSetDestroy(metadataItemSet);
    1231      105538 :     CPLFree(pszUnitType);
    1232      105538 :     CSLDestroy(papszCategoryNames);
    1233      105538 :     if (poColorTable)
    1234           6 :         delete poColorTable;
    1235             : 
    1236      105562 :     for (int i = 0; i < nSizeProxyOverviewRasterBand; i++)
    1237             :     {
    1238          24 :         if (papoProxyOverviewRasterBand[i])
    1239          24 :             delete papoProxyOverviewRasterBand[i];
    1240             :     }
    1241      105538 :     CPLFree(papoProxyOverviewRasterBand);
    1242      105538 :     if (poProxyMaskBand)
    1243          60 :         delete poProxyMaskBand;
    1244      210992 : }
    1245             : 
    1246             : /************************************************************************/
    1247             : /*                AddSrcMaskBandDescriptionFromUnderlying()             */
    1248             : /************************************************************************/
    1249             : 
    1250          15 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescriptionFromUnderlying()
    1251             : {
    1252          15 :     if (poProxyMaskBand != nullptr)
    1253           6 :         return;
    1254           9 :     GDALRasterBand *poUnderlyingBand = RefUnderlyingRasterBand();
    1255           9 :     if (poUnderlyingBand == nullptr)
    1256           0 :         return;
    1257           9 :     auto poSrcMaskBand = poUnderlyingBand->GetMaskBand();
    1258             :     int nSrcBlockXSize, nSrcBlockYSize;
    1259           9 :     poSrcMaskBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1260           9 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1261           9 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this,
    1262           9 :         poSrcMaskBand->GetRasterDataType(), nSrcBlockXSize, nSrcBlockYSize);
    1263           9 :     UnrefUnderlyingRasterBand(poUnderlyingBand);
    1264             : }
    1265             : 
    1266             : /************************************************************************/
    1267             : /*                 AddSrcMaskBandDescription()                          */
    1268             : /************************************************************************/
    1269             : 
    1270          13 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescription(
    1271             :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1272             : {
    1273          13 :     CPLAssert(poProxyMaskBand == nullptr);
    1274          13 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1275          13 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this, eDataTypeIn,
    1276          13 :         nBlockXSizeIn, nBlockYSizeIn);
    1277          13 : }
    1278             : 
    1279             : /************************************************************************/
    1280             : /*                  RefUnderlyingRasterBand()                           */
    1281             : /************************************************************************/
    1282             : 
    1283             : GDALRasterBand *
    1284      227324 : GDALProxyPoolRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1285             : {
    1286             :     GDALDataset *poUnderlyingDataset =
    1287      227324 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1288      227324 :             ->RefUnderlyingDataset(bForceOpen);
    1289      227325 :     if (poUnderlyingDataset == nullptr)
    1290        2163 :         return nullptr;
    1291             : 
    1292      225162 :     GDALRasterBand *poBand = poUnderlyingDataset->GetRasterBand(nBand);
    1293      225162 :     if (poBand == nullptr)
    1294             :     {
    1295           0 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1296           0 :             ->UnrefUnderlyingDataset(poUnderlyingDataset);
    1297             :     }
    1298      225162 :     else if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1299             :     {
    1300             :         // Here we try to load nBlockXSize&nBlockYSize from underlying band
    1301             :         // but we must guarantee that we will not access directly to
    1302             :         // nBlockXSize/nBlockYSize before RefUnderlyingRasterBand() is called
    1303             :         int nSrcBlockXSize, nSrcBlockYSize;
    1304          11 :         poBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1305          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockXSize =
    1306             :             nSrcBlockXSize;
    1307          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockYSize =
    1308             :             nSrcBlockYSize;
    1309             :     }
    1310             : 
    1311      225162 :     return poBand;
    1312             : }
    1313             : 
    1314             : /************************************************************************/
    1315             : /*                  UnrefUnderlyingRasterBand()                       */
    1316             : /************************************************************************/
    1317             : 
    1318      225162 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(
    1319             :     GDALRasterBand *poUnderlyingRasterBand) const
    1320             : {
    1321      225162 :     if (poUnderlyingRasterBand)
    1322      225162 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1323      225162 :             ->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
    1324      225162 : }
    1325             : 
    1326             : /************************************************************************/
    1327             : /*                             FlushCache()                             */
    1328             : /************************************************************************/
    1329             : 
    1330      104454 : CPLErr GDALProxyPoolRasterBand::FlushCache(bool bAtClosing)
    1331             : {
    1332      104454 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand(false);
    1333      104454 :     if (poUnderlyingRasterBand)
    1334             :     {
    1335      102291 :         CPLErr eErr = poUnderlyingRasterBand->FlushCache(bAtClosing);
    1336      102291 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1337      102291 :         return eErr;
    1338             :     }
    1339        2163 :     return CE_None;
    1340             : }
    1341             : 
    1342             : /************************************************************************/
    1343             : /*                            GetMetadata()                             */
    1344             : /************************************************************************/
    1345             : 
    1346           2 : char **GDALProxyPoolRasterBand::GetMetadata(const char *pszDomain)
    1347             : {
    1348           2 :     if (metadataSet == nullptr)
    1349           2 :         metadataSet =
    1350           2 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1351             :                           free_func_get_metadata);
    1352             : 
    1353           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1354           2 :     if (poUnderlyingRasterBand == nullptr)
    1355           0 :         return nullptr;
    1356             : 
    1357             :     char **papszUnderlyingMetadata =
    1358           2 :         poUnderlyingRasterBand->GetMetadata(pszDomain);
    1359             : 
    1360             :     GetMetadataElt *pElt =
    1361           2 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1362           2 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1363           2 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1364           2 :     CPLHashSetInsert(metadataSet, pElt);
    1365             : 
    1366           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1367             : 
    1368           2 :     return pElt->papszMetadata;
    1369             : }
    1370             : 
    1371             : /************************************************************************/
    1372             : /*                        GetMetadataItem()                             */
    1373             : /************************************************************************/
    1374             : 
    1375          40 : const char *GDALProxyPoolRasterBand::GetMetadataItem(const char *pszName,
    1376             :                                                      const char *pszDomain)
    1377             : {
    1378          40 :     if (metadataItemSet == nullptr)
    1379          20 :         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
    1380             :                                         equal_func_get_metadata_item,
    1381             :                                         free_func_get_metadata_item);
    1382             : 
    1383          40 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1384          40 :     if (poUnderlyingRasterBand == nullptr)
    1385           0 :         return nullptr;
    1386             : 
    1387             :     const char *pszUnderlyingMetadataItem =
    1388          40 :         poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
    1389             : 
    1390             :     GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
    1391          40 :         CPLMalloc(sizeof(GetMetadataItemElt)));
    1392          40 :     pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
    1393          40 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1394          40 :     pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
    1395          40 :                                 ? CPLStrdup(pszUnderlyingMetadataItem)
    1396             :                                 : nullptr;
    1397          40 :     CPLHashSetInsert(metadataItemSet, pElt);
    1398             : 
    1399          40 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1400             : 
    1401          40 :     return pElt->pszMetadataItem;
    1402             : }
    1403             : 
    1404             : /* ******************************************************************** */
    1405             : /*                       GetCategoryNames()                             */
    1406             : /* ******************************************************************** */
    1407             : 
    1408           2 : char **GDALProxyPoolRasterBand::GetCategoryNames()
    1409             : {
    1410           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1411           2 :     if (poUnderlyingRasterBand == nullptr)
    1412           0 :         return nullptr;
    1413             : 
    1414           2 :     CSLDestroy(papszCategoryNames);
    1415           2 :     papszCategoryNames = nullptr;
    1416             : 
    1417             :     char **papszUnderlyingCategoryNames =
    1418           2 :         poUnderlyingRasterBand->GetCategoryNames();
    1419           2 :     if (papszUnderlyingCategoryNames)
    1420           0 :         papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
    1421             : 
    1422           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1423             : 
    1424           2 :     return papszCategoryNames;
    1425             : }
    1426             : 
    1427             : /* ******************************************************************** */
    1428             : /*                           GetUnitType()                              */
    1429             : /* ******************************************************************** */
    1430             : 
    1431           2 : const char *GDALProxyPoolRasterBand::GetUnitType()
    1432             : {
    1433           2 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1434           2 :     if (poUnderlyingRasterBand == nullptr)
    1435           0 :         return nullptr;
    1436             : 
    1437           2 :     CPLFree(pszUnitType);
    1438           2 :     pszUnitType = nullptr;
    1439             : 
    1440           2 :     const char *pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
    1441           2 :     if (pszUnderlyingUnitType)
    1442           2 :         pszUnitType = CPLStrdup(pszUnderlyingUnitType);
    1443             : 
    1444           2 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1445             : 
    1446           2 :     return pszUnitType;
    1447             : }
    1448             : 
    1449             : /* ******************************************************************** */
    1450             : /*                          GetColorTable()                             */
    1451             : /* ******************************************************************** */
    1452             : 
    1453         436 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
    1454             : {
    1455         436 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1456         436 :     if (poUnderlyingRasterBand == nullptr)
    1457           0 :         return nullptr;
    1458             : 
    1459         436 :     if (poColorTable)
    1460          31 :         delete poColorTable;
    1461         436 :     poColorTable = nullptr;
    1462             : 
    1463             :     GDALColorTable *poUnderlyingColorTable =
    1464         436 :         poUnderlyingRasterBand->GetColorTable();
    1465         436 :     if (poUnderlyingColorTable)
    1466          37 :         poColorTable = poUnderlyingColorTable->Clone();
    1467             : 
    1468         436 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1469             : 
    1470         436 :     return poColorTable;
    1471             : }
    1472             : 
    1473             : /* ******************************************************************** */
    1474             : /*                           GetOverview()                              */
    1475             : /* ******************************************************************** */
    1476             : 
    1477          36 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
    1478             : {
    1479          36 :     if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
    1480             :     {
    1481          12 :         if (papoProxyOverviewRasterBand[nOverviewBand])
    1482          12 :             return papoProxyOverviewRasterBand[nOverviewBand];
    1483             :     }
    1484             : 
    1485          24 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1486          24 :     if (poUnderlyingRasterBand == nullptr)
    1487           0 :         return nullptr;
    1488             : 
    1489             :     GDALRasterBand *poOverviewRasterBand =
    1490          24 :         poUnderlyingRasterBand->GetOverview(nOverviewBand);
    1491          24 :     if (poOverviewRasterBand == nullptr)
    1492             :     {
    1493           0 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1494           0 :         return nullptr;
    1495             :     }
    1496             : 
    1497          24 :     if (nOverviewBand >= nSizeProxyOverviewRasterBand)
    1498             :     {
    1499          24 :         papoProxyOverviewRasterBand =
    1500             :             static_cast<GDALProxyPoolOverviewRasterBand **>(
    1501          48 :                 CPLRealloc(papoProxyOverviewRasterBand,
    1502             :                            sizeof(GDALProxyPoolOverviewRasterBand *) *
    1503          24 :                                (nOverviewBand + 1)));
    1504          48 :         for (int i = nSizeProxyOverviewRasterBand; i < nOverviewBand + 1; i++)
    1505          24 :             papoProxyOverviewRasterBand[i] = nullptr;
    1506          24 :         nSizeProxyOverviewRasterBand = nOverviewBand + 1;
    1507             :     }
    1508             : 
    1509          24 :     papoProxyOverviewRasterBand[nOverviewBand] =
    1510             :         new GDALProxyPoolOverviewRasterBand(
    1511          24 :             cpl::down_cast<GDALProxyPoolDataset *>(poDS), poOverviewRasterBand,
    1512          24 :             this, nOverviewBand);
    1513             : 
    1514          24 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1515             : 
    1516          24 :     return papoProxyOverviewRasterBand[nOverviewBand];
    1517             : }
    1518             : 
    1519             : /* ******************************************************************** */
    1520             : /*                     GetRasterSampleOverview()                        */
    1521             : /* ******************************************************************** */
    1522             : 
    1523             : GDALRasterBand *
    1524           0 : GDALProxyPoolRasterBand::GetRasterSampleOverview(GUIntBig /* nDesiredSamples */)
    1525             : {
    1526           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    1527             :              "GDALProxyPoolRasterBand::GetRasterSampleOverview : not "
    1528             :              "implemented yet");
    1529           0 :     return nullptr;
    1530             : }
    1531             : 
    1532             : /* ******************************************************************** */
    1533             : /*                           GetMaskBand()                              */
    1534             : /* ******************************************************************** */
    1535             : 
    1536          88 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
    1537             : {
    1538          88 :     if (poProxyMaskBand)
    1539          50 :         return poProxyMaskBand;
    1540             : 
    1541          38 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1542          38 :     if (poUnderlyingRasterBand == nullptr)
    1543           0 :         return nullptr;
    1544             : 
    1545          38 :     GDALRasterBand *poMaskBand = poUnderlyingRasterBand->GetMaskBand();
    1546             : 
    1547          38 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1548          38 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), poMaskBand, this);
    1549             : 
    1550          38 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1551             : 
    1552          38 :     return poProxyMaskBand;
    1553             : }
    1554             : 
    1555             : /* ******************************************************************** */
    1556             : /*             GDALProxyPoolOverviewRasterBand()                        */
    1557             : /* ******************************************************************** */
    1558             : 
    1559          24 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(
    1560             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingOverviewBand,
    1561          24 :     GDALProxyPoolRasterBand *poMainBandIn, int nOverviewBandIn)
    1562             :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingOverviewBand),
    1563          24 :       poMainBand(poMainBandIn), nOverviewBand(nOverviewBandIn)
    1564             : {
    1565          24 : }
    1566             : 
    1567             : /* ******************************************************************** */
    1568             : /*                  ~GDALProxyPoolOverviewRasterBand()                  */
    1569             : /* ******************************************************************** */
    1570             : 
    1571          48 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
    1572             : {
    1573          24 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1574          48 : }
    1575             : 
    1576             : /* ******************************************************************** */
    1577             : /*                    RefUnderlyingRasterBand()                         */
    1578             : /* ******************************************************************** */
    1579             : 
    1580             : GDALRasterBand *
    1581           0 : GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1582             : {
    1583           0 :     poUnderlyingMainRasterBand =
    1584           0 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1585           0 :     if (poUnderlyingMainRasterBand == nullptr)
    1586           0 :         return nullptr;
    1587             : 
    1588           0 :     nRefCountUnderlyingMainRasterBand++;
    1589           0 :     return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
    1590             : }
    1591             : 
    1592             : /* ******************************************************************** */
    1593             : /*                  UnrefUnderlyingRasterBand()                         */
    1594             : /* ******************************************************************** */
    1595             : 
    1596           0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(
    1597             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1598             : {
    1599           0 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1600           0 :     nRefCountUnderlyingMainRasterBand--;
    1601           0 : }
    1602             : 
    1603             : /* ******************************************************************** */
    1604             : /*                     GDALProxyPoolMaskBand()                          */
    1605             : /* ******************************************************************** */
    1606             : 
    1607          38 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1608             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingMaskBand,
    1609          38 :     GDALProxyPoolRasterBand *poMainBandIn)
    1610          38 :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingMaskBand)
    1611             : {
    1612          38 :     poMainBand = poMainBandIn;
    1613             : 
    1614          38 :     poUnderlyingMainRasterBand = nullptr;
    1615          38 :     nRefCountUnderlyingMainRasterBand = 0;
    1616          38 : }
    1617             : 
    1618             : /* ******************************************************************** */
    1619             : /*                     GDALProxyPoolMaskBand()                          */
    1620             : /* ******************************************************************** */
    1621             : 
    1622          22 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1623             :     GDALProxyPoolDataset *poDSIn, GDALProxyPoolRasterBand *poMainBandIn,
    1624          22 :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1625             :     : GDALProxyPoolRasterBand(poDSIn, 1, eDataTypeIn, nBlockXSizeIn,
    1626             :                               nBlockYSizeIn),
    1627          22 :       poMainBand(poMainBandIn)
    1628             : {
    1629          22 : }
    1630             : 
    1631             : /* ******************************************************************** */
    1632             : /*                          ~GDALProxyPoolMaskBand()                    */
    1633             : /* ******************************************************************** */
    1634             : 
    1635         120 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
    1636             : {
    1637          60 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1638         120 : }
    1639             : 
    1640             : /* ******************************************************************** */
    1641             : /*                    RefUnderlyingRasterBand()                         */
    1642             : /* ******************************************************************** */
    1643             : 
    1644             : GDALRasterBand *
    1645         245 : GDALProxyPoolMaskBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1646             : {
    1647         245 :     poUnderlyingMainRasterBand =
    1648         245 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1649         245 :     if (poUnderlyingMainRasterBand == nullptr)
    1650           0 :         return nullptr;
    1651             : 
    1652         245 :     nRefCountUnderlyingMainRasterBand++;
    1653         245 :     return poUnderlyingMainRasterBand->GetMaskBand();
    1654             : }
    1655             : 
    1656             : /* ******************************************************************** */
    1657             : /*                  UnrefUnderlyingRasterBand()                         */
    1658             : /* ******************************************************************** */
    1659             : 
    1660         245 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(
    1661             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1662             : {
    1663         245 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1664         245 :     nRefCountUnderlyingMainRasterBand--;
    1665         245 : }
    1666             : 
    1667             : //! @endcond

Generated by: LCOV version 1.14