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