• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.02
/gcore/gdalarraybandblockcache.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Store cached blocks in a array or a two-level array
5
 * Author:   Even Rouault, <even dot rouault at spatialys dot org>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, Frank Warmerdam
9
 * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot org>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_port.h"
15
#include "gdal_priv.h"
16

17
#include <cassert>
18
#include <climits>
19
#include <cstddef>
20
#include <new>
21

22
#include "cpl_conv.h"
23
#include "cpl_error.h"
24
#include "cpl_multiproc.h"
25
#include "cpl_vsi.h"
26

27
//! @cond Doxygen_Suppress
28

29
constexpr int SUBBLOCK_SIZE = 64;
30
#define TO_SUBBLOCK(x) ((x) >> 6)
31
#define WITHIN_SUBBLOCK(x) ((x)&0x3f)
32

33
/* ******************************************************************** */
34
/*                        GDALArrayBandBlockCache                       */
35
/* ******************************************************************** */
36

37
class GDALArrayBandBlockCache final : public GDALAbstractBandBlockCache
38
{
39
    bool bSubBlockingActive = false;
40
    int nSubBlocksPerRow = 0;
41
    int nSubBlocksPerColumn = 0;
42

43
    union u
44
    {
45
        GDALRasterBlock **papoBlocks;
46
        GDALRasterBlock ***papapoBlocks;
47

48
        u() : papoBlocks(nullptr)
236,020✔
49
        {
50
        }
236,020✔
51
    } u{};
52

53
    CPL_DISALLOW_COPY_ASSIGN(GDALArrayBandBlockCache)
54

55
  public:
56
    explicit GDALArrayBandBlockCache(GDALRasterBand *poBand);
57
    ~GDALArrayBandBlockCache() override;
58

59
    bool Init() override;
60
    bool IsInitOK() override;
61
    CPLErr FlushCache() override;
62
    CPLErr AdoptBlock(GDALRasterBlock *) override;
63
    GDALRasterBlock *TryGetLockedBlockRef(int nXBlockOff,
64
                                          int nYBlockYOff) override;
65
    CPLErr UnreferenceBlock(GDALRasterBlock *poBlock) override;
66
    CPLErr FlushBlock(int nXBlockOff, int nYBlockOff,
67
                      int bWriteDirtyBlock) override;
68
};
69

70
/************************************************************************/
71
/*                     GDALArrayBandBlockCacheCreate()                 */
72
/************************************************************************/
73

74
GDALAbstractBandBlockCache *
75
GDALArrayBandBlockCacheCreate(GDALRasterBand *poBand)
236,020✔
76
{
77
    return new (std::nothrow) GDALArrayBandBlockCache(poBand);
236,020✔
78
}
79

80
/************************************************************************/
81
/*                       GDALArrayBandBlockCache()                      */
82
/************************************************************************/
83

84
GDALArrayBandBlockCache::GDALArrayBandBlockCache(GDALRasterBand *poBandIn)
236,020✔
85
    : GDALAbstractBandBlockCache(poBandIn)
236,020✔
86
{
87
}
236,020✔
88

89
/************************************************************************/
90
/*                      ~GDALArrayBandBlockCache()                     */
91
/************************************************************************/
92

93
GDALArrayBandBlockCache::~GDALArrayBandBlockCache()
472,040✔
94
{
95
    GDALArrayBandBlockCache::FlushCache();
236,020✔
96

97
    if (!bSubBlockingActive)
236,020✔
98
        CPLFree(u.papoBlocks);
235,901✔
99
    else
100
        CPLFree(u.papapoBlocks);
119✔
101
}
472,040✔
102

103
/************************************************************************/
104
/*                                  Init()                              */
105
/************************************************************************/
106

107
bool GDALArrayBandBlockCache::Init()
236,020✔
108
{
109
    if (poBand->nBlocksPerRow < SUBBLOCK_SIZE / 2)
236,020✔
110
    {
111
        bSubBlockingActive = false;
235,901✔
112

113
        if (poBand->nBlocksPerRow < INT_MAX / poBand->nBlocksPerColumn)
235,901✔
114
        {
115
            u.papoBlocks = static_cast<GDALRasterBlock **>(VSICalloc(
235,900✔
116
                sizeof(void *), cpl::fits_on<int>(poBand->nBlocksPerRow *
235,901✔
117
                                                  poBand->nBlocksPerColumn)));
235,901✔
118
            if (u.papoBlocks == nullptr)
235,899✔
119
            {
120
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
121
                                    "Out of memory in InitBlockInfo().");
122
                return false;
×
123
            }
124
        }
125
        else
126
        {
UNCOV
127
            poBand->ReportError(
×
128
                CE_Failure, CPLE_NotSupported, "Too many blocks : %d x %d",
UNCOV
129
                poBand->nBlocksPerRow, poBand->nBlocksPerColumn);
×
130
            return false;
×
131
        }
132
    }
