LCOV - code coverage report
Current view: top level - gcore - gdalproxypool.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 567 673 84.2 %
Date: 2024-05-03 15:49:35 Functions: 62 74 83.8 %

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

Generated by: LCOV version 1.14