Coverage Report

Created: 2025-12-31 08:30

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
61.2M
        {
43
61.2M
            if (lhs->GetYOff() < rhs->GetYOff())
44
38.0M
                return true;
45
23.1M
            if (lhs->GetYOff() > rhs->GetYOff())
46
18.3M
                return false;
47
4.81M
            return lhs->GetXOff() < rhs->GetXOff();
48
23.1M
        }
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
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
3.64M
{
117
3.64M
    return true;
118
3.64M
}
119
120
/************************************************************************/
121
/*                            AdoptBlock()                              */
122
/************************************************************************/
123
124
CPLErr GDALHashSetBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
125
126
1.66M
{
127
1.66M
    FreeDanglingBlocks();
128
129
1.66M
    CPLLockHolderOptionalLockD(hLock);
130
1.66M
    m_oSet.insert(poBlock);
131
132
1.66M
    return CE_None;
133
1.66M
}
134
135
/************************************************************************/
136
/*                            FlushCache()                              */
137
/************************************************************************/
138
139
CPLErr GDALHashSetBandBlockCache::FlushCache()
140
115k
{
141
115k
    FreeDanglingBlocks();
142
143
115k
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
144
145
115k
    std::set<GDALRasterBlock *, BlockComparator> oOldSet;
146
115k
    {
147
115k
        CPLLockHolderOptionalLockD(hLock);
148
115k
        oOldSet = std::move(m_oSet);
149
115k
    }
150
151
115k
    StartDirtyBlockFlushingLog();
152
115k
    for (auto &poBlock : oOldSet)
153
1.64M
    {
154
1.64M
        if (poBlock->DropLockForRemovalFromStorage())
155
1.64M
        {
156
1.64M
            CPLErr eErr = CE_None;
157
158
1.64M
            if (!m_nWriteDirtyBlocksDisabled && eGlobalErr == CE_None &&
159
1.64M
                poBlock->GetDirty())
160
0
            {
161
0
                UpdateDirtyBlockFlushingLog();
162
0
                eErr = poBlock->Write();
163
0
            }
164
165
1.64M
            delete poBlock;
166
167
1.64M
            if (eErr != CE_None)
168
0
                eGlobalErr = eErr;
169
1.64M
        }
170
1.64M
    }
171
115k
    EndDirtyBlockFlushingLog();
172
173
115k
    WaitCompletionPendingTasks();
174
175
115k
    return (eGlobalErr);
176
115k
}
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
21.6k
{
199
21.6k
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
200
21.6k
    GDALRasterBlock *poBlock = nullptr;
201
21.6k
    {
202
21.6k
        CPLLockHolderOptionalLockD(hLock);
203
21.6k
        auto oIter = m_oSet.find(&oBlockForLookup);
204
21.6k
        if (oIter == m_oSet.end())
205
0
            return CE_None;
206
21.6k
        poBlock = *oIter;
207
21.6k
        m_oSet.erase(oIter);
208
21.6k
    }
209
210
21.6k
    if (!poBlock->DropLockForRemovalFromStorage())
211
0
        return CE_None;
212
213
21.6k
    CPLErr eErr = CE_None;
214
215
21.6k
    if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
216
0
        eErr = poBlock->Write();
217
218
21.6k
    delete poBlock;
219
220
21.6k
    return eErr;
221
21.6k
}
222
223
/************************************************************************/
224
/*                        TryGetLockedBlockRef()                        */
225
/************************************************************************/
226
227
GDALRasterBlock *GDALHashSetBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
228
                                                                 int nYBlockOff)
229
230
1.90M
{
231
1.90M
    GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
232
1.90M
    GDALRasterBlock *poBlock;
233
1.90M
    {
234
1.90M
        CPLLockHolderOptionalLockD(hLock);
235
1.90M
        auto oIter = m_oSet.find(&oBlockForLookup);
236
1.90M
        if (oIter == m_oSet.end())
237
1.77M
            return nullptr;
238
137k
        poBlock = *oIter;
239
137k
    }
240
137k
    if (!poBlock->TakeLock())
241
0
        return nullptr;
242
137k
    return poBlock;
243
137k
}
244
245
//! @endcond