1 /******************************************************************************
2  * $Id: gdalproxypool.cpp 29326 2015-06-10 20:36:31Z rouault $
3  *
4  * Project:  GDAL Core
5  * Purpose:  A dataset and raster band classes that differ the opening of the
6  *           underlying dataset in a limited pool of opened datasets.
7  * Author:   Even Rouault <even dot rouault at mines dash paris dot org>
8  *
9  ******************************************************************************
10  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "gdal_proxy.h"
32 #include "cpl_multiproc.h"
33 
34 CPL_CVSID("$Id: gdalproxypool.cpp 29326 2015-06-10 20:36:31Z rouault $");
35 
36 /* We *must* share the same mutex as the gdaldataset.cpp file, as we are */
37 /* doing GDALOpen() calls that can indirectly call GDALOpenShared() on */
38 /* an auxiliary dataset ... */
39 /* Then we could get dead-locks in multi-threaded use case */
40 
41 /* ******************************************************************** */
42 /*                         GDALDatasetPool                              */
43 /* ******************************************************************** */
44 
45 /* This class is a singleton that maintains a pool of opened datasets */
46 /* The cache uses a LRU strategy */
47 
48 class GDALDatasetPool;
49 static GDALDatasetPool* singleton = NULL;
50 
GDALNullifyProxyPoolSingleton()51 void GDALNullifyProxyPoolSingleton() { singleton = NULL; }
52 
53 struct _GDALProxyPoolCacheEntry
54 {
55     GIntBig       responsiblePID;
56     char         *pszFileName;
57     GDALDataset  *poDS;
58 
59     /* Ref count of the cached dataset */
60     int           refCount;
61 
62     GDALProxyPoolCacheEntry* prev;
63     GDALProxyPoolCacheEntry* next;
64 };
65 
66 class GDALDatasetPool
67 {
68     private:
69         /* Ref count of the pool singleton */
70         /* Taken by "toplevel" GDALProxyPoolDataset in its constructor and released */
71         /* in its destructor. See also refCountOfDisableRefCount for the difference */
72         /* between toplevel and inner GDALProxyPoolDataset */
73         int refCount;
74 
75         int maxSize;
76         int currentSize;
77         GDALProxyPoolCacheEntry* firstEntry;
78         GDALProxyPoolCacheEntry* lastEntry;
79 
80         /* This variable prevents a dataset that is going to be opened in GDALDatasetPool::_RefDataset */
81         /* from increasing refCount if, during its opening, it creates a GDALProxyPoolDataset */
82         /* We increment it before opening or closing a cached dataset and decrement it afterwards */
83         /* The typical use case is a VRT made of simple sources that are VRT */
84         /* We don't want the "inner" VRT to take a reference on the pool, otherwise there is */
85         /* a high chance that this reference will not be dropped and the pool remain ghost */
86         int refCountOfDisableRefCount;
87 
88         /* Caution : to be sure that we don't run out of entries, size must be at */
89         /* least greater or equal than the maximum number of threads */
90         GDALDatasetPool(int maxSize);
91         ~GDALDatasetPool();
92         GDALProxyPoolCacheEntry* _RefDataset(const char* pszFileName,
93                                              GDALAccess eAccess,
94                                              char** papszOpenOptions,
95                                              int bShared);
96         void _CloseDataset(const char* pszFileName, GDALAccess eAccess);
97 
98         void ShowContent();
99         void CheckLinks();
100 
101     public:
102         static void Ref();
103         static void Unref();
104         static GDALProxyPoolCacheEntry* RefDataset(const char* pszFileName,
105                                                    GDALAccess eAccess,
106                                                    char** papszOpenOptions,
107                                                    int bShared);
108         static void UnrefDataset(GDALProxyPoolCacheEntry* cacheEntry);
109         static void CloseDataset(const char* pszFileName, GDALAccess eAccess);
110 
111         static void PreventDestroy();
112         static void ForceDestroy();
113 };
114 
115 
116 /************************************************************************/
117 /*                         GDALDatasetPool()                            */
118 /************************************************************************/
119 
GDALDatasetPool(int maxSize)120 GDALDatasetPool::GDALDatasetPool(int maxSize)
121 {
122     this->maxSize = maxSize;
123     currentSize = 0;
124     firstEntry = NULL;
125     lastEntry = NULL;
126     refCount = 0;
127     refCountOfDisableRefCount = 0;
128 }
129 
130 /************************************************************************/
131 /*                        ~GDALDatasetPool()                            */
132 /************************************************************************/
133 
~GDALDatasetPool()134 GDALDatasetPool::~GDALDatasetPool()
135 {
136     GDALProxyPoolCacheEntry* cur = firstEntry;
137     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
138     while(cur)
139     {
140         GDALProxyPoolCacheEntry* next = cur->next;
141         CPLFree(cur->pszFileName);
142         CPLAssert(cur->refCount == 0);
143         if (cur->poDS)
144         {
145             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
146             GDALClose(cur->poDS);
147         }
148         CPLFree(cur);
149         cur = next;
150     }
151     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
152 }
153 
154 /************************************************************************/
155 /*                            ShowContent()                             */
156 /************************************************************************/
157 
ShowContent()158 void GDALDatasetPool::ShowContent()
159 {
160     GDALProxyPoolCacheEntry* cur = firstEntry;
161     int i = 0;
162     while(cur)
163     {
164         printf("[%d] pszFileName=%s, refCount=%d, responsiblePID=%d\n",
165                i, cur->pszFileName, cur->refCount, (int)cur->responsiblePID);
166         i++;
167         cur = cur->next;
168     }
169 }
170 
171 /************************************************************************/
172 /*                             CheckLinks()                             */
173 /************************************************************************/
174 
CheckLinks()175 void GDALDatasetPool::CheckLinks()
176 {
177     GDALProxyPoolCacheEntry* cur = firstEntry;
178     int i = 0;
179     while(cur)
180     {
181         CPLAssert(cur == firstEntry || cur->prev->next == cur);
182         CPLAssert(cur == lastEntry || cur->next->prev == cur);
183         i++;
184 	CPLAssert(cur->next != NULL || cur == lastEntry);
185         cur = cur->next;
186     }
187     CPLAssert(i == currentSize);
188 }
189 
190 /************************************************************************/
191 /*                            _RefDataset()                             */
192 /************************************************************************/
193 
_RefDataset(const char * pszFileName,GDALAccess eAccess,char ** papszOpenOptions,int bShared)194 GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName,
195                                                       GDALAccess eAccess,
196                                                       char** papszOpenOptions,
197                                                       int bShared)
198 {
199     GDALProxyPoolCacheEntry* cur = firstEntry;
200     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
201     GDALProxyPoolCacheEntry* lastEntryWithZeroRefCount = NULL;
202 
203     while(cur)
204     {
205         GDALProxyPoolCacheEntry* next = cur->next;
206 
207         if (strcmp(cur->pszFileName, pszFileName) == 0 &&
208             ((bShared && cur->responsiblePID == responsiblePID) ||
209              (!bShared && cur->refCount == 0)) )
210         {
211             if (cur != firstEntry)
212             {
213                 /* Move to begin */
214                 if (cur->next)
215                     cur->next->prev = cur->prev;
216                 else
217                     lastEntry = cur->prev;
218                 cur->prev->next = cur->next;
219                 cur->prev = NULL;
220                 firstEntry->prev = cur;
221                 cur->next = firstEntry;
222                 firstEntry = cur;
223 
224 #ifdef DEBUG_PROXY_POOL
225                 CheckLinks();
226 #endif
227             }
228 
229             cur->refCount ++;
230             return cur;
231         }
232 
233         if (cur->refCount == 0)
234             lastEntryWithZeroRefCount = cur;
235 
236         cur = next;
237     }
238 
239     if (currentSize == maxSize)
240     {
241         if (lastEntryWithZeroRefCount == NULL)
242         {
243             CPLError(CE_Failure, CPLE_AppDefined,
244                      "Too many threads are running for the current value of the dataset pool size (%d).\n"
245                      "or too many proxy datasets are opened in a cascaded way.\n"
246                      "Try increasing GDAL_MAX_DATASET_POOL_SIZE.", maxSize);
247             return NULL;
248         }
249 
250         CPLFree(lastEntryWithZeroRefCount->pszFileName);
251         lastEntryWithZeroRefCount->pszFileName = NULL;
252         if (lastEntryWithZeroRefCount->poDS)
253         {
254             /* Close by pretending we are the thread that GDALOpen'ed this */
255             /* dataset */
256             GDALSetResponsiblePIDForCurrentThread(lastEntryWithZeroRefCount->responsiblePID);
257 
258             refCountOfDisableRefCount ++;
259             GDALClose(lastEntryWithZeroRefCount->poDS);
260             refCountOfDisableRefCount --;
261 
262             lastEntryWithZeroRefCount->poDS = NULL;
263             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
264         }
265 
266         /* Recycle this entry for the to-be-openeded dataset and */
267         /* moves it to the top of the list */
268         if (lastEntryWithZeroRefCount->prev)
269             lastEntryWithZeroRefCount->prev->next = lastEntryWithZeroRefCount->next;
270         else {
271             CPLAssert(0);
272         }
273         if (lastEntryWithZeroRefCount->next)
274             lastEntryWithZeroRefCount->next->prev = lastEntryWithZeroRefCount->prev;
275         else
276         {
277             CPLAssert(lastEntryWithZeroRefCount == lastEntry);
278             lastEntry->prev->next = NULL;
279             lastEntry = lastEntry->prev;
280         }
281         lastEntryWithZeroRefCount->prev = NULL;
282         lastEntryWithZeroRefCount->next = firstEntry;
283         firstEntry->prev = lastEntryWithZeroRefCount;
284         cur = firstEntry = lastEntryWithZeroRefCount;
285 #ifdef DEBUG_PROXY_POOL
286         CheckLinks();
287 #endif
288     }
289     else
290     {
291         /* Prepend */
292         cur = (GDALProxyPoolCacheEntry*) CPLMalloc(sizeof(GDALProxyPoolCacheEntry));
293         if (lastEntry == NULL)
294             lastEntry = cur;
295         cur->prev = NULL;
296         cur->next = firstEntry;
297         if (firstEntry)
298             firstEntry->prev = cur;
299         firstEntry = cur;
300         currentSize ++;
301 #ifdef DEBUG_PROXY_POOL
302         CheckLinks();
303 #endif
304     }
305 
306     cur->pszFileName = CPLStrdup(pszFileName);
307     cur->responsiblePID = responsiblePID;
308     cur->refCount = 1;
309 
310     refCountOfDisableRefCount ++;
311     int nFlag = ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
312     cur->poDS = (GDALDataset*) GDALOpenEx( pszFileName, nFlag, NULL,
313                            (const char* const* )papszOpenOptions, NULL );
314     refCountOfDisableRefCount --;
315 
316     return cur;
317 }
318 
319 /************************************************************************/
320 /*                       _CloseDataset()                                */
321 /************************************************************************/
322 
_CloseDataset(const char * pszFileName,GDALAccess eAccess)323 void GDALDatasetPool::_CloseDataset(const char* pszFileName, GDALAccess eAccess)
324 {
325     GDALProxyPoolCacheEntry* cur = firstEntry;
326     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
327 
328     while(cur)
329     {
330         GDALProxyPoolCacheEntry* next = cur->next;
331 
332         if (strcmp(cur->pszFileName, pszFileName) == 0 && cur->refCount == 0 &&
333             cur->poDS != NULL )
334         {
335             /* Close by pretending we are the thread that GDALOpen'ed this */
336             /* dataset */
337             GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
338 
339             refCountOfDisableRefCount ++;
340             GDALClose(cur->poDS);
341             refCountOfDisableRefCount --;
342 
343             GDALSetResponsiblePIDForCurrentThread(responsiblePID);
344 
345             cur->poDS = NULL;
346             cur->pszFileName[0] = '\0';
347             break;
348         }
349 
350         cur = next;
351     }
352 }
353 
354 /************************************************************************/
355 /*                                 Ref()                                */
356 /************************************************************************/
357 
Ref()358 void GDALDatasetPool::Ref()
359 {
360     CPLMutexHolderD( GDALGetphDLMutex() );
361     if (singleton == NULL)
362     {
363         int maxSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
364         if (maxSize < 2 || maxSize > 1000)
365             maxSize = 100;
366         singleton = new GDALDatasetPool(maxSize);
367     }
368     if (singleton->refCountOfDisableRefCount == 0)
369       singleton->refCount++;
370 }
371 
372 /* keep that in sync with gdaldrivermanager.cpp */
PreventDestroy()373 void GDALDatasetPool::PreventDestroy()
374 {
375     CPLMutexHolderD( GDALGetphDLMutex() );
376     if (! singleton)
377         return;
378     singleton->refCountOfDisableRefCount ++;
379 }
380 
381 /* keep that in sync with gdaldrivermanager.cpp */
GDALDatasetPoolPreventDestroy()382 void GDALDatasetPoolPreventDestroy()
383 {
384     GDALDatasetPool::PreventDestroy();
385 }
386 
387 
388 /************************************************************************/
389 /*                               Unref()                                */
390 /************************************************************************/
391 
Unref()392 void GDALDatasetPool::Unref()
393 {
394     CPLMutexHolderD( GDALGetphDLMutex() );
395     if (! singleton)
396     {
397         CPLAssert(0);
398         return;
399     }
400     if (singleton->refCountOfDisableRefCount == 0)
401     {
402       singleton->refCount--;
403       if (singleton->refCount == 0)
404       {
405           delete singleton;
406           singleton = NULL;
407       }
408     }
409 }
410 
411 /* keep that in sync with gdaldrivermanager.cpp */
ForceDestroy()412 void GDALDatasetPool::ForceDestroy()
413 {
414     CPLMutexHolderD( GDALGetphDLMutex() );
415     if (! singleton)
416         return;
417     singleton->refCountOfDisableRefCount --;
418     CPLAssert(singleton->refCountOfDisableRefCount == 0);
419     singleton->refCount = 0;
420     delete singleton;
421     singleton = NULL;
422 }
423 
424 /* keep that in sync with gdaldrivermanager.cpp */
GDALDatasetPoolForceDestroy()425 void GDALDatasetPoolForceDestroy()
426 {
427     GDALDatasetPool::ForceDestroy();
428 }
429 
430 /************************************************************************/
431 /*                           RefDataset()                               */
432 /************************************************************************/
433 
RefDataset(const char * pszFileName,GDALAccess eAccess,char ** papszOpenOptions,int bShared)434 GDALProxyPoolCacheEntry* GDALDatasetPool::RefDataset(const char* pszFileName,
435                                                      GDALAccess eAccess,
436                                                      char** papszOpenOptions,
437                                                      int bShared)
438 {
439     CPLMutexHolderD( GDALGetphDLMutex() );
440     return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions, bShared);
441 }
442 
443 /************************************************************************/
444 /*                       UnrefDataset()                                 */
445 /************************************************************************/
446 
UnrefDataset(GDALProxyPoolCacheEntry * cacheEntry)447 void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry* cacheEntry)
448 {
449     CPLMutexHolderD( GDALGetphDLMutex() );
450     cacheEntry->refCount --;
451 }
452 
453 /************************************************************************/
454 /*                       CloseDataset()                                 */
455 /************************************************************************/
456 
CloseDataset(const char * pszFileName,GDALAccess eAccess)457 void GDALDatasetPool::CloseDataset(const char* pszFileName, GDALAccess eAccess)
458 {
459     CPLMutexHolderD( GDALGetphDLMutex() );
460     singleton->_CloseDataset(pszFileName, eAccess);
461 }
462 
463 CPL_C_START
464 
465 typedef struct
466 {
467     char* pszDomain;
468     char** papszMetadata;
469 } GetMetadataElt;
470 
471 static
hash_func_get_metadata(const void * _elt)472 unsigned long hash_func_get_metadata(const void* _elt)
473 {
474     GetMetadataElt* elt = (GetMetadataElt*) _elt;
475     return CPLHashSetHashStr(elt->pszDomain);
476 }
477 
478 static
equal_func_get_metadata(const void * _elt1,const void * _elt2)479 int equal_func_get_metadata(const void* _elt1, const void* _elt2)
480 {
481     GetMetadataElt* elt1 = (GetMetadataElt*) _elt1;
482     GetMetadataElt* elt2 = (GetMetadataElt*) _elt2;
483     return CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
484 }
485 
486 static
free_func_get_metadata(void * _elt)487 void free_func_get_metadata(void* _elt)
488 {
489     GetMetadataElt* elt = (GetMetadataElt*) _elt;
490     CPLFree(elt->pszDomain);
491     CSLDestroy(elt->papszMetadata);
492 }
493 
494 
495 typedef struct
496 {
497     char* pszName;
498     char* pszDomain;
499     char* pszMetadataItem;
500 } GetMetadataItemElt;
501 
502 static
hash_func_get_metadata_item(const void * _elt)503 unsigned long hash_func_get_metadata_item(const void* _elt)
504 {
505     GetMetadataItemElt* elt = (GetMetadataItemElt*) _elt;
506     return CPLHashSetHashStr(elt->pszName) ^ CPLHashSetHashStr(elt->pszDomain);
507 }
508 
509 static
equal_func_get_metadata_item(const void * _elt1,const void * _elt2)510 int equal_func_get_metadata_item(const void* _elt1, const void* _elt2)
511 {
512     GetMetadataItemElt* elt1 = (GetMetadataItemElt*) _elt1;
513     GetMetadataItemElt* elt2 = (GetMetadataItemElt*) _elt2;
514     return CPLHashSetEqualStr(elt1->pszName, elt2->pszName) &&
515            CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
516 }
517 
518 static
free_func_get_metadata_item(void * _elt)519 void free_func_get_metadata_item(void* _elt)
520 {
521     GetMetadataItemElt* elt = (GetMetadataItemElt*) _elt;
522     CPLFree(elt->pszName);
523     CPLFree(elt->pszDomain);
524     CPLFree(elt->pszMetadataItem);
525 }
526 
527 CPL_C_END
528 
529 /* ******************************************************************** */
530 /*                     GDALProxyPoolDataset                             */
531 /* ******************************************************************** */
532 
533 /* Note : the bShared parameter must be used with caution. You can */
534 /* set it to TRUE  for being used as a VRT source : in that case, */
535 /* VRTSimpleSource will take care of destroying it when there are no */
536 /* reference to it (in VRTSimpleSource::~VRTSimpleSource()) */
537 /* However this will not be registered as a genuine shared dataset, like it */
538 /* would have been with MarkAsShared(). But MarkAsShared() is not usable for */
539 /* GDALProxyPoolDataset objects, as they share the same description as their */
540 /* underlying dataset. So *NEVER* call MarkAsShared() on a GDALProxyPoolDataset */
541 /* object */
542 
GDALProxyPoolDataset(const char * pszSourceDatasetDescription,int nRasterXSize,int nRasterYSize,GDALAccess eAccess,int bShared,const char * pszProjectionRef,double * padfGeoTransform)543 GDALProxyPoolDataset::GDALProxyPoolDataset(const char* pszSourceDatasetDescription,
544                                    int nRasterXSize, int nRasterYSize,
545                                    GDALAccess eAccess, int bShared,
546                                    const char * pszProjectionRef,
547                                    double * padfGeoTransform)
548 {
549     GDALDatasetPool::Ref();
550 
551     SetDescription(pszSourceDatasetDescription);
552 
553     this->nRasterXSize = nRasterXSize;
554     this->nRasterYSize = nRasterYSize;
555     this->eAccess = eAccess;
556 
557     this->bShared = bShared;
558 
559     this->responsiblePID = GDALGetResponsiblePIDForCurrentThread();
560 
561     if (pszProjectionRef)
562     {
563         this->pszProjectionRef = NULL;
564         bHasSrcProjection = FALSE;
565     }
566     else
567     {
568         this->pszProjectionRef = CPLStrdup(pszProjectionRef);
569         bHasSrcProjection = TRUE;
570     }
571     if (padfGeoTransform)
572     {
573         memcpy(adfGeoTransform, padfGeoTransform,6 * sizeof(double));
574         bHasSrcGeoTransform = TRUE;
575     }
576     else
577     {
578         adfGeoTransform[0] = 0;
579         adfGeoTransform[1] = 1;
580         adfGeoTransform[2] = 0;
581         adfGeoTransform[3] = 0;
582         adfGeoTransform[4] = 0;
583         adfGeoTransform[5] = 1;
584         bHasSrcGeoTransform = FALSE;
585     }
586 
587     pszGCPProjection = NULL;
588     nGCPCount = 0;
589     pasGCPList = NULL;
590     metadataSet = NULL;
591     metadataItemSet = NULL;
592     cacheEntry = NULL;
593 }
594 
595 /************************************************************************/
596 /*                    ~GDALProxyPoolDataset()                           */
597 /************************************************************************/
598 
~GDALProxyPoolDataset()599 GDALProxyPoolDataset::~GDALProxyPoolDataset()
600 {
601     if( !bShared )
602     {
603         GDALDatasetPool::CloseDataset(GetDescription(), eAccess);
604     }
605     /* See comment in constructor */
606     /* It is not really a genuine shared dataset, so we don't */
607     /* want ~GDALDataset() to try to release it from its */
608     /* shared dataset hashset. This will save a */
609     /* "Should not happen. Cannot find %s, this=%p in phSharedDatasetSet" debug message */
610     bShared = FALSE;
611 
612     CPLFree(pszProjectionRef);
613     CPLFree(pszGCPProjection);
614     if (nGCPCount)
615     {
616         GDALDeinitGCPs( nGCPCount, pasGCPList );
617         CPLFree( pasGCPList );
618     }
619     if (metadataSet)
620         CPLHashSetDestroy(metadataSet);
621     if (metadataItemSet)
622         CPLHashSetDestroy(metadataItemSet);
623 
624     GDALDatasetPool::Unref();
625 }
626 
627 /************************************************************************/
628 /*                        SetOpenOptions()                              */
629 /************************************************************************/
630 
SetOpenOptions(char ** papszOpenOptions)631 void GDALProxyPoolDataset::SetOpenOptions(char** papszOpenOptions)
632 {
633     CPLAssert(this->papszOpenOptions == NULL);
634     this->papszOpenOptions = CSLDuplicate(papszOpenOptions);
635 }
636 
637 /************************************************************************/
638 /*                    AddSrcBandDescription()                           */
639 /************************************************************************/
640 
AddSrcBandDescription(GDALDataType eDataType,int nBlockXSize,int nBlockYSize)641 void GDALProxyPoolDataset::AddSrcBandDescription( GDALDataType eDataType, int nBlockXSize, int nBlockYSize)
642 {
643     SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType, nBlockXSize, nBlockYSize));
644 }
645 
646 /************************************************************************/
647 /*                    RefUnderlyingDataset()                            */
648 /************************************************************************/
649 
RefUnderlyingDataset()650 GDALDataset* GDALProxyPoolDataset::RefUnderlyingDataset()
651 {
652     /* We pretend that the current thread is responsiblePID, that is */
653     /* to say the thread that created that GDALProxyPoolDataset object. */
654     /* This is for the case when a GDALProxyPoolDataset is created by a */
655     /* thread and used by other threads. These other threads, when doing actual */
656     /* IO, will come there and potentially open the underlying dataset. */
657     /* By doing this, they can indirectly call GDALOpenShared() on .aux file */
658     /* for example. So this call to GDALOpenShared() must occur as if it */
659     /* was done by the creating thread, otherwise it will not be correctly closed afterwards... */
660     /* To make a long story short : this is necessary when warping with ChunkAndWarpMulti */
661     /* a VRT of GeoTIFFs that have associated .aux files */
662     GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
663     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
664     cacheEntry = GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
665                                              GetShared());
666     GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
667     if (cacheEntry != NULL)
668     {
669         if (cacheEntry->poDS != NULL)
670             return cacheEntry->poDS;
671         else
672             GDALDatasetPool::UnrefDataset(cacheEntry);
673     }
674     return NULL;
675 }
676 
677 /************************************************************************/
678 /*                    UnrefUnderlyingDataset()                        */
679 /************************************************************************/
680 
UnrefUnderlyingDataset(CPL_UNUSED GDALDataset * poUnderlyingDataset)681 void GDALProxyPoolDataset::UnrefUnderlyingDataset(CPL_UNUSED GDALDataset* poUnderlyingDataset)
682 {
683     if (cacheEntry != NULL)
684     {
685         CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
686         if (cacheEntry->poDS != NULL)
687             GDALDatasetPool::UnrefDataset(cacheEntry);
688     }
689 }
690 
691 /************************************************************************/
692 /*                        SetProjection()                               */
693 /************************************************************************/
694 
SetProjection(const char * pszProjectionRef)695 CPLErr GDALProxyPoolDataset::SetProjection(const char* pszProjectionRef)
696 {
697     bHasSrcProjection = FALSE;
698     return GDALProxyDataset::SetProjection(pszProjectionRef);
699 }
700 
701 /************************************************************************/
702 /*                        GetProjectionRef()                            */
703 /************************************************************************/
704 
GetProjectionRef()705 const char *GDALProxyPoolDataset::GetProjectionRef()
706 {
707     if (bHasSrcProjection)
708         return pszProjectionRef;
709     else
710         return GDALProxyDataset::GetProjectionRef();
711 }
712 
713 /************************************************************************/
714 /*                        SetGeoTransform()                             */
715 /************************************************************************/
716 
SetGeoTransform(double * padfGeoTransform)717 CPLErr GDALProxyPoolDataset::SetGeoTransform( double * padfGeoTransform )
718 {
719     bHasSrcGeoTransform = FALSE;
720     return GDALProxyDataset::SetGeoTransform(padfGeoTransform);
721 }
722 
723 /************************************************************************/
724 /*                        GetGeoTransform()                             */
725 /************************************************************************/
726 
GetGeoTransform(double * padfGeoTransform)727 CPLErr GDALProxyPoolDataset::GetGeoTransform( double * padfGeoTransform )
728 {
729     if (bHasSrcGeoTransform)
730     {
731         memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
732         return CE_None;
733     }
734     else
735     {
736         return GDALProxyDataset::GetGeoTransform(padfGeoTransform);
737     }
738 }
739 
740 /************************************************************************/
741 /*                            GetMetadata()                             */
742 /************************************************************************/
743 
GetMetadata(const char * pszDomain)744 char      **GDALProxyPoolDataset::GetMetadata( const char * pszDomain  )
745 {
746     if (metadataSet == NULL)
747         metadataSet = CPLHashSetNew(hash_func_get_metadata,
748                                     equal_func_get_metadata,
749                                     free_func_get_metadata);
750 
751     GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
752     if (poUnderlyingDataset == NULL)
753         return NULL;
754 
755     char** papszUnderlyingMetadata = poUnderlyingDataset->GetMetadata(pszDomain);
756 
757     GetMetadataElt* pElt = (GetMetadataElt*) CPLMalloc(sizeof(GetMetadataElt));
758     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
759     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
760     CPLHashSetInsert(metadataSet, pElt);
761 
762     UnrefUnderlyingDataset(poUnderlyingDataset);
763 
764     return pElt->papszMetadata;
765 }
766 
767 /************************************************************************/
768 /*                        GetMetadataItem()                             */
769 /************************************************************************/
770 
GetMetadataItem(const char * pszName,const char * pszDomain)771 const char *GDALProxyPoolDataset::GetMetadataItem( const char * pszName,
772                                                    const char * pszDomain  )
773 {
774     if (metadataItemSet == NULL)
775         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
776                                         equal_func_get_metadata_item,
777                                         free_func_get_metadata_item);
778 
779     GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
780     if (poUnderlyingDataset == NULL)
781         return NULL;
782 
783     const char* pszUnderlyingMetadataItem =
784             poUnderlyingDataset->GetMetadataItem(pszName, pszDomain);
785 
786     GetMetadataItemElt* pElt = (GetMetadataItemElt*) CPLMalloc(sizeof(GetMetadataItemElt));
787     pElt->pszName = (pszName) ? CPLStrdup(pszName) : NULL;
788     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
789     pElt->pszMetadataItem = (pszUnderlyingMetadataItem) ? CPLStrdup(pszUnderlyingMetadataItem) : NULL;
790     CPLHashSetInsert(metadataItemSet, pElt);
791 
792     UnrefUnderlyingDataset(poUnderlyingDataset);
793 
794     return pElt->pszMetadataItem;
795 }
796 
797 /************************************************************************/
798 /*                      GetInternalHandle()                             */
799 /************************************************************************/
800 
GetInternalHandle(const char * pszRequest)801 void *GDALProxyPoolDataset::GetInternalHandle( const char * pszRequest)
802 {
803     CPLError(CE_Warning, CPLE_AppDefined,
804              "GetInternalHandle() cannot be safely called on a proxy pool dataset\n"
805              "as the returned value may be invalidated at any time.\n");
806     return GDALProxyDataset::GetInternalHandle(pszRequest);
807 }
808 
809 /************************************************************************/
810 /*                     GetGCPProjection()                               */
811 /************************************************************************/
812 
GetGCPProjection()813 const char *GDALProxyPoolDataset::GetGCPProjection()
814 {
815     GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
816     if (poUnderlyingDataset == NULL)
817         return NULL;
818 
819     CPLFree(pszGCPProjection);
820     pszGCPProjection = NULL;
821 
822     const char* pszUnderlyingGCPProjection = poUnderlyingDataset->GetGCPProjection();
823     if (pszUnderlyingGCPProjection)
824         pszGCPProjection = CPLStrdup(pszUnderlyingGCPProjection);
825 
826     UnrefUnderlyingDataset(poUnderlyingDataset);
827 
828     return pszGCPProjection;
829 }
830 
831 /************************************************************************/
832 /*                            GetGCPs()                                 */
833 /************************************************************************/
834 
GetGCPs()835 const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
836 {
837     GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
838     if (poUnderlyingDataset == NULL)
839         return NULL;
840 
841     if (nGCPCount)
842     {
843         GDALDeinitGCPs( nGCPCount, pasGCPList );
844         CPLFree( pasGCPList );
845         pasGCPList = NULL;
846     }
847 
848     const GDAL_GCP* pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
849     nGCPCount = poUnderlyingDataset->GetGCPCount();
850     if (nGCPCount)
851         pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList );
852 
853     UnrefUnderlyingDataset(poUnderlyingDataset);
854 
855     return pasGCPList;
856 }
857 
858 /************************************************************************/
859 /*                     GDALProxyPoolDatasetCreate()                     */
860 /************************************************************************/
861 
GDALProxyPoolDatasetCreate(const char * pszSourceDatasetDescription,int nRasterXSize,int nRasterYSize,GDALAccess eAccess,int bShared,const char * pszProjectionRef,double * padfGeoTransform)862 GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(const char* pszSourceDatasetDescription,
863                                                  int nRasterXSize, int nRasterYSize,
864                                                  GDALAccess eAccess, int bShared,
865                                                  const char * pszProjectionRef,
866                                                  double * padfGeoTransform)
867 {
868     return (GDALProxyPoolDatasetH)
869            new GDALProxyPoolDataset(pszSourceDatasetDescription,
870                                     nRasterXSize, nRasterYSize,
871                                     eAccess, bShared,
872                                     pszProjectionRef, padfGeoTransform);
873 }
874 
875 /************************************************************************/
876 /*                       GDALProxyPoolDatasetDelete()                   */
877 /************************************************************************/
878 
GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)879 void CPL_DLL GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
880 {
881     delete (GDALProxyPoolDataset*)hProxyPoolDataset;
882 }
883 
884 /************************************************************************/
885 /*              GDALProxyPoolDatasetAddSrcBandDescription()             */
886 /************************************************************************/
887 
GDALProxyPoolDatasetAddSrcBandDescription(GDALProxyPoolDatasetH hProxyPoolDataset,GDALDataType eDataType,int nBlockXSize,int nBlockYSize)888 void GDALProxyPoolDatasetAddSrcBandDescription( GDALProxyPoolDatasetH hProxyPoolDataset,
889                                                 GDALDataType eDataType,
890                                                 int nBlockXSize, int nBlockYSize)
891 {
892     ((GDALProxyPoolDataset*)hProxyPoolDataset)->
893             AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
894 }
895 
896 /* ******************************************************************** */
897 /*                    GDALProxyPoolRasterBand()                         */
898 /* ******************************************************************** */
899 
GDALProxyPoolRasterBand(GDALProxyPoolDataset * poDS,int nBand,GDALDataType eDataType,int nBlockXSize,int nBlockYSize)900 GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset* poDS, int nBand,
901                                                  GDALDataType eDataType,
902                                                  int nBlockXSize, int nBlockYSize)
903 {
904     this->poDS         = poDS;
905     this->nBand        = nBand;
906     this->eDataType    = eDataType;
907     this->nRasterXSize = poDS->GetRasterXSize();
908     this->nRasterYSize = poDS->GetRasterYSize();
909     this->nBlockXSize  = nBlockXSize;
910     this->nBlockYSize  = nBlockYSize;
911 
912     Init();
913 }
914 
915 /* ******************************************************************** */
916 /*                    GDALProxyPoolRasterBand()                         */
917 /* ******************************************************************** */
918 
GDALProxyPoolRasterBand(GDALProxyPoolDataset * poDS,GDALRasterBand * poUnderlyingRasterBand)919 GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset* poDS,
920                                                  GDALRasterBand* poUnderlyingRasterBand)
921 {
922     this->poDS         = poDS;
923     this->nBand        = poUnderlyingRasterBand->GetBand();
924     this->eDataType    = poUnderlyingRasterBand->GetRasterDataType();
925     this->nRasterXSize = poUnderlyingRasterBand->GetXSize();
926     this->nRasterYSize = poUnderlyingRasterBand->GetYSize();
927     poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
928 
929     Init();
930 }
931 
932 /* ******************************************************************** */
933  /*                                  Init()                             */
934 /* ******************************************************************** */
935 
Init()936 void GDALProxyPoolRasterBand::Init()
937 {
938     metadataSet = NULL;
939     metadataItemSet = NULL;
940     pszUnitType = NULL;
941     papszCategoryNames = NULL;
942     poColorTable = NULL;
943 
944     nSizeProxyOverviewRasterBand = 0;
945     papoProxyOverviewRasterBand = NULL;
946     poProxyMaskBand = NULL;
947 }
948 
949 /* ******************************************************************** */
950 /*                   ~GDALProxyPoolRasterBand()                         */
951 /* ******************************************************************** */
~GDALProxyPoolRasterBand()952 GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
953 {
954     if (metadataSet)
955         CPLHashSetDestroy(metadataSet);
956     if (metadataItemSet)
957         CPLHashSetDestroy(metadataItemSet);
958     CPLFree(pszUnitType);
959     CSLDestroy(papszCategoryNames);
960     if (poColorTable)
961         delete poColorTable;
962 
963     int i;
964     for(i=0;i<nSizeProxyOverviewRasterBand;i++)
965     {
966         if (papoProxyOverviewRasterBand[i])
967             delete papoProxyOverviewRasterBand[i];
968     }
969     CPLFree(papoProxyOverviewRasterBand);
970     if (poProxyMaskBand)
971         delete poProxyMaskBand;
972 }
973 
974 
975 /************************************************************************/
976 /*                 AddSrcMaskBandDescription()                          */
977 /************************************************************************/
978 
AddSrcMaskBandDescription(GDALDataType eDataType,int nBlockXSize,int nBlockYSize)979 void GDALProxyPoolRasterBand::AddSrcMaskBandDescription( GDALDataType eDataType,
980                                                          int nBlockXSize,
981                                                          int nBlockYSize)
982 {
983     CPLAssert(poProxyMaskBand == NULL);
984     poProxyMaskBand = new GDALProxyPoolMaskBand((GDALProxyPoolDataset*)poDS,
985                                                 this, eDataType,
986                                                 nBlockXSize, nBlockYSize);
987 }
988 
989 /************************************************************************/
990 /*                  RefUnderlyingRasterBand()                           */
991 /************************************************************************/
992 
RefUnderlyingRasterBand()993 GDALRasterBand* GDALProxyPoolRasterBand::RefUnderlyingRasterBand()
994 {
995     GDALDataset* poUnderlyingDataset = ((GDALProxyPoolDataset*)poDS)->RefUnderlyingDataset();
996     if (poUnderlyingDataset == NULL)
997         return NULL;
998 
999     GDALRasterBand* poBand = poUnderlyingDataset->GetRasterBand(nBand);
1000     if (poBand == NULL)
1001     {
1002         ((GDALProxyPoolDataset*)poDS)->UnrefUnderlyingDataset(poUnderlyingDataset);
1003     }
1004 
1005     return poBand;
1006 }
1007 
1008 /************************************************************************/
1009 /*                  UnrefUnderlyingRasterBand()                       */
1010 /************************************************************************/
1011 
UnrefUnderlyingRasterBand(GDALRasterBand * poUnderlyingRasterBand)1012 void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand* poUnderlyingRasterBand)
1013 {
1014     if (poUnderlyingRasterBand)
1015         ((GDALProxyPoolDataset*)poDS)->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
1016 }
1017 
1018 /************************************************************************/
1019 /*                            GetMetadata()                             */
1020 /************************************************************************/
1021 
GetMetadata(const char * pszDomain)1022 char      **GDALProxyPoolRasterBand::GetMetadata( const char * pszDomain  )
1023 {
1024     if (metadataSet == NULL)
1025         metadataSet = CPLHashSetNew(hash_func_get_metadata,
1026                                     equal_func_get_metadata,
1027                                     free_func_get_metadata);
1028 
1029     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1030     if (poUnderlyingRasterBand == NULL)
1031         return NULL;
1032 
1033     char** papszUnderlyingMetadata = poUnderlyingRasterBand->GetMetadata(pszDomain);
1034 
1035     GetMetadataElt* pElt = (GetMetadataElt*) CPLMalloc(sizeof(GetMetadataElt));
1036     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
1037     pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
1038     CPLHashSetInsert(metadataSet, pElt);
1039 
1040     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1041 
1042     return pElt->papszMetadata;
1043 }
1044 
1045 /************************************************************************/
1046 /*                        GetMetadataItem()                             */
1047 /************************************************************************/
1048 
GetMetadataItem(const char * pszName,const char * pszDomain)1049 const char *GDALProxyPoolRasterBand::GetMetadataItem( const char * pszName,
1050                                                    const char * pszDomain  )
1051 {
1052     if (metadataItemSet == NULL)
1053         metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
1054                                         equal_func_get_metadata_item,
1055                                         free_func_get_metadata_item);
1056 
1057     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1058     if (poUnderlyingRasterBand == NULL)
1059         return NULL;
1060 
1061     const char* pszUnderlyingMetadataItem =
1062             poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
1063 
1064     GetMetadataItemElt* pElt = (GetMetadataItemElt*) CPLMalloc(sizeof(GetMetadataItemElt));
1065     pElt->pszName = (pszName) ? CPLStrdup(pszName) : NULL;
1066     pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
1067     pElt->pszMetadataItem = (pszUnderlyingMetadataItem) ? CPLStrdup(pszUnderlyingMetadataItem) : NULL;
1068     CPLHashSetInsert(metadataItemSet, pElt);
1069 
1070     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1071 
1072     return pElt->pszMetadataItem;
1073 }
1074 
1075 /* ******************************************************************** */
1076 /*                       GetCategoryNames()                             */
1077 /* ******************************************************************** */
1078 
GetCategoryNames()1079 char **GDALProxyPoolRasterBand::GetCategoryNames()
1080 {
1081     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1082     if (poUnderlyingRasterBand == NULL)
1083         return NULL;
1084 
1085     CSLDestroy(papszCategoryNames);
1086     papszCategoryNames = NULL;
1087 
1088     char** papszUnderlyingCategoryNames = poUnderlyingRasterBand->GetCategoryNames();
1089     if (papszUnderlyingCategoryNames)
1090         papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
1091 
1092     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1093 
1094     return papszCategoryNames;
1095 }
1096 
1097 /* ******************************************************************** */
1098 /*                           GetUnitType()                              */
1099 /* ******************************************************************** */
1100 
GetUnitType()1101 const char *GDALProxyPoolRasterBand::GetUnitType()
1102 {
1103     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1104     if (poUnderlyingRasterBand == NULL)
1105         return NULL;
1106 
1107     CPLFree(pszUnitType);
1108     pszUnitType = NULL;
1109 
1110     const char* pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
1111     if (pszUnderlyingUnitType)
1112         pszUnitType = CPLStrdup(pszUnderlyingUnitType);
1113 
1114     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1115 
1116     return pszUnitType;
1117 }
1118 
1119 /* ******************************************************************** */
1120 /*                          GetColorTable()                             */
1121 /* ******************************************************************** */
1122 
GetColorTable()1123 GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
1124 {
1125     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1126     if (poUnderlyingRasterBand == NULL)
1127         return NULL;
1128 
1129     if (poColorTable)
1130         delete poColorTable;
1131     poColorTable = NULL;
1132 
1133     GDALColorTable* poUnderlyingColorTable = poUnderlyingRasterBand->GetColorTable();
1134     if (poUnderlyingColorTable)
1135         poColorTable = poUnderlyingColorTable->Clone();
1136 
1137     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1138 
1139     return poColorTable;
1140 }
1141 
1142 /* ******************************************************************** */
1143 /*                           GetOverview()                              */
1144 /* ******************************************************************** */
1145 
GetOverview(int nOverviewBand)1146 GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
1147 {
1148     if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
1149     {
1150         if (papoProxyOverviewRasterBand[nOverviewBand])
1151             return papoProxyOverviewRasterBand[nOverviewBand];
1152     }
1153 
1154     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1155     if (poUnderlyingRasterBand == NULL)
1156         return NULL;
1157 
1158     GDALRasterBand* poOverviewRasterBand = poUnderlyingRasterBand->GetOverview(nOverviewBand);
1159     if (poOverviewRasterBand == NULL)
1160     {
1161         UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1162         return NULL;
1163     }
1164 
1165     if (nOverviewBand >= nSizeProxyOverviewRasterBand)
1166     {
1167         int i;
1168         papoProxyOverviewRasterBand = (GDALProxyPoolOverviewRasterBand**)
1169                 CPLRealloc(papoProxyOverviewRasterBand,
1170                         sizeof(GDALProxyPoolOverviewRasterBand*) * (nOverviewBand + 1));
1171         for(i=nSizeProxyOverviewRasterBand; i<nOverviewBand + 1;i++)
1172             papoProxyOverviewRasterBand[i] = NULL;
1173         nSizeProxyOverviewRasterBand = nOverviewBand + 1;
1174     }
1175 
1176     papoProxyOverviewRasterBand[nOverviewBand] =
1177             new GDALProxyPoolOverviewRasterBand((GDALProxyPoolDataset*)poDS,
1178                                                 poOverviewRasterBand,
1179                                                 this, nOverviewBand);
1180 
1181     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1182 
1183     return papoProxyOverviewRasterBand[nOverviewBand];
1184 }
1185 
1186 /* ******************************************************************** */
1187 /*                     GetRasterSampleOverview()                        */
1188 /* ******************************************************************** */
1189 
GetRasterSampleOverview(CPL_UNUSED GUIntBig nDesiredSamples)1190 GDALRasterBand *GDALProxyPoolRasterBand::GetRasterSampleOverview( CPL_UNUSED GUIntBig nDesiredSamples)
1191 {
1192     CPLError(CE_Failure, CPLE_AppDefined,
1193              "GDALProxyPoolRasterBand::GetRasterSampleOverview : not implemented yet");
1194     return NULL;
1195 }
1196 
1197 /* ******************************************************************** */
1198 /*                           GetMaskBand()                              */
1199 /* ******************************************************************** */
1200 
GetMaskBand()1201 GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
1202 {
1203     if (poProxyMaskBand)
1204         return poProxyMaskBand;
1205 
1206     GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1207     if (poUnderlyingRasterBand == NULL)
1208         return NULL;
1209 
1210     GDALRasterBand* poMaskBand = poUnderlyingRasterBand->GetMaskBand();
1211 
1212     poProxyMaskBand =
1213             new GDALProxyPoolMaskBand((GDALProxyPoolDataset*)poDS,
1214                                        poMaskBand,
1215                                        this);
1216 
1217     UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1218 
1219     return poProxyMaskBand;
1220 }
1221 
1222 /* ******************************************************************** */
1223 /*             GDALProxyPoolOverviewRasterBand()                        */
1224 /* ******************************************************************** */
1225 
GDALProxyPoolOverviewRasterBand(GDALProxyPoolDataset * poDS,GDALRasterBand * poUnderlyingOverviewBand,GDALProxyPoolRasterBand * poMainBand,int nOverviewBand)1226 GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(GDALProxyPoolDataset* poDS,
1227                                                                  GDALRasterBand* poUnderlyingOverviewBand,
1228                                                                  GDALProxyPoolRasterBand* poMainBand,
1229                                                                  int nOverviewBand) :
1230         GDALProxyPoolRasterBand(poDS, poUnderlyingOverviewBand)
1231 {
1232     this->poMainBand = poMainBand;
1233     this->nOverviewBand = nOverviewBand;
1234 
1235     poUnderlyingMainRasterBand = NULL;
1236     nRefCountUnderlyingMainRasterBand = 0;
1237 }
1238 
1239 /* ******************************************************************** */
1240 /*                  ~GDALProxyPoolOverviewRasterBand()                  */
1241 /* ******************************************************************** */
1242 
~GDALProxyPoolOverviewRasterBand()1243 GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
1244 {
1245     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1246 }
1247 
1248 /* ******************************************************************** */
1249 /*                    RefUnderlyingRasterBand()                         */
1250 /* ******************************************************************** */
1251 
RefUnderlyingRasterBand()1252 GDALRasterBand* GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand()
1253 {
1254     poUnderlyingMainRasterBand = poMainBand->RefUnderlyingRasterBand();
1255     if (poUnderlyingMainRasterBand == NULL)
1256         return NULL;
1257 
1258     nRefCountUnderlyingMainRasterBand ++;
1259     return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
1260 }
1261 
1262 /* ******************************************************************** */
1263 /*                  UnrefUnderlyingRasterBand()                         */
1264 /* ******************************************************************** */
1265 
UnrefUnderlyingRasterBand(CPL_UNUSED GDALRasterBand * poUnderlyingRasterBand)1266 void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(CPL_UNUSED GDALRasterBand* poUnderlyingRasterBand)
1267 {
1268     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1269     nRefCountUnderlyingMainRasterBand --;
1270 }
1271 
1272 
1273 /* ******************************************************************** */
1274 /*                     GDALProxyPoolMaskBand()                          */
1275 /* ******************************************************************** */
1276 
GDALProxyPoolMaskBand(GDALProxyPoolDataset * poDS,GDALRasterBand * poUnderlyingMaskBand,GDALProxyPoolRasterBand * poMainBand)1277 GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(GDALProxyPoolDataset* poDS,
1278                                              GDALRasterBand* poUnderlyingMaskBand,
1279                                              GDALProxyPoolRasterBand* poMainBand) :
1280         GDALProxyPoolRasterBand(poDS, poUnderlyingMaskBand)
1281 {
1282     this->poMainBand = poMainBand;
1283 
1284     poUnderlyingMainRasterBand = NULL;
1285     nRefCountUnderlyingMainRasterBand = 0;
1286 }
1287 
1288 /* ******************************************************************** */
1289 /*                     GDALProxyPoolMaskBand()                          */
1290 /* ******************************************************************** */
1291 
GDALProxyPoolMaskBand(GDALProxyPoolDataset * poDS,GDALProxyPoolRasterBand * poMainBand,GDALDataType eDataType,int nBlockXSize,int nBlockYSize)1292 GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(GDALProxyPoolDataset* poDS,
1293                                              GDALProxyPoolRasterBand* poMainBand,
1294                                              GDALDataType eDataType,
1295                                              int nBlockXSize, int nBlockYSize) :
1296         GDALProxyPoolRasterBand(poDS, 1, eDataType, nBlockXSize, nBlockYSize)
1297 {
1298     this->poMainBand = poMainBand;
1299 
1300     poUnderlyingMainRasterBand = NULL;
1301     nRefCountUnderlyingMainRasterBand = 0;
1302 }
1303 
1304 /* ******************************************************************** */
1305 /*                          ~GDALProxyPoolMaskBand()                    */
1306 /* ******************************************************************** */
1307 
~GDALProxyPoolMaskBand()1308 GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
1309 {
1310     CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1311 }
1312 
1313 /* ******************************************************************** */
1314 /*                    RefUnderlyingRasterBand()                         */
1315 /* ******************************************************************** */
1316 
RefUnderlyingRasterBand()1317 GDALRasterBand* GDALProxyPoolMaskBand::RefUnderlyingRasterBand()
1318 {
1319     poUnderlyingMainRasterBand = poMainBand->RefUnderlyingRasterBand();
1320     if (poUnderlyingMainRasterBand == NULL)
1321         return NULL;
1322 
1323     nRefCountUnderlyingMainRasterBand ++;
1324     return poUnderlyingMainRasterBand->GetMaskBand();
1325 }
1326 
1327 /* ******************************************************************** */
1328 /*                  UnrefUnderlyingRasterBand()                         */
1329 /* ******************************************************************** */
1330 
UnrefUnderlyingRasterBand(CPL_UNUSED GDALRasterBand * poUnderlyingRasterBand)1331 void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(CPL_UNUSED GDALRasterBand* poUnderlyingRasterBand)
1332 {
1333     poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1334     nRefCountUnderlyingMainRasterBand --;
1335 }
1336