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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31 #include "gdal_priv.h"
32
33 #include <cstddef>
34 #include <algorithm>
35 #include <set>
36 #include <vector>
37
38 #include "cpl_config.h"
39 #include "cpl_error.h"
40 #include "cpl_multiproc.h"
41
42 CPL_CVSID("$Id: gdalhashsetbandblockcache.cpp 2cef454ab06723a32379690b46581a40eb2e5af2 2019-11-13 16:36:03 +0100 Even Rouault $")
43
44 //! @cond Doxygen_Suppress
45
46 /* ******************************************************************** */
47 /* GDALHashSetBandBlockCache */
48 /* ******************************************************************** */
49
50 class GDALHashSetBandBlockCache final : public GDALAbstractBandBlockCache
51 {
52 struct BlockComparator
53 {
54 // Do not change this comparator, because this order is assumed by
55 // tests like tiff_write_133 for flushing from top to bottom, left
56 // to right.
operator ()GDALHashSetBandBlockCache::BlockComparator57 bool operator() (const GDALRasterBlock* const& lhs,
58 const GDALRasterBlock* const& rhs) const
59 {
60 if( lhs->GetYOff() < rhs->GetYOff() )
61 return true;
62 if( lhs->GetYOff() > rhs->GetYOff() )
63 return false;
64 return lhs->GetXOff() < rhs->GetXOff();
65 }
66 };
67
68 std::set<GDALRasterBlock*, BlockComparator> m_oSet{};
69 CPLLock *hLock = nullptr;
70
71 CPL_DISALLOW_COPY_ASSIGN(GDALHashSetBandBlockCache)
72
73 public:
74 explicit GDALHashSetBandBlockCache( GDALRasterBand* poBand );
75 ~GDALHashSetBandBlockCache() override;
76
77 bool Init() override;
78 bool IsInitOK() override;
79 CPLErr FlushCache() override;
80 CPLErr AdoptBlock( GDALRasterBlock * ) override;
81 GDALRasterBlock *TryGetLockedBlockRef( int nXBlockOff,
82 int nYBlockYOff ) override;
83 CPLErr UnreferenceBlock( GDALRasterBlock* poBlock ) override;
84 CPLErr FlushBlock( int nXBlockOff, int nYBlockOff,
85 int bWriteDirtyBlock ) override;
86 };
87
88 /************************************************************************/
89 /* GDALHashSetBandBlockCacheCreate() */
90 /************************************************************************/
91
GDALHashSetBandBlockCacheCreate(GDALRasterBand * poBand)92 GDALAbstractBandBlockCache* GDALHashSetBandBlockCacheCreate(
93 GDALRasterBand* poBand )
94 {
95 return new GDALHashSetBandBlockCache(poBand);
96 }
97
98 /************************************************************************/
99 /* GDALHashSetBandBlockCache() */
100 /************************************************************************/
101
GDALHashSetBandBlockCache(GDALRasterBand * poBandIn)102 GDALHashSetBandBlockCache::GDALHashSetBandBlockCache(
103 GDALRasterBand* poBandIn ) :
104 GDALAbstractBandBlockCache(poBandIn),
105
106 hLock(CPLCreateLock(LOCK_ADAPTIVE_MUTEX))
107 {}
108
109 /************************************************************************/
110 /* ~GDALHashSetBandBlockCache() */
111 /************************************************************************/
112
~GDALHashSetBandBlockCache()113 GDALHashSetBandBlockCache::~GDALHashSetBandBlockCache()
114 {
115 GDALHashSetBandBlockCache::FlushCache();
116 CPLDestroyLock(hLock);
117 }
118
119 /************************************************************************/
120 /* Init() */
121 /************************************************************************/
122
Init()123 bool GDALHashSetBandBlockCache::Init()
124 {
125 return true;
126 }
127
128 /************************************************************************/
129 /* IsInitOK() */
130 /************************************************************************/
131
IsInitOK()132 bool GDALHashSetBandBlockCache::IsInitOK()
133 {
134 return true;
135 }
136
137 /************************************************************************/
138 /* AdoptBlock() */
139 /************************************************************************/
140
AdoptBlock(GDALRasterBlock * poBlock)141 CPLErr GDALHashSetBandBlockCache::AdoptBlock( GDALRasterBlock * poBlock )
142
143 {
144 FreeDanglingBlocks();
145
146 CPLLockHolderOptionalLockD( hLock );
147 m_oSet.insert(poBlock);
148
149 return CE_None;
150 }
151
152 /************************************************************************/
153 /* FlushCache() */
154 /************************************************************************/
155
FlushCache()156 CPLErr GDALHashSetBandBlockCache::FlushCache()
157 {
158 FreeDanglingBlocks();
159
160 CPLErr eGlobalErr = poBand->eFlushBlockErr;
161
162 std::set<GDALRasterBlock*, BlockComparator> oOldSet;
163 {
164 CPLLockHolderOptionalLockD( hLock );
165 oOldSet = std::move(m_oSet);
166 }
167
168 StartDirtyBlockFlushingLog();
169 for( auto& poBlock: oOldSet )
170 {
171 if( poBlock->DropLockForRemovalFromStorage() )
172 {
173 CPLErr eErr = CE_None;
174
175 if( eGlobalErr == CE_None && poBlock->GetDirty() )
176 {
177 UpdateDirtyBlockFlushingLog();
178 eErr = poBlock->Write();
179 }
180
181 delete poBlock;
182
183 if( eErr != CE_None )
184 eGlobalErr = eErr;
185 }
186 }
187 EndDirtyBlockFlushingLog();
188
189 WaitCompletionPendingTasks();
190
191 return( eGlobalErr );
192 }
193
194 /************************************************************************/
195 /* UnreferenceBlock() */
196 /************************************************************************/
197
UnreferenceBlock(GDALRasterBlock * poBlock)198 CPLErr GDALHashSetBandBlockCache::UnreferenceBlock( GDALRasterBlock* poBlock )
199 {
200 UnreferenceBlockBase();
201
202 CPLLockHolderOptionalLockD( hLock );
203 m_oSet.erase(poBlock);
204 return CE_None;
205 }
206
207 /************************************************************************/
208 /* FlushBlock() */
209 /************************************************************************/
210
FlushBlock(int nXBlockOff,int nYBlockOff,int bWriteDirtyBlock)211 CPLErr GDALHashSetBandBlockCache::FlushBlock( int nXBlockOff, int nYBlockOff,
212 int bWriteDirtyBlock )
213
214 {
215 GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
216 GDALRasterBlock* poBlock = nullptr;
217 {
218 CPLLockHolderOptionalLockD( hLock );
219 auto oIter = m_oSet.find(&oBlockForLookup);
220 if( oIter == m_oSet.end() )
221 return CE_None;
222 poBlock = *oIter;
223 m_oSet.erase(oIter);
224 }
225
226 if( !poBlock->DropLockForRemovalFromStorage() )
227 return CE_None;
228
229 CPLErr eErr = CE_None;
230
231 if( bWriteDirtyBlock && poBlock->GetDirty() )
232 eErr = poBlock->Write();
233
234 delete poBlock;
235
236 return eErr;
237 }
238
239 /************************************************************************/
240 /* TryGetLockedBlockRef() */
241 /************************************************************************/
242
TryGetLockedBlockRef(int nXBlockOff,int nYBlockOff)243 GDALRasterBlock *GDALHashSetBandBlockCache::TryGetLockedBlockRef(
244 int nXBlockOff, int nYBlockOff )
245
246 {
247 GDALRasterBlock oBlockForLookup(nXBlockOff, nYBlockOff);
248 GDALRasterBlock* poBlock;
249 {
250 CPLLockHolderOptionalLockD( hLock );
251 auto oIter = m_oSet.find(&oBlockForLookup);
252 if( oIter == m_oSet.end() )
253 return nullptr;
254 poBlock = *oIter;
255 }
256 if( !poBlock->TakeLock() )
257 return nullptr;
258 return poBlock;
259 }
260
261 //! @endcond
262