1 /*
2 * readcell.c - reads an entire cell layer into a buffer
3 *
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include "global.h"
14
readcell(int fdi,int size,int target_env)15 struct cache *readcell(int fdi, int size, int target_env)
16 {
17 DCELL *tmpbuf;
18 struct cache *c;
19 int nrows;
20 int ncols;
21 int row;
22 char *filename;
23 int nx, ny;
24 int nblocks;
25 int i;
26
27 if (target_env){
28 select_target_env();
29 nrows = Rast_output_window_rows();
30 ncols = Rast_output_window_cols();
31 }else{
32 select_current_env();
33 nrows = Rast_input_window_rows();
34 ncols = Rast_input_window_cols();
35 }
36 G_srand48(0);
37
38
39 /* Temporary file must be created in the same location/mapset
40 * where the module was called */
41 if (target_env)
42 select_current_env();
43
44 ny = (nrows + BDIM - 1) / BDIM;
45 nx = (ncols + BDIM - 1) / BDIM;
46
47 if (size > 0)
48 nblocks = size * ((1 << 20) / sizeof(block));
49 else
50 nblocks = (nx + ny) * 2; /* guess */
51
52 if (nblocks > nx * ny)
53 nblocks = nx * ny;
54
55 c = G_malloc(sizeof(struct cache));
56 c->stride = nx;
57 c->nblocks = nblocks;
58 c->grid = (block **) G_calloc(nx * ny, sizeof(block *));
59 c->blocks = (block *) G_malloc(nblocks * sizeof(block));
60 c->refs = (int *)G_malloc(nblocks * sizeof(int));
61
62 if (nblocks < nx * ny) {
63 filename = G_tempfile();
64 c->fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
65 if (c->fd < 0)
66 G_fatal_error(_("Unable to open temporary file"));
67 remove(filename);
68 }
69 else
70 c->fd = -1;
71
72 G_debug(1, "%d of %d blocks in memory", nblocks, nx * ny);
73
74 G_important_message(_("Allocating memory and reading input map..."));
75 G_percent(0, nrows, 5);
76
77 for (i = 0; i < c->nblocks; i++)
78 c->refs[i] = -1;
79
80 tmpbuf = (DCELL *) G_malloc(nx * sizeof(block));
81
82 if (target_env)
83 select_target_env();
84 for (row = 0; row < nrows; row += BDIM) {
85 int x, y;
86
87 for (y = 0; y < BDIM; y++) {
88 G_percent(row + y, nrows, 5);
89
90 if (row + y >= nrows)
91 break;
92
93 Rast_get_d_row(fdi, &tmpbuf[y * nx * BDIM], row + y);
94 }
95
96 for (x = 0; x < nx; x++)
97 for (y = 0; y < BDIM; y++)
98 if (c->fd >= 0) {
99 if (write
100 (c->fd, &tmpbuf[(y * nx + x) * BDIM],
101 BDIM * sizeof(DCELL)) < 0)
102 G_fatal_error(_("Error writing segment file"));
103 }
104 else
105 memcpy(&c->blocks[BKIDX(c, HI(row), x)][LO(y)][0],
106 &tmpbuf[(y * nx + x) * BDIM],
107 BDIM * sizeof(DCELL));
108 }
109
110 G_free(tmpbuf);
111
112 if (c->fd < 0)
113 for (i = 0; i < c->nblocks; i++) {
114 c->grid[i] = &c->blocks[i];
115 c->refs[i] = i;
116 }
117
118 if (target_env)
119 select_current_env();
120
121 return c;
122 }
123
get_block(struct cache * c,int idx)124 block *get_block(struct cache * c, int idx)
125 {
126 int replace = G_lrand48() % c->nblocks;
127 block *p = &c->blocks[replace];
128 int cref = c->refs[replace];
129 off_t offset = (off_t) idx * sizeof(DCELL) << L2BSIZE;
130
131 if (c->fd < 0)
132 G_fatal_error(_("Internal error: cache miss on fully-cached map"));
133
134 if (cref >= 0)
135 c->grid[cref] = NULL;
136
137 c->grid[idx] = p;
138 c->refs[replace] = idx;
139
140 if (lseek(c->fd, offset, SEEK_SET) < 0)
141 G_fatal_error(_("Error seeking on segment file"));
142
143 if (read(c->fd, p, sizeof(block)) < 0)
144 G_fatal_error(_("Error reading segment file"));
145
146 return p;
147 }
148
release_cache(struct cache * c)149 void release_cache(struct cache *c)
150 {
151 G_free(c->refs);
152 G_free(c->blocks);
153 G_free(c->grid);
154
155 G_free(c);
156 c = NULL;
157 }
158