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