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