GRASS Programmer's Manual
6.4.2(2012)
|
00001 #include <stdio.h> 00002 #include <stdlib.h> 00003 #include <fcntl.h> 00004 #include <sys/types.h> 00005 #include <unistd.h> 00006 #include "G3d_intern.h" 00007 00008 /*---------------------------------------------------------------------------*/ 00009 00010 static int cacheRead_readFun(int tileIndex, void *tileBuf, void *closure) 00011 { 00012 G3D_Map *map = closure; 00013 00014 if (!G3d_readTile(map, tileIndex, tileBuf, map->typeIntern)) { 00015 G3d_error("cacheRead_readFun: error in G3d_readTile"); 00016 return 0; 00017 } 00018 return 1; 00019 } 00020 00021 /*---------------------------------------------------------------------------*/ 00022 00023 static int initCacheRead(G3D_Map * map, int nCached) 00024 { 00025 map->cache = G3d_cache_new_read(nCached, 00026 map->tileSize * map->numLengthIntern, 00027 map->nTiles, cacheRead_readFun, map); 00028 if (map->cache == NULL) { 00029 G3d_error("initCacheRead: error in G3d_cache_new_read"); 00030 return 0; 00031 } 00032 00033 return 1; 00034 } 00035 00036 /*---------------------------------------------------------------------------*/ 00037 00038 /* 00039 the map->index array is (ab)used to store the positions of the tiles in the 00040 file-cash. we can do this since we maintain the invariant for every tile 00041 that it is either in no file (index == -1) or in either the output-file 00042 (index >= 0) or the cash-file (index <= -2). to convert the file-position in 00043 the cash-file into an index we use the following function: 00044 00045 index = - (fileposition + 2) 00046 00047 symmetrically, we use 00048 00049 fileposition = - (index + 2) 00050 00051 to convert from index to the fileposition. 00052 */ 00053 00054 /*---------------------------------------------------------------------------*/ 00055 00056 static int cacheWrite_readFun(int tileIndex, void *tileBuf, void *closure) 00057 { 00058 G3D_Map *map = closure; 00059 int index, nBytes; 00060 long pos, offs, offsLast; 00061 00062 pos = map->index[tileIndex]; 00063 00064 /* tile has already been flushed onto output file or does not exist yet */ 00065 if (pos >= -1) { /* note, G3d_readTile takes care of the case pos == -1 */ 00066 G3d_readTile(map, tileIndex, tileBuf, map->typeIntern); 00067 return 1; 00068 } 00069 00070 /* tile is in cache file */ 00071 00072 pos = -pos - 2; /* pos is shifted by 2 to avoid 0 and -1 */ 00073 00074 nBytes = map->tileSize * map->numLengthIntern; 00075 offs = pos * (nBytes + sizeof(int)); 00076 00077 /* seek tile and read it into buffer */ 00078 00079 if (lseek(map->cacheFD, offs, SEEK_SET) == -1) { 00080 G3d_error("cacheWrite_readFun: can't position file"); 00081 return 0; 00082 } 00083 if (read(map->cacheFD, tileBuf, nBytes) != nBytes) { 00084 G3d_error("cacheWrite_readFun: can't read file"); 00085 return 0; 00086 } 00087 00088 /* remove it from index */ 00089 00090 map->index[tileIndex] = -1; 00091 00092 /* if it is the last tile in the file we are done */ 00093 /* map->cachePosLast tells us the position of the last tile in the file */ 00094 00095 if (map->cachePosLast == pos) { 00096 map->cachePosLast--; 00097 return 1; 00098 } 00099 00100 /* otherwise we move the last tile in the file into the position of */ 00101 /* the tile we just read and update the hash information */ 00102 00103 offsLast = map->cachePosLast * (nBytes + sizeof(int)); 00104 00105 if (lseek(map->cacheFD, offsLast, SEEK_SET) == -1) { 00106 G3d_error("cacheWrite_readFun: can't position file"); 00107 return 0; 00108 } 00109 if (read(map->cacheFD, xdr, nBytes + sizeof(int)) != nBytes + sizeof(int)) { 00110 G3d_error("cacheWrite_readFun: can't read file"); 00111 return 0; 00112 } 00113 00114 if (lseek(map->cacheFD, offs, SEEK_SET) == -1) { 00115 G3d_error("cacheWrite_readFun: can't position file"); 00116 return 0; 00117 } 00118 if (write(map->cacheFD, xdr, nBytes + sizeof(int)) != 00119 nBytes + sizeof(int)) { 00120 G3d_error("cacheWrite_readFun: can't write file"); 00121 return 0; 00122 } 00123 00124 index = *((int *)((unsigned char *)xdr + nBytes)); 00125 map->index[index] = -pos - 2; 00126 00127 map->cachePosLast--; 00128 00129 return 1; 00130 } 00131 00132 /*---------------------------------------------------------------------------*/ 00133 00134 static int 00135 cacheWrite_writeFun(int tileIndex, const void *tileBuf, void *closure) 00136 { 00137 G3D_Map *map = closure; 00138 int nBytes; 00139 long offs; 00140 00141 if (map->index[tileIndex] != -1) 00142 return 1; 00143 00144 map->cachePosLast++; 00145 nBytes = map->tileSize * map->numLengthIntern; 00146 offs = map->cachePosLast * (nBytes + sizeof(int)); 00147 00148 if (lseek(map->cacheFD, offs, SEEK_SET) == -1) { 00149 G3d_error("cacheWrite_writeFun: can't position file"); 00150 return 0; 00151 } 00152 if (write(map->cacheFD, tileBuf, nBytes) != nBytes) { 00153 G3d_error("cacheWrite_writeFun: can't write file"); 00154 return 0; 00155 } 00156 if (write(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) { 00157 G3d_error("cacheWrite_writeFun: can't write file"); 00158 return 0; 00159 } 00160 00161 map->index[tileIndex] = -map->cachePosLast - 2; 00162 00163 return 1; 00164 } 00165 00166 /*---------------------------------------------------------------------------*/ 00167 00168 static int disposeCacheWrite(G3D_Map * map) 00169 { 00170 if (map->cacheFD >= 0) { 00171 if (close(map->cacheFD) != 0) { 00172 G3d_error("disposeCacheWrite: could not close file"); 00173 return 0; 00174 } 00175 remove(map->cacheFileName); 00176 G3d_free(map->cacheFileName); 00177 } 00178 00179 G3d_cache_dispose(map->cache); 00180 00181 return 1; 00182 } 00183 00184 /*---------------------------------------------------------------------------*/ 00185 00186 static int initCacheWrite(G3D_Map * map, int nCached) 00187 { 00188 map->cacheFileName = G_tempfile(); 00189 map->cacheFD = open(map->cacheFileName, O_RDWR | O_CREAT | O_TRUNC, 0666); 00190 00191 if (map->cacheFD < 0) { 00192 G3d_error("initCacheWrite: could not open file"); 00193 return 0; 00194 } 00195 00196 map->cachePosLast = -1; 00197 00198 map->cache = G3d_cache_new(nCached, 00199 map->tileSize * map->numLengthIntern, 00200 map->nTiles, 00201 cacheWrite_writeFun, map, 00202 cacheWrite_readFun, map); 00203 00204 if (map->cache == NULL) { 00205 disposeCacheWrite(map); 00206 G3d_error("initCacheWrite: error in G3d_cache_new"); 00207 return 0; 00208 } 00209 00210 return 1; 00211 } 00212 00213 /*---------------------------------------------------------------------------*/ 00214 00215 int G3d_initCache(G3D_Map * map, int nCached) 00216 { 00217 if (map->operation == G3D_READ_DATA) { 00218 if (!initCacheRead(map, nCached)) { 00219 G3d_error("G3d_initCache: error in initCacheRead"); 00220 return 0; 00221 } 00222 return 1; 00223 } 00224 00225 if (!initCacheWrite(map, nCached)) { 00226 G3d_error("G3d_initCache: error in initCacheWrite"); 00227 return 0; 00228 } 00229 00230 return 1; 00231 } 00232 00233 /*---------------------------------------------------------------------------*/ 00234 00235 static int disposeCacheRead(G3D_Map * map) 00236 { 00237 G3d_cache_dispose(map->cache); 00238 return 1; 00239 } 00240 00241 /*---------------------------------------------------------------------------*/ 00242 00243 int G3d_disposeCache(G3D_Map * map) 00244 { 00245 if (map->operation == G3D_READ_DATA) { 00246 if (!disposeCacheRead(map)) { 00247 G3d_error("G3d_disposeCache: error in disposeCacheRead"); 00248 return 0; 00249 } 00250 return 1; 00251 } 00252 00253 if (!disposeCacheWrite(map)) { 00254 G3d_error("G3d_disposeCache: error in disposeCacheWrite"); 00255 return 0; 00256 } 00257 00258 return 1; 00259 } 00260 00261 00262 /*---------------------------------------------------------------------------*/ 00263 00264 static int cacheFlushFun(int tileIndex, const void *tileBuf, void *closure) 00265 { 00266 G3D_Map *map = closure; 00267 00268 if (!G3d_writeTile(map, tileIndex, tileBuf, map->typeIntern)) { 00269 G3d_error("cacheFlushFun: error in G3d_writeTile"); 00270 return 0; 00271 } 00272 00273 return 1; 00274 } 00275 00276 /*---------------------------------------------------------------------------*/ 00277 00278 int G3d_flushAllTiles(G3D_Map * map) 00279 { 00280 int tileIndex, nBytes; 00281 long offs; 00282 00283 if (map->operation == G3D_READ_DATA) { 00284 if (!G3d_cache_remove_all(map->cache)) { 00285 G3d_error("G3d_flushAllTiles: error in G3d_cache_remove_all"); 00286 return 0; 00287 } 00288 return 1; 00289 } 00290 00291 /* make cache write into output file instead of cache file */ 00292 G3d_cache_set_removeFun(map->cache, cacheFlushFun, map); 00293 00294 /* first flush all the tiles which are in the file cache */ 00295 00296 nBytes = map->tileSize * map->numLengthIntern; 00297 00298 while (map->cachePosLast >= 0) { 00299 offs = map->cachePosLast * (nBytes + sizeof(int)) + nBytes; 00300 00301 if (lseek(map->cacheFD, offs, SEEK_SET) == -1) { 00302 G3d_error("G3d_flushAllTiles: can't position file"); 00303 return 0; 00304 } 00305 if (read(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) { 00306 G3d_error("G3d_flushAllTiles: can't read file"); 00307 return 0; 00308 } 00309 00310 if (!G3d_cache_load(map->cache, tileIndex)) { 00311 G3d_error("G3d_flushAllTiles: error in G3d_cache_load"); 00312 return 0; 00313 } 00314 if (!G3d_cache_flush(map->cache, tileIndex)) { 00315 G3d_error("G3d_flushAllTiles: error in G3d_cache_flush"); 00316 return 0; 00317 } 00318 } 00319 00320 /* then flush all the tiles which remain in the non-file cache */ 00321 if (!G3d_cache_flush_all(map->cache)) { 00322 G3d_error("G3d_flushAllTiles: error in G3d_cache_flush_all"); 00323 return 0; 00324 } 00325 00326 /* now the cache should write into the cache file again */ 00327 G3d_cache_set_removeFun(map->cache, cacheWrite_writeFun, map); 00328 00329 return 1; 00330 }