Coverage Report

Created: 2026-09-26 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdalhashsetbandblockcache.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Store cached blocks in a hash set
5
 * Author:   Even Rouault, <even dot rouault at spatialys dot org>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2010, Tamas Szekeres
9
 * Copyright (c) 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 <cstddef>
18
#include <algorithm>
19
#include <set>
20
#include <vector>
21
22
#include "cpl_config.h"
23
#include "cpl_error.h"
24
#include "cpl_multiproc.h"
25
#include "gdal_abstractbandblockcache.h"
26
27
//! @cond Doxygen_Suppress
28
29
/* ******************************************************************** */
30
/*                        GDALHashSetBandBlockCache                     */
31
/* ******************************************************************** */
32
33
class GDALHashSetBandBlockCache final : public GDALAbstractBandBlockCache
34
{
35
    struct BlockComparator
36
    {
37
        // Do not change this comparator, because this order is assumed by
38
        // tests like tiff_write_133 for flushing from top to bottom, left
39
        // to right.
40
        bool operator()(const GDALRasterBlock *const &lhs,
41
                        const GDALRasterBlock *const &rhs) const
42
67.6M
        {
43
67.6M
            if (lhs->GetYOff() < rhs->GetYOff())
44
41.9M
                return true;
45
25.7M
            if (lhs->GetYOff() > rhs->GetYOff())
46
20.3M
                return false;
47
5.37M
            return lhs->GetXOff() < rhs->GetXOff();
48
25.7M
        }
49
    };
50
51
    std::set<GDALRasterBlock *, BlockComparator> m_oSet{};
52
    CPLLock *hLock = nullptr;
53
54
    CPL_DISALLOW_COPY_ASSIGN(GDALHashSetBandBlockCache)
55
56
  public:
57
    explicit GDALHashSetBandBlockCache(GDALRasterBand *poBand);
58
    ~GDALHashSetBandBlockCache() override;
59
60
    bool Init() override;
61
    bool IsInitOK() override;
62
    CPLErr FlushCache() override;
63
    CPLErr AdoptBlock(GDALRasterBlock *) override;
64
    GDALRasterBlock *TryGetLockedBlockRef(int nXBlockOff,
65
                                          int nYBlockOff) override;
66
    CPLErr UnreferenceBlock(GDALRasterBlock *poBlock) override;
67
    CPLErr FlushBlock(int nXBlockOff, int nYBlockOff,
68
                      int bWriteDirtyBlock) override;
69
};
70
71
/************************************************************************/
72
/*                  GDALHashSetBandBlockCacheCreate()                   */
73
/************************************************************************/
74
75
GDALAbstractBandBlockCache *
76
GDALHashSetBandBlockCacheCreate(GDALRasterBand *poBand)
77
32.4k
{
78
32.4k
    return new GDALHashSetBandBlockCache(poBand);
79
32.4k
}
80
81
/************************************************************************/
82
/*                     GDALHashSetBandBlockCache()                      */
83
/************************************************************************/
84
85
GDALHashSetBandBlockCache::GDALHashSetBandBlockCache(GDALRasterBand *poBandIn)
86
32.4k
    : GDALAbstractBandBlockCache(poBandIn),
87
88
32.4k
      hLock(CPLCreateLock(LOCK_ADAPTIVE_MUTEX))
