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