LCOV - code coverage report
Current view: top level - gcore - gdalproxypool.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 576 676 85.2 %
Date: 2025-11-27 10:26:27 Functions: 64 75 85.3 %

          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         496 : GDALDatasetPool::GDALDatasetPool(int maxSizeIn, int64_t nMaxRAMUsageIn)
     142         496 :     : maxSize(maxSizeIn), nMaxRAMUsage(nMaxRAMUsageIn)
     143             : {
     144         496 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                        ~GDALDatasetPool()                            */
     148             : /************************************************************************/
     149             : 
     150         986 : GDALDatasetPool::~GDALDatasetPool()
     151             : {
     152         493 :     bInDestruction = true;
     153         493 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     154         493 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     155        1005 :     while (cur)
     156             :     {
     157         512 :         GDALProxyPoolCacheEntry *next = cur->next;
     158         512 :         CPLFree(cur->pszFileNameAndOpenOptions);
     159         512 :         CPLFree(cur->pszOwner);
     160         512 :         CPLAssert(cur->refCount == 0);
     161         512 :         if (cur->poDS)
     162             :         {
     163           0 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     164           0 :             GDALClose(cur->poDS);
     165             :         }
     166         512 :         CPLFree(cur);
     167         512 :         cur = next;
     168             :     }
     169         493 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     170         493 : }
     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      237507 : static std::string GetFilenameAndOpenOptions(const char *pszFileName,
     221             :                                              CSLConstList papszOpenOptions)
     222             : {
     223      237507 :     std::string osFilenameAndOO(pszFileName);
     224      237571 :     for (int i = 0; papszOpenOptions && papszOpenOptions[i]; ++i)
     225             :     {
     226          64 :         osFilenameAndOO += "||";
     227          64 :         osFilenameAndOO += papszOpenOptions[i];
     228             :     }
     229      237507 :     return osFilenameAndOO;
     230             : }
     231             : 
     232             : /************************************************************************/
     233             : /*                            _RefDataset()                             */
     234             : /************************************************************************/
     235             : 
     236             : GDALProxyPoolCacheEntry *
     237      232685 : GDALDatasetPool::_RefDataset(const char *pszFileName, GDALAccess eAccess,
     238             :                              CSLConstList papszOpenOptions, int bShared,
     239             :                              bool bForceOpen, const char *pszOwner)
     240             : {
     241      232685 :     CPLMutex **pMutex = GDALGetphDLMutex();
     242      465370 :     CPLMutexHolderD(pMutex);
     243             : 
     244      232687 :     if (bInDestruction)
     245           0 :         return nullptr;
     246             : 
     247      232687 :     const GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     248             : 
     249             :     const auto EvictEntryWithZeroRefCount =
     250       17384 :         [this, responsiblePID](bool evictEntryWithOpenedDataset)
     251             :     {
     252        2897 :         GDALProxyPoolCacheEntry *cur = firstEntry;
     253        2897 :         GDALProxyPoolCacheEntry *candidate = nullptr;
     254      292403 :         while (cur)
     255             :         {
     256      289506 :             GDALProxyPoolCacheEntry *next = cur->next;
     257             : 
     258      289506 :             if (cur->refCount == 0 &&
     259      285243 :                 (!evictEntryWithOpenedDataset || cur->nRAMUsage > 0))
     260             :             {
     261      285243 :                 candidate = cur;
     262             :             }
     263             : 
     264      289506 :             cur = next;
     265             :         }
     266        2897 :         if (candidate == nullptr)
     267           0 :             return false;
     268             : 
     269        2897 :         nRAMUsage -= candidate->nRAMUsage;
     270        2897 :         candidate->nRAMUsage = 0;
     271             : 
     272        2897 :         CPLFree(candidate->pszFileNameAndOpenOptions);
     273        2897 :         candidate->pszFileNameAndOpenOptions = nullptr;
     274             : 
     275        2897 :         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        2897 :         CPLFree(candidate->pszOwner);
     289        2897 :         candidate->pszOwner = nullptr;
     290             : 
     291        2897 :         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        2897 :             if (candidate->prev)
     296        2897 :                 candidate->prev->next = candidate->next;
     297             : 
     298        2897 :             if (candidate->next)
     299           0 :                 candidate->next->prev = candidate->prev;
     300             :             else
     301             :             {
     302        2897 :                 CPLAssert(candidate == lastEntry);
     303        2897 :                 lastEntry->prev->next = nullptr;
     304        2897 :                 lastEntry = lastEntry->prev;
     305             :             }
     306        2897 :             candidate->prev = nullptr;
     307        2897 :             candidate->next = firstEntry;
     308        2897 :             firstEntry->prev = candidate;
     309        2897 :             firstEntry = candidate;
     310             : 
     311             : #ifdef DEBUG_PROXY_POOL
     312             :             CheckLinks();
     313             : #endif
     314             :         }
     315             : 
     316        2897 :         return true;
     317      232687 :     };
     318             : 
     319      232687 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     320             : 
     321             :     const std::string osFilenameAndOO =
     322      465374 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     323             : 
     324      747400 :     while (cur)
     325             :     {
     326      741538 :         GDALProxyPoolCacheEntry *next = cur->next;
     327             : 
     328     1028960 :         if (cur->refCount >= 0 && cur->pszFileNameAndOpenOptions &&
     329     1997600 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     330      227001 :             ((bShared && cur->responsiblePID == responsiblePID &&
     331      226782 :               ((cur->pszOwner == nullptr && pszOwner == nullptr) ||
     332      225876 :                (cur->pszOwner != nullptr && pszOwner != nullptr &&
     333      226194 :                 strcmp(cur->pszOwner, pszOwner) == 0))) ||
     334          99 :              (!bShared && cur->refCount == 0)))
     335             :         {
     336      226825 :             if (cur != firstEntry)
     337             :             {
     338             :                 /* Move to begin */
     339        7536 :                 if (cur->next)
     340        7173 :                     cur->next->prev = cur->prev;
     341             :                 else
     342         363 :                     lastEntry = cur->prev;
     343        7536 :                 cur->prev->next = cur->next;
     344        7536 :                 cur->prev = nullptr;
     345        7536 :                 firstEntry->prev = cur;
     346        7536 :                 cur->next = firstEntry;
     347        7536 :                 firstEntry = cur;
     348             : 
     349             : #ifdef DEBUG_PROXY_POOL
     350             :                 CheckLinks();
     351             : #endif
     352             :             }
     353             : 
     354      226825 :             cur->refCount++;
     355      226825 :             return cur;
     356             :         }
     357             : 
     358      514713 :         cur = next;
     359             :     }
     360             : 
     361        5862 :     if (!bForceOpen)
     362        2185 :         return nullptr;
     363             : 
     364        3677 :     if (currentSize == maxSize)
     365             :     {
     366        2897 :         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        2897 :         CPLAssert(firstEntry);
     379        2897 :         cur = firstEntry;
     380             :     }
     381             :     else
     382             :     {
     383             :         /* Prepend */
     384             :         cur = static_cast<GDALProxyPoolCacheEntry *>(
     385         780 :             CPLCalloc(1, sizeof(GDALProxyPoolCacheEntry)));
     386         780 :         if (lastEntry == nullptr)
     387         446 :             lastEntry = cur;
     388         780 :         cur->prev = nullptr;
     389         780 :         cur->next = firstEntry;
     390         780 :         if (firstEntry)
     391         334 :             firstEntry->prev = cur;
     392         780 :         firstEntry = cur;
     393         780 :         currentSize++;
     394             : #ifdef DEBUG_PROXY_POOL
     395             :         CheckLinks();
     396             : #endif
     397             :     }
     398             : 
     399        3677 :     cur->pszFileNameAndOpenOptions = CPLStrdup(osFilenameAndOO.c_str());
     400        3677 :     cur->pszOwner = (pszOwner) ? CPLStrdup(pszOwner) : nullptr;
     401        3677 :     cur->responsiblePID = responsiblePID;
     402        3677 :     cur->refCount = -1;  // to mark loading of dataset in progress
     403        3677 :     cur->nRAMUsage = 0;
     404             : 
     405        3677 :     refCountOfDisabledRefCount++;
     406        3677 :     const int nFlag =
     407             :         ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) |
     408        3677 :         GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
     409        3677 :     CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
     410             : 
     411             :     // Release mutex while opening dataset to avoid lock contention.
     412        3677 :     CPLReleaseMutex(*pMutex);
     413        3677 :     auto poDS = GDALDataset::Open(pszFileName, nFlag, nullptr, papszOpenOptions,
     414             :                                   nullptr);
     415        3677 :     CPLAcquireMutex(*pMutex, 1000.0);
     416             : 
     417        3677 :     cur->poDS = poDS;
     418        3677 :     cur->refCount = 1;
     419             : 
     420        3677 :     refCountOfDisabledRefCount--;
     421             : 
     422        3677 :     if (cur->poDS)
     423             :     {
     424        3429 :         cur->nRAMUsage =
     425        3429 :             std::max<GIntBig>(0, cur->poDS->GetEstimatedRAMUsage());
     426        3429 :         nRAMUsage += cur->nRAMUsage;
     427             :     }
     428             : 
     429        3677 :     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        3677 :     return cur;
     439             : }
     440             : 
     441             : /************************************************************************/
     442             : /*                   _CloseDatasetIfZeroRefCount()                      */
     443             : /************************************************************************/
     444             : 
     445        4820 : 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        4820 :     if (bInDestruction)
     452           0 :         return;
     453             : 
     454        4820 :     GDALProxyPoolCacheEntry *cur = firstEntry;
     455        4820 :     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
     456             : 
     457             :     const std::string osFilenameAndOO =
     458        9640 :         GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
     459             : 
     460       84385 :     while (cur)
     461             :     {
     462       82992 :         GDALProxyPoolCacheEntry *next = cur->next;
     463             : 
     464      103587 :         if (cur->refCount == 0 && cur->pszFileNameAndOpenOptions &&
     465       24291 :             osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
     466        3692 :             ((pszOwner == nullptr && cur->pszOwner == nullptr) ||
     467        3494 :              (pszOwner != nullptr && cur->pszOwner != nullptr &&
     468      169473 :               strcmp(cur->pszOwner, pszOwner) == 0)) &&
     469        3682 :             cur->poDS != nullptr)
     470             :         {
     471             :             /* Close by pretending we are the thread that GDALOpen'ed this */
     472             :             /* dataset */
     473        3427 :             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
     474             : 
     475        3427 :             GDALDataset *poDS = cur->poDS;
     476             : 
     477        3427 :             nRAMUsage -= cur->nRAMUsage;
     478        3427 :             cur->nRAMUsage = 0;
     479             : 
     480        3427 :             cur->poDS = nullptr;
     481        3427 :             CPLFree(cur->pszFileNameAndOpenOptions);
     482        3427 :             cur->pszFileNameAndOpenOptions = nullptr;
     483        3427 :             CPLFree(cur->pszOwner);
     484        3427 :             cur->pszOwner = nullptr;
     485             : 
     486        3427 :             refCountOfDisabledRefCount++;
     487        3427 :             GDALClose(poDS);
     488        3427 :             refCountOfDisabledRefCount--;
     489             : 
     490        3427 :             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     491        3427 :             break;
     492             :         }
     493             : 
     494       79565 :         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         533 : int GDALGetMaxDatasetPoolSize()
     506             : {
     507         533 :     int nSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
     508         533 :     if (nSize < 2)
     509           0 :         nSize = 2;
     510         533 :     else if (nSize > 1000)
     511           0 :         nSize = 1000;
     512         533 :     return nSize;
     513             : }
     514             : 
     515             : /************************************************************************/
     516             : /*                                 Ref()                                */
     517             : /************************************************************************/
     518             : 
     519        4820 : void GDALDatasetPool::Ref()
     520             : {
     521        9640 :     CPLMutexHolderD(GDALGetphDLMutex());
     522        4820 :     if (singleton == nullptr)
     523             :     {
     524             : 
     525             :         // Try to not consume more than 25% of the usable RAM
     526             :         GIntBig l_nMaxRAMUsage =
     527         496 :             (CPLGetUsablePhysicalRAM() - GDALGetCacheMax64()) / 4;
     528             :         const char *pszMaxRAMUsage =
     529         496 :             CPLGetConfigOption("GDAL_MAX_DATASET_POOL_RAM_USAGE", nullptr);
     530         496 :         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         496 :         singleton =
     540         496 :             new GDALDatasetPool(GDALGetMaxDatasetPoolSize(), l_nMaxRAMUsage);
     541             :     }
     542        4820 :     if (refCountOfDisabledRefCount == 0)
     543        4820 :         singleton->refCount++;
     544        4820 : }
     545             : 
     546             : /* keep that in sync with gdaldrivermanager.cpp */
     547        1123 : void GDALDatasetPool::PreventDestroy()
     548             : {
     549        1123 :     CPLMutexHolderD(GDALGetphDLMutex());
     550        1123 :     if (!singleton)
     551        1120 :         return;
     552           3 :     refCountOfDisabledRefCount++;
     553             : }
     554             : 
     555             : /* keep that in sync with gdaldrivermanager.cpp */
     556             : extern void GDALDatasetPoolPreventDestroy();
     557             : 
     558        1123 : void GDALDatasetPoolPreventDestroy()
     559             : {
     560        1123 :     GDALDatasetPool::PreventDestroy();
     561        1123 : }
     562             : 
     563             : /************************************************************************/
     564             : /*                               Unref()                                */
     565             : /************************************************************************/
     566             : 
     567        4820 : void GDALDatasetPool::Unref()
     568             : {
     569        4820 :     CPLMutexHolderD(GDALGetphDLMutex());
     570        4820 :     if (!singleton)
     571             :     {
     572           0 :         CPLAssert(false);
     573             :         return;
     574             :     }
     575        4820 :     if (refCountOfDisabledRefCount == 0)
     576             :     {
     577        4783 :         singleton->refCount--;
     578        4783 :         if (singleton->refCount == 0)
     579             :         {
     580         490 :             delete singleton;
     581         490 :             singleton = nullptr;
     582             :         }
     583             :     }
     584             : }
     585             : 
     586             : /* keep that in sync with gdaldrivermanager.cpp */
     587        1123 : void GDALDatasetPool::ForceDestroy()
     588             : {
     589        1123 :     CPLMutexHolderD(GDALGetphDLMutex());
     590        1123 :     if (!singleton)
     591        1120 :         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        1123 : void GDALDatasetPoolForceDestroy()
     603             : {
     604        1123 :     GDALDatasetPool::ForceDestroy();
     605        1123 : }
     606             : 
     607             : /************************************************************************/
     608             : /*                           RefDataset()                               */
     609             : /************************************************************************/
     610             : 
     611             : GDALProxyPoolCacheEntry *
     612      232685 : GDALDatasetPool::RefDataset(const char *pszFileName, GDALAccess eAccess,
     613             :                             char **papszOpenOptions, int bShared,
     614             :                             bool bForceOpen, const char *pszOwner)
     615             : {
     616      232685 :     return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions,
     617      232686 :                                   bShared, bForceOpen, pszOwner);
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                       UnrefDataset()                                 */
     622             : /************************************************************************/
     623             : 
     624      230500 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry)
     625             : {
     626      230500 :     CPLMutexHolderD(GDALGetphDLMutex());
     627      230502 :     cacheEntry->refCount--;
     628      230502 : }
     629             : 
     630             : /************************************************************************/
     631             : /*                   CloseDatasetIfZeroRefCount()                       */
     632             : /************************************************************************/
     633             : 
     634        4820 : void GDALDatasetPool::CloseDatasetIfZeroRefCount(const char *pszFileName,
     635             :                                                  CSLConstList papszOpenOptions,
     636             :                                                  GDALAccess eAccess,
     637             :                                                  const char *pszOwner)
     638             : {
     639        9640 :     CPLMutexHolderD(GDALGetphDLMutex());
     640        4820 :     singleton->_CloseDatasetIfZeroRefCount(pszFileName, papszOpenOptions,
     641             :                                            eAccess, pszOwner);
     642        4820 : }
     643             : 
     644             : struct GetMetadataElt
     645             : {
     646             :     char *pszDomain;
     647             :     char **papszMetadata;
     648             : };
     649             : 
     650          56 : static unsigned long hash_func_get_metadata(const void *_elt)
     651             : {
     652          56 :     const GetMetadataElt *elt = static_cast<const GetMetadataElt *>(_elt);
     653          56 :     return CPLHashSetHashStr(elt->pszDomain);
     654             : }
     655             : 
     656          14 : static int equal_func_get_metadata(const void *_elt1, const void *_elt2)
     657             : {
     658          14 :     const GetMetadataElt *elt1 = static_cast<const GetMetadataElt *>(_elt1);
     659          14 :     const GetMetadataElt *elt2 = static_cast<const GetMetadataElt *>(_elt2);
     660          14 :     return CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
     661             : }
     662             : 
     663          34 : static void free_func_get_metadata(void *_elt)
     664             : {
     665          34 :     GetMetadataElt *elt = static_cast<GetMetadataElt *>(_elt);
     666          34 :     CPLFree(elt->pszDomain);
     667          34 :     CSLDestroy(elt->papszMetadata);
     668          34 :     CPLFree(elt);
     669          34 : }
     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        1317 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     733             :     const char *pszSourceDatasetDescription, int nRasterXSizeIn,
     734             :     int nRasterYSizeIn, GDALAccess eAccessIn, int bSharedIn,
     735             :     const char *pszProjectionRefIn, const GDALGeoTransform *pGT,
     736        1317 :     const char *pszOwner)
     737        2634 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread()),
     738        1317 :       pszProjectionRef(pszProjectionRefIn ? CPLStrdup(pszProjectionRefIn)
     739        2634 :                                           : nullptr)
     740             : {
     741        1317 :     GDALDatasetPool::Ref();
     742             : 
     743        1317 :     SetDescription(pszSourceDatasetDescription);
     744             : 
     745        1317 :     nRasterXSize = nRasterXSizeIn;
     746        1317 :     nRasterYSize = nRasterYSizeIn;
     747        1317 :     eAccess = eAccessIn;
     748             : 
     749        1317 :     bShared = CPL_TO_BOOL(bSharedIn);
     750        1317 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     751             : 
     752        1317 :     if (pGT)
     753             :     {
     754        1268 :         m_gt = *pGT;
     755        1268 :         m_bHasSrcGeoTransform = true;
     756             :     }
     757             : 
     758        1317 :     if (pszProjectionRefIn)
     759             :     {
     760        1278 :         m_poSRS = new OGRSpatialReference();
     761        1278 :         m_poSRS->importFromWkt(pszProjectionRefIn);
     762        1278 :         m_bHasSrcSRS = true;
     763             :     }
     764        1317 : }
     765             : 
     766             : /* Constructor where the parameters (raster size, etc.) are obtained
     767             :  * by opening the underlying dataset.
     768             :  */
     769        3503 : GDALProxyPoolDataset::GDALProxyPoolDataset(
     770             :     const char *pszSourceDatasetDescription, GDALAccess eAccessIn,
     771        3503 :     int bSharedIn, const char *pszOwner)
     772        3503 :     : responsiblePID(GDALGetResponsiblePIDForCurrentThread())
     773             : {
     774        3503 :     GDALDatasetPool::Ref();
     775             : 
     776        3503 :     SetDescription(pszSourceDatasetDescription);
     777             : 
     778        3503 :     eAccess = eAccessIn;
     779             : 
     780        3503 :     bShared = CPL_TO_BOOL(bSharedIn);
     781        3503 :     m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
     782        3503 : }
     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        3503 : 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        7006 :         pszSourceDatasetDescription, eAccessIn, bSharedIn, pszOwner));
     798        3503 :     poSelf->SetOpenOptions(papszOpenOptionsIn);
     799        3503 :     GDALDataset *poUnderlyingDS = poSelf->RefUnderlyingDataset();
     800        3503 :     if (!poUnderlyingDS)
     801         255 :         return nullptr;
     802        3248 :     poSelf->nRasterXSize = poUnderlyingDS->GetRasterXSize();
     803        3248 :     poSelf->nRasterYSize = poUnderlyingDS->GetRasterYSize();
     804        3248 :     if (poUnderlyingDS->GetGeoTransform(poSelf->m_gt) == CE_None)
     805         980 :         poSelf->m_bHasSrcGeoTransform = true;
     806        3248 :     const auto poSRS = poUnderlyingDS->GetSpatialRef();
     807        3247 :     if (poSRS)
     808             :     {
     809         883 :         poSelf->m_poSRS = poSRS->Clone();
     810         884 :         poSelf->m_bHasSrcSRS = true;
     811             :     }
     812      106361 :     for (int i = 1; i <= poUnderlyingDS->GetRasterCount(); ++i)
     813             :     {
     814      103111 :         auto poSrcBand = poUnderlyingDS->GetRasterBand(i);
     815      103112 :         if (!poSrcBand)
     816             :         {
     817           0 :             poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     818           0 :             return nullptr;
     819             :         }
     820             :         int nSrcBlockXSize, nSrcBlockYSize;
     821      103112 :         poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
     822      103114 :         poSelf->AddSrcBandDescription(poSrcBand->GetRasterDataType(),
     823             :                                       nSrcBlockXSize, nSrcBlockYSize);
     824             :     }
     825        3248 :     poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
     826        3248 :     return poSelf.release();
     827             : }
     828             : 
     829             : /************************************************************************/
     830             : /*                    ~GDALProxyPoolDataset()                           */
     831             : /************************************************************************/
     832             : 
     833        9630 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
     834             : {
     835        4820 :     GDALDatasetPool::CloseDatasetIfZeroRefCount(
     836        4820 :         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        4820 :     bShared = false;
     845             : 
     846        4820 :     CPLFree(pszProjectionRef);
     847        4820 :     CPLFree(pszGCPProjection);
     848        4820 :     if (nGCPCount)
     849             :     {
     850           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     851           0 :         CPLFree(pasGCPList);
     852             :     }
     853        4820 :     if (metadataSet)
     854           5 :         CPLHashSetDestroy(metadataSet);
     855        4820 :     if (metadataItemSet)
     856           2 :         CPLHashSetDestroy(metadataItemSet);
     857        4820 :     CPLFree(m_pszOwner);
     858        4820 :     if (m_poSRS)
     859        2162 :         m_poSRS->Release();
     860        4820 :     if (m_poGCPSRS)
     861           0 :         m_poGCPSRS->Release();
     862             : 
     863        4820 :     GDALDatasetPool::Unref();
     864        9630 : }
     865             : 
     866             : /************************************************************************/
     867             : /*                        SetOpenOptions()                              */
     868             : /************************************************************************/
     869             : 
     870        4771 : void GDALProxyPoolDataset::SetOpenOptions(CSLConstList papszOpenOptionsIn)
     871             : {
     872        4771 :     CPLAssert(papszOpenOptions == nullptr);
     873        4771 :     papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
     874        4771 : }
     875             : 
     876             : /************************************************************************/
     877             : /*                    AddSrcBandDescription()                           */
     878             : /************************************************************************/
     879             : 
     880      105538 : void GDALProxyPoolDataset::AddSrcBandDescription(GDALDataType eDataType,
     881             :                                                  int nBlockXSize,
     882             :                                                  int nBlockYSize)
     883             : {
     884      105537 :     SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType,
     885      105538 :                                                     nBlockXSize, nBlockYSize));
     886      105538 : }
     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        4946 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset() const
     904             : {
     905        4946 :     return RefUnderlyingDataset(true);
     906             : }
     907             : 
     908      232686 : 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      232686 :     GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
     924      232687 :     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
     925      232686 :     cacheEntry =
     926      232685 :         GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
     927      232686 :                                     GetShared(), bForceOpen, m_pszOwner);
     928      232686 :     GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
     929      232687 :     if (cacheEntry != nullptr)
     930             :     {
     931      230502 :         if (cacheEntry->poDS != nullptr)
     932      230247 :             return cacheEntry->poDS;
     933             :         else
     934         255 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     935             :     }
     936        2440 :     return nullptr;
     937             : }
     938             : 
     939             : /************************************************************************/
     940             : /*                    UnrefUnderlyingDataset()                        */
     941             : /************************************************************************/
     942             : 
     943      230245 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(
     944             :     CPL_UNUSED GDALDataset *poUnderlyingDataset) const
     945             : {
     946      230245 :     if (cacheEntry != nullptr)
     947             :     {
     948      230245 :         CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
     949      230245 :         if (cacheEntry->poDS != nullptr)
     950      230246 :             GDALDatasetPool::UnrefDataset(cacheEntry);
     951             :     }
     952      230246 : }
     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         272 : const OGRSpatialReference *GDALProxyPoolDataset::GetSpatialRef() const
     985             : {
     986         272 :     if (m_bHasSrcSRS)
     987         203 :         return m_poSRS;
     988             :     else
     989             :     {
     990          69 :         if (m_poSRS)
     991           0 :             m_poSRS->Release();
     992          69 :         m_poSRS = nullptr;
     993          69 :         auto poSRS = GDALProxyDataset::GetSpatialRef();
     994          69 :         if (poSRS)
     995           0 :             m_poSRS = poSRS->Clone();
     996          69 :         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         818 : CPLErr GDALProxyPoolDataset::GetGeoTransform(GDALGeoTransform &gt) const
    1016             : {
    1017         818 :     if (m_bHasSrcGeoTransform)
    1018             :     {
    1019         818 :         gt = m_gt;
    1020         818 :         return CE_None;
    1021             :     }
    1022             :     else
    1023             :     {
    1024           0 :         return GDALProxyDataset::GetGeoTransform(gt);
    1025             :     }
    1026             : }
    1027             : 
    1028             : /************************************************************************/
    1029             : /*                            GetMetadata()                             */
    1030             : /************************************************************************/
    1031             : 
    1032          30 : char **GDALProxyPoolDataset::GetMetadata(const char *pszDomain)
    1033             : {
    1034          30 :     if (metadataSet == nullptr)
    1035           5 :         metadataSet =
    1036           5 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1037             :                           free_func_get_metadata);
    1038             : 
    1039          30 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1040          30 :     if (poUnderlyingDataset == nullptr)
    1041           0 :         return nullptr;
    1042             : 
    1043             :     char **papszUnderlyingMetadata =
    1044          30 :         poUnderlyingDataset->GetMetadata(pszDomain);
    1045             : 
    1046             :     GetMetadataElt *pElt =
    1047          30 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1048          30 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1049          30 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1050          30 :     CPLHashSetInsert(metadataSet, pElt);
    1051             : 
    1052          30 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1053             : 
    1054          30 :     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           4 : const OGRSpatialReference *GDALProxyPoolDataset::GetGCPSpatialRef() const
    1108             : {
    1109           4 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1110           4 :     if (poUnderlyingDataset == nullptr)
    1111           0 :         return nullptr;
    1112             : 
    1113           4 :     if (m_poGCPSRS)
    1114             :     {
    1115           0 :         m_poGCPSRS->Release();
    1116           0 :         m_poGCPSRS = nullptr;
    1117             :     }
    1118             : 
    1119           4 :     const auto poUnderlyingGCPSRS = poUnderlyingDataset->GetGCPSpatialRef();
    1120           4 :     if (poUnderlyingGCPSRS)
    1121           0 :         m_poGCPSRS = poUnderlyingGCPSRS->Clone();
    1122             : 
    1123           4 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1124             : 
    1125           4 :     return m_poGCPSRS;
    1126             : }
    1127             : 
    1128             : /************************************************************************/
    1129             : /*                            GetGCPs()                                 */
    1130             : /************************************************************************/
    1131             : 
    1132           0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
    1133             : {
    1134           0 :     GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
    1135           0 :     if (poUnderlyingDataset == nullptr)
    1136           0 :         return nullptr;
    1137             : 
    1138           0 :     if (nGCPCount)
    1139             :     {
    1140           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
    1141           0 :         CPLFree(pasGCPList);
    1142           0 :         pasGCPList = nullptr;
    1143             :     }
    1144             : 
    1145           0 :     const GDAL_GCP *pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
    1146           0 :     nGCPCount = poUnderlyingDataset->GetGCPCount();
    1147           0 :     if (nGCPCount)
    1148           0 :         pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList);
    1149             : 
    1150           0 :     UnrefUnderlyingDataset(poUnderlyingDataset);
    1151             : 
    1152           0 :     return pasGCPList;
    1153             : }
    1154             : 
    1155             : /************************************************************************/
    1156             : /*                     GDALProxyPoolDatasetCreate()                     */
    1157             : /************************************************************************/
    1158             : 
    1159        1268 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(
    1160             :     const char *pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize,
    1161             :     GDALAccess eAccess, int bShared, const char *pszProjectionRef,
    1162             :     const double *padfGeoTransform)
    1163             : {
    1164             :     return reinterpret_cast<GDALProxyPoolDatasetH>(new GDALProxyPoolDataset(
    1165             :         pszSourceDatasetDescription, nRasterXSize, nRasterYSize, eAccess,
    1166             :         bShared, pszProjectionRef,
    1167        1268 :         reinterpret_cast<const GDALGeoTransform *>(padfGeoTransform)));
    1168             : }
    1169             : 
    1170             : /************************************************************************/
    1171             : /*                       GDALProxyPoolDatasetDelete()                   */
    1172             : /************************************************************************/
    1173             : 
    1174           0 : void GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
    1175             : {
    1176           0 :     delete reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset);
    1177           0 : }
    1178             : 
    1179             : /************************************************************************/
    1180             : /*              GDALProxyPoolDatasetAddSrcBandDescription()             */
    1181             : /************************************************************************/
    1182             : 
    1183        2385 : void GDALProxyPoolDatasetAddSrcBandDescription(
    1184             :     GDALProxyPoolDatasetH hProxyPoolDataset, GDALDataType eDataType,
    1185             :     int nBlockXSize, int nBlockYSize)
    1186             : {
    1187             :     reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset)
    1188        2385 :         ->AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
    1189        2385 : }
    1190             : 
    1191             : /* ******************************************************************** */
    1192             : /*                    GDALProxyPoolRasterBand()                         */
    1193             : /* ******************************************************************** */
    1194             : 
    1195      105560 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset *poDSIn,
    1196             :                                                  int nBandIn,
    1197             :                                                  GDALDataType eDataTypeIn,
    1198             :                                                  int nBlockXSizeIn,
    1199      105560 :                                                  int nBlockYSizeIn)
    1200             : {
    1201      105559 :     poDS = poDSIn;
    1202      105559 :     nBand = nBandIn;
    1203      105559 :     eDataType = eDataTypeIn;
    1204      105559 :     nRasterXSize = poDSIn->GetRasterXSize();
    1205      105560 :     nRasterYSize = poDSIn->GetRasterYSize();
    1206      105560 :     nBlockXSize = nBlockXSizeIn;
    1207      105560 :     nBlockYSize = nBlockYSizeIn;
    1208      105560 : }
    1209             : 
    1210             : /* ******************************************************************** */
    1211             : /*                    GDALProxyPoolRasterBand()                         */
    1212             : /* ******************************************************************** */
    1213             : 
    1214          62 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(
    1215          62 :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingRasterBand)
    1216             : {
    1217          62 :     poDS = poDSIn;
    1218          62 :     nBand = poUnderlyingRasterBand->GetBand();
    1219          62 :     eDataType = poUnderlyingRasterBand->GetRasterDataType();
    1220          62 :     nRasterXSize = poUnderlyingRasterBand->GetXSize();
    1221          62 :     nRasterYSize = poUnderlyingRasterBand->GetYSize();
    1222          62 :     poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    1223          62 : }
    1224             : 
    1225             : /* ******************************************************************** */
    1226             : /*                   ~GDALProxyPoolRasterBand()                         */
    1227             : /* ******************************************************************** */
    1228      211160 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
    1229             : {
    1230      105622 :     if (metadataSet)
    1231           3 :         CPLHashSetDestroy(metadataSet);
    1232      105622 :     if (metadataItemSet)
    1233          20 :         CPLHashSetDestroy(metadataItemSet);
    1234      105622 :     CPLFree(pszUnitType);
    1235      105622 :     CSLDestroy(papszCategoryNames);
    1236      105622 :     if (poColorTable)
    1237           6 :         delete poColorTable;
    1238             : 
    1239      105646 :     for (int i = 0; i < nSizeProxyOverviewRasterBand; i++)
    1240             :     {
    1241          24 :         if (papoProxyOverviewRasterBand[i])
    1242          24 :             delete papoProxyOverviewRasterBand[i];
    1243             :     }
    1244      105622 :     CPLFree(papoProxyOverviewRasterBand);
    1245      105622 :     if (poProxyMaskBand)
    1246          60 :         delete poProxyMaskBand;
    1247      211160 : }
    1248             : 
    1249             : /************************************************************************/
    1250             : /*                AddSrcMaskBandDescriptionFromUnderlying()             */
    1251             : /************************************************************************/
    1252             : 
    1253          15 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescriptionFromUnderlying()
    1254             : {
    1255          15 :     if (poProxyMaskBand != nullptr)
    1256           6 :         return;
    1257           9 :     GDALRasterBand *poUnderlyingBand = RefUnderlyingRasterBand();
    1258           9 :     if (poUnderlyingBand == nullptr)
    1259           0 :         return;
    1260           9 :     auto poSrcMaskBand = poUnderlyingBand->GetMaskBand();
    1261             :     int nSrcBlockXSize, nSrcBlockYSize;
    1262           9 :     poSrcMaskBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1263           9 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1264           9 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this,
    1265           9 :         poSrcMaskBand->GetRasterDataType(), nSrcBlockXSize, nSrcBlockYSize);
    1266           9 :     UnrefUnderlyingRasterBand(poUnderlyingBand);
    1267             : }
    1268             : 
    1269             : /************************************************************************/
    1270             : /*                 AddSrcMaskBandDescription()                          */
    1271             : /************************************************************************/
    1272             : 
    1273          13 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescription(
    1274             :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1275             : {
    1276          13 :     CPLAssert(poProxyMaskBand == nullptr);
    1277          13 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1278          13 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), this, eDataTypeIn,
    1279          13 :         nBlockXSizeIn, nBlockYSizeIn);
    1280          13 : }
    1281             : 
    1282             : /************************************************************************/
    1283             : /*                  RefUnderlyingRasterBand()                           */
    1284             : /************************************************************************/
    1285             : 
    1286             : GDALRasterBand *
    1287      227741 : GDALProxyPoolRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1288             : {
    1289             :     GDALDataset *poUnderlyingDataset =
    1290      227741 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1291      227741 :             ->RefUnderlyingDataset(bForceOpen);
    1292      227741 :     if (poUnderlyingDataset == nullptr)
    1293        2185 :         return nullptr;
    1294             : 
    1295      225556 :     GDALRasterBand *poBand = poUnderlyingDataset->GetRasterBand(nBand);
    1296      225556 :     if (poBand == nullptr)
    1297             :     {
    1298           0 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1299           0 :             ->UnrefUnderlyingDataset(poUnderlyingDataset);
    1300             :     }
    1301      225556 :     else if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1302             :     {
    1303             :         // Here we try to load nBlockXSize&nBlockYSize from underlying band
    1304             :         // but we must guarantee that we will not access directly to
    1305             :         // nBlockXSize/nBlockYSize before RefUnderlyingRasterBand() is called
    1306             :         int nSrcBlockXSize, nSrcBlockYSize;
    1307          10 :         poBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
    1308          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockXSize =
    1309             :             nSrcBlockXSize;
    1310          10 :         const_cast<GDALProxyPoolRasterBand *>(this)->nBlockYSize =
    1311             :             nSrcBlockYSize;
    1312             :     }
    1313             : 
    1314      225556 :     return poBand;
    1315             : }
    1316             : 
    1317             : /************************************************************************/
    1318             : /*                  UnrefUnderlyingRasterBand()                       */
    1319             : /************************************************************************/
    1320             : 
    1321      225555 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(
    1322             :     GDALRasterBand *poUnderlyingRasterBand) const
    1323             : {
    1324      225555 :     if (poUnderlyingRasterBand)
    1325      225555 :         (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
    1326      225554 :             ->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
    1327      225556 : }
    1328             : 
    1329             : /************************************************************************/
    1330             : /*                             FlushCache()                             */
    1331             : /************************************************************************/
    1332             : 
    1333      104640 : CPLErr GDALProxyPoolRasterBand::FlushCache(bool bAtClosing)
    1334             : {
    1335      104640 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand(false);
    1336      104640 :     if (poUnderlyingRasterBand)
    1337             :     {
    1338      102455 :         CPLErr eErr = poUnderlyingRasterBand->FlushCache(bAtClosing);
    1339      102455 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1340      102455 :         return eErr;
    1341             :     }
    1342        2185 :     return CE_None;
    1343             : }
    1344             : 
    1345             : /************************************************************************/
    1346             : /*                            GetMetadata()                             */
    1347             : /************************************************************************/
    1348             : 
    1349           4 : char **GDALProxyPoolRasterBand::GetMetadata(const char *pszDomain)
    1350             : {
    1351           4 :     if (metadataSet == nullptr)
    1352           3 :         metadataSet =
    1353           3 :             CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
    1354             :                           free_func_get_metadata);
    1355             : 
    1356           4 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1357           4 :     if (poUnderlyingRasterBand == nullptr)
    1358           0 :         return nullptr;
    1359             : 
    1360             :     char **papszUnderlyingMetadata =
    1361           4 :         poUnderlyingRasterBand->GetMetadata(pszDomain);
    1362             : 
    1363             :     GetMetadataElt *pElt =
    1364           4 :         static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
    1365           4 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1366           4 :     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
    1367           4 :     CPLHashSetInsert(metadataSet, pElt);
    1368             : 
    1369           4 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1370             : 
    1371           4 :     return pElt->papszMetadata;
    1372             : }
    1373             : 
    1374             : /************************************************************************/
    1375             : /*                        GetMetadataItem()                             */
    1376             : /************************************************************************/
    1377             : 
    1378          40 : const char *GDALProxyPoolRasterBand::GetMetadataItem(const char *pszName,
    1379             :                                                      const char *pszDomain)
    1380             : {
    1381          40 :     if (metadataItemSet == nullptr)
    1382          20 :         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
    1383             :                                         equal_func_get_metadata_item,
    1384             :                                         free_func_get_metadata_item);
    1385             : 
    1386          40 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1387          40 :     if (poUnderlyingRasterBand == nullptr)
    1388           0 :         return nullptr;
    1389             : 
    1390             :     const char *pszUnderlyingMetadataItem =
    1391          40 :         poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
    1392             : 
    1393             :     GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
    1394          40 :         CPLMalloc(sizeof(GetMetadataItemElt)));
    1395          40 :     pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
    1396          40 :     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
    1397          40 :     pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
    1398          40 :                                 ? CPLStrdup(pszUnderlyingMetadataItem)
    1399             :                                 : nullptr;
    1400          40 :     CPLHashSetInsert(metadataItemSet, pElt);
    1401             : 
    1402          40 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1403             : 
    1404          40 :     return pElt->pszMetadataItem;
    1405             : }
    1406             : 
    1407             : /* ******************************************************************** */
    1408             : /*                       GetCategoryNames()                             */
    1409             : /* ******************************************************************** */
    1410             : 
    1411           3 : char **GDALProxyPoolRasterBand::GetCategoryNames()
    1412             : {
    1413           3 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1414           3 :     if (poUnderlyingRasterBand == nullptr)
    1415           0 :         return nullptr;
    1416             : 
    1417           3 :     CSLDestroy(papszCategoryNames);
    1418           3 :     papszCategoryNames = nullptr;
    1419             : 
    1420             :     char **papszUnderlyingCategoryNames =
    1421           3 :         poUnderlyingRasterBand->GetCategoryNames();
    1422           3 :     if (papszUnderlyingCategoryNames)
    1423           0 :         papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
    1424             : 
    1425           3 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1426             : 
    1427           3 :     return papszCategoryNames;
    1428             : }
    1429             : 
    1430             : /* ******************************************************************** */
    1431             : /*                           GetUnitType()                              */
    1432             : /* ******************************************************************** */
    1433             : 
    1434           4 : const char *GDALProxyPoolRasterBand::GetUnitType()
    1435             : {
    1436           4 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1437           4 :     if (poUnderlyingRasterBand == nullptr)
    1438           0 :         return nullptr;
    1439             : 
    1440           4 :     CPLFree(pszUnitType);
    1441           4 :     pszUnitType = nullptr;
    1442             : 
    1443           4 :     const char *pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
    1444           4 :     if (pszUnderlyingUnitType)
    1445           4 :         pszUnitType = CPLStrdup(pszUnderlyingUnitType);
    1446             : 
    1447           4 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1448             : 
    1449           4 :     return pszUnitType;
    1450             : }
    1451             : 
    1452             : /* ******************************************************************** */
    1453             : /*                          GetColorTable()                             */
    1454             : /* ******************************************************************** */
    1455             : 
    1456         454 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
    1457             : {
    1458         454 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1459         454 :     if (poUnderlyingRasterBand == nullptr)
    1460           0 :         return nullptr;
    1461             : 
    1462         454 :     if (poColorTable)
    1463          31 :         delete poColorTable;
    1464         454 :     poColorTable = nullptr;
    1465             : 
    1466             :     GDALColorTable *poUnderlyingColorTable =
    1467         454 :         poUnderlyingRasterBand->GetColorTable();
    1468         454 :     if (poUnderlyingColorTable)
    1469          37 :         poColorTable = poUnderlyingColorTable->Clone();
    1470             : 
    1471         454 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1472             : 
    1473         454 :     return poColorTable;
    1474             : }
    1475             : 
    1476             : /* ******************************************************************** */
    1477             : /*                           GetOverview()                              */
    1478             : /* ******************************************************************** */
    1479             : 
    1480          36 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
    1481             : {
    1482          36 :     if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
    1483             :     {
    1484          12 :         if (papoProxyOverviewRasterBand[nOverviewBand])
    1485          12 :             return papoProxyOverviewRasterBand[nOverviewBand];
    1486             :     }
    1487             : 
    1488          24 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1489          24 :     if (poUnderlyingRasterBand == nullptr)
    1490           0 :         return nullptr;
    1491             : 
    1492             :     GDALRasterBand *poOverviewRasterBand =
    1493          24 :         poUnderlyingRasterBand->GetOverview(nOverviewBand);
    1494          24 :     if (poOverviewRasterBand == nullptr)
    1495             :     {
    1496           0 :         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1497           0 :         return nullptr;
    1498             :     }
    1499             : 
    1500          24 :     if (nOverviewBand >= nSizeProxyOverviewRasterBand)
    1501             :     {
    1502          24 :         papoProxyOverviewRasterBand =
    1503             :             static_cast<GDALProxyPoolOverviewRasterBand **>(
    1504          48 :                 CPLRealloc(papoProxyOverviewRasterBand,
    1505             :                            sizeof(GDALProxyPoolOverviewRasterBand *) *
    1506          24 :                                (nOverviewBand + 1)));
    1507          48 :         for (int i = nSizeProxyOverviewRasterBand; i < nOverviewBand + 1; i++)
    1508          24 :             papoProxyOverviewRasterBand[i] = nullptr;
    1509          24 :         nSizeProxyOverviewRasterBand = nOverviewBand + 1;
    1510             :     }
    1511             : 
    1512          24 :     papoProxyOverviewRasterBand[nOverviewBand] =
    1513             :         new GDALProxyPoolOverviewRasterBand(
    1514          24 :             cpl::down_cast<GDALProxyPoolDataset *>(poDS), poOverviewRasterBand,
    1515          24 :             this, nOverviewBand);
    1516             : 
    1517          24 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1518             : 
    1519          24 :     return papoProxyOverviewRasterBand[nOverviewBand];
    1520             : }
    1521             : 
    1522             : /* ******************************************************************** */
    1523             : /*                     GetRasterSampleOverview()                        */
    1524             : /* ******************************************************************** */
    1525             : 
    1526             : GDALRasterBand *
    1527           0 : GDALProxyPoolRasterBand::GetRasterSampleOverview(GUIntBig /* nDesiredSamples */)
    1528             : {
    1529           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    1530             :              "GDALProxyPoolRasterBand::GetRasterSampleOverview : not "
    1531             :              "implemented yet");
    1532           0 :     return nullptr;
    1533             : }
    1534             : 
    1535             : /* ******************************************************************** */
    1536             : /*                           GetMaskBand()                              */
    1537             : /* ******************************************************************** */
    1538             : 
    1539          88 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
    1540             : {
    1541          88 :     if (poProxyMaskBand)
    1542          50 :         return poProxyMaskBand;
    1543             : 
    1544          38 :     GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
    1545          38 :     if (poUnderlyingRasterBand == nullptr)
    1546           0 :         return nullptr;
    1547             : 
    1548          38 :     GDALRasterBand *poMaskBand = poUnderlyingRasterBand->GetMaskBand();
    1549             : 
    1550          38 :     poProxyMaskBand = new GDALProxyPoolMaskBand(
    1551          38 :         cpl::down_cast<GDALProxyPoolDataset *>(poDS), poMaskBand, this);
    1552             : 
    1553          38 :     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
    1554             : 
    1555          38 :     return poProxyMaskBand;
    1556             : }
    1557             : 
    1558             : /* ******************************************************************** */
    1559             : /*             GDALProxyPoolOverviewRasterBand()                        */
    1560             : /* ******************************************************************** */
    1561             : 
    1562          24 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(
    1563             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingOverviewBand,
    1564          24 :     GDALProxyPoolRasterBand *poMainBandIn, int nOverviewBandIn)
    1565             :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingOverviewBand),
    1566          24 :       poMainBand(poMainBandIn), nOverviewBand(nOverviewBandIn)
    1567             : {
    1568          24 : }
    1569             : 
    1570             : /* ******************************************************************** */
    1571             : /*                  ~GDALProxyPoolOverviewRasterBand()                  */
    1572             : /* ******************************************************************** */
    1573             : 
    1574          48 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
    1575             : {
    1576          24 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1577          48 : }
    1578             : 
    1579             : /* ******************************************************************** */
    1580             : /*                    RefUnderlyingRasterBand()                         */
    1581             : /* ******************************************************************** */
    1582             : 
    1583             : GDALRasterBand *
    1584           0 : GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1585             : {
    1586           0 :     poUnderlyingMainRasterBand =
    1587           0 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1588           0 :     if (poUnderlyingMainRasterBand == nullptr)
    1589           0 :         return nullptr;
    1590             : 
    1591           0 :     nRefCountUnderlyingMainRasterBand++;
    1592           0 :     return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
    1593             : }
    1594             : 
    1595             : /* ******************************************************************** */
    1596             : /*                  UnrefUnderlyingRasterBand()                         */
    1597             : /* ******************************************************************** */
    1598             : 
    1599           0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(
    1600             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1601             : {
    1602           0 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1603           0 :     nRefCountUnderlyingMainRasterBand--;
    1604           0 : }
    1605             : 
    1606             : /* ******************************************************************** */
    1607             : /*                     GDALProxyPoolMaskBand()                          */
    1608             : /* ******************************************************************** */
    1609             : 
    1610          38 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1611             :     GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingMaskBand,
    1612          38 :     GDALProxyPoolRasterBand *poMainBandIn)
    1613          38 :     : GDALProxyPoolRasterBand(poDSIn, poUnderlyingMaskBand)
    1614             : {
    1615          38 :     poMainBand = poMainBandIn;
    1616             : 
    1617          38 :     poUnderlyingMainRasterBand = nullptr;
    1618          38 :     nRefCountUnderlyingMainRasterBand = 0;
    1619          38 : }
    1620             : 
    1621             : /* ******************************************************************** */
    1622             : /*                     GDALProxyPoolMaskBand()                          */
    1623             : /* ******************************************************************** */
    1624             : 
    1625          22 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
    1626             :     GDALProxyPoolDataset *poDSIn, GDALProxyPoolRasterBand *poMainBandIn,
    1627          22 :     GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
    1628             :     : GDALProxyPoolRasterBand(poDSIn, 1, eDataTypeIn, nBlockXSizeIn,
    1629             :                               nBlockYSizeIn),
    1630          22 :       poMainBand(poMainBandIn)
    1631             : {
    1632          22 : }
    1633             : 
    1634             : /* ******************************************************************** */
    1635             : /*                          ~GDALProxyPoolMaskBand()                    */
    1636             : /* ******************************************************************** */
    1637             : 
    1638         120 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
    1639             : {
    1640          60 :     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
    1641         120 : }
    1642             : 
    1643             : /* ******************************************************************** */
    1644             : /*                    RefUnderlyingRasterBand()                         */
    1645             : /* ******************************************************************** */
    1646             : 
    1647             : GDALRasterBand *
    1648         245 : GDALProxyPoolMaskBand::RefUnderlyingRasterBand(bool bForceOpen) const
    1649             : {
    1650         245 :     poUnderlyingMainRasterBand =
    1651         245 :         poMainBand->RefUnderlyingRasterBand(bForceOpen);
    1652         245 :     if (poUnderlyingMainRasterBand == nullptr)
    1653           0 :         return nullptr;
    1654             : 
    1655         245 :     nRefCountUnderlyingMainRasterBand++;
    1656         245 :     return poUnderlyingMainRasterBand->GetMaskBand();
    1657             : }
    1658             : 
    1659             : /* ******************************************************************** */
    1660             : /*                  UnrefUnderlyingRasterBand()                         */
    1661             : /* ******************************************************************** */
    1662             : 
    1663         245 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(
    1664             :     GDALRasterBand * /* poUnderlyingRasterBand */) const
    1665             : {
    1666         245 :     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
    1667         245 :     nRefCountUnderlyingMainRasterBand--;
    1668         245 : }
    1669             : 
    1670             : //! @endcond

Generated by: LCOV version 1.14