Coverage Report

Created: 2026-05-16 08:20

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