133
    else
134
    {
135
        bSubBlockingActive = true;
119✔
136

137
        nSubBlocksPerRow = DIV_ROUND_UP(poBand->nBlocksPerRow, SUBBLOCK_SIZE);
119✔
138
        nSubBlocksPerColumn =
119✔
139
            DIV_ROUND_UP(poBand->nBlocksPerColumn, SUBBLOCK_SIZE);
119✔
140

141
        if (nSubBlocksPerRow < INT_MAX / nSubBlocksPerColumn)
119✔
142
        {
143
            u.papapoBlocks = static_cast<GDALRasterBlock ***>(VSICalloc(
119✔
144
                sizeof(void *),
145
                cpl::fits_on<int>(nSubBlocksPerRow * nSubBlocksPerColumn)));
119✔
146
            if (u.papapoBlocks == nullptr)
121✔
147
            {
148
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
149
                                    "Out of memory in InitBlockInfo().");
150
                return false;
×
151
            }
152
        }
153
        else
154
        {
155
            poBand->ReportError(CE_Failure, CPLE_NotSupported,
×
156
                                "Too many subblocks : %d x %d",
157
                                nSubBlocksPerRow, nSubBlocksPerColumn);
158
            return false;
×
159
        }
160
    }
161

162
    return true;
236,020✔
163
}
164

165
/************************************************************************/
166
/*                             IsInitOK()                               */
167
/************************************************************************/
168

169
bool GDALArrayBandBlockCache::IsInitOK()
9,698,300✔
170
{
171
    return (!bSubBlockingActive) ? u.papoBlocks != nullptr
9,698,300✔
172
                                 : u.papapoBlocks != nullptr;
9,698,300✔
173
}
174

175
/************************************************************************/
176
/*                            AdoptBlock()                              */
177
/************************************************************************/
178

179
CPLErr GDALArrayBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
1,345,310✔
180

181
{
182
    const int nXBlockOff = poBlock->GetXOff();
1,345,310✔
183
    const int nYBlockOff = poBlock->GetYOff();
1,345,310✔
184

185
    FreeDanglingBlocks();
1,345,310✔
186

187
    /* -------------------------------------------------------------------- */
188
    /*      Simple case without subblocking.                                */
189
    /* -------------------------------------------------------------------- */
190

191
    if (!bSubBlockingActive)
1,345,310✔
192
    {
193
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
1,287,840✔
194

195
        CPLAssert(u.papoBlocks[nBlockIndex] == nullptr);
1,287,840✔
196
        u.papoBlocks[nBlockIndex] = poBlock;
1,287,840✔
197
    }
198
    else
199
    {
200
        /* --------------------------------------------------------------------
201
         */
202
        /*      Identify the subblock in which our target occurs, and create */
203
        /*      it if necessary. */
204
        /* --------------------------------------------------------------------
205
         */
206
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
57,467✔
207
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
57,467✔
208

209
        if (u.papapoBlocks[nSubBlock] == nullptr)
57,467✔
210
        {
211
            const int nSubGridSize =
161✔
212
                sizeof(GDALRasterBlock *) * SUBBLOCK_SIZE * SUBBLOCK_SIZE;
213

214
            u.papapoBlocks[nSubBlock] =
322✔
215
                static_cast<GDALRasterBlock **>(VSICalloc(1, nSubGridSize));
161✔
216
            if (u.papapoBlocks[nSubBlock] == nullptr)
161✔
217
            {
218
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
219
                                    "Out of memory in AdoptBlock().");
220
                return CE_Failure;
×
221
            }
222
        }
223

224
        /* --------------------------------------------------------------------
225
         */
226
        /*      Check within subblock. */
227
        /* --------------------------------------------------------------------
228
         */
229
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
57,467✔
230

231
        const int nBlockInSubBlock =
57,467✔
232
            WITHIN_SUBBLOCK(nXBlockOff) +
57,467✔
233
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
57,467✔
234

235
        CPLAssert(papoSubBlockGrid[nBlockInSubBlock] == nullptr);
57,467✔
236
        papoSubBlockGrid[nBlockInSubBlock] = poBlock;
57,467✔
237
    }
238

239
    return CE_None;
1,345,310✔
240
}
241

242
/************************************************************************/
243
/*                            FlushCache()                              */
244
/************************************************************************/
245

