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.8 2001/07/05 13:24:08 warmerda 00028 * *** empty log message *** 00028 * 00029 * Revision 1.5 2001/06/22 21:00:06 warmerda 00030 * fixed support for caching override by environment variable 00031 * 00032 * Revision 1.4 2001/06/22 20:09:13 warmerda 00033 * added GDAL_CACHEMAX environment variable support 00034 * 00035 * Revision 1.3 2000/03/31 13:42:49 warmerda 00036 * added debugging code 00037 * 00038 * Revision 1.2 2000/03/24 00:09:05 warmerda 00039 * rewrote cache management 00040 * 00041 * Revision 1.1 1998/12/31 18:52:58 warmerda 00042 * New 00043 * 00044 */ 00045 00046 #include "gdal_priv.h" 00047 00048 static int nTileAgeTicker = 0; 00049 static int bCacheMaxInitialized = FALSE; 00050 static int nCacheMax = 5 * 1024*1024; 00051 static int nCacheUsed = 0; 00052 00053 static GDALRasterBlock *poOldest = NULL; /* tail */ 00054 static GDALRasterBlock *poNewest = NULL; /* head */ 00055 00056 00057 /************************************************************************/ 00058 /* GDALSetCacheMax() */ 00059 /************************************************************************/ 00060 00061 void GDALSetCacheMax( int nNewSize ) 00062 00063 { 00064 nCacheMax = nNewSize; 00065 if( nCacheUsed > nCacheMax ) 00066 GDALFlushCacheBlock(); 00067 } 00068 00069 /************************************************************************/ 00070 /* GDALGetCacheMax() */ 00071 /************************************************************************/ 00072 00073 int GDALGetCacheMax() 00074 { 00075 if( !bCacheMaxInitialized ) 00076 { 00077 if( getenv("GDAL_CACHEMAX") != NULL ) 00078 { 00079 nCacheMax = atoi(getenv("GDAL_CACHEMAX")); 00080 if( nCacheMax < 1000 ) 00081 nCacheMax *= 1024 * 1024; 00082 } 00083 bCacheMaxInitialized = TRUE; 00084 } 00085 00086 return nCacheMax; 00087 } 00088 00089 /************************************************************************/ 00090 /* GDALGetCacheUsed() */ 00091 /************************************************************************/ 00092 00093 int GDALGetCacheUsed() 00094 { 00095 return nCacheUsed; 00096 } 00097 00098 /************************************************************************/ 00099 /* GDALFlushCacheBlock() */ 00100 /* */ 00101 /* The workhorse of cache management! */ 00102 /************************************************************************/ 00103 00104 int GDALFlushCacheBlock() 00105 00106 { 00107 if( poOldest == NULL ) 00108 return FALSE; 00109 poOldest->GetBand()->FlushBlock( poOldest->GetXOff(), 00110 poOldest->GetYOff() ); 00111 00112 return TRUE; 00113 } 00114 00115 /************************************************************************/ 00116 /* GDALRasterBand() */ 00117 /************************************************************************/ 00118 00119 GDALRasterBlock::GDALRasterBlock( GDALRasterBand *poBandIn, 00120 int nXOffIn, int nYOffIn ) 00121 00122 { 00123 poBand = poBandIn; 00124 00125 poBand->GetBlockSize( &nXSize, &nYSize ); 00126 eType = poBand->GetRasterDataType(); 00127 pData = NULL; 00128 bDirty = FALSE; 00129 00130 poNext = poPrevious = NULL; 00131 00132 nXOff = nXOffIn; 00133 nYOff = nYOffIn; 00134 } 00135 00136 /************************************************************************/ 00137 /* ~GDALRasterBlock() */ 00138 /************************************************************************/ 00139 00140 GDALRasterBlock::~GDALRasterBlock() 00141 00142 { 00143 if( pData != NULL ) 00144 { 00145 int nSizeInBytes; 00146 00147 VSIFree( pData ); 00148 00149 nSizeInBytes = (nXSize * nYSize * GDALGetDataTypeSize(eType)+7)/8; 00150 nCacheUsed -= nSizeInBytes; 00151 } 00152 00153 if( poOldest == this ) 00154 poOldest = poPrevious; 00155 00156 if( poNewest == this ) 00157 { 00158 poNewest = poNext; 00159 } 00160 00161 if( poPrevious != NULL ) 00162 poPrevious->poNext = poNext; 00163 00164 if( poNext != NULL ) 00165 poNext->poPrevious = poPrevious; 00166 00167 #ifdef ENABLE_DEBUG 00168 Verify(); 00169 #endif 00170 00171 nAge = -1; 00172 } 00173 00174 /************************************************************************/ 00175 /* Verify() */ 00176 /************************************************************************/ 00177 00178 void GDALRasterBlock::Verify() 00179 00180 { 00181 CPLAssert( (poNewest == NULL && poOldest == NULL) 00182 || (poNewest != NULL && poOldest != NULL) ); 00183 00184 if( poNewest != NULL ) 00185 { 00186 CPLAssert( poNewest->poPrevious == NULL ); 00187 CPLAssert( poOldest->poNext == NULL ); 00188 00189 00190 for( GDALRasterBlock *poBlock = poNewest; 00191 poBlock != NULL; 00192 poBlock = poBlock->poNext ) 00193 { 00194 if( poBlock->poPrevious ) 00195 { 00196 CPLAssert( poBlock->poPrevious->poNext == poBlock ); 00197 } 00198 00199 if( poBlock->poNext ) 00200 { 00201 CPLAssert( poBlock->poNext->poPrevious == poBlock ); 00202 } 00203 } 00204 } 00205 } 00206 00207 /************************************************************************/ 00208 /* Write() */ 00209 /************************************************************************/ 00210 00211 CPLErr GDALRasterBlock::Write() 00212 00213 { 00214 if( !GetDirty() ) 00215 return CE_None; 00216 00217 if( poBand == NULL ) 00218 return CE_Failure; 00219 00220 MarkClean(); 00221 00222 return poBand->IWriteBlock( nXOff, nYOff, pData ); 00223 } 00224 00225 /************************************************************************/ 00226 /* Touch() */ 00227 /************************************************************************/ 00228 00229 void GDALRasterBlock::Touch() 00230 00231 { 00232 nAge = nTileAgeTicker++; 00233 00234 if( poNewest == this ) 00235 return; 00236 00237 if( poOldest == this ) 00238 poOldest = this->poPrevious; 00239 00240 if( poPrevious != NULL ) 00241 poPrevious->poNext = poNext; 00242 00243 if( poNext != NULL ) 00244 poNext->poPrevious = poPrevious; 00245 00246 poPrevious = NULL; 00247 poNext = poNewest; 00248 00249 if( poNewest != NULL ) 00250 { 00251 CPLAssert( poNewest->poPrevious == NULL ); 00252 poNewest->poPrevious = this; 00253 } 00254 poNewest = this; 00255 00256 if( poOldest == NULL ) 00257 { 00258 CPLAssert( poPrevious == NULL && poNext == NULL ); 00259 poOldest = this; 00260 } 00261 #ifdef ENABLE_DEBUG 00262 Verify(); 00263 #endif 00264 } 00265 00266 /************************************************************************/ 00267 /* Internalize() */ 00268 /************************************************************************/ 00269 00270 CPLErr GDALRasterBlock::Internalize() 00271 00272 { 00273 void *pNewData; 00274 int nSizeInBytes; 00275 int nCurCacheMax = GDALGetCacheMax(); 00276 00277 nSizeInBytes = (nXSize * nYSize * GDALGetDataTypeSize( eType ) + 7) / 8; 00278 00279 pNewData = VSIMalloc( nSizeInBytes ); 00280 if( pNewData == NULL ) 00281 return( CE_Failure ); 00282 00283 if( pData != NULL ) 00284 memcpy( pNewData, pData, nSizeInBytes ); 00285 00286 pData = pNewData; 00287 00288 /* -------------------------------------------------------------------- */ 00289 /* Flush old blocks if we are nearing our memory limit. */ 00290 /* -------------------------------------------------------------------- */ 00291 nCacheUsed += nSizeInBytes; 00292 while( nCacheUsed > nCurCacheMax ) 00293 { 00294 int nOldCacheUsed = nCacheUsed; 00295 00296 GDALFlushCacheBlock(); 00297 00298 if( nCacheUsed == nOldCacheUsed ) 00299 { 00300 static int bReported = FALSE; 00301 00302 if( !bReported ) 00303 { 00304 bReported = TRUE; 00305 } 00306 break; 00307 } 00308 } 00309 00310 /* -------------------------------------------------------------------- */ 00311 /* Add this block to the list. */ 00312 /* -------------------------------------------------------------------- */ 00313 Touch(); 00314 return( CE_None ); 00315 } 00316 00317 /************************************************************************/ 00318 /* MarkDirty() */ 00319 /************************************************************************/ 00320 00321 void GDALRasterBlock::MarkDirty() 00322 00323 { 00324 bDirty = TRUE; 00325 } 00326 00327 00328 /************************************************************************/ 00329 /* MarkClean() */ 00330 /************************************************************************/ 00331 00332 void GDALRasterBlock::MarkClean() 00333 00334 { 00335 bDirty = FALSE; 00336 } 00337 00338