89
32.4k
{
90
32.4k
}
91
92
/************************************************************************/
93
/*                     ~GDALHashSetBandBlockCache()                     */
94
/************************************************************************/
95
96
GDALHashSetBandBlockCache::~GDALHashSetBandBlockCache()
97
32.4k
{
98
32.4k
    GDALHashSetBandBlockCache::FlushCache();
99
32.4k
    CPLDestroyLock(hLock);
100
32.4k
}
101
102
/************************************************************************/
103
/*                                Init()                                */
104
/************************************************************************/
105
106
bool GDALHashSetBandBlockCache::Init()
107
32.4k
{
108
32.4k
    return true;
109
32.4k
}
110
111
/************************************************************************/
112
/*                              IsInitOK()                              */
113
/************************************************************************/
114
115
bool GDALHashSetBandBlockCache::IsInitOK()
116
4.00M
{
117
4.00M
    return true;
118
4.00M
}
119
120
/************************************************************************/
121
/*                             AdoptBlock()                             */
122
/************************************************************************/
123
124
CPLErr GDALHashSetBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
125
126
1.83M
{
127
1.83M
    FreeDanglingBlocks();
128
129
1.83M
    CPLLockHolderOptionalLockD(hLock);
130
1.83M
    m_oSet.insert(poBlock);
131
132
1.83M
    return CE_None;
133
1.83M
}
134
135
/************************************************************************/
136
/*                             FlushCache()                             */
137
/************************************************************************/
138
139
CPLErr GDALHashSetBandBlockCache::FlushCache()
140
96.9k
{
141
96.9k
    FreeDanglingBlocks();
142
143
96.9k
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
144
145
96.9k
    std::set<GDALRasterBlock *, BlockComparator> oOldSet;
146
96.9k
    {
147
96.9k
        CPLLockHolderOptionalLockD(hLock);
148
96.9k
        oOldSet = std::move(m_oSet);
149
96.9k
    }
150
151
96.9k
    StartDirtyBlockFlushingLog();
152
96.9k
    for (auto &poBlock : oOldSet)
153
1.80M
    {
154
1.80M
        if (poBlock->DropLockForRemovalFromStorage())
155
1.80M
        {
156
1.80M
            CPLErr eErr = CE_None;
157
158
1.80M
            if (!m_nWriteDirtyBlocksDisabled && eGlobalErr == CE_None &&
159
1.80M
                poBlock->GetDirty())
160
0
            {
161
0
                UpdateDirtyBlockFlushingLog();
162
0
                eErr = poBlock->Write();
163
0
            }
164
165
1.80M
            delete poBlock;
166
167
1.80M
            if (eErr != CE_None)
168
0
                eGlobalErr = eErr;
169
1.80M
        }
170
1.80M
    }
171
96.9k
    EndDirtyBlockFlushingLog();
172
173
96.9k
    WaitCompletionPendingTasks();
174
175
96.9k
    return (eGlobalErr);
176
96.9k
}
177
178
/************************************************************************/
179
/*                          UnreferenceBlock()                          */
180
/************************************************************************/
181
182
CPLErr GDALHashSetBandBlockCache::UnreferenceBlock(GDALRasterBlock *poBlock)
183
0
{
184
0
    UnreferenceBlockBase();
185
186
0
    CPLLockHolderOptionalLockD(hLock);
187
0
    m_oSet.erase(poBlock);
188
0
    return CE_None;
189
0
}
190
191
/************************************************************************/
192
/*                             FlushBlock()                             */
193
/************************************************************************/
194
195
CPLErr GDALHashSetBandBlockCache::FlushBlock(int nXBlockOff, int nYBlockOff,
196
                                             int bWriteDirtyBlock)
197
198
29.2k
{
199
29.2k
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
200
29.2k
    GDALRasterBlock *poBlock = nullptr;
201
29.2k
    {
202
29.2k
        CPLLockHolderOptionalLockD(hLock);
203
29.2k
        auto oIter = m_oSet.find(&oBlockForLookup);
204
29.2k
        if (oIter == m_oSet.end())
205
0
            return CE_None;
206
29.2k
        poBlock = *oIter;
207
29.2k
        m_oSet.erase(oIter);
208
29.2k
    }
209
210
29.2k
    if (!poBlock->DropLockForRemovalFromStorage())
211
0
        return CE_None;
212
213
29.2k
    CPLErr eErr = CE_None;
214
215
29.2k
    if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
216
0
        eErr = poBlock->Write();
217
218
29.2k
    delete poBlock;
219
220
29.2k
    return eErr;
221
29.2k
}
222
223
/************************************************************************/
224
/*                        TryGetLockedBlockRef()                        */
225
/************************************************************************/
226
227
GDALRasterBlock *GDALHashSetBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
228
                                                                 int nYBlockOff)
229
230
2.10M
{
231
2.10M
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
232
2.10M
    GDALRasterBlock *poBlock;
233
2.10M
    {
234
2.10M
        CPLLockHolderOptionalLockD(hLock);
235
2.10M
        auto oIter = m_oSet.find(&oBlockForLookup);
236
2.10M
        if (oIter == m_oSet.end())
237
1.92M
            return nullptr;
238
185k
        poBlock = *oIter;
239
185k
    }
240
185k
    if (!poBlock->TakeLock())
241
0
        return nullptr;
242
185k
    return poBlock;
243
185k
}
244
245
//! @endcond