246
CPLErr GDALArrayBandBlockCache::FlushCache()
992,153✔
247
{
248
    FreeDanglingBlocks();
992,153✔
249

250
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
992,153✔
251

252
    StartDirtyBlockFlushingLog();
992,153✔
253

254
    /* -------------------------------------------------------------------- */
255
    /*      Flush all blocks in memory ... this case is without subblocking.*/
256
    /* -------------------------------------------------------------------- */
257
    if (!bSubBlockingActive && u.papoBlocks != nullptr)
992,152✔
258
    {
259
        const int nBlocksPerColumn = poBand->nBlocksPerColumn;
991,744✔
260
        const int nBlocksPerRow = poBand->nBlocksPerRow;
991,744✔
261
        for (int iY = 0; iY < nBlocksPerColumn; iY++)
90,040,700✔
262
        {
263
            for (int iX = 0; iX < nBlocksPerRow; iX++)
178,434,000✔
264
            {
265
                if (u.papoBlocks[iX + iY * nBlocksPerRow] != nullptr)
89,384,700✔
266
                {
267
                    CPLErr eErr = FlushBlock(iX, iY, eGlobalErr == CE_None);
1,258,340✔
268

269
                    if (eErr != CE_None)
1,258,340✔
270
                        eGlobalErr = eErr;
5✔
271
                }
272
            }
273
        }
991,744✔
274
    }
275

276
    /* -------------------------------------------------------------------- */
277
    /*      With subblocking.  We can short circuit missing subblocks.      */
278
    /* -------------------------------------------------------------------- */
279
    else if (u.papapoBlocks != nullptr)
408✔
280
    {
281
        for (int iSBY = 0; iSBY < nSubBlocksPerColumn; iSBY++)
876✔
282
        {
283
            for (int iSBX = 0; iSBX < nSubBlocksPerRow; iSBX++)
1,483✔
284
            {
285
                const int nSubBlock = iSBX + iSBY * nSubBlocksPerRow;
1,015✔
286

287
                GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
1,015✔
288

289
                if (papoSubBlockGrid == nullptr)
1,015✔
290
                    continue;
854✔
291

292
                for (int iY = 0; iY < SUBBLOCK_SIZE; iY++)
10,465✔
293
                {
294
                    for (int iX = 0; iX < SUBBLOCK_SIZE; iX++)
669,760✔
295
                    {
296
                        if (papoSubBlockGrid[iX + iY * SUBBLOCK_SIZE] !=
659,456✔
297
                            nullptr)
298
                        {
299
                            CPLErr eErr = FlushBlock(iX + iSBX * SUBBLOCK_SIZE,
111,474✔
300
                                                     iY + iSBY * SUBBLOCK_SIZE,
55,737✔
301
                                                     eGlobalErr == CE_None);
302
                            if (eErr != CE_None)
55,737✔
303
                                eGlobalErr = eErr;
2✔
304
                        }
305
                    }
306
                }
307

308
                // We might as well get rid of this grid chunk since we know
309
                // it is now empty.
310
                u.papapoBlocks[nSubBlock] = nullptr;
161✔
311
                CPLFree(papoSubBlockGrid);
161✔
312
            }
313
        }
314
    }
315

316
    EndDirtyBlockFlushingLog();
992,152✔
317

318
    WaitCompletionPendingTasks();
992,152✔
319

320
    return (eGlobalErr);
992,153✔
321
}
322

323
/************************************************************************/
324
/*                        UnreferenceBlock()                            */
325
/************************************************************************/
326

327
CPLErr GDALArrayBandBlockCache::UnreferenceBlock(GDALRasterBlock *poBlock)
29,647✔
328
{
329
    const int nXBlockOff = poBlock->GetXOff();
29,647✔
330
    const int nYBlockOff = poBlock->GetYOff();
29,647✔
331

332
    UnreferenceBlockBase();
29,647✔
333

334
    /* -------------------------------------------------------------------- */
335
    /*      Simple case for single level caches.                            */
336
    /* -------------------------------------------------------------------- */
337
    if (!bSubBlockingActive)
29,647✔
338
    {
339
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
27,919✔
340

341
        u.papoBlocks[nBlockIndex] = nullptr;
27,919✔
342
    }
343

344
    /* -------------------------------------------------------------------- */
345
    /*      Identify our subblock.                                          */
346
    /* -------------------------------------------------------------------- */
347
    else
348
    {
349
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
1,728✔
350
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
1,728✔
351

352
        /* --------------------------------------------------------------------
353
         */
354
        /*      Check within subblock. */
355
        /* --------------------------------------------------------------------
356
         */
357
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
1,728✔
358
        if (papoSubBlockGrid == nullptr)
1,728✔
359
            return CE_None;
×
360

361
        const int nBlockInSubBlock =
1,728✔
362
            WITHIN_SUBBLOCK(nXBlockOff) +
1,728✔
363
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
1,728✔
364

365
        papoSubBlockGrid[nBlockInSubBlock] = nullptr;
1,728✔
366
    }
367

368
    return CE_None;
29,647✔
369
}
370

