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 402 : GDALDatasetPool::GDALDatasetPool(int maxSizeIn, int64_t nMaxRAMUsageIn)
142 402 : : maxSize(maxSizeIn), nMaxRAMUsage(nMaxRAMUsageIn)
143 : {
144 402 : }
145 :
146 : /************************************************************************/
147 : /* ~GDALDatasetPool() */
148 : /************************************************************************/
149 :
150 798 : GDALDatasetPool::~GDALDatasetPool()
151 : {
152 399 : bInDestruction = true;
153 399 : GDALProxyPoolCacheEntry *cur = firstEntry;
154 399 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
155 817 : while (cur)
156 : {
157 418 : GDALProxyPoolCacheEntry *next = cur->next;
158 418 : CPLFree(cur->pszFileNameAndOpenOptions);
159 418 : CPLFree(cur->pszOwner);
160 418 : CPLAssert(cur->refCount == 0);
161 418 : if (cur->poDS)
162 : {
163 0 : GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
164 0 : GDALClose(cur->poDS);
165 : }
166 418 : CPLFree(cur);
167 418 : cur = next;
168 : }
169 399 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
170 399 : }
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 236711 : static std::string GetFilenameAndOpenOptions(const char *pszFileName,
221 : CSLConstList papszOpenOptions)
222 : {
223 236711 : std::string osFilenameAndOO(pszFileName);
224 236775 : for (int i = 0; papszOpenOptions && papszOpenOptions[i]; ++i)
225 : {
226 64 : osFilenameAndOO += "||";
227 64 : osFilenameAndOO += papszOpenOptions[i];
228 : }
229 236711 : return osFilenameAndOO;
230 : }
231 :
232 : /************************************************************************/
233 : /* _RefDataset() */
234 : /************************************************************************/
235 :
236 : GDALProxyPoolCacheEntry *
237 232017 : GDALDatasetPool::_RefDataset(const char *pszFileName, GDALAccess eAccess,
238 : CSLConstList papszOpenOptions, int bShared,
239 : bool bForceOpen, const char *pszOwner)
240 : {
241 232017 : CPLMutex **pMutex = GDALGetphDLMutex();
242 464034 : CPLMutexHolderD(pMutex);
243 :
244 232019 : if (bInDestruction)
245 0 : return nullptr;
246 :
247 232019 : const GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
248 :
249 : const auto EvictEntryWithZeroRefCount =
250 17324 : [this, responsiblePID](bool evictEntryWithOpenedDataset)
251 : {
252 2887 : GDALProxyPoolCacheEntry *cur = firstEntry;
253 2887 : GDALProxyPoolCacheEntry *candidate = nullptr;
254 291393 : while (cur)
255 : {
256 288506 : GDALProxyPoolCacheEntry *next = cur->next;
257 :
258 288506 : if (cur->refCount == 0 &&
259 284302 : (!evictEntryWithOpenedDataset || cur->nRAMUsage > 0))
260 : {
261 284302 : candidate = cur;
262 : }
263 :
264 288506 : cur = next;
265 : }
266 2887 : if (candidate == nullptr)
267 0 : return false;
268 :
269 2887 : nRAMUsage -= candidate->nRAMUsage;
270 2887 : candidate->nRAMUsage = 0;
271 :
272 2887 : CPLFree(candidate->pszFileNameAndOpenOptions);
273 2887 : candidate->pszFileNameAndOpenOptions = nullptr;
274 :
275 2887 : 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 2887 : CPLFree(candidate->pszOwner);
289 2887 : candidate->pszOwner = nullptr;
290 :
291 2887 : 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 2887 : if (candidate->prev)
296 2887 : candidate->prev->next = candidate->next;
297 :
298 2887 : if (candidate->next)
299 0 : candidate->next->prev = candidate->prev;
300 : else
301 : {
302 2887 : CPLAssert(candidate == lastEntry);
303 2887 : lastEntry->prev->next = nullptr;
304 2887 : lastEntry = lastEntry->prev;
305 : }
306 2887 : candidate->prev = nullptr;
307 2887 : candidate->next = firstEntry;
308 2887 : firstEntry->prev = candidate;
309 2887 : firstEntry = candidate;
310 :
311 : #ifdef DEBUG_PROXY_POOL
312 : CheckLinks();
313 : #endif
314 : }
315 :
316 2887 : return true;
317 232019 : };
318 :
319 232019 : GDALProxyPoolCacheEntry *cur = firstEntry;
320 :
321 : const std::string osFilenameAndOO =
322 464038 : GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
323 :
324 744988 : while (cur)
325 : {
326 739253 : GDALProxyPoolCacheEntry *next = cur->next;
327 :
328 1026110 : if (cur->refCount >= 0 && cur->pszFileNameAndOpenOptions &&
329 1991710 : osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
330 226247 : ((bShared && cur->responsiblePID == responsiblePID &&
331 226241 : ((cur->pszOwner == nullptr && pszOwner == nullptr) ||
332 225491 : (cur->pszOwner != nullptr && pszOwner != nullptr &&
333 225596 : strcmp(cur->pszOwner, pszOwner) == 0))) ||
334 99 : (!bShared && cur->refCount == 0)))
335 : {
336 226284 : if (cur != firstEntry)
337 : {
338 : /* Move to begin */
339 7479 : if (cur->next)
340 7116 : cur->next->prev = cur->prev;
341 : else
342 363 : lastEntry = cur->prev;
343 7479 : cur->prev->next = cur->next;
344 7479 : cur->prev = nullptr;
345 7479 : firstEntry->prev = cur;
346 7479 : cur->next = firstEntry;
347 7479 : firstEntry = cur;
348 :
349 : #ifdef DEBUG_PROXY_POOL
350 : CheckLinks();
351 : #endif
352 : }
353 :
354 226284 : cur->refCount++;
355 226284 : return cur;
356 : }
357 :
358 512969 : cur = next;
359 : }
360 :
361 5735 : if (!bForceOpen)
362 2163 : return nullptr;
363 :
364 3572 : if (currentSize == maxSize)
365 : {
366 2887 : 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 2887 : CPLAssert(firstEntry);
379 2887 : cur = firstEntry;
380 : }
381 : else
382 : {
383 : /* Prepend */
384 : cur = static_cast<GDALProxyPoolCacheEntry *>(
385 685 : CPLCalloc(1, sizeof(GDALProxyPoolCacheEntry)));
386 685 : if (lastEntry == nullptr)
387 352 : lastEntry = cur;
388 685 : cur->prev = nullptr;
389 685 : cur->next = firstEntry;
390 685 : if (firstEntry)
391 333 : firstEntry->prev = cur;
392 685 : firstEntry = cur;
393 685 : currentSize++;
394 : #ifdef DEBUG_PROXY_POOL
395 : CheckLinks();
396 : #endif
397 : }
398 :
399 3572 : cur->pszFileNameAndOpenOptions = CPLStrdup(osFilenameAndOO.c_str());
400 3572 : cur->pszOwner = (pszOwner) ? CPLStrdup(pszOwner) : nullptr;
401 3572 : cur->responsiblePID = responsiblePID;
402 3572 : cur->refCount = -1; // to mark loading of dataset in progress
403 3572 : cur->nRAMUsage = 0;
404 :
405 3572 : refCountOfDisabledRefCount++;
406 3572 : const int nFlag =
407 : ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) |
408 3572 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
409 3572 : CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
410 :
411 : // Release mutex while opening dataset to avoid lock contention.
412 3572 : CPLReleaseMutex(*pMutex);
413 3572 : auto poDS = GDALDataset::Open(pszFileName, nFlag, nullptr, papszOpenOptions,
414 : nullptr);
415 3572 : CPLAcquireMutex(*pMutex, 1000.0);
416 :
417 3572 : cur->poDS = poDS;
418 3572 : cur->refCount = 1;
419 :
420 3572 : refCountOfDisabledRefCount--;
421 :
422 3572 : if (cur->poDS)
423 : {
424 3403 : cur->nRAMUsage =
425 3403 : std::max<GIntBig>(0, cur->poDS->GetEstimatedRAMUsage());
426 3403 : nRAMUsage += cur->nRAMUsage;
427 : }
428 :
429 3572 : 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 3572 : return cur;
439 : }
440 :
441 : /************************************************************************/
442 : /* _CloseDatasetIfZeroRefCount() */
443 : /************************************************************************/
444 :
445 4692 : 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 4692 : if (bInDestruction)
452 0 : return;
453 :
454 4692 : GDALProxyPoolCacheEntry *cur = firstEntry;
455 4692 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
456 :
457 : const std::string osFilenameAndOO =
458 9384 : GetFilenameAndOpenOptions(pszFileName, papszOpenOptions);
459 :
460 82928 : while (cur)
461 : {
462 81637 : GDALProxyPoolCacheEntry *next = cur->next;
463 :
464 102124 : if (cur->refCount == 0 && cur->pszFileNameAndOpenOptions &&
465 24077 : osFilenameAndOO == cur->pszFileNameAndOpenOptions &&
466 3586 : ((pszOwner == nullptr && cur->pszOwner == nullptr) ||
467 3401 : (pszOwner != nullptr && cur->pszOwner != nullptr &&
468 166670 : strcmp(cur->pszOwner, pszOwner) == 0)) &&
469 3576 : cur->poDS != nullptr)
470 : {
471 : /* Close by pretending we are the thread that GDALOpen'ed this */
472 : /* dataset */
473 3401 : GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
474 :
475 3401 : GDALDataset *poDS = cur->poDS;
476 :
477 3401 : nRAMUsage -= cur->nRAMUsage;
478 3401 : cur->nRAMUsage = 0;
479 :
480 3401 : cur->poDS = nullptr;
481 3401 : CPLFree(cur->pszFileNameAndOpenOptions);
482 3401 : cur->pszFileNameAndOpenOptions = nullptr;
483 3401 : CPLFree(cur->pszOwner);
484 3401 : cur->pszOwner = nullptr;
485 :
486 3401 : refCountOfDisabledRefCount++;
487 3401 : GDALClose(poDS);
488 3401 : refCountOfDisabledRefCount--;
489 :
490 3401 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
491 3401 : break;
492 : }
493 :
494 78236 : 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 439 : int GDALGetMaxDatasetPoolSize()
506 : {
507 439 : int nSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
508 439 : if (nSize < 2)
509 0 : nSize = 2;
510 439 : else if (nSize > 1000)
511 0 : nSize = 1000;
512 439 : return nSize;
513 : }
514 :
515 : /************************************************************************/
516 : /* Ref() */
517 : /************************************************************************/
518 :
519 4691 : void GDALDatasetPool::Ref()
520 : {
521 9383 : CPLMutexHolderD(GDALGetphDLMutex());
522 4692 : if (singleton == nullptr)
523 : {
524 :
525 : // Try to not consume more than 25% of the usable RAM
526 : GIntBig l_nMaxRAMUsage =
527 402 : (CPLGetUsablePhysicalRAM() - GDALGetCacheMax64()) / 4;
528 : const char *pszMaxRAMUsage =
529 402 : CPLGetConfigOption("GDAL_MAX_DATASET_POOL_RAM_USAGE", nullptr);
530 402 : 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 402 : singleton =
540 402 : new GDALDatasetPool(GDALGetMaxDatasetPoolSize(), l_nMaxRAMUsage);
541 : }
542 4692 : if (refCountOfDisabledRefCount == 0)
543 4692 : singleton->refCount++;
544 4692 : }
545 :
546 : /* keep that in sync with gdaldrivermanager.cpp */
547 1113 : void GDALDatasetPool::PreventDestroy()
548 : {
549 1113 : CPLMutexHolderD(GDALGetphDLMutex());
550 1113 : if (!singleton)
551 1110 : return;
552 3 : refCountOfDisabledRefCount++;
553 : }
554 :
555 : /* keep that in sync with gdaldrivermanager.cpp */
556 : extern void GDALDatasetPoolPreventDestroy();
557 :
558 1113 : void GDALDatasetPoolPreventDestroy()
559 : {
560 1113 : GDALDatasetPool::PreventDestroy();
561 1113 : }
562 :
563 : /************************************************************************/
564 : /* Unref() */
565 : /************************************************************************/
566 :
567 4692 : void GDALDatasetPool::Unref()
568 : {
569 4692 : CPLMutexHolderD(GDALGetphDLMutex());
570 4692 : if (!singleton)
571 : {
572 0 : CPLAssert(false);
573 : return;
574 : }
575 4692 : if (refCountOfDisabledRefCount == 0)
576 : {
577 4655 : singleton->refCount--;
578 4655 : if (singleton->refCount == 0)
579 : {
580 396 : delete singleton;
581 396 : singleton = nullptr;
582 : }
583 : }
584 : }
585 :
586 : /* keep that in sync with gdaldrivermanager.cpp */
587 1113 : void GDALDatasetPool::ForceDestroy()
588 : {
589 1113 : CPLMutexHolderD(GDALGetphDLMutex());
590 1113 : if (!singleton)
591 1110 : 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 1113 : void GDALDatasetPoolForceDestroy()
603 : {
604 1113 : GDALDatasetPool::ForceDestroy();
605 1113 : }
606 :
607 : /************************************************************************/
608 : /* RefDataset() */
609 : /************************************************************************/
610 :
611 : GDALProxyPoolCacheEntry *
612 232016 : GDALDatasetPool::RefDataset(const char *pszFileName, GDALAccess eAccess,
613 : char **papszOpenOptions, int bShared,
614 : bool bForceOpen, const char *pszOwner)
615 : {
616 232016 : return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions,
617 232019 : bShared, bForceOpen, pszOwner);
618 : }
619 :
620 : /************************************************************************/
621 : /* UnrefDataset() */
622 : /************************************************************************/
623 :
624 229856 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry *cacheEntry)
625 : {
626 229856 : CPLMutexHolderD(GDALGetphDLMutex());
627 229856 : cacheEntry->refCount--;
628 229856 : }
629 :
630 : /************************************************************************/
631 : /* CloseDatasetIfZeroRefCount() */
632 : /************************************************************************/
633 :
634 4692 : void GDALDatasetPool::CloseDatasetIfZeroRefCount(const char *pszFileName,
635 : CSLConstList papszOpenOptions,
636 : GDALAccess eAccess,
637 : const char *pszOwner)
638 : {
639 9384 : CPLMutexHolderD(GDALGetphDLMutex());
640 4692 : singleton->_CloseDatasetIfZeroRefCount(pszFileName, papszOpenOptions,
641 : eAccess, pszOwner);
642 4692 : }
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 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 1282 : GDALProxyPoolDataset::GDALProxyPoolDataset(
733 : const char *pszSourceDatasetDescription, int nRasterXSizeIn,
734 : int nRasterYSizeIn, GDALAccess eAccessIn, int bSharedIn,
735 : const char *pszProjectionRefIn, const GDALGeoTransform *pGT,
736 1282 : const char *pszOwner)
737 2564 : : responsiblePID(GDALGetResponsiblePIDForCurrentThread()),
738 1282 : pszProjectionRef(pszProjectionRefIn ? CPLStrdup(pszProjectionRefIn)
739 2564 : : nullptr)
740 : {
741 1282 : GDALDatasetPool::Ref();
742 :
743 1282 : SetDescription(pszSourceDatasetDescription);
744 :
745 1282 : nRasterXSize = nRasterXSizeIn;
746 1282 : nRasterYSize = nRasterYSizeIn;
747 1282 : eAccess = eAccessIn;
748 :
749 1282 : bShared = CPL_TO_BOOL(bSharedIn);
750 1282 : m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
751 :
752 1282 : if (pGT)
753 : {
754 1233 : m_gt = *pGT;
755 1233 : m_bHasSrcGeoTransform = true;
756 : }
757 :
758 1282 : if (pszProjectionRefIn)
759 : {
760 1243 : m_poSRS = new OGRSpatialReference();
761 1243 : m_poSRS->importFromWkt(pszProjectionRefIn);
762 1243 : m_bHasSrcSRS = true;
763 : }
764 1282 : }
765 :
766 : /* Constructor where the parameters (raster size, etc.) are obtained
767 : * by opening the underlying dataset.
768 : */
769 3410 : GDALProxyPoolDataset::GDALProxyPoolDataset(
770 : const char *pszSourceDatasetDescription, GDALAccess eAccessIn,
771 3410 : int bSharedIn, const char *pszOwner)
772 3410 : : responsiblePID(GDALGetResponsiblePIDForCurrentThread())
773 : {
774 3409 : GDALDatasetPool::Ref();
775 :
776 3410 : SetDescription(pszSourceDatasetDescription);
777 :
778 3409 : eAccess = eAccessIn;
779 :
780 3409 : bShared = CPL_TO_BOOL(bSharedIn);
781 3410 : m_pszOwner = pszOwner ? CPLStrdup(pszOwner) : nullptr;
782 3410 : }
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 3410 : 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 6820 : pszSourceDatasetDescription, eAccessIn, bSharedIn, pszOwner));
798 3407 : poSelf->SetOpenOptions(papszOpenOptionsIn);
799 3408 : GDALDataset *poUnderlyingDS = poSelf->RefUnderlyingDataset();
800 3410 : if (!poUnderlyingDS)
801 175 : return nullptr;
802 3235 : poSelf->nRasterXSize = poUnderlyingDS->GetRasterXSize();
803 3235 : poSelf->nRasterYSize = poUnderlyingDS->GetRasterYSize();
804 3235 : if (poUnderlyingDS->GetGeoTransform(poSelf->m_gt) == CE_None)
805 970 : poSelf->m_bHasSrcGeoTransform = true;
806 3235 : const auto poSRS = poUnderlyingDS->GetSpatialRef();
807 3235 : if (poSRS)
808 : {
809 878 : poSelf->m_poSRS = poSRS->Clone();
810 878 : poSelf->m_bHasSrcSRS = true;
811 : }
812 106326 : for (int i = 1; i <= poUnderlyingDS->GetRasterCount(); ++i)
813 : {
814 103091 : auto poSrcBand = poUnderlyingDS->GetRasterBand(i);
815 103091 : if (!poSrcBand)
816 : {
817 0 : poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
818 0 : return nullptr;
819 : }
820 : int nSrcBlockXSize, nSrcBlockYSize;
821 103091 : poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
822 103091 : poSelf->AddSrcBandDescription(poSrcBand->GetRasterDataType(),
823 : nSrcBlockXSize, nSrcBlockYSize);
824 : }
825 3235 : poSelf->UnrefUnderlyingDataset(poUnderlyingDS);
826 3235 : return poSelf.release();
827 : }
828 :
829 : /************************************************************************/
830 : /* ~GDALProxyPoolDataset() */
831 : /************************************************************************/
832 :
833 9374 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
834 : {
835 4692 : GDALDatasetPool::CloseDatasetIfZeroRefCount(
836 4692 : 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 4692 : bShared = false;
845 :
846 4692 : CPLFree(pszProjectionRef);
847 4692 : CPLFree(pszGCPProjection);
848 4692 : if (nGCPCount)
849 : {
850 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
851 0 : CPLFree(pasGCPList);
852 : }
853 4692 : if (metadataSet)
854 4 : CPLHashSetDestroy(metadataSet);
855 4692 : if (metadataItemSet)
856 2 : CPLHashSetDestroy(metadataItemSet);
857 4692 : CPLFree(m_pszOwner);
858 4692 : if (m_poSRS)
859 2121 : m_poSRS->Release();
860 4692 : if (m_poGCPSRS)
861 0 : m_poGCPSRS->Release();
862 :
863 4692 : GDALDatasetPool::Unref();
864 9374 : }
865 :
866 : /************************************************************************/
867 : /* SetOpenOptions() */
868 : /************************************************************************/
869 :
870 4642 : void GDALProxyPoolDataset::SetOpenOptions(CSLConstList papszOpenOptionsIn)
871 : {
872 4642 : CPLAssert(papszOpenOptions == nullptr);
873 4642 : papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
874 4639 : }
875 :
876 : /************************************************************************/
877 : /* AddSrcBandDescription() */
878 : /************************************************************************/
879 :
880 105454 : void GDALProxyPoolDataset::AddSrcBandDescription(GDALDataType eDataType,
881 : int nBlockXSize,
882 : int nBlockYSize)
883 : {
884 105454 : SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType,
885 105454 : nBlockXSize, nBlockYSize));
886 105454 : }
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 4692 : GDALDataset *GDALProxyPoolDataset::RefUnderlyingDataset() const
904 : {
905 4692 : return RefUnderlyingDataset(true);
906 : }
907 :
908 232015 : 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 232015 : GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
924 232015 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
925 232019 : cacheEntry =
926 232014 : GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions,
927 232016 : GetShared(), bForceOpen, m_pszOwner);
928 232019 : GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
929 232019 : if (cacheEntry != nullptr)
930 : {
931 229856 : if (cacheEntry->poDS != nullptr)
932 229681 : return cacheEntry->poDS;
933 : else
934 175 : GDALDatasetPool::UnrefDataset(cacheEntry);
935 : }
936 2338 : return nullptr;
937 : }
938 :
939 : /************************************************************************/
940 : /* UnrefUnderlyingDataset() */
941 : /************************************************************************/
942 :
943 229681 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(
944 : CPL_UNUSED GDALDataset *poUnderlyingDataset) const
945 : {
946 229681 : if (cacheEntry != nullptr)
947 : {
948 229681 : CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
949 229681 : if (cacheEntry->poDS != nullptr)
950 229681 : GDALDatasetPool::UnrefDataset(cacheEntry);
951 : }
952 229681 : }
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 204 : const OGRSpatialReference *GDALProxyPoolDataset::GetSpatialRef() const
985 : {
986 204 : if (m_bHasSrcSRS)
987 202 : return m_poSRS;
988 : else
989 : {
990 2 : if (m_poSRS)
991 0 : m_poSRS->Release();
992 2 : m_poSRS = nullptr;
993 2 : auto poSRS = GDALProxyDataset::GetSpatialRef();
994 2 : if (poSRS)
995 0 : m_poSRS = poSRS->Clone();
996 2 : 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 573 : CPLErr GDALProxyPoolDataset::GetGeoTransform(GDALGeoTransform >) const
1016 : {
1017 573 : if (m_bHasSrcGeoTransform)
1018 : {
1019 573 : gt = m_gt;
1020 573 : return CE_None;
1021 : }
1022 : else
1023 : {
1024 0 : return GDALProxyDataset::GetGeoTransform(gt);
1025 : }
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* GetMetadata() */
1030 : /************************************************************************/
1031 :
1032 22 : char **GDALProxyPoolDataset::GetMetadata(const char *pszDomain)
1033 : {
1034 22 : if (metadataSet == nullptr)
1035 4 : metadataSet =
1036 4 : CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
1037 : free_func_get_metadata);
1038 :
1039 22 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1040 22 : if (poUnderlyingDataset == nullptr)
1041 0 : return nullptr;
1042 :
1043 : char **papszUnderlyingMetadata =
1044 22 : poUnderlyingDataset->GetMetadata(pszDomain);
1045 :
1046 : GetMetadataElt *pElt =
1047 22 : static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
1048 22 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1049 22 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
1050 22 : CPLHashSetInsert(metadataSet, pElt);
1051 :
1052 22 : UnrefUnderlyingDataset(poUnderlyingDataset);
1053 :
1054 22 : 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 0 : const OGRSpatialReference *GDALProxyPoolDataset::GetGCPSpatialRef() const
1108 : {
1109 0 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1110 0 : if (poUnderlyingDataset == nullptr)
1111 0 : return nullptr;
1112 :
1113 0 : m_poGCPSRS->Release();
1114 0 : m_poGCPSRS = nullptr;
1115 :
1116 0 : const auto poUnderlyingGCPSRS = poUnderlyingDataset->GetGCPSpatialRef();
1117 0 : if (poUnderlyingGCPSRS)
1118 0 : m_poGCPSRS = poUnderlyingGCPSRS->Clone();
1119 :
1120 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
1121 :
1122 0 : return m_poGCPSRS;
1123 : }
1124 :
1125 : /************************************************************************/
1126 : /* GetGCPs() */
1127 : /************************************************************************/
1128 :
1129 0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
1130 : {
1131 0 : GDALDataset *poUnderlyingDataset = RefUnderlyingDataset();
1132 0 : if (poUnderlyingDataset == nullptr)
1133 0 : return nullptr;
1134 :
1135 0 : if (nGCPCount)
1136 : {
1137 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
1138 0 : CPLFree(pasGCPList);
1139 0 : pasGCPList = nullptr;
1140 : }
1141 :
1142 0 : const GDAL_GCP *pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
1143 0 : nGCPCount = poUnderlyingDataset->GetGCPCount();
1144 0 : if (nGCPCount)
1145 0 : pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList);
1146 :
1147 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
1148 :
1149 0 : return pasGCPList;
1150 : }
1151 :
1152 : /************************************************************************/
1153 : /* GDALProxyPoolDatasetCreate() */
1154 : /************************************************************************/
1155 :
1156 1233 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(
1157 : const char *pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize,
1158 : GDALAccess eAccess, int bShared, const char *pszProjectionRef,
1159 : const double *padfGeoTransform)
1160 : {
1161 : return reinterpret_cast<GDALProxyPoolDatasetH>(new GDALProxyPoolDataset(
1162 : pszSourceDatasetDescription, nRasterXSize, nRasterYSize, eAccess,
1163 : bShared, pszProjectionRef,
1164 1233 : reinterpret_cast<const GDALGeoTransform *>(padfGeoTransform)));
1165 : }
1166 :
1167 : /************************************************************************/
1168 : /* GDALProxyPoolDatasetDelete() */
1169 : /************************************************************************/
1170 :
1171 0 : void GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
1172 : {
1173 0 : delete reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset);
1174 0 : }
1175 :
1176 : /************************************************************************/
1177 : /* GDALProxyPoolDatasetAddSrcBandDescription() */
1178 : /************************************************************************/
1179 :
1180 2324 : void GDALProxyPoolDatasetAddSrcBandDescription(
1181 : GDALProxyPoolDatasetH hProxyPoolDataset, GDALDataType eDataType,
1182 : int nBlockXSize, int nBlockYSize)
1183 : {
1184 : reinterpret_cast<GDALProxyPoolDataset *>(hProxyPoolDataset)
1185 2324 : ->AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
1186 2324 : }
1187 :
1188 : /* ******************************************************************** */
1189 : /* GDALProxyPoolRasterBand() */
1190 : /* ******************************************************************** */
1191 :
1192 105476 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset *poDSIn,
1193 : int nBandIn,
1194 : GDALDataType eDataTypeIn,
1195 : int nBlockXSizeIn,
1196 105476 : int nBlockYSizeIn)
1197 : {
1198 105476 : poDS = poDSIn;
1199 105476 : nBand = nBandIn;
1200 105476 : eDataType = eDataTypeIn;
1201 105476 : nRasterXSize = poDSIn->GetRasterXSize();
1202 105476 : nRasterYSize = poDSIn->GetRasterYSize();
1203 105476 : nBlockXSize = nBlockXSizeIn;
1204 105476 : nBlockYSize = nBlockYSizeIn;
1205 105476 : }
1206 :
1207 : /* ******************************************************************** */
1208 : /* GDALProxyPoolRasterBand() */
1209 : /* ******************************************************************** */
1210 :
1211 62 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(
1212 62 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingRasterBand)
1213 : {
1214 62 : poDS = poDSIn;
1215 62 : nBand = poUnderlyingRasterBand->GetBand();
1216 62 : eDataType = poUnderlyingRasterBand->GetRasterDataType();
1217 62 : nRasterXSize = poUnderlyingRasterBand->GetXSize();
1218 62 : nRasterYSize = poUnderlyingRasterBand->GetYSize();
1219 62 : poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1220 62 : }
1221 :
1222 : /* ******************************************************************** */
1223 : /* ~GDALProxyPoolRasterBand() */
1224 : /* ******************************************************************** */
1225 210992 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
1226 : {
1227 105538 : if (metadataSet)
1228 2 : CPLHashSetDestroy(metadataSet);
1229 105538 : if (metadataItemSet)
1230 20 : CPLHashSetDestroy(metadataItemSet);
1231 105538 : CPLFree(pszUnitType);
1232 105538 : CSLDestroy(papszCategoryNames);
1233 105538 : if (poColorTable)
1234 6 : delete poColorTable;
1235 :
1236 105562 : for (int i = 0; i < nSizeProxyOverviewRasterBand; i++)
1237 : {
1238 24 : if (papoProxyOverviewRasterBand[i])
1239 24 : delete papoProxyOverviewRasterBand[i];
1240 : }
1241 105538 : CPLFree(papoProxyOverviewRasterBand);
1242 105538 : if (poProxyMaskBand)
1243 60 : delete poProxyMaskBand;
1244 210992 : }
1245 :
1246 : /************************************************************************/
1247 : /* AddSrcMaskBandDescriptionFromUnderlying() */
1248 : /************************************************************************/
1249 :
1250 15 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescriptionFromUnderlying()
1251 : {
1252 15 : if (poProxyMaskBand != nullptr)
1253 6 : return;
1254 9 : GDALRasterBand *poUnderlyingBand = RefUnderlyingRasterBand();
1255 9 : if (poUnderlyingBand == nullptr)
1256 0 : return;
1257 9 : auto poSrcMaskBand = poUnderlyingBand->GetMaskBand();
1258 : int nSrcBlockXSize, nSrcBlockYSize;
1259 9 : poSrcMaskBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
1260 9 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1261 9 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), this,
1262 9 : poSrcMaskBand->GetRasterDataType(), nSrcBlockXSize, nSrcBlockYSize);
1263 9 : UnrefUnderlyingRasterBand(poUnderlyingBand);
1264 : }
1265 :
1266 : /************************************************************************/
1267 : /* AddSrcMaskBandDescription() */
1268 : /************************************************************************/
1269 :
1270 13 : void GDALProxyPoolRasterBand::AddSrcMaskBandDescription(
1271 : GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
1272 : {
1273 13 : CPLAssert(poProxyMaskBand == nullptr);
1274 13 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1275 13 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), this, eDataTypeIn,
1276 13 : nBlockXSizeIn, nBlockYSizeIn);
1277 13 : }
1278 :
1279 : /************************************************************************/
1280 : /* RefUnderlyingRasterBand() */
1281 : /************************************************************************/
1282 :
1283 : GDALRasterBand *
1284 227324 : GDALProxyPoolRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
1285 : {
1286 : GDALDataset *poUnderlyingDataset =
1287 227324 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1288 227324 : ->RefUnderlyingDataset(bForceOpen);
1289 227325 : if (poUnderlyingDataset == nullptr)
1290 2163 : return nullptr;
1291 :
1292 225162 : GDALRasterBand *poBand = poUnderlyingDataset->GetRasterBand(nBand);
1293 225162 : if (poBand == nullptr)
1294 : {
1295 0 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1296 0 : ->UnrefUnderlyingDataset(poUnderlyingDataset);
1297 : }
1298 225162 : else if (nBlockXSize <= 0 || nBlockYSize <= 0)
1299 : {
1300 : // Here we try to load nBlockXSize&nBlockYSize from underlying band
1301 : // but we must guarantee that we will not access directly to
1302 : // nBlockXSize/nBlockYSize before RefUnderlyingRasterBand() is called
1303 : int nSrcBlockXSize, nSrcBlockYSize;
1304 11 : poBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
1305 10 : const_cast<GDALProxyPoolRasterBand *>(this)->nBlockXSize =
1306 : nSrcBlockXSize;
1307 10 : const_cast<GDALProxyPoolRasterBand *>(this)->nBlockYSize =
1308 : nSrcBlockYSize;
1309 : }
1310 :
1311 225162 : return poBand;
1312 : }
1313 :
1314 : /************************************************************************/
1315 : /* UnrefUnderlyingRasterBand() */
1316 : /************************************************************************/
1317 :
1318 225162 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(
1319 : GDALRasterBand *poUnderlyingRasterBand) const
1320 : {
1321 225162 : if (poUnderlyingRasterBand)
1322 225162 : (cpl::down_cast<GDALProxyPoolDataset *>(poDS))
1323 225162 : ->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
1324 225162 : }
1325 :
1326 : /************************************************************************/
1327 : /* FlushCache() */
1328 : /************************************************************************/
1329 :
1330 104454 : CPLErr GDALProxyPoolRasterBand::FlushCache(bool bAtClosing)
1331 : {
1332 104454 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand(false);
1333 104454 : if (poUnderlyingRasterBand)
1334 : {
1335 102291 : CPLErr eErr = poUnderlyingRasterBand->FlushCache(bAtClosing);
1336 102291 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1337 102291 : return eErr;
1338 : }
1339 2163 : return CE_None;
1340 : }
1341 :
1342 : /************************************************************************/
1343 : /* GetMetadata() */
1344 : /************************************************************************/
1345 :
1346 2 : char **GDALProxyPoolRasterBand::GetMetadata(const char *pszDomain)
1347 : {
1348 2 : if (metadataSet == nullptr)
1349 2 : metadataSet =
1350 2 : CPLHashSetNew(hash_func_get_metadata, equal_func_get_metadata,
1351 : free_func_get_metadata);
1352 :
1353 2 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1354 2 : if (poUnderlyingRasterBand == nullptr)
1355 0 : return nullptr;
1356 :
1357 : char **papszUnderlyingMetadata =
1358 2 : poUnderlyingRasterBand->GetMetadata(pszDomain);
1359 :
1360 : GetMetadataElt *pElt =
1361 2 : static_cast<GetMetadataElt *>(CPLMalloc(sizeof(GetMetadataElt)));
1362 2 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1363 2 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
1364 2 : CPLHashSetInsert(metadataSet, pElt);
1365 :
1366 2 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1367 :
1368 2 : return pElt->papszMetadata;
1369 : }
1370 :
1371 : /************************************************************************/
1372 : /* GetMetadataItem() */
1373 : /************************************************************************/
1374 :
1375 40 : const char *GDALProxyPoolRasterBand::GetMetadataItem(const char *pszName,
1376 : const char *pszDomain)
1377 : {
1378 40 : if (metadataItemSet == nullptr)
1379 20 : metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
1380 : equal_func_get_metadata_item,
1381 : free_func_get_metadata_item);
1382 :
1383 40 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1384 40 : if (poUnderlyingRasterBand == nullptr)
1385 0 : return nullptr;
1386 :
1387 : const char *pszUnderlyingMetadataItem =
1388 40 : poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
1389 :
1390 : GetMetadataItemElt *pElt = static_cast<GetMetadataItemElt *>(
1391 40 : CPLMalloc(sizeof(GetMetadataItemElt)));
1392 40 : pElt->pszName = (pszName) ? CPLStrdup(pszName) : nullptr;
1393 40 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : nullptr;
1394 40 : pElt->pszMetadataItem = (pszUnderlyingMetadataItem)
1395 40 : ? CPLStrdup(pszUnderlyingMetadataItem)
1396 : : nullptr;
1397 40 : CPLHashSetInsert(metadataItemSet, pElt);
1398 :
1399 40 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1400 :
1401 40 : return pElt->pszMetadataItem;
1402 : }
1403 :
1404 : /* ******************************************************************** */
1405 : /* GetCategoryNames() */
1406 : /* ******************************************************************** */
1407 :
1408 2 : char **GDALProxyPoolRasterBand::GetCategoryNames()
1409 : {
1410 2 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1411 2 : if (poUnderlyingRasterBand == nullptr)
1412 0 : return nullptr;
1413 :
1414 2 : CSLDestroy(papszCategoryNames);
1415 2 : papszCategoryNames = nullptr;
1416 :
1417 : char **papszUnderlyingCategoryNames =
1418 2 : poUnderlyingRasterBand->GetCategoryNames();
1419 2 : if (papszUnderlyingCategoryNames)
1420 0 : papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
1421 :
1422 2 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1423 :
1424 2 : return papszCategoryNames;
1425 : }
1426 :
1427 : /* ******************************************************************** */
1428 : /* GetUnitType() */
1429 : /* ******************************************************************** */
1430 :
1431 2 : const char *GDALProxyPoolRasterBand::GetUnitType()
1432 : {
1433 2 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1434 2 : if (poUnderlyingRasterBand == nullptr)
1435 0 : return nullptr;
1436 :
1437 2 : CPLFree(pszUnitType);
1438 2 : pszUnitType = nullptr;
1439 :
1440 2 : const char *pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
1441 2 : if (pszUnderlyingUnitType)
1442 2 : pszUnitType = CPLStrdup(pszUnderlyingUnitType);
1443 :
1444 2 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1445 :
1446 2 : return pszUnitType;
1447 : }
1448 :
1449 : /* ******************************************************************** */
1450 : /* GetColorTable() */
1451 : /* ******************************************************************** */
1452 :
1453 436 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
1454 : {
1455 436 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1456 436 : if (poUnderlyingRasterBand == nullptr)
1457 0 : return nullptr;
1458 :
1459 436 : if (poColorTable)
1460 31 : delete poColorTable;
1461 436 : poColorTable = nullptr;
1462 :
1463 : GDALColorTable *poUnderlyingColorTable =
1464 436 : poUnderlyingRasterBand->GetColorTable();
1465 436 : if (poUnderlyingColorTable)
1466 37 : poColorTable = poUnderlyingColorTable->Clone();
1467 :
1468 436 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1469 :
1470 436 : return poColorTable;
1471 : }
1472 :
1473 : /* ******************************************************************** */
1474 : /* GetOverview() */
1475 : /* ******************************************************************** */
1476 :
1477 36 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
1478 : {
1479 36 : if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
1480 : {
1481 12 : if (papoProxyOverviewRasterBand[nOverviewBand])
1482 12 : return papoProxyOverviewRasterBand[nOverviewBand];
1483 : }
1484 :
1485 24 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1486 24 : if (poUnderlyingRasterBand == nullptr)
1487 0 : return nullptr;
1488 :
1489 : GDALRasterBand *poOverviewRasterBand =
1490 24 : poUnderlyingRasterBand->GetOverview(nOverviewBand);
1491 24 : if (poOverviewRasterBand == nullptr)
1492 : {
1493 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1494 0 : return nullptr;
1495 : }
1496 :
1497 24 : if (nOverviewBand >= nSizeProxyOverviewRasterBand)
1498 : {
1499 24 : papoProxyOverviewRasterBand =
1500 : static_cast<GDALProxyPoolOverviewRasterBand **>(
1501 48 : CPLRealloc(papoProxyOverviewRasterBand,
1502 : sizeof(GDALProxyPoolOverviewRasterBand *) *
1503 24 : (nOverviewBand + 1)));
1504 48 : for (int i = nSizeProxyOverviewRasterBand; i < nOverviewBand + 1; i++)
1505 24 : papoProxyOverviewRasterBand[i] = nullptr;
1506 24 : nSizeProxyOverviewRasterBand = nOverviewBand + 1;
1507 : }
1508 :
1509 24 : papoProxyOverviewRasterBand[nOverviewBand] =
1510 : new GDALProxyPoolOverviewRasterBand(
1511 24 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), poOverviewRasterBand,
1512 24 : this, nOverviewBand);
1513 :
1514 24 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1515 :
1516 24 : return papoProxyOverviewRasterBand[nOverviewBand];
1517 : }
1518 :
1519 : /* ******************************************************************** */
1520 : /* GetRasterSampleOverview() */
1521 : /* ******************************************************************** */
1522 :
1523 : GDALRasterBand *
1524 0 : GDALProxyPoolRasterBand::GetRasterSampleOverview(GUIntBig /* nDesiredSamples */)
1525 : {
1526 0 : CPLError(CE_Failure, CPLE_AppDefined,
1527 : "GDALProxyPoolRasterBand::GetRasterSampleOverview : not "
1528 : "implemented yet");
1529 0 : return nullptr;
1530 : }
1531 :
1532 : /* ******************************************************************** */
1533 : /* GetMaskBand() */
1534 : /* ******************************************************************** */
1535 :
1536 88 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
1537 : {
1538 88 : if (poProxyMaskBand)
1539 50 : return poProxyMaskBand;
1540 :
1541 38 : GDALRasterBand *poUnderlyingRasterBand = RefUnderlyingRasterBand();
1542 38 : if (poUnderlyingRasterBand == nullptr)
1543 0 : return nullptr;
1544 :
1545 38 : GDALRasterBand *poMaskBand = poUnderlyingRasterBand->GetMaskBand();
1546 :
1547 38 : poProxyMaskBand = new GDALProxyPoolMaskBand(
1548 38 : cpl::down_cast<GDALProxyPoolDataset *>(poDS), poMaskBand, this);
1549 :
1550 38 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1551 :
1552 38 : return poProxyMaskBand;
1553 : }
1554 :
1555 : /* ******************************************************************** */
1556 : /* GDALProxyPoolOverviewRasterBand() */
1557 : /* ******************************************************************** */
1558 :
1559 24 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(
1560 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingOverviewBand,
1561 24 : GDALProxyPoolRasterBand *poMainBandIn, int nOverviewBandIn)
1562 : : GDALProxyPoolRasterBand(poDSIn, poUnderlyingOverviewBand),
1563 24 : poMainBand(poMainBandIn), nOverviewBand(nOverviewBandIn)
1564 : {
1565 24 : }
1566 :
1567 : /* ******************************************************************** */
1568 : /* ~GDALProxyPoolOverviewRasterBand() */
1569 : /* ******************************************************************** */
1570 :
1571 48 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
1572 : {
1573 24 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1574 48 : }
1575 :
1576 : /* ******************************************************************** */
1577 : /* RefUnderlyingRasterBand() */
1578 : /* ******************************************************************** */
1579 :
1580 : GDALRasterBand *
1581 0 : GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand(bool bForceOpen) const
1582 : {
1583 0 : poUnderlyingMainRasterBand =
1584 0 : poMainBand->RefUnderlyingRasterBand(bForceOpen);
1585 0 : if (poUnderlyingMainRasterBand == nullptr)
1586 0 : return nullptr;
1587 :
1588 0 : nRefCountUnderlyingMainRasterBand++;
1589 0 : return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
1590 : }
1591 :
1592 : /* ******************************************************************** */
1593 : /* UnrefUnderlyingRasterBand() */
1594 : /* ******************************************************************** */
1595 :
1596 0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(
1597 : GDALRasterBand * /* poUnderlyingRasterBand */) const
1598 : {
1599 0 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1600 0 : nRefCountUnderlyingMainRasterBand--;
1601 0 : }
1602 :
1603 : /* ******************************************************************** */
1604 : /* GDALProxyPoolMaskBand() */
1605 : /* ******************************************************************** */
1606 :
1607 38 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
1608 : GDALProxyPoolDataset *poDSIn, GDALRasterBand *poUnderlyingMaskBand,
1609 38 : GDALProxyPoolRasterBand *poMainBandIn)
1610 38 : : GDALProxyPoolRasterBand(poDSIn, poUnderlyingMaskBand)
1611 : {
1612 38 : poMainBand = poMainBandIn;
1613 :
1614 38 : poUnderlyingMainRasterBand = nullptr;
1615 38 : nRefCountUnderlyingMainRasterBand = 0;
1616 38 : }
1617 :
1618 : /* ******************************************************************** */
1619 : /* GDALProxyPoolMaskBand() */
1620 : /* ******************************************************************** */
1621 :
1622 22 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(
1623 : GDALProxyPoolDataset *poDSIn, GDALProxyPoolRasterBand *poMainBandIn,
1624 22 : GDALDataType eDataTypeIn, int nBlockXSizeIn, int nBlockYSizeIn)
1625 : : GDALProxyPoolRasterBand(poDSIn, 1, eDataTypeIn, nBlockXSizeIn,
1626 : nBlockYSizeIn),
1627 22 : poMainBand(poMainBandIn)
1628 : {
1629 22 : }
1630 :
1631 : /* ******************************************************************** */
1632 : /* ~GDALProxyPoolMaskBand() */
1633 : /* ******************************************************************** */
1634 :
1635 120 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
1636 : {
1637 60 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1638 120 : }
1639 :
1640 : /* ******************************************************************** */
1641 : /* RefUnderlyingRasterBand() */
1642 : /* ******************************************************************** */
1643 :
1644 : GDALRasterBand *
1645 245 : GDALProxyPoolMaskBand::RefUnderlyingRasterBand(bool bForceOpen) const
1646 : {
1647 245 : poUnderlyingMainRasterBand =
1648 245 : poMainBand->RefUnderlyingRasterBand(bForceOpen);
1649 245 : if (poUnderlyingMainRasterBand == nullptr)
1650 0 : return nullptr;
1651 :
1652 245 : nRefCountUnderlyingMainRasterBand++;
1653 245 : return poUnderlyingMainRasterBand->GetMaskBand();
1654 : }
1655 :
1656 : /* ******************************************************************** */
1657 : /* UnrefUnderlyingRasterBand() */
1658 : /* ******************************************************************** */
1659 :
1660 245 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(
1661 : GDALRasterBand * /* poUnderlyingRasterBand */) const
1662 : {
1663 245 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1664 245 : nRefCountUnderlyingMainRasterBand--;
1665 245 : }
1666 :
1667 : //! @endcond
|