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