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 496 : GDALDatasetPool::GDALDatasetPool(int maxSizeIn, int64_t nMaxRAMUsageIn)
142 496 : : maxSize(maxSizeIn), nMaxRAMUsage(nMaxRAMUsageIn)
143 : {
144 496 : }
145 :
146 : /************************************************************************/
147 : /* ~GDALDatasetPool() */
148 : /************************************************************************/
149 :
150 986 : GDALDatasetPool::~GDALDatasetPool()
151 : {
152 493 : bInDestruction = true;
153 493 : GDALProxyPoolCacheEntry *cur = firstEntry;
154 493 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
155 1005 : while (cur)
156 : {
157 512 : GDALProxyPoolCacheEntry *next = cur->next;
158 512 : CPLFree(cur->pszFileNameAndOpenOptions);
159 512 : CPLFree(cur->pszOwner);
160 512 : CPLAssert(cur->refCount == 0);
161 512 : if (cur->poDS)
162 : {
163 0 : GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
164 0 : GDALClose(cur->poDS);
165 : }
166 512 : CPLFree(cur);
167 512 : cur = next;
168 : }
169 493 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
170 493 : }
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 237507 : static std::string GetFilenameAndOpenOptions(const char *pszFileName,
221 : CSLConstList papszOpenOptions)
222 : {
223 237507 : std::string osFilenameAndOO(pszFileName);
224 237571 : for (int i = 0; papszOpenOptions && papszOpenOptions[i]; ++i)
225 : {
226 64 : osFilenameAndOO += "||";
227 64 : osFilenameAndOO += papszOpenOptions[i];
228 : }
229 237507 : return osFilenameAndOO;
230 : }
231 :
232 : /************************************************************************/
233 : /* _RefDataset() */
234 : /************************************************************************/
235 :
236 : GDALProxyPoolCacheEntry *
237 232685 : GDALDatasetPool::_RefDataset(const char *pszFileName, GDALAccess eAccess,
238 : CSLConstList papszOpenOptions, int bShared,
239 : bool bForceOpen, const char *pszOwner)
240 : {
241 232685 : CPLMutex **pMutex = GDALGetphDLMutex();
242 465370 : CPLMutexHolderD(pMutex);
243 :
244 232687 : if (bInDestruction)
245 0 : return nullptr;
246 :
247 232687 : const GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
248 :
249 : const auto EvictEntryWithZeroRefCount =
250 17384 : [this, responsiblePID](bool evictEntryWithOpenedDataset)
251 : {
252 2897 : GDALProxyPoolCacheEntry *cur = firstEntry;
253 2897 : GDALProxyPoolCacheEntry *candidate = nullptr;
254 292403 : while (cur)
255 : {
256 289506 : GDALProxyPoolCacheEntry *next = cur->next;
257 :
258 289506 : if (cur->refCount == 0 &&
259 285243 : (!evictEntryWithOpenedDataset || cur->nRAMUsage > 0))
260 : {
261 285243 : candidate = cur;
262 : }
263 :
264 289506 : cur = next;
265 : }
266 2897 : if (candidate == nullptr)
267 0 : return false;
268 :
269 2897 : nRAMUsage -= candidate->nRAMUsage;
270 2897 : candidate->nRAMUsage = 0;
271 :
272 2897 : CPLFree(candidate->pszFileNameAndOpenOptions);
273 2897 : candidate->pszFileNameAndOpenOptions = nullptr;
274 :
275 2897 : 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 2897 : CPLFree(candidate->pszOwner);
289 2897 : candidate->pszOwner = nullptr;
290 :
291 2897 : 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 2897 : if (candidate->prev)
296 2897 : candidate->prev->next = candidate->next;
297 :
298 2897 : if (candidate->next)
299 0 : candidate->next->prev = candidate->prev;
300 : else
301 : {
302 2897 : CPLAssert(candidate == lastEntry);
303 2897 : lastEntry->prev->next = nullptr;
304 2897 : lastEntry = lastEntry->prev;
305 : }
306 2897 : candidate->prev = nullptr;
307 2897 : candidate->next = firstEntry;
308 2897 : firstEntry->prev = candidate;
309 2897 : firstEntry = candidate;
310 :
311 : #ifdef DEBUG_PROXY_POOL
312 : CheckLinks();
313 : #endif
314 : }
315 :
316 2897 : return true;
317 232687 : };
318 :
319 232687 : GDALProxyPoolCacheEntry *cur = firstEntry;
320 :
321 : const std::string osFilenameAndOO =
322 465374 : GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
323 :
324 747400 : while (cur)
325 : {
326 741538 : GDALProxyPoolCacheEntry *next = cur->next;
327 :
328 1028960 : if (cur->refCount >= 0 && cur->pszFileNameAndOpenOptions &&
329 1997600 : osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
330 227001 : ((bShared && cur->responsiblePID == responsiblePID &&
331 226782 : ((cur->pszOwner == nullptr && pszOwner == nullptr) ||
332 225876 : (cur->pszOwner != nullptr && pszOwner != nullptr &&
333 226194 : strcmp(cur->pszOwner, pszOwner) == 0))) ||
334 99 : (!bShared && cur->refCount == 0)))
335 : {
336 226825 : if (cur != firstEntry)
337 : {
338 : /* Move to begin */
339 7536 : if (cur->next)
340 7173 : cur->next->prev = cur->prev;
341 : else
342 363 : lastEntry = cur->prev;
343 7536 : cur->prev->next = cur->next;
344 7536 : cur->prev = nullptr;
345 7536 : firstEntry->prev = cur;
346 7536 : cur->next = firstEntry;
347 7536 : firstEntry = cur;
348 :
349 : #ifdef DEBUG_PROXY_POOL
350 : CheckLinks();
351 : #endif
352 : }
353 :
354 226825 : cur->refCount++;
355 226825 : return cur;
356 : }
357 :
358 514713 : cur = next;
359 : }
360 :
361 5862 : if (!bForceOpen)
362 2185 : return nullptr;
363 :
364 3677 : if (currentSize == maxSize)
365 : {
366 2897 : 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 2897 : CPLAssert(firstEntry);
379 2897 : cur = firstEntry;
380 : }
381 : else
382 : {
383 : /* Prepend */
384 : cur = static_cast<GDALProxyPoolCacheEntry *>(
385 780 : CPLCalloc(1, sizeof(GDALProxyPoolCacheEntry)));
386 780 : if (lastEntry == nullptr)
387 446 : lastEntry = cur;
388 780 : cur->prev = nullptr;
389 780 : cur->next = firstEntry;
390 780 : if (firstEntry)
391 334 : firstEntry->prev = cur;
392 780 : firstEntry = cur;
393 780 : currentSize++;
394 : #ifdef DEBUG_PROXY_POOL
395 : CheckLinks();
396 : #endif
397 : }
398 :
399 3677 : cur->pszFileNameAndOpenOptions = CPLStrdup(osFilenameAndOO.c_str());
400 3677 : cur->pszOwner = (pszOwner) ? CPLStrdup(pszOwner) : nullptr;
401 3677 : cur->responsiblePID = responsiblePID;
402 3677 : cur->refCount = -1; // to mark loading of dataset in progress
403 3677 : cur->nRAMUsage = 0;
404 :
405 3677 : refCountOfDisabledRefCount++;
406 3677 : const int nFlag =
407 : ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) |
408 3677 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
409 3677 : CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
410 :
411 : // Release mutex while opening dataset to avoid lock contention.
412 3677 : CPLReleaseMutex(*pMutex);
413 3677 : auto poDS = GDALDataset::Open(pszFileName, nFlag, nullptr, papszOpenOptions,
414 : nullptr);
415 3677 : CPLAcquireMutex(*pMutex, 1000.0);
416 :
417 3677 : cur->poDS = poDS;
418 3677 : cur->refCount = 1;
419 :
420 3677 : refCountOfDisabledRefCount--;
421 :
422 3677 : if (cur->poDS)
423 : {
424 3429 : cur->nRAMUsage =
425 3429 : std::max<GIntBig>(0, cur->poDS->GetEstimatedRAMUsage());
426 3429 : nRAMUsage += cur->nRAMUsage;
427 : }
428 :
429 3677 : 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 3677 : return cur;
439 : }
440 :
441 : /************************************************************************/
442 : /* _CloseDatasetIfZeroRefCount() */
443 : /************************************************************************/
444 :
445 4820 : 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 4820 : if (bInDestruction)
452 0 : return;
453 :
454 4820 : GDALProxyPoolCacheEntry *cur = firstEntry;
455 4820 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
456 :
457 : const std::string osFilenameAndOO =
458 9640 : GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
459 :
460 84385 : while (cur)
461 : {
462 82992 : GDALProxyPoolCacheEntry *next = cur->next;
463 :
464 103587 : if (cur->refCount == 0 && cur->pszFileNameAndOpenOptions &&
465 24291 : osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
466 3692 : ((pszOwner == nullptr && cur->pszOwner == nullptr) ||
467 3494 : (pszOwner != nullptr && cur->pszOwner != nullptr &&
468 169473 : strcmp(cur->pszOwner, pszOwner) == 0)) &&
469 3682 : cur->poDS != nullptr)
470 : {
471 : /* Close by pretending we are the thread that GDALOpen'ed this */
472 : /* dataset */
473 3427 : GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
474 :
475 3427 : GDALDataset *poDS = cur->poDS;
476 :
477 3427 : nRAMUsage -= cur->nRAMUsage;
478 3427 : cur->nRAMUsage = 0;
479 :
480 3427 : cur->poDS = nullptr;
481 3427 : CPLFree(cur->pszFileNameAndOpenOptions);
482 3427 : cur->pszFileNameAndOpenOptions = nullptr;
483 3427 : CPLFree(cur->pszOwner);
484 3427 : cur->pszOwner = nullptr;
485 :
486 3427 : refCountOfDisabledRefCount++;
487 3427 : GDALClose(poDS);
488 3427 : refCountOfDisabledRefCount--;
489 :
490 3427 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
491 3427 : break;
492 : }
493 :
494 79565 : 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 533 : int GDALGetMaxDatasetPoolSize()
506 : {
507 533 : int nSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
508 533 : if (nSize < 2)
509 0 : nSize = 2;
510 533 : else if (nSize > 1000)
511 0 : nSize = 1000;
512 533 : return nSize;
513 : }
514 :
515 : /************************************************************************/
516 : /* Ref() */
517 : /************************************************************************/
518 :
519 4820 : void GDALDatasetPool::Ref()
520 : {
521 9640 : CPLMutexHolderD(GDALGetphDLMutex());
522 4820 : if (singleton == nullptr)
523 : {
524 :
525 : // Try to not consume more than 25% of the usable RAM
526 : GIntBig l_nMaxRAMUsage =
527 496 : (CPLGetUsablePhysicalRAM() - GDALGetCacheMax64()) / 4;
528 : const char *pszMaxRAMUsage =
529 496 : CPLGetConfigOption("GDAL_MAX_DATASET_POOL_RAM_USAGE", nullptr);
530 496 : 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 496 : singleton =
540 496 : new GDALDatasetPool(GDALGetMaxDatasetPoolSize(), l_nMaxRAMUsage);
541 : }
542 4820 : if (refCountOfDisabledRefCount == 0)
543 4820 : singleton->refCount++;
544 4820 : }
545 :
546 : /* keep that in sync with gdaldrivermanager.cpp */
547 1123 : void GDALDatasetPool::PreventDestroy()
548 : {
549 1123 : CPLMutexHolderD(GDALGetphDLMutex());
550 1123 : if (!singleton)
551 1120 : return;
552 3 : refCountOfDisabledRefCount++;
553 : }
554 :
555 : /* keep that in sync with gdaldrivermanager.cpp */
556 : extern void GDALDatasetPoolPreventDestroy();
557 :
558 1123 : void GDALDatasetPoolPreventDestroy()
559 : {
560 1123 : GDALDatasetPool::PreventDestroy();
561 1123 : }
562 :
563 : /************************************************************************/
564 : /* Unref() */
565 : /************************************************************************/
566 :
567 4820 : void GDALDatasetPool::Unref()
568 : {
569 4820 : CPLMutexHolderD(GDALGetphDLMutex());
570 4820 : if (!singleton)
571 : {
572 0 : CPLAssert(false);
573 : return;
574 : }
575 4820 : if (refCountOfDisabledRefCount == 0)
576 : {
577 4783 : singleton->refCount--;
578 4783 : if (singleton->refCount == 0)
579 : {
580 490 : delete singleton;
581 490 : singleton = nullptr;
582 : }
583 : }
584 : }
585 :
586 : /* keep that in sync with gdaldrivermanager.cpp */
587 1123 : void GDALDatasetPool::ForceDestroy()
588 : {
589 1123 : CPLMutexHolderD(GDALGetphDLMutex());
590 1123 : if (!singleton)
591 1120 : 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 1123 : void GDALDatasetPoolForceDestroy()
603 : {
604 1123 : GDALDatasetPool::ForceDestroy();
605 1123 : }
606 :
607 : /************************************************************************/
608 : /* RefDataset() */
609 : /************************************************************************/
610 :
611 : GDALProxyPoolCacheEntry *
612 232685 : GDALDatasetPool::RefDataset(const char *pszFileName, GDALAccess eAccess,
613 : char **papszOpenOptions, int bShared,
614 : bool bForceOpen, const char *pszOwner)
615 : {
616 232685 : return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions,
617 232686 : bShared, bForceOpen, pszOwner);
618 : }
619 :
620 : /************************************************************************/
621 : /* UnrefDataset() */
622 : /************************************************************************/
623 :
624 230500 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry)
625 : {
626 230500 : CPLMutexHolderD(GDALGetphDLMutex());
627 230502 : cacheEntry->refCount--;
628 230502 : }
629 :
630 : /************************************************************************/
631 : /* CloseDatasetIfZeroRefCount() */
632 : /************************************************************************/
633 :
634 4820 : void GDALDatasetPool::CloseDatasetIfZeroRefCount(const char *pszFileName,
635 : CSLConstList papszOpenOptions,
636 : GDALAccess eAccess,
637 : const char *pszOwner)
638 : {
639 9640 : CPLMutexHolderD(GDALGetphDLMutex());
640 4820 : singleton->_CloseDatasetIfZeroRefCount(pszFileName, papszOpenOptions,
641 : eAccess, pszOwner);
642 4820 : }
643 :
644 : struct GetMetadataElt
645 : {
646 : char *pszDomain;
647 : char **papszMetadata;
648 : };
649 :
650 56 : static unsigned long hash_func_get_metadata(const void *_elt)
651 : {
652 56 : const GetMetadataElt *elt = static_cast<const GetMetadataElt *>(_elt);
653 56 : return CPLHashSetHashStr(elt->pszDomain);
654 : }
655 :
656 14 : static int equal_func_get_metadata(const void *_elt1, const void *_elt2)
657 : {
658 14 : const GetMetadataElt *elt1 = static_cast<const GetMetadataElt *>(_elt1);
659 14 : const GetMetadataElt *elt2 = static_cast<const GetMetadataElt *>(_elt2);
660 14 : return CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
661 : }
662 :
663 34 : static void free_func_get_metadata(void *_elt)
664 : {
665 34 : GetMetadataElt *elt = static_cast<GetMetadataElt *>(_elt);
666 34 : CPLFree(elt->pszDomain);
667 34 : CSLDestroy(elt->papszMetadata);
668 34 : CPLFree(elt);
669 34 : }
670 :
671 : struct GetMetadataItemElt
672 : {
673 : char *pszName;
674 : char *pszDomain;
675 : char *pszMetadataItem;
676 : };
677 :
678 70 : static unsigned long hash_func_get_metadata_item(const void *_elt)
679 : {
680 70 : const GetMetadataItemElt *elt =
681 : static_cast<const GetMetadataItemElt *>(_elt);
682 70 : 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 44 : static void free_func_get_metadata_item(void *_elt)
696 : {
697 44 : GetMetadataItemElt *elt = static_cast<GetMetadataItemElt *>(_elt);
698 44 : CPLFree(elt->pszName);
699 44 : CPLFree(elt->pszDomain);
700 44 : CPLFree(elt->pszMetadataItem);
701 44 : CPLFree(elt);
702 44 : }
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 1317 : GDALProxyPoolDataset::GDALProxyPoolDataset(
733 : const char *pszSourceDatasetDescription, int nRasterXSizeIn,
734 : int nRasterYSizeIn, GDALAccess eAccessIn, int bSharedIn,
735 : const char *pszProjectionRefIn, const GDALGeoTransform *pGT,
736 1317 : const char *pszOwner)
737 2634 : : responsiblePID(GDALGetResponsiblePIDForCurrentThread()),
738 1317 : pszProjectionRef(pszProjectionRefIn ? CPLStrdup(pszProjectionRefIn)
739 2634 : : nullptr)
740 : {
741 1317 : GDALDatasetPool::Ref();
742 :
743 1317 : SetDescription(pszSourceDatasetDescription);
744 :
745 1317 : nRasterXSize = nRasterXSizeIn;
746 1317 : nRasterYSize = nRasterYSizeIn;
747 1317 : eAccess = eAccessIn;
748 :
749 1317 : bShared = CPL_TO_BOOL(bSharedIn);
750 1317 : m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
751 :
752 1317 : if (pGT)
753 : {
754 1268 : m_gt = *pGT;
755 1268 : m_bHasSrcGeoTransform = true;
756 : }
757 :
758 1317 : if (pszProjectionRefIn)
759 : {
760 1278 : m_poSRS = new OGRSpatialReference();
761 1278 : m_poSRS->importFromWkt(pszProjectionRefIn);
762 1278 : m_bHasSrcSRS = true;
763 : }
764 1317 : }
765 :
766 : /* Constructor where the parameters (raster size, etc.) are obtained
767 : * by opening the underlying dataset.
768 : */
769 3503 : GDALProxyPoolDataset::GDALProxyPoolDataset(
770 : const char *pszSourceDatasetDescription, GDALAccess eAccessIn,
771 3503 : int bSharedIn, const char *pszOwner)
772 3503 : : responsiblePID(GDALGetResponsiblePIDForCurrentThread())
773 : {
774 3503 : GDALDatasetPool::Ref();
775 :
776 3503 : SetDescription(pszSourceDatasetDescription);
777 :
778 3503 : eAccess = eAccessIn;
779 :
780 3503 : bShared = CPL_TO_BOOL(bSharedIn);
781 3503 : m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
782 3503 : }
783 :
784 : /************************************************************************/
785 : /* Create() */
786 : /************************************************************************/
787 :
788 : /* Instantiate a GDALProxyPoolDataset where the parameters (raster size, etc.)
789 : * are obtained by opening the underlying dataset.
790 : * Its bands are also instantiated.
791 : */
792 3503 : GDALProxyPoolDataset *GDALProxyPoolDataset::Create(
793 : const char *pszSourceDatasetDescription, CSLConstList papszOpenOptionsIn,
794 : GDALAccess eAccessIn, int bSharedIn, const char *pszOwner)
795 : {
796 : std::unique_ptr<GDALProxyPoolDataset> poSelf(new GDALProxyPoolDataset(
797 7006 : pszSourceDatasetDescription, eAccessIn, bSharedIn, pszOwner));
798 3503 : poSelf->SetOpenOptions(papszOpenOptionsIn);
799 3503 : GDALDataset *poUnderlyingDS = poSelf->RefUnderlyingDataset();
800 3503 : if (!poUnderlyingDS)
801 255 : return nullptr;
802 3248 : poSelf->nRasterXSize = poUnderlyingDS->GetRasterXSize();
803 3248 : poSelf->nRasterYSize = poUnderlyingDS->GetRasterYSize();
804 3248 : if (poUnderlyingDS->GetGeoTransform(poSelf->m_gt) == CE_None)
805 980 : poSelf->m_bHasSrcGeoTransform = true;
806 3248 : const auto poSRS = poUnderlyingDS->GetSpatialRef();
807 3247 : if (poSRS)
808 : {
809 883 : poSelf->m_poSRS = poSRS->Clone();
810 884 : poSelf->m_bHasSrcSRS = true;
811 : }
812 106361 : for (int i = 1; i <= poUnderlyingDS->GetRasterCount(); ++i)
813 : {
814 103111 : auto poSrcBand = poUnderlyingDS->GetRasterBand(i);
815 103112 : if (!poSrcBand)
816 : {
817 0 : poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
818 0 : return nullptr;
819 : }
820 : int nSrcBlockXSize, nSrcBlockYSize;
821 103112 : poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
822 103114 : poSelf->AddSrcBandDescription(poSrcBand->GetRasterDataType(),
823 : nSrcBlockXSize, nSrcBlockYSize);
824 : }
825 3248 : poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
826 3248 : return poSelf.release();
827 : }
828 :
829 : /************************************************************************/
830 : /* ~GDALProxyPoolDataset() */
831 : /************************************************************************/
832 :
833 9630 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
834 : {
835 4820 : GDALDatasetPool::CloseDatasetIfZeroRefCount(
836 4820 : GetDescription(), papszOpenOptions, eAccess, m_pszOwner);
837 :
838 : /* See comment in constructor */
839 : /* It is not really a genuine shared dataset, so we don't */
840 : /* want ~GDALDataset() to try to release it from its */
841 : /* shared dataset hashset. This will save a */
842 : /* "Should not happen. Cannot find %s, this=%p in phSharedDatasetSet" debug
843 : * message */
844 4820 : bShared = false;
845 :
846 4820 : CPLFree(pszProjectionRef);
847 4820 : CPLFree(pszGCPProjection);
848 4820 : if (nGCPCount)
849 : {
850 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
851 0 : CPLFree(pasGCPList);
852 : }
853 4820 : if (metadataSet)
854 5 : CPLHashSetDestroy(metadataSet);
855 4820 : if (metadataItemSet)
856 2 : CPLHashSetDestroy(metadataItemSet);
857 4820 : CPLFree(m_pszOwner);
858 4820 : if (m_poSRS)
859 2162 : m_poSRS->Release();
860 4820 : if (m_poGCPSRS)
861 0 : m_poGCPSRS->Release();
862 :
863 4820 : GDALDatasetPool::Unref();
864 9630 : }
865 :
866 : /************************************************************************/
867 : /* SetOpenOptions() */
868 : /************************************************************************/
869 :
870 4771 : void GDALProxyPoolDataset::SetOpenOptions(CSLConstList papszOpenOptionsIn)
871 : {
872 4771 : CPLAssert(papszOpenOptions == nullptr);
873 4771 : papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
874 4771 : }
875 :
876 : /************************************************************************/
877 : /* AddSrcBandDescription() */
878 : /************************************************************************/
879 :
880 105538 : void GDALProxyPoolDataset::AddSrcBandDescription(GDALDataType eDataType,
881 : int nBlockXSize,
882 : int nBlockYSize)
883 : {
884 105537 : SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType,
885 105538 : nBlockXSize, nBlockYSize));
886 105538 : }
887 :
888 : /************************************************************************/
889 : /* AddSrcBand() */
890 : /************************************************************************/
891 :
892 0 : void GDALProxyPoolDataset::AddSrcBand(int nBand, GDALDataType eDataType,
893 : int nBlockXSize, int nBlockYSize)
894 : {
895 0 : SetBand(nBand, new GDALProxyPoolRasterBand(this, nBand, eDataType,
896 0 : nBlockXSize, nBlockYSize));
897 0 : }
898 :
899 : /************************************************************************/
900 : /* RefUnderlyingDataset() */
901 : /************************************************************************/
902 :
903 4946 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset() const
904 : {
905 4946 : return RefUnderlyingDataset(true);
906 : }
907 :
908 232686 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset(bool bForceOpen) const
909 : {
910 : /* We pretend that the current thread is responsiblePID, that is */
911 : /* to say the thread that created that GDALProxyPoolDataset object. */
912 : /* This is for the case when a GDALProxyPoolDataset is created by a */
913 : /* thread and used by other threads. These other threads, when doing actual
914 : */
915 : /* IO, will come there and potentially open the underlying dataset. */
916 : /* By doing this, they can indirectly call GDALOpenShared() on .aux file */
917 : /* for example. So this call to GDALOpenShared() must occur as if it */
918 : /* was done by the creating thread, otherwise it will not be correctly
919 : * closed afterwards... */
920 : /* To make a long story short : this is necessary when warping with
921 : * ChunkAndWarpMulti */
922 : /* a VRT of GeoTIFFs that have associated .aux files */
923 232686 : GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
924 232687 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
925 232686 : cacheEntry =
926 232685 : GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
927 232686 : GetShared(), bForceOpen, m_pszOwner);
928 232686 : GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
929 232687 : if (cacheEntry != nullptr)
930 : {
931 230502 : if (cacheEntry->poDS != nullptr)
932 230247 : return cacheEntry->poDS;
933 : else
934 255 : GDALDatasetPool::UnrefDataset(cacheEntry);
935 : }
936 2440 : return nullptr;
937 : }
938 :
939 : /************************************************************************/
940 : /* UnrefUnderlyingDataset() */
941 : /************************************************************************/
942 :
943 230245 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(
944 : CPL_UNUSED GDALDataset *poUnderlyingDataset) const
945 : {
946 230245 : if (cacheEntry != nullptr)
947 : {
948 230245 : CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
949 230245 : if (cacheEntry->poDS != nullptr)
950 230246 : GDALDatasetPool::UnrefDataset(cacheEntry);
951 : }
952 230246 : }
953 :
954 : /************************************************************************/
955 : /* FlushCache() */
956 : /************************************************************************/
957 :
958 0 : CPLErr GDALProxyPoolDataset::FlushCache(bool bAtClosing)
959 : {
960 0 : CPLErr eErr = CE_None;
961 0 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset(false);
962 0 : if (poUnderlyingDataset)
963 : {
964 0 : eErr = poUnderlyingDataset->FlushCache(bAtClosing);
965 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
966 : }
967 0 : return eErr;
968 : }
969 :
970 : /************************************************************************/
971 : /* SetSpatialRef() */
972 : /************************************************************************/
973 :
974 0 : CPLErr GDALProxyPoolDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
975 : {
976 0 : m_bHasSrcSRS = false;
977 0 : return GDALProxyDataset::SetSpatialRef(poSRS);
978 : }
979 :
980 : /************************************************************************/
981 : /* GetSpatialRef() */
982 : /************************************************************************/
983 :
984 272 : const OGRSpatialReference *GDALProxyPoolDataset::GetSpatialRef() const
985 : {
986 272 : if (m_bHasSrcSRS)
987 203 : return m_poSRS;
988 : else
989 : {
990 69 : if (m_poSRS)
991 0 : m_poSRS->Release();
992 69 : m_poSRS = nullptr;
993 69 : auto poSRS = GDALProxyDataset::GetSpatialRef();
994 69 : if (poSRS)
995 0 : m_poSRS = poSRS->Clone();
996 69 : return m_poSRS;
997 : }
998 : }
999 :
1000 : /************************************************************************/
1001 : /* SetGeoTransform() */
1002 : /************************************************************************/
1003 :
1004 0 : CPLErr GDALProxyPoolDataset::SetGeoTransform(const GDALGeoTransform >)
1005 : {
1006 0 : m_gt = gt;
1007 0 : m_bHasSrcGeoTransform = false;
1008 0 : return GDALProxyDataset::SetGeoTransform(gt);
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GetGeoTransform() */
1013 : /************************************************************************/
1014 :
1015 818 : CPLErr GDALProxyPoolDataset::GetGeoTransform(GDALGeoTransform >) const
1016 : {
1017 818 : if (m_bHasSrcGeoTransform)
1018 : {
1019 818 : gt = m_gt;
1020 818 : return CE_None;
1021 : }
1022 : else
1023 : {
1024 0 : return GDALProxyDataset::GetGeoTransform(gt);
1025 : }
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* GetMetadata() */
1030 : /************************************************************************/
1031 :
1032 30 : char **GDALProxyPoolDataset::GetMetadata(const char *pszDomain)
1033 : {
1034 30 : if (metadataSet == nullptr)
1035 5 : metadataSet =
1036 5 : CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
1037 : free_func_get_metadata);
1038 :
1039 30 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1040 30 : if (poUnderlyingDataset == nullptr)
1041 0 : return nullptr;
1042 :
1043 : char **papszUnderlyingMetadata =
1044 30 : poUnderlyingDataset->GetMetadata(pszDomain);
1045 :
1046 : GetMetadataElt *pElt =
1047 30 : static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
1048 30 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1049 30 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
1050 30 : CPLHashSetInsert(metadataSet, pElt);
1051 :
1052 30 : UnrefUnderlyingDataset(poUnderlyingDataset);
1053 :
1054 30 : return pElt->papszMetadata;
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* GetMetadataItem() */
1059 : /************************************************************************/
1060 :
1061 4 : const char *GDALProxyPoolDataset::GetMetadataItem(const char *pszName,
1062 : const char *pszDomain)
1063 : {
1064 4 : if (metadataItemSet == nullptr)
1065 2 : metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
1066 : equal_func_get_metadata_item,
1067 : free_func_get_metadata_item);
1068 :
1069 4 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1070 4 : if (poUnderlyingDataset == nullptr)
1071 0 : return nullptr;
1072 :
1073 : const char *pszUnderlyingMetadataItem =
1074 4 : poUnderlyingDataset->GetMetadataItem(pszName, pszDomain);
1075 :
1076 : GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
1077 4 : CPLMalloc(sizeof(GetMetadataItemElt)));
1078 4 : pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
1079 4 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1080 4 : pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
1081 4 : ? CPLStrdup(pszUnderlyingMetadataItem)
1082 : : nullptr;
1083 4 : CPLHashSetInsert(metadataItemSet, pElt);
1084 :
1085 4 : UnrefUnderlyingDataset(poUnderlyingDataset);
1086 :
1087 4 : return pElt->pszMetadataItem;
1088 : }
1089 :
1090 : /************************************************************************/
1091 : /* GetInternalHandle() */
1092 : /************************************************************************/
1093 :
1094 0 : void *GDALProxyPoolDataset::GetInternalHandle(const char *pszRequest)
1095 : {
1096 0 : CPLError(
1097 : CE_Warning, CPLE_AppDefined,
1098 : "GetInternalHandle() cannot be safely called on a proxy pool dataset\n"
1099 : "as the returned value may be invalidated at any time.\n");
1100 0 : return GDALProxyDataset::GetInternalHandle(pszRequest);
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* GetGCPSpatialRef() */
1105 : /************************************************************************/
1106 :
1107 4 : const OGRSpatialReference *GDALProxyPoolDataset::GetGCPSpatialRef() const
1108 : {
1109 4 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1110 4 : if (poUnderlyingDataset == nullptr)
1111 0 : return nullptr;
1112 :
1113 4 : if (m_poGCPSRS)
1114 : {
1115 0 : m_poGCPSRS->Release();
1116 0 : m_poGCPSRS = nullptr;
1117 : }
1118 :
1119 4 : const auto poUnderlyingGCPSRS = poUnderlyingDataset->GetGCPSpatialRef();
1120 4 : if (poUnderlyingGCPSRS)
1121 0 : m_poGCPSRS = poUnderlyingGCPSRS->Clone();
1122 :
1123 4 : UnrefUnderlyingDataset(poUnderlyingDataset);
1124 :
1125 4 : return m_poGCPSRS;
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* GetGCPs() */
1130 : /************************************************************************/
1131 :
1132 0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
1133 : {
1134 0 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1135 0 : if (poUnderlyingDataset == nullptr)
1136 0 : return nullptr;
1137 :
1138 0 : if (nGCPCount)
1139 : {
1140 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
1141 0 : CPLFree(pasGCPList);
1142 0 : pasGCPList = nullptr;
1143 : }
1144 :
1145 0 : const GDAL_GCP *pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
1146 0 : nGCPCount = poUnderlyingDataset->GetGCPCount();
1147 0 : if (nGCPCount)
1148 0 : pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList);
1149 :
1150 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
1151 :
1152 0 : return pasGCPList;
1153 : }
1154 :
1155 : /************************************************************************/
1156 : /* GDALProxyPoolDatasetCreate() */
1157 : /************************************************************************/
1158 :
1159 1268 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(
1160 : const char *pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize,
1161 : GDALAccess eAccess, int bShared, const char *pszProjectionRef,
1162 : const double *padfGeoTransform)
1163 : {
1164 : return reinterpret_cast<GDALProxyPoolDatasetH>(new GDALProxyPoolDataset(
1165 : pszSourceDatasetDescription, nRasterXSize, nRasterYSize, eAccess,
1166 : bShared, pszProjectionRef,
1167 1268 : reinterpret_cast<const GDALGeoTransform *>(padfGeoTransform)));
1168 : }
1169 :
1170 : /************************************************************************/
1171 : /* GDALProxyPoolDatasetDelete() */
1172 : /************************************************************************/
1173 :
1174 0 : void GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
1175 : {
1176 0 : delete reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset);
1177 0 : }
1178 :
1179 : /************************************************************************/
1180 : /* GDALProxyPoolDatasetAddSrcBandDescription() */
1181 : /************************************************************************/
1182 :
1183 2385 : void GDALProxyPoolDatasetAddSrcBandDescription(
1184 : GDALProxyPoolDatasetH hProxyPoolDataset, GDALDataType eDataType,
1185 : int nBlockXSize, int nBlockYSize)
1186 : {
1187 : reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset)
1188 2385 : ->AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
1189 2385 : }
1190 :
1191 : /* ******************************************************************** */
1192 : /* GDALProxyPoolRasterBand() */
1193 : /* ******************************************************************** */
1194 :
1195 105560 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset *poDSIn,
1196 : int nBandIn,
1197 : GDALDataType eDataTypeIn,
1198 : int nBlockXSizeIn,
1199 105560 : int nBlockYSizeIn)
1200 : {
1201 105559 : poDS = poDSIn;
1202 105559 : nBand = nBandIn;
1203 105559 : eDataType = eDataTypeIn;
1204 105559 : nRasterXSize = poDSIn->GetRasterXSize();
1205 105560 : nRasterYSize = poDSIn->GetRasterYSize();
1206 105560 : nBlockXSize = nBlockXSizeIn;
1207 105560 : nBlockYSize = nBlockYSizeIn;
1208 105560 : }
1209 :
1210 : /* ******************************************************************** */
1211 : /* GDALProxyPoolRasterBand() */
1212 : /* ******************************************************************** */
1213 :
1214 62 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(
1215 62 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingRasterBand)
1216 : {
1217 62 : poDS = poDSIn;
1218 62 : nBand = poUnderlyingRasterBand->GetBand();
1219 62 : eDataType = poUnderlyingRasterBand->GetRasterDataType();
1220 62 : nRasterXSize = poUnderlyingRasterBand->GetXSize();
1221 62 : nRasterYSize = poUnderlyingRasterBand->GetYSize();
1222 62 : poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1223 62 : }
1224 :
1225 : /* ******************************************************************** */
1226 : /* ~GDALProxyPoolRasterBand() */
1227 : /* ******************************************************************** */
1228 211160 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
1229 : {
1230 105622 : if (metadataSet)
1231 3 : CPLHashSetDestroy(metadataSet);
1232 105622 : if (metadataItemSet)
1233 20 : CPLHashSetDestroy(metadataItemSet);
1234 105622 : CPLFree(pszUnitType);
1235 105622 : CSLDestroy(papszCategoryNames);
1236 105622 : if (poColorTable)
1237 6 : delete poColorTable;
1238 :
1239 105646 : for (int i = 0; i < nSizeProxyOverviewRasterBand; i++)
1240 : {
1241 24 : if (papoProxyOverviewRasterBand[i])
1242 24 : delete papoProxyOverviewRasterBand[i];
1243 : }
1244 105622 : CPLFree(papoProxyOverviewRasterBand);
1245 105622 : if (poProxyMaskBand)
1246 60 : delete poProxyMaskBand;
1247 211160 : }
1248 :
1249 : /************************************************************************/
1250 : /* AddSrcMaskBandDescriptionFromUnderlying() */
1251 : /************************************************************************/
1252 :
1253 15 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescriptionFromUnderlying()
1254 : {
1255 15 : if (poProxyMaskBand != nullptr)
1256 6 : return;
1257 9 : GDALRasterBand *poUnderlyingBand = RefUnderlyingRasterBand();
1258 9 : if (poUnderlyingBand == nullptr)
1259 0 : return;
1260 9 : auto poSrcMaskBand = poUnderlyingBand->GetMaskBand();
1261 : int nSrcBlockXSize, nSrcBlockYSize;
1262 9 : poSrcMaskBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
1263 9 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1264 9 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), this,
1265 9 : poSrcMaskBand->GetRasterDataType(), nSrcBlockXSize, nSrcBlockYSize);
1266 9 : UnrefUnderlyingRasterBand(poUnderlyingBand);
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* AddSrcMaskBandDescription() */
1271 : /************************************************************************/
1272 :
1273 13 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescription(
1274 : GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
1275 : {
1276 13 : CPLAssert(poProxyMaskBand == nullptr);
1277 13 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1278 13 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), this, eDataTypeIn,
1279 13 : nBlockXSizeIn, nBlockYSizeIn);
1280 13 : }
1281 :
1282 : /************************************************************************/
1283 : /* RefUnderlyingRasterBand() */
1284 : /************************************************************************/
1285 :
1286 : GDALRasterBand *
1287 227741 : GDALProxyPoolRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
1288 : {
1289 : GDALDataset *poUnderlyingDataset =
1290 227741 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1291 227741 : ->RefUnderlyingDataset(bForceOpen);
1292 227741 : if (poUnderlyingDataset == nullptr)
1293 2185 : return nullptr;
1294 :
1295 225556 : GDALRasterBand *poBand = poUnderlyingDataset->GetRasterBand(nBand);
1296 225556 : if (poBand == nullptr)
1297 : {
1298 0 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1299 0 : ->UnrefUnderlyingDataset(poUnderlyingDataset);
1300 : }
1301 225556 : else if (nBlockXSize <= 0 || nBlockYSize <= 0)
1302 : {
1303 : // Here we try to load nBlockXSize&nBlockYSize from underlying band
1304 : // but we must guarantee that we will not access directly to
1305 : // nBlockXSize/nBlockYSize before RefUnderlyingRasterBand() is called
1306 : int nSrcBlockXSize, nSrcBlockYSize;
1307 10 : poBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
1308 10 : const_cast<GDALProxyPoolRasterBand *>(this)->nBlockXSize =
1309 : nSrcBlockXSize;
1310 10 : const_cast<GDALProxyPoolRasterBand *>(this)->nBlockYSize =
1311 : nSrcBlockYSize;
1312 : }
1313 :
1314 225556 : return poBand;
1315 : }
1316 :
1317 : /************************************************************************/
1318 : /* UnrefUnderlyingRasterBand() */
1319 : /************************************************************************/
1320 :
1321 225555 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(
1322 : GDALRasterBand *poUnderlyingRasterBand) const
1323 : {
1324 225555 : if (poUnderlyingRasterBand)
1325 225555 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1326 225554 : ->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
1327 225556 : }
1328 :
1329 : /************************************************************************/
1330 : /* FlushCache() */
1331 : /************************************************************************/
1332 :
1333 104640 : CPLErr GDALProxyPoolRasterBand::FlushCache(bool bAtClosing)
1334 : {
1335 104640 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand(false);
1336 104640 : if (poUnderlyingRasterBand)
1337 : {
1338 102455 : CPLErr eErr = poUnderlyingRasterBand->FlushCache(bAtClosing);
1339 102455 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1340 102455 : return eErr;
1341 : }
1342 2185 : return CE_None;
1343 : }
1344 :
1345 : /************************************************************************/
1346 : /* GetMetadata() */
1347 : /************************************************************************/
1348 :
1349 4 : char **GDALProxyPoolRasterBand::GetMetadata(const char *pszDomain)
1350 : {
1351 4 : if (metadataSet == nullptr)
1352 3 : metadataSet =
1353 3 : CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
1354 : free_func_get_metadata);
1355 :
1356 4 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1357 4 : if (poUnderlyingRasterBand == nullptr)
1358 0 : return nullptr;
1359 :
1360 : char **papszUnderlyingMetadata =
1361 4 : poUnderlyingRasterBand->GetMetadata(pszDomain);
1362 :
1363 : GetMetadataElt *pElt =
1364 4 : static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
1365 4 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1366 4 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
1367 4 : CPLHashSetInsert(metadataSet, pElt);
1368 :
1369 4 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1370 :
1371 4 : return pElt->papszMetadata;
1372 : }
1373 :
1374 : /************************************************************************/
1375 : /* GetMetadataItem() */
1376 : /************************************************************************/
1377 :
1378 40 : const char *GDALProxyPoolRasterBand::GetMetadataItem(const char *pszName,
1379 : const char *pszDomain)
1380 : {
1381 40 : if (metadataItemSet == nullptr)
1382 20 : metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
1383 : equal_func_get_metadata_item,
1384 : free_func_get_metadata_item);
1385 :
1386 40 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1387 40 : if (poUnderlyingRasterBand == nullptr)
1388 0 : return nullptr;
1389 :
1390 : const char *pszUnderlyingMetadataItem =
1391 40 : poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
1392 :
1393 : GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
1394 40 : CPLMalloc(sizeof(GetMetadataItemElt)));
1395 40 : pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
1396 40 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1397 40 : pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
1398 40 : ? CPLStrdup(pszUnderlyingMetadataItem)
1399 : : nullptr;
1400 40 : CPLHashSetInsert(metadataItemSet, pElt);
1401 :
1402 40 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1403 :
1404 40 : return pElt->pszMetadataItem;
1405 : }
1406 :
1407 : /* ******************************************************************** */
1408 : /* GetCategoryNames() */
1409 : /* ******************************************************************** */
1410 :
1411 3 : char **GDALProxyPoolRasterBand::GetCategoryNames()
1412 : {
1413 3 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1414 3 : if (poUnderlyingRasterBand == nullptr)
1415 0 : return nullptr;
1416 :
1417 3 : CSLDestroy(papszCategoryNames);
1418 3 : papszCategoryNames = nullptr;
1419 :
1420 : char **papszUnderlyingCategoryNames =
1421 3 : poUnderlyingRasterBand->GetCategoryNames();
1422 3 : if (papszUnderlyingCategoryNames)
1423 0 : papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
1424 :
1425 3 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1426 :
1427 3 : return papszCategoryNames;
1428 : }
1429 :
1430 : /* ******************************************************************** */
1431 : /* GetUnitType() */
1432 : /* ******************************************************************** */
1433 :
1434 4 : const char *GDALProxyPoolRasterBand::GetUnitType()
1435 : {
1436 4 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1437 4 : if (poUnderlyingRasterBand == nullptr)
1438 0 : return nullptr;
1439 :
1440 4 : CPLFree(pszUnitType);
1441 4 : pszUnitType = nullptr;
1442 :
1443 4 : const char *pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
1444 4 : if (pszUnderlyingUnitType)
1445 4 : pszUnitType = CPLStrdup(pszUnderlyingUnitType);
1446 :
1447 4 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1448 :
1449 4 : return pszUnitType;
1450 : }
1451 :
1452 : /* ******************************************************************** */
1453 : /* GetColorTable() */
1454 : /* ******************************************************************** */
1455 :
1456 454 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
1457 : {
1458 454 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1459 454 : if (poUnderlyingRasterBand == nullptr)
1460 0 : return nullptr;
1461 :
1462 454 : if (poColorTable)
1463 31 : delete poColorTable;
1464 454 : poColorTable = nullptr;
1465 :
1466 : GDALColorTable *poUnderlyingColorTable =
1467 454 : poUnderlyingRasterBand->GetColorTable();
1468 454 : if (poUnderlyingColorTable)
1469 37 : poColorTable = poUnderlyingColorTable->Clone();
1470 :
1471 454 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1472 :
1473 454 : return poColorTable;
1474 : }
1475 :
1476 : /* ******************************************************************** */
1477 : /* GetOverview() */
1478 : /* ******************************************************************** */
1479 :
1480 36 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
1481 : {
1482 36 : if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
1483 : {
1484 12 : if (papoProxyOverviewRasterBand[nOverviewBand])
1485 12 : return papoProxyOverviewRasterBand[nOverviewBand];
1486 : }
1487 :
1488 24 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1489 24 : if (poUnderlyingRasterBand == nullptr)
1490 0 : return nullptr;
1491 :
1492 : GDALRasterBand *poOverviewRasterBand =
1493 24 : poUnderlyingRasterBand->GetOverview(nOverviewBand);
1494 24 : if (poOverviewRasterBand == nullptr)
1495 : {
1496 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1497 0 : return nullptr;
1498 : }
1499 :
1500 24 : if (nOverviewBand >= nSizeProxyOverviewRasterBand)
1501 : {
1502 24 : papoProxyOverviewRasterBand =
1503 : static_cast<GDALProxyPoolOverviewRasterBand **>(
1504 48 : CPLRealloc(papoProxyOverviewRasterBand,
1505 : sizeof(GDALProxyPoolOverviewRasterBand *) *
1506 24 : (nOverviewBand + 1)));
1507 48 : for (int i = nSizeProxyOverviewRasterBand; i < nOverviewBand + 1; i++)
1508 24 : papoProxyOverviewRasterBand[i] = nullptr;
1509 24 : nSizeProxyOverviewRasterBand = nOverviewBand + 1;
1510 : }
1511 :
1512 24 : papoProxyOverviewRasterBand[nOverviewBand] =
1513 : new GDALProxyPoolOverviewRasterBand(
1514 24 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), poOverviewRasterBand,
1515 24 : this, nOverviewBand);
1516 :
1517 24 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1518 :
1519 24 : return papoProxyOverviewRasterBand[nOverviewBand];
1520 : }
1521 :
1522 : /* ******************************************************************** */
1523 : /* GetRasterSampleOverview() */
1524 : /* ******************************************************************** */
1525 :
1526 : GDALRasterBand *
1527 0 : GDALProxyPoolRasterBand::GetRasterSampleOverview(GUIntBig /* nDesiredSamples */)
1528 : {
1529 0 : CPLError(CE_Failure, CPLE_AppDefined,
1530 : "GDALProxyPoolRasterBand::GetRasterSampleOverview : not "
1531 : "implemented yet");
1532 0 : return nullptr;
1533 : }
1534 :
1535 : /* ******************************************************************** */
1536 : /* GetMaskBand() */
1537 : /* ******************************************************************** */
1538 :
1539 88 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
1540 : {
1541 88 : if (poProxyMaskBand)
1542 50 : return poProxyMaskBand;
1543 :
1544 38 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1545 38 : if (poUnderlyingRasterBand == nullptr)
1546 0 : return nullptr;
1547 :
1548 38 : GDALRasterBand *poMaskBand = poUnderlyingRasterBand->GetMaskBand();
1549 :
1550 38 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1551 38 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), poMaskBand, this);
1552 :
1553 38 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1554 :
1555 38 : return poProxyMaskBand;
1556 : }
1557 :
1558 : /* ******************************************************************** */
1559 : /* GDALProxyPoolOverviewRasterBand() */
1560 : /* ******************************************************************** */
1561 :
1562 24 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(
1563 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingOverviewBand,
1564 24 : GDALProxyPoolRasterBand *poMainBandIn, int nOverviewBandIn)
1565 : : GDALProxyPoolRasterBand(poDSIn, poUnderlyingOverviewBand),
1566 24 : poMainBand(poMainBandIn), nOverviewBand(nOverviewBandIn)
1567 : {
1568 24 : }
1569 :
1570 : /* ******************************************************************** */
1571 : /* ~GDALProxyPoolOverviewRasterBand() */
1572 : /* ******************************************************************** */
1573 :
1574 48 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
1575 : {
1576 24 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1577 48 : }
1578 :
1579 : /* ******************************************************************** */
1580 : /* RefUnderlyingRasterBand() */
1581 : /* ******************************************************************** */
1582 :
1583 : GDALRasterBand *
1584 0 : GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
1585 : {
1586 0 : poUnderlyingMainRasterBand =
1587 0 : poMainBand->RefUnderlyingRasterBand(bForceOpen);
1588 0 : if (poUnderlyingMainRasterBand == nullptr)
1589 0 : return nullptr;
1590 :
1591 0 : nRefCountUnderlyingMainRasterBand++;
1592 0 : return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
1593 : }
1594 :
1595 : /* ******************************************************************** */
1596 : /* UnrefUnderlyingRasterBand() */
1597 : /* ******************************************************************** */
1598 :
1599 0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(
1600 : GDALRasterBand * /* poUnderlyingRasterBand */) const
1601 : {
1602 0 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1603 0 : nRefCountUnderlyingMainRasterBand--;
1604 0 : }
1605 :
1606 : /* ******************************************************************** */
1607 : /* GDALProxyPoolMaskBand() */
1608 : /* ******************************************************************** */
1609 :
1610 38 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
1611 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingMaskBand,
1612 38 : GDALProxyPoolRasterBand *poMainBandIn)
1613 38 : : GDALProxyPoolRasterBand(poDSIn, poUnderlyingMaskBand)
1614 : {
1615 38 : poMainBand = poMainBandIn;
1616 :
1617 38 : poUnderlyingMainRasterBand = nullptr;
1618 38 : nRefCountUnderlyingMainRasterBand = 0;
1619 38 : }
1620 :
1621 : /* ******************************************************************** */
1622 : /* GDALProxyPoolMaskBand() */
1623 : /* ******************************************************************** */
1624 :
1625 22 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
1626 : GDALProxyPoolDataset *poDSIn, GDALProxyPoolRasterBand *poMainBandIn,
1627 22 : GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
1628 : : GDALProxyPoolRasterBand(poDSIn, 1, eDataTypeIn, nBlockXSizeIn,
1629 : nBlockYSizeIn),
1630 22 : poMainBand(poMainBandIn)
1631 : {
1632 22 : }
1633 :
1634 : /* ******************************************************************** */
1635 : /* ~GDALProxyPoolMaskBand() */
1636 : /* ******************************************************************** */
1637 :
1638 120 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
1639 : {
1640 60 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1641 120 : }
1642 :
1643 : /* ******************************************************************** */
1644 : /* RefUnderlyingRasterBand() */
1645 : /* ******************************************************************** */
1646 :
1647 : GDALRasterBand *
1648 245 : GDALProxyPoolMaskBand::RefUnderlyingRasterBand(bool bForceOpen) const
1649 : {
1650 245 : poUnderlyingMainRasterBand =
1651 245 : poMainBand->RefUnderlyingRasterBand(bForceOpen);
1652 245 : if (poUnderlyingMainRasterBand == nullptr)
1653 0 : return nullptr;
1654 :
1655 245 : nRefCountUnderlyingMainRasterBand++;
1656 245 : return poUnderlyingMainRasterBand->GetMaskBand();
1657 : }
1658 :
1659 : /* ******************************************************************** */
1660 : /* UnrefUnderlyingRasterBand() */
1661 : /* ******************************************************************** */
1662 :
1663 245 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(
1664 : GDALRasterBand * /* poUnderlyingRasterBand */) const
1665 : {
1666 245 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1667 245 : nRefCountUnderlyingMainRasterBand--;
1668 245 : }
1669 :
1670 : //! @endcond
|