GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-602118adcc
cache.c
Go to the documentation of this file.
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 /*---------------------------------------------------------------------------*/
9 
10 static int cacheRead_readFun(int tileIndex, void *tileBuf, void *closure)
11 {
12  RASTER3D_Map *map = closure;
13 
14  if (!Rast3d_read_tile(map, tileIndex, tileBuf, map->typeIntern)) {
15  Rast3d_error("cacheRead_readFun: error in Rast3d_read_tile");
16  return 0;
17  }
18  return 1;
19 }
20 
21 /*---------------------------------------------------------------------------*/
22 
23 static int initCacheRead(RASTER3D_Map *map, int nCached)
24 {
25  map->cache =
26  Rast3d_cache_new_read(nCached, map->tileSize * map->numLengthIntern,
27  map->nTiles, cacheRead_readFun, map);
28  if (map->cache == NULL) {
29  Rast3d_error("initCacheRead: error in Rast3d_cache_new_read");
30  return 0;
31  }
32 
33  return 1;
34 }
35 
36 /*---------------------------------------------------------------------------*/
37 
38 /*
39  the map->index array is (ab)used to store the positions of the tiles in the
40  file-cash. we can do this since we maintain the invariant for every tile
41  that it is either in no file (index == -1) or in either the output-file
42  (index >= 0) or the cash-file (index <= -2). to convert the file-position in
43  the cash-file into an index we use the following function:
44 
45  index = - (fileposition + 2)
46 
47  symmetrically, we use
48 
49  fileposition = - (index + 2)
50 
51  to convert from index to the fileposition.
52  */
53 
54 /*---------------------------------------------------------------------------*/
55 
56 static int cacheWrite_readFun(int tileIndex, void *tileBuf, void *closure)
57 {
58  RASTER3D_Map *map = closure;
59  int index;
60  size_t nBytes;
61  size_t offs, offsLast;
62  ssize_t res;
63  long int pos;
64 
65  pos = map->index[tileIndex];
66 
67  /* tile has already been flushed onto output file or does not exist yet */
68  if (pos >=
69  -1) { /* note, Rast3d_read_tile takes care of the case pos == -1 */
70  Rast3d_read_tile(map, tileIndex, tileBuf, map->typeIntern);
71  return 1;
72  }
73 
74  /* tile is in cache file */
75 
76  pos = -pos - 2; /* pos is shifted by 2 to avoid 0 and -1 */
77 
78  nBytes = map->tileSize * map->numLengthIntern;
79  offs = pos * (nBytes + sizeof(int));
80 
81  /* seek tile and read it into buffer */
82 
83  if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
84  Rast3d_error("cacheWrite_readFun: can't position file");
85  return 0;
86  }
87  if ((res = read(map->cacheFD, tileBuf, nBytes)) < 0 ||
88  (size_t)res != nBytes) {
89  Rast3d_error("cacheWrite_readFun: can't read file");
90  return 0;
91  }
92 
93  /* remove it from index */
94 
95  map->index[tileIndex] = -1;
96 
97  /* if it is the last tile in the file we are done */
98  /* map->cachePosLast tells us the position of the last tile in the file */
99 
100  if (map->cachePosLast == pos) {
101  map->cachePosLast--;
102  return 1;
103  }
104 
105  /* otherwise we move the last tile in the file into the position of */
106  /* the tile we just read and update the hash information */
107 
108  offsLast = map->cachePosLast * (nBytes + sizeof(int));
109 
110  if (lseek(map->cacheFD, offsLast, SEEK_SET) == -1) {
111  Rast3d_error("cacheWrite_readFun: can't position file");
112  return 0;
113  }
114  if ((res = read(map->cacheFD, xdr, nBytes + sizeof(int))) < 0 ||
115  (size_t)res != nBytes + sizeof(int)) {
116  Rast3d_error("cacheWrite_readFun: can't read file");
117  return 0;
118  }
119 
120  if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
121  Rast3d_error("cacheWrite_readFun: can't position file");
122  return 0;
123  }
124  if ((res = write(map->cacheFD, xdr, nBytes + sizeof(int))) < 0 ||
125  (size_t)res != nBytes + sizeof(int)) {
126  Rast3d_error("cacheWrite_readFun: can't write file");
127  return 0;
128  }
129 
130  index = *((int *)((unsigned char *)xdr + nBytes));
131  map->index[index] = -pos - 2;
132 
133  map->cachePosLast--;
134 
135  return 1;
136 }
137 
138 /*---------------------------------------------------------------------------*/
139 
140 static int cacheWrite_writeFun(int tileIndex, const void *tileBuf,
141  void *closure)
142 {
143  RASTER3D_Map *map = closure;
144  size_t nBytes;
145  size_t offs;
146  ssize_t res;
147 
148  if (map->index[tileIndex] != -1)
149  return 1;
150 
151  map->cachePosLast++;
152  nBytes = map->tileSize * map->numLengthIntern;
153  offs = map->cachePosLast * (nBytes + sizeof(int));
154 
155  if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
156  Rast3d_error("cacheWrite_writeFun: can't position file");
157  return 0;
158  }
159  if ((res = write(map->cacheFD, tileBuf, nBytes)) < 0 ||
160  (size_t)res != nBytes) {
161  Rast3d_error("cacheWrite_writeFun: can't write file");
162  return 0;
163  }
164  if (write(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) {
165  Rast3d_error("cacheWrite_writeFun: can't write file");
166  return 0;
167  }
168 
169  map->index[tileIndex] = -map->cachePosLast - 2;
170 
171  return 1;
172 }
173 
174 /*---------------------------------------------------------------------------*/
175 
176 static int disposeCacheWrite(RASTER3D_Map *map)
177 {
178  if (map->cacheFD >= 0) {
179  if (close(map->cacheFD) != 0) {
180  Rast3d_error("disposeCacheWrite: could not close file");
181  return 0;
182  }
183  remove(map->cacheFileName);
185  }
186 
188 
189  return 1;
190 }
191 
192 /*---------------------------------------------------------------------------*/
193 
194 static int initCacheWrite(RASTER3D_Map *map, int nCached)
195 {
196  map->cacheFileName = G_tempfile();
197  map->cacheFD = open(map->cacheFileName, O_RDWR | O_CREAT | O_TRUNC, 0666);
198 
199  if (map->cacheFD < 0) {
200  Rast3d_error("initCacheWrite: could not open file");
201  return 0;
202  }
203 
204  map->cachePosLast = -1;
205 
206  map->cache = Rast3d_cache_new(nCached, map->tileSize * map->numLengthIntern,
207  map->nTiles, cacheWrite_writeFun, map,
208  cacheWrite_readFun, map);
209 
210  if (map->cache == NULL) {
211  disposeCacheWrite(map);
212  Rast3d_error("initCacheWrite: error in Rast3d_cache_new");
213  return 0;
214  }
215 
216  return 1;
217 }
218 
219 /*---------------------------------------------------------------------------*/
220 
221 int Rast3d_init_cache(RASTER3D_Map *map, int nCached)
222 {
223  if (map->operation == RASTER3D_READ_DATA) {
224  if (!initCacheRead(map, nCached)) {
225  Rast3d_error("Rast3d_init_cache: error in initCacheRead");
226  return 0;
227  }
228  return 1;
229  }
230 
231  if (!initCacheWrite(map, nCached)) {
232  Rast3d_error("Rast3d_init_cache: error in initCacheWrite");
233  return 0;
234  }
235 
236  return 1;
237 }
238 
239 /*---------------------------------------------------------------------------*/
240 
241 static int disposeCacheRead(RASTER3D_Map *map)
242 {
244  return 1;
245 }
246 
247 /*---------------------------------------------------------------------------*/
248 
250 {
251  if (map->operation == RASTER3D_READ_DATA) {
252  if (!disposeCacheRead(map)) {
253  Rast3d_error("Rast3d_dispose_cache: error in disposeCacheRead");
254  return 0;
255  }
256  return 1;
257  }
258 
259  if (!disposeCacheWrite(map)) {
260  Rast3d_error("Rast3d_dispose_cache: error in disposeCacheWrite");
261  return 0;
262  }
263 
264  return 1;
265 }
266 
267 /*---------------------------------------------------------------------------*/
268 
269 static int cacheFlushFun(int tileIndex, const void *tileBuf, void *closure)
270 {
271  RASTER3D_Map *map = closure;
272 
273  if (!Rast3d_write_tile(map, tileIndex, tileBuf, map->typeIntern)) {
274  Rast3d_error("cacheFlushFun: error in Rast3d_write_tile");
275  return 0;
276  }
277 
278  return 1;
279 }
280 
281 /*---------------------------------------------------------------------------*/
282 
284 {
285  size_t tileIndex, nBytes;
286  size_t offs;
287 
288  if (map->operation == RASTER3D_READ_DATA) {
289  if (!Rast3d_cache_remove_all(map->cache)) {
290  Rast3d_error(
291  "Rast3d_flush_all_tiles: error in Rast3d_cache_remove_all");
292  return 0;
293  }
294  return 1;
295  }
296 
297  /* make cache write into output file instead of cache file */
298  Rast3d_cache_set_remove_fun(map->cache, cacheFlushFun, map);
299 
300  /* first flush all the tiles which are in the file cache */
301 
302  nBytes = map->tileSize * map->numLengthIntern;
303 
304  while (map->cachePosLast >= 0) {
305  offs = map->cachePosLast * (nBytes + sizeof(int)) + nBytes;
306 
307  if (lseek(map->cacheFD, offs, SEEK_SET) == -1) {
308  Rast3d_error("Rast3d_flush_all_tiles: can't position file");
309  return 0;
310  }
311  if (read(map->cacheFD, &tileIndex, sizeof(int)) != sizeof(int)) {
312  Rast3d_error("Rast3d_flush_all_tiles: can't read file");
313  return 0;
314  }
315 
316  if (!Rast3d_cache_load(map->cache, tileIndex)) {
317  Rast3d_error("Rast3d_flush_all_tiles: error in Rast3d_cache_load");
318  return 0;
319  }
320  if (!Rast3d_cache_flush(map->cache, tileIndex)) {
321  Rast3d_error("Rast3d_flush_all_tiles: error in Rast3d_cache_flush");
322  return 0;
323  }
324  }
325 
326  /* then flush all the tiles which remain in the non-file cache */
327  if (!Rast3d_cache_flush_all(map->cache)) {
328  Rast3d_error("Rast3d_flush_all_tiles: error in Rast3d_cache_flush_all");
329  return 0;
330  }
331 
332  /* now the cache should write into the cache file again */
333  Rast3d_cache_set_remove_fun(map->cache, cacheWrite_writeFun, map);
334 
335  return 1;
336 }
int Rast3d_flush_all_tiles(RASTER3D_Map *map)
Definition: cache.c:283
int Rast3d_dispose_cache(RASTER3D_Map *map)
Definition: cache.c:249
int Rast3d_init_cache(RASTER3D_Map *map, int nCached)
Definition: cache.c:221
#define NULL
Definition: ccmath.h:32
char * G_tempfile(void)
Returns a temporary file name.
Definition: tempfile.c:62
void * Rast3d_cache_new_read(int, int, int, read_fn *, void *)
Definition: cache1.c:161
int Rast3d_cache_flush_all(RASTER3D_cache *)
Definition: cache1.c:451
void Rast3d_cache_dispose(RASTER3D_cache *)
Definition: cache1.c:63
void Rast3d_free(void *)
Same as free (ptr).
int Rast3d_cache_load(RASTER3D_cache *, int)
Definition: cache1.c:518
int Rast3d_cache_flush(RASTER3D_cache *, int)
Definition: cache1.c:422
void * Rast3d_cache_new(int, int, int, write_fn *, void *, read_fn *, void *)
void Rast3d_cache_set_remove_fun(RASTER3D_cache *, write_fn *, void *)
int Rast3d_read_tile(RASTER3D_Map *, int, void *, int)
Reads tile with index tileIndex into the tile buffer. The cells are stored with type type which must ...
Definition: tileread.c:151
void Rast3d_error(const char *,...) __attribute__((format(printf
int Rast3d_write_tile(RASTER3D_Map *, int, const void *, int)
Writes tile with index tileIndex to the file corresponding to map. It is assumed that the cells in ti...
Definition: tilewrite.c:126
int Rast3d_cache_remove_all(RASTER3D_cache *)
Definition: cache1.c:434
void * xdr
#define RASTER3D_READ_DATA
long * index
Definition: raster3d.h:142
char * cacheFileName
Definition: raster3d.h:163
long cachePosLast
Definition: raster3d.h:164
void * cache
Definition: raster3d.h:161
int operation
Definition: raster3d.h:79
int tileSize
Definition: raster3d.h:180
int numLengthIntern
Definition: raster3d.h:176
int typeIntern
Definition: raster3d.h:150