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