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

Generated by: LCOV version 1.14