cache.c 8.7 KB

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