Coverage Report

Created: 2026-08-14 09:29

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
71.1M
        {
43
71.1M
            if (lhs->GetYOff() < rhs->GetYOff())
44
44.3M
                return true;
45
26.8M
            if (lhs->GetYOff() > rhs->GetYOff())
46
21.5M
                return false;
47
5.22M
            return lhs->GetXOff() < rhs->GetXOff();
48
26.8M
        }
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 nYBlockYOff) 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
31.6k
{
78
31.6k
    return new GDALHashSetBandBlockCache(poBand);
79
31.6k
}
80
81
/************************************************************************/
82
/*                     GDALHashSetBandBlockCache()                      */
83
/************************************************************************/
84
85
GDALHashSetBandBlockCache::GDALHashSetBandBlockCache(GDALRasterBand *poBandIn)
86
31.6k
    : GDALAbstractBandBlockCache(poBandIn),
87
88
31.6k
      hLock(CPLCreateLock(LOCK_ADAPTIVE_MUTEX))
89
31.6k
{
90
31.6k
}
91
92
/************************************************************************/
93
/*                     ~GDALHashSetBandBlockCache()                     */
94
/************************************************************************/
95
96
GDALHashSetBandBlockCache::~GDALHashSetBandBlockCache()
97
31.6k
{
98
31.6k
    GDALHashSetBandBlockCache::FlushCache();
99
31.6k
    CPLDestroyLock(hLock);
100
31.6k
}
101
102
/************************************************************************/
103
/*                                Init()                                */
104
/************************************************************************/
105
106
bool GDALHashSetBandBlockCache::Init()
107
31.6k
{
108
31.6k
    return true;
109
31.6k
}
110
111
/************************************************************************/
112
/*                              IsInitOK()                              */
113
/************************************************************************/
114
115
bool GDALHashSetBandBlockCache::IsInitOK()
116
4.21M
{
117
4.21M
    return true;
118
4.21M
}
119
120
/************************************************************************/
121
/*                             AdoptBlock()                             */
122
/************************************************************************/
123
124
CPLErr GDALHashSetBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
125
126
1.93M
{
127
1.93M
    FreeDanglingBlocks();
128
129
1.93M
    CPLLockHolderOptionalLockD(hLock);
130
1.93M
    m_oSet.insert(poBlock);
131
132
1.93M
    return CE_None;
133
1.93M
}
134
135
/************************************************************************/
136
/*                             FlushCache()                             */
137
/************************************************************************/
138
139
CPLErr GDALHashSetBandBlockCache::FlushCache()
140
92.8k
{
141
92.8k
    FreeDanglingBlocks();
142
143
92.8k
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
144
145
92.8k
    std::set<GDALRasterBlock *, BlockComparator> oOldSet;
146
92.8k
    {
147
92.8k
        CPLLockHolderOptionalLockD(hLock);
148
92.8k
        oOldSet = std::move(m_oSet);
149
92.8k
    }
150
151
92.8k
    StartDirtyBlockFlushingLog();
152
92.8k
    for (auto &poBlock : oOldSet)
153
1.90M
    {
154
1.90M
        if (poBlock->DropLockForRemovalFromStorage())
155
1.90M
        {
156
1.90M
            CPLErr eErr = CE_None;
157
158
1.90M
            if (!m_nWriteDirtyBlocksDisabled && eGlobalErr == CE_None &&
159
1.90M
                poBlock->GetDirty())
160
0
            {
161
0
                UpdateDirtyBlockFlushingLog();
162
0
                eErr = poBlock->Write();
163
0
            }
164
165
1.90M
            delete poBlock;
166
167
1.90M
            if (eErr != CE_None)
168
0
                eGlobalErr = eErr;
169
1.90M
        }
170
1.90M
    }
171
92.8k
    EndDirtyBlockFlushingLog();
172
173
92.8k
    WaitCompletionPendingTasks();
174
175
92.8k
    return (eGlobalErr);
176
92.8k
}
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.21M
{
231
2.21M
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
232
2.21M
    GDALRasterBlock *poBlock;
233
2.21M
    {
234
2.21M
        CPLLockHolderOptionalLockD(hLock);
235
2.21M
        auto oIter = m_oSet.find(&oBlockForLookup);
236
2.21M
        if (oIter == m_oSet.end())
237
2.02M
            return nullptr;
238
192k
        poBlock = *oIter;
239
192k
    }
240
192k
    if (!poBlock->TakeLock())
241
0
        return nullptr;
242
192k
    return poBlock;
243
192k
}
244
245
//! @endcond