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