00001 /****************************************************************************** 00002 * Copyright (c) 1998, Frank Warmerdam 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00020 * DEALINGS IN THE SOFTWARE. 00021 ****************************************************************************** 00022 * 00023 * gdalrasterblock.cpp 00024 * 00025 * The GDALRasterBlock class. 00026 * 00027 * 00028 * $Log: gdalrasterblock_cpp-source.html,v $ 00028 * Revision 1.5 2000/11/06 04:49:01 warmerda 00028 * *** empty log message *** 00028 * 00029 * Revision 1.3 2000/03/31 13:42:49 warmerda 00030 * added debugging code 00031 * 00032 * Revision 1.2 2000/03/24 00:09:05 warmerda 00033 * rewrote cache management 00034 * 00035 * Revision 1.1 1998/12/31 18:52:58 warmerda 00036 * New 00037 * 00038 */ 00039 00040 #include "gdal_priv.h" 00041 00042 static int nTileAgeTicker = 0; 00043 static int nCacheMax = 5 * 1024*1024; 00044 static int nCacheUsed = 0; 00045 00046 static GDALRasterBlock *poOldest = NULL; /* tail */ 00047 static GDALRasterBlock *poNewest = NULL; /* head */ 00048 00049 00050 /************************************************************************/ 00051 /* GDALSetCacheMax() */ 00052 /************************************************************************/ 00053 00054 void GDALSetCacheMax( int nNewSize ) 00055 00056 { 00057 nCacheMax = nNewSize; 00058 if( nCacheUsed > nCacheMax ) 00059 GDALFlushCacheBlock(); 00060 } 00061 00062 /************************************************************************/ 00063 /* GDALGetCacheMax() */ 00064 /************************************************************************/ 00065 00066 int GDALGetCacheMax() 00067 { 00068 return nCacheMax; 00069 } 00070 00071 /************************************************************************/ 00072 /* GDALGetCacheUsed() */ 00073 /************************************************************************/ 00074 00075 int GDALGetCacheUsed() 00076 { 00077 return nCacheUsed; 00078 } 00079 00080 /************************************************************************/ 00081 /* GDALFlushCacheBlock() */ 00082 /* */ 00083 /* The workhorse of cache management! */ 00084 /************************************************************************/ 00085 00086 int GDALFlushCacheBlock() 00087 00088 { 00089 if( poOldest == NULL ) 00090 return FALSE; 00091 poOldest->GetBand()->FlushBlock( poOldest->GetXOff(), 00092 poOldest->GetYOff() ); 00093 00094 return TRUE; 00095 } 00096 00097 /************************************************************************/ 00098 /* GDALRasterBand() */ 00099 /************************************************************************/ 00100 00101 GDALRasterBlock::GDALRasterBlock( GDALRasterBand *poBandIn, 00102 int nXOffIn, int nYOffIn ) 00103 00104 { 00105 poBand = poBandIn; 00106 00107 poBand->GetBlockSize( &nXSize, &nYSize ); 00108 eType = poBand->GetRasterDataType(); 00109 pData = NULL; 00110 bDirty = FALSE; 00111 00112 poNext = poPrevious = NULL; 00113 00114 nXOff = nXOffIn; 00115 nYOff = nYOffIn; 00116 } 00117 00118 /************************************************************************/ 00119 /* ~GDALRasterBlock() */ 00120 /************************************************************************/ 00121 00122 GDALRasterBlock::~GDALRasterBlock() 00123 00124 { 00125 if( pData != NULL ) 00126 { 00127 int nSizeInBytes; 00128 00129 VSIFree( pData ); 00130 00131 nSizeInBytes = (nXSize * nYSize * GDALGetDataTypeSize(eType)+7)/8; 00132 nCacheUsed -= nSizeInBytes; 00133 } 00134 00135 if( poOldest == this ) 00136 poOldest = poPrevious; 00137 00138 if( poNewest == this ) 00139 { 00140 poNewest = poNext; 00141 } 00142 00143 if( poPrevious != NULL ) 00144 poPrevious->poNext = poNext; 00145 00146 if( poNext != NULL ) 00147 poNext->poPrevious = poPrevious; 00148 00149 #ifdef ENABLE_DEBUG 00150 Verify(); 00151 #endif 00152 00153 nAge = -1; 00154 } 00155 00156 /************************************************************************/ 00157 /* Verify() */ 00158 /************************************************************************/ 00159 00160 void GDALRasterBlock::Verify() 00161 00162 { 00163 CPLAssert( (poNewest == NULL && poOldest == NULL) 00164 || (poNewest != NULL && poOldest != NULL) ); 00165 00166 if( poNewest != NULL ) 00167 { 00168 CPLAssert( poNewest->poPrevious == NULL ); 00169 CPLAssert( poOldest->poNext == NULL ); 00170 00171 00172 for( GDALRasterBlock *poBlock = poNewest; 00173 poBlock != NULL; 00174 poBlock = poBlock->poNext ) 00175 { 00176 if( poBlock->poPrevious ) 00177 { 00178 CPLAssert( poBlock->poPrevious->poNext == poBlock ); 00179 } 00180 00181 if( poBlock->poNext ) 00182 { 00183 CPLAssert( poBlock->poNext->poPrevious == poBlock ); 00184 } 00185 } 00186 } 00187 } 00188 00189 /************************************************************************/ 00190 /* Write() */ 00191 /************************************************************************/ 00192 00193 CPLErr GDALRasterBlock::Write() 00194 00195 { 00196 if( !GetDirty() ) 00197 return CE_None; 00198 00199 if( poBand == NULL ) 00200 return CE_Failure; 00201 00202 MarkClean(); 00203 00204 return poBand->IWriteBlock( nXOff, nYOff, pData ); 00205 } 00206 00207 /************************************************************************/ 00208 /* Touch() */ 00209 /************************************************************************/ 00210 00211 void GDALRasterBlock::Touch() 00212 00213 { 00214 nAge = nTileAgeTicker++; 00215 00216 if( poNewest == this ) 00217 return; 00218 00219 if( poOldest == this ) 00220 poOldest = this->poPrevious; 00221 00222 if( poPrevious != NULL ) 00223 poPrevious->poNext = poNext; 00224 00225 if( poNext != NULL ) 00226 poNext->poPrevious = poPrevious; 00227 00228 poPrevious = NULL; 00229 poNext = poNewest; 00230 00231 if( poNewest != NULL ) 00232 { 00233 CPLAssert( poNewest->poPrevious == NULL ); 00234 poNewest->poPrevious = this; 00235 } 00236 poNewest = this; 00237 00238 if( poOldest == NULL ) 00239 { 00240 CPLAssert( poPrevious == NULL && poNext == NULL ); 00241 poOldest = this; 00242 } 00243 #ifdef ENABLE_DEBUG 00244 Verify(); 00245 #endif 00246 } 00247 00248 /************************************************************************/ 00249 /* Internalize() */ 00250 /************************************************************************/ 00251 00252 CPLErr GDALRasterBlock::Internalize() 00253 00254 { 00255 void *pNewData; 00256 int nSizeInBytes; 00257 00258 nSizeInBytes = (nXSize * nYSize * GDALGetDataTypeSize( eType ) + 7) / 8; 00259 00260 pNewData = VSIMalloc( nSizeInBytes ); 00261 if( pNewData == NULL ) 00262 return( CE_Failure ); 00263 00264 if( pData != NULL ) 00265 memcpy( pNewData, pData, nSizeInBytes ); 00266 00267 pData = pNewData; 00268 00269 /* -------------------------------------------------------------------- */ 00270 /* Flush old blocks if we are nearing our memory limit. */ 00271 /* -------------------------------------------------------------------- */ 00272 nCacheUsed += nSizeInBytes; 00273 while( nCacheUsed > nCacheMax ) 00274 { 00275 int nOldCacheUsed = nCacheUsed; 00276 00277 GDALFlushCacheBlock(); 00278 00279 if( nCacheUsed == nOldCacheUsed ) 00280 { 00281 static int bReported = FALSE; 00282 00283 if( !bReported ) 00284 { 00285 bReported = TRUE; 00286 } 00287 break; 00288 } 00289 } 00290 00291 /* -------------------------------------------------------------------- */ 00292 /* Add this block to the list. */ 00293 /* -------------------------------------------------------------------- */ 00294 Touch(); 00295 return( CE_None ); 00296 } 00297 00298 /************************************************************************/ 00299 /* MarkDirty() */ 00300 /************************************************************************/ 00301 00302 void GDALRasterBlock::MarkDirty() 00303 00304 { 00305 bDirty = TRUE; 00306 } 00307 00308 00309 /************************************************************************/ 00310 /* MarkClean() */ 00311 /************************************************************************/ 00312 00313 void GDALRasterBlock::MarkClean() 00314 00315 { 00316 bDirty = FALSE; 00317 } 00318 00319