371
/************************************************************************/
372
/*                            FlushBlock()                              */
373
/************************************************************************/
374

375
CPLErr GDALArrayBandBlockCache::FlushBlock(int nXBlockOff, int nYBlockOff,
1,316,370✔
376
                                           int bWriteDirtyBlock)
377

378
{
379
    GDALRasterBlock *poBlock = nullptr;
1,316,370✔
380

381
    /* -------------------------------------------------------------------- */
382
    /*      Simple case for single level caches.                            */
383
    /* -------------------------------------------------------------------- */
384
    if (!bSubBlockingActive)
1,316,370✔
385
    {
386
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
1,260,630✔
387

388
        assert(u.papoBlocks);
1,260,630✔
389
        poBlock = u.papoBlocks[nBlockIndex];
1,260,630✔
390
        u.papoBlocks[nBlockIndex] = nullptr;
1,260,630✔
391
    }
392

393
    /* -------------------------------------------------------------------- */
394
    /*      Identify our subblock.                                          */
395
    /* -------------------------------------------------------------------- */
396
    else
397
    {
398
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
55,740✔
399
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
55,740✔
400

401
        /* --------------------------------------------------------------------
402
         */
403
        /*      Check within subblock. */
404
        /* --------------------------------------------------------------------
405
         */
406
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
55,740✔
407
        if (papoSubBlockGrid == nullptr)
55,740✔
408
            return CE_None;
×
409

410
        const int nBlockInSubBlock =
55,740✔
411
            WITHIN_SUBBLOCK(nXBlockOff) +
55,740✔
412
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
55,740✔
413

414
        poBlock = papoSubBlockGrid[nBlockInSubBlock];
55,740✔
415
        papoSubBlockGrid[nBlockInSubBlock] = nullptr;
55,740✔
416
    }
417

418
    if (poBlock == nullptr)
1,316,370✔
419
        return CE_None;
701✔
420

421
    if (!poBlock->DropLockForRemovalFromStorage())
1,315,670✔
422
        return CE_None;
2✔
423

424
    /* -------------------------------------------------------------------- */
425
    /*      Is the target block dirty?  If so we need to write it.          */
426
    /* -------------------------------------------------------------------- */
427
    poBlock->Detach();
1,315,670✔
428

429
    CPLErr eErr = CE_None;
1,315,670✔
430

431
    if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
1,315,670✔
432
    {
433
        UpdateDirtyBlockFlushingLog();
193,324✔
434

435
        eErr = poBlock->Write();
193,324✔
436
    }
437

438
    /* -------------------------------------------------------------------- */
439
    /*      Deallocate the block;                                           */
440
    /* -------------------------------------------------------------------- */
441
    delete poBlock;
1,315,670✔
442

443
    return eErr;
1,315,670✔
444
}
445

446
/************************************************************************/
447
/*                        TryGetLockedBlockRef()                        */
448
/************************************************************************/
449

450
GDALRasterBlock *GDALArrayBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
7,495,220✔
451
                                                               int nYBlockOff)
452

453
{
454
    /* -------------------------------------------------------------------- */
455
    /*      Simple case for single level caches.                            */
456
    /* -------------------------------------------------------------------- */
457
    if (!bSubBlockingActive)
7,495,220✔
458
    {
459
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
6,712,460✔
460

461
        GDALRasterBlock *poBlock = u.papoBlocks[nBlockIndex];
6,712,460✔
462
        if (poBlock == nullptr || !poBlock->TakeLock())
6,712,460✔
463
            return nullptr;
1,235,980✔
464
        return poBlock;
5,477,910✔
465
    }
466
    else
467
    {
468
        /* --------------------------------------------------------------------
469
         */
470
        /*      Identify our subblock. */
471
        /* --------------------------------------------------------------------
472
         */
473
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
782,768✔
474
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
782,768✔
475

476
        /* --------------------------------------------------------------------
477
         */
478
        /*      Check within subblock. */
479
        /* --------------------------------------------------------------------
480
         */
481
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
782,768✔
482
        if (papoSubBlockGrid == nullptr)
782,768✔
483
            return nullptr;
50✔
484

485
        const int nBlockInSubBlock =
782,718✔
486
            WITHIN_SUBBLOCK(nXBlockOff) +
782,718✔
487
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
782,718✔
488

489
        GDALRasterBlock *poBlock = papoSubBlockGrid[nBlockInSubBlock];
782,718✔
490
        if (poBlock == nullptr || !poBlock->TakeLock())
782,718✔
491
            return nullptr;
57,313✔
492
        return poBlock;
725,405✔
493
    }
494
}
495

496
//! @endcond
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc