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