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