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