Coverage Report

Created: 2025-11-16 06:25

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