GRASS Programmer's Manual  6.4.2(2012)
g3dcache.c
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines