g3dcache.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include "G3d_intern.h"
  7. /*---------------------------------------------------------------------------*/
  8. static int cacheRead_readFun(int tileIndex, void *tileBuf, void *closure)
  9. {
  10. G3D_Map *map = closure;
  11. if (!G3d_readTile(map, tileIndex, tileBuf, map->typeIntern)) {
  12. G3d_error("cacheRead_readFun: error in G3d_readTile");
  13. return 0;
  14. }
  15. return 1;
  16. }
  17. /*---------------------------------------------------------------------------*/
  18. static int initCacheRead(G3D_Map * map, int nCached)
  19. {
  20. map->cache = G3d_cache_new_read(nCached,
  21. map->tileSize * map->numLengthIntern,
  22. map->nTiles, cacheRead_readFun, map);
  23. if (map->cache == NULL) {
  24. G3d_error("initCacheRead: error in G3d_cache_new_read");
  25. return 0;
  26. }
  27. return 1;
  28. }
  29. /*---------------------------------------------------------------------------*/
  30. /*
  31. the map->index array is (ab)used to store the positions of the tiles in the
  32. file-cash. we can do this since we maintain the invariant for every tile
  33. that it is either in no file (index == -1) or in either the output-file
  34. (index >= 0) or the cash-file (index <= -2). to convert the file-position in
  35. the cash-file into an index we use the following function:
  36. index = - (fileposition + 2)
  37. symmetrically, we use
  38. fileposition = - (index + 2)
  39. to convert from index to the fileposition.
  40. */
  41. /*---------------------------------------------------------------------------*/
  42. static int cacheWrite_readFun(int tileIndex, void *tileBuf, void *closure)
  43. {
  44. G3D_Map *map = closure;
  45. int index, nBytes;
  46. long pos, offs, offsLast;
  47. pos = map->index[tileIndex];
  48. /* tile has already been flushed onto output file or does not exist yet */
  49. if (pos >= -1) { /* note, G3d_readTile takes care of the case pos == -1 */
  50. G3d_readTile(map, tileIndex, tileBuf, map->typeIntern);
  51. return 1;
  52. }
  53. /* tile is in cache file */
  54. pos = -pos - 2; /* pos is shifted by 2 to avoid 0 and -1 */
  55. nBytes = map->tileSize * map->numLengthIntern;
  56. offs = pos * (nBytes + sizeof(int));
  57. /* seek tile and read it into buffer */
  58. if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
  59. G3d_error("cacheWrite_readFun: can't position file");
  60. return 0;
  61. }
  62. if (read(map->cacheFD, tileBuf, nBytes) != nBytes) {
  63. G3d_error("cacheWrite_readFun: can't read file");
  64. return 0;
  65. }
  66. /* remove it from index */
  67. map->index[tileIndex] = -1;
  68. /* if it is the last tile in the file we are done */
  69. /* map->cachePosLast tells us the position of the last tile in the file */
  70. if (map->cachePosLast == pos) {
  71. map->cachePosLast--;
  72. return 1;
  73. }
  74. /* otherwise we move the last tile in the file into the position of */
  75. /* the tile we just read and update the hash information */
  76. offsLast = map->cachePosLast * (nBytes + sizeof(int));
  77. if (lseek(map->cacheFD, offsLast, SEEK_SET) == -1) {
  78. G3d_error("cacheWrite_readFun: can't position file");
  79. return 0;
  80. }
  81. if (read(map->cacheFD, xdr, nBytes + sizeof(int)) != nBytes + sizeof(int)) {
  82. G3d_error("cacheWrite_readFun: can't read file");
  83. return 0;
  84. }
  85. if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
  86. G3d_error("cacheWrite_readFun: can't position file");
  87. return 0;
  88. }
  89. if (write(map->cacheFD, xdr, nBytes + sizeof(int)) !=
  90. nBytes + sizeof(int)) {
  91. G3d_error("cacheWrite_readFun: can't write file");
  92. return 0;
  93. }
  94. index = *((int *)((unsigned char *)xdr + nBytes));
  95. map->index[index] = -pos - 2;
  96. map->cachePosLast--;
  97. return 1;
  98. }
  99. /*---------------------------------------------------------------------------*/
  100. static int
  101. cacheWrite_writeFun(int tileIndex, const void *tileBuf, void *closure)
  102. {
  103. G3D_Map *map = closure;
  104. int nBytes;
  105. long offs;
  106. if (map->index[tileIndex] != -1)
  107. return 1;
  108. map->cachePosLast++;
  109. nBytes = map->tileSize * map->numLengthIntern;
  110. offs = map->cachePosLast * (nBytes + sizeof(int));
  111. if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
  112. G3d_error("cacheWrite_writeFun: can't position file");
  113. return 0;
  114. }
  115. if (write(map->cacheFD, tileBuf, nBytes) != nBytes) {
  116. G3d_error("cacheWrite_writeFun: can't write file");
  117. return 0;
  118. }
  119. if (write(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) {
  120. G3d_error("cacheWrite_writeFun: can't write file");
  121. return 0;
  122. }
  123. map->index[tileIndex] = -map->cachePosLast - 2;
  124. return 1;
  125. }
  126. /*---------------------------------------------------------------------------*/
  127. static int disposeCacheWrite(G3D_Map * map)
  128. {
  129. if (map->cacheFD >= 0) {
  130. if (close(map->cacheFD) != 0) {
  131. G3d_error("disposeCacheWrite: could not close file");
  132. return 0;
  133. }
  134. remove(map->cacheFileName);
  135. G3d_free(map->cacheFileName);
  136. }
  137. G3d_cache_dispose(map->cache);
  138. return 1;
  139. }
  140. /*---------------------------------------------------------------------------*/
  141. static int initCacheWrite(G3D_Map * map, int nCached)
  142. {
  143. map->cacheFileName = G_tempfile();
  144. map->cacheFD = open(map->cacheFileName, O_RDWR | O_CREAT | O_TRUNC, 0666);
  145. if (map->cacheFD < 0) {
  146. G3d_error("initCacheWrite: could not open file");
  147. return 0;
  148. }
  149. map->cachePosLast = -1;
  150. map->cache = G3d_cache_new(nCached,
  151. map->tileSize * map->numLengthIntern,
  152. map->nTiles,
  153. cacheWrite_writeFun, map,
  154. cacheWrite_readFun, map);
  155. if (map->cache == NULL) {
  156. disposeCacheWrite(map);
  157. G3d_error("initCacheWrite: error in G3d_cache_new");
  158. return 0;
  159. }
  160. return 1;
  161. }
  162. /*---------------------------------------------------------------------------*/
  163. int G3d_initCache(G3D_Map * map, int nCached)
  164. {
  165. if (map->operation == G3D_READ_DATA) {
  166. if (!initCacheRead(map, nCached)) {
  167. G3d_error("G3d_initCache: error in initCacheRead");
  168. return 0;
  169. }
  170. return 1;
  171. }
  172. if (!initCacheWrite(map, nCached)) {
  173. G3d_error("G3d_initCache: error in initCacheWrite");
  174. return 0;
  175. }
  176. return 1;
  177. }
  178. /*---------------------------------------------------------------------------*/
  179. static int disposeCacheRead(G3D_Map * map)
  180. {
  181. G3d_cache_dispose(map->cache);
  182. return 1;
  183. }
  184. /*---------------------------------------------------------------------------*/
  185. int G3d_disposeCache(G3D_Map * map)
  186. {
  187. if (map->operation == G3D_READ_DATA) {
  188. if (!disposeCacheRead(map)) {
  189. G3d_error("G3d_disposeCache: error in disposeCacheRead");
  190. return 0;
  191. }
  192. return 1;
  193. }
  194. if (!disposeCacheWrite(map)) {
  195. G3d_error("G3d_disposeCache: error in disposeCacheWrite");
  196. return 0;
  197. }
  198. return 1;
  199. }
  200. /*---------------------------------------------------------------------------*/
  201. static int cacheFlushFun(int tileIndex, const void *tileBuf, void *closure)
  202. {
  203. G3D_Map *map = closure;
  204. if (!G3d_writeTile(map, tileIndex, tileBuf, map->typeIntern)) {
  205. G3d_error("cacheFlushFun: error in G3d_writeTile");
  206. return 0;
  207. }
  208. return 1;
  209. }
  210. /*---------------------------------------------------------------------------*/
  211. int G3d_flushAllTiles(G3D_Map * map)
  212. {
  213. int tileIndex, nBytes;
  214. long offs;
  215. if (map->operation == G3D_READ_DATA) {
  216. if (!G3d_cache_remove_all(map->cache)) {
  217. G3d_error("G3d_flushAllTiles: error in G3d_cache_remove_all");
  218. return 0;
  219. }
  220. return 1;
  221. }
  222. /* make cache write into output file instead of cache file */
  223. G3d_cache_set_removeFun(map->cache, cacheFlushFun, map);
  224. /* first flush all the tiles which are in the file cache */
  225. nBytes = map->tileSize * map->numLengthIntern;
  226. while (map->cachePosLast >= 0) {
  227. offs = map->cachePosLast * (nBytes + sizeof(int)) + nBytes;
  228. if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
  229. G3d_error("G3d_flushAllTiles: can't position file");
  230. return 0;
  231. }
  232. if (read(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) {
  233. G3d_error("G3d_flushAllTiles: can't read file");
  234. return 0;
  235. }
  236. if (!G3d_cache_load(map->cache, tileIndex)) {
  237. G3d_error("G3d_flushAllTiles: error in G3d_cache_load");
  238. return 0;
  239. }
  240. if (!G3d_cache_flush(map->cache, tileIndex)) {
  241. G3d_error("G3d_flushAllTiles: error in G3d_cache_flush");
  242. return 0;
  243. }
  244. }
  245. /* then flush all the tiles which remain in the non-file cache */
  246. if (!G3d_cache_flush_all(map->cache)) {
  247. G3d_error("G3d_flushAllTiles: error in G3d_cache_flush_all");
  248. return 0;
  249. }
  250. /* now the cache should write into the cache file again */
  251. G3d_cache_set_removeFun(map->cache, cacheWrite_writeFun, map);
  252. return 1;
  253. }