Coverage Report

Created: 2025-12-03 08:24

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
144M
        {
43
144M
            if (lhs->GetYOff() < rhs->GetYOff())
44
94.7M
                return true;
45
49.3M
            if (lhs->GetYOff() > rhs->GetYOff())
46
31.9M
                return false;
47
17.4M
            return lhs->GetXOff() < rhs->GetXOff();
48
49.3M
        }
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
36.8k
{
78
36.8k
    return new GDALHashSetBandBlockCache(poBand);
79
36.8k
}
80
81
/************************************************************************/
82
/*                       GDALHashSetBandBlockCache()                    */
83
/************************************************************************/
84
85
GDALHashSetBandBlockCache::GDALHashSetBandBlockCache(GDALRasterBand *poBandIn)
86
36.8k
    : GDALAbstractBandBlockCache(poBandIn),
87
88
36.8k
      hLock(CPLCreateLock(LOCK_ADAPTIVE_MUTEX))
89
36.8k
{
90
36.8k
}
91
92
/************************************************************************/
93
/*                      ~GDALHashSetBandBlockCache()                    */
94
/************************************************************************/
95
96
GDALHashSetBandBlockCache::~GDALHashSetBandBlockCache()
97
36.8k
{
98
36.8k
    GDALHashSetBandBlockCache::FlushCache();
99
36.8k
    CPLDestroyLock(hLock);
100
36.8k
}
101
102
/************************************************************************/
103
/*                                  Init()                              */
104
/************************************************************************/
105
106
bool GDALHashSetBandBlockCache::Init()
107
36.8k
{
108
36.8k
    return true;
109
36.8k
}
110
111
/************************************************************************/
112
/*                             IsInitOK()                               */
113
/************************************************************************/
114
115
bool GDALHashSetBandBlockCache::IsInitOK()
116
9.10M
{
117
9.10M
    return true;
118
9.10M
}
119
120
/************************************************************************/
121
/*                            AdoptBlock()                              */
122
/************************************************************************/
123
124
CPLErr GDALHashSetBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
125
126
2.14M
{
127
2.14M
    FreeDanglingBlocks();
128
129
2.14M
    CPLLockHolderOptionalLockD(hLock);
130
2.14M
    m_oSet.insert(poBlock);
131
132
2.14M
    return CE_None;
133
2.14M
}
134
135
/************************************************************************/
136
/*                            FlushCache()                              */
137
/************************************************************************/
138
139
CPLErr GDALHashSetBandBlockCache::FlushCache()
140
129k
{
141
129k
    FreeDanglingBlocks();
142
143
129k
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
144
145
129k
    std::set<GDALRasterBlock *, BlockComparator> oOldSet;
146
129k
    {
147
129k
        CPLLockHolderOptionalLockD(hLock);
148
129k
        oOldSet = std::move(m_oSet);
149
129k
    }
150
151
129k
    StartDirtyBlockFlushingLog();
152
129k
    for (auto &poBlock : oOldSet)
153
2.11M
    {
154
2.11M
        if (poBlock->DropLockForRemovalFromStorage())
155
2.11M
        {
156
2.11M
            CPLErr eErr = CE_None;
157
158
2.11M
            if (!m_nWriteDirtyBlocksDisabled && eGlobalErr == CE_None &&
159
2.11M
                poBlock->GetDirty())
160
0
            {
161
0
                UpdateDirtyBlockFlushingLog();
162
0
                eErr = poBlock->Write();
163
0
            }
164
165
2.11M
            delete poBlock;
166
167
2.11M
            if (eErr != CE_None)
168
0
                eGlobalErr = eErr;
169
2.11M
        }
170
2.11M
    }
171
129k
    EndDirtyBlockFlushingLog();
172
173
129k
    WaitCompletionPendingTasks();
174
175
129k
    return (eGlobalErr);
176
129k
}
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
24.0k
{
199
24.0k
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
200
24.0k
    GDALRasterBlock *poBlock = nullptr;
201
24.0k
    {
202
24.0k
        CPLLockHolderOptionalLockD(hLock);
203
24.0k
        auto oIter = m_oSet.find(&oBlockForLookup);
204
24.0k
        if (oIter == m_oSet.end())
205
0
            return CE_None;
206
24.0k
        poBlock = *oIter;
207
24.0k
        m_oSet.erase(oIter);
208
24.0k
    }
209
210
24.0k
    if (!poBlock->DropLockForRemovalFromStorage())
211
0
        return CE_None;
212
213
24.0k
    CPLErr eErr = CE_None;
214
215
24.0k
    if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
216
0
        eErr = poBlock->Write();
217
218
24.0k
    delete poBlock;
219
220
24.0k
    return eErr;
221
24.0k
}
222
223
/************************************************************************/
224
/*                        TryGetLockedBlockRef()                        */
225
/************************************************************************/
226
227
GDALRasterBlock *GDALHashSetBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
228
                                                                 int nYBlockOff)
229
230
6.88M
{
231
6.88M
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
232
6.88M
    GDALRasterBlock *poBlock;
233
6.88M
    {
234
6.88M
        CPLLockHolderOptionalLockD(hLock);
235
6.88M
        auto oIter = m_oSet.find(&oBlockForLookup);
236
6.88M
        if (oIter == m_oSet.end())
237
2.22M
            return nullptr;
238
4.65M
        poBlock = *oIter;
239
4.65M
    }
240
4.65M
    if (!poBlock->TakeLock())
241
0
        return nullptr;
242
4.65M
    return poBlock;
243
4.65M
}
244
245
//! @endcond