source: subversion/applications/utils/mod_tile/store.c @ 16252

Last change on this file since 16252 was 15835, checked in by jochen, 11 years ago

More changes to make the tile cache directory configurable at runtime

-ttile-dir option for render_list and convert_meta
  • renderd reads it from renderd.conf section "[renderd]" setting "tile_dir"
  • mod_tile reads from Apache conf ModTileTileDir? directive

There are still some places in store.c left, where HASH_DIR is used directly. More fixes needed.

File size: 9.2 KB
Line 
1/* Meta-tile optimised file storage
2 *
3 * Instead of storing each individual tile as a file,
4 * bundle the 8x8 meta tile into a special meta-file.
5 * This reduces the Inode usage and more efficient
6 * utilisation of disk space.
7 */
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <limits.h>
13#include <string.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <utime.h>
17#include <fcntl.h>
18#include <assert.h>
19
20
21#include "store.h"
22#include "render_config.h"
23#include "dir_utils.h"
24#include "protocol.h"
25
26#ifdef METATILE
27int read_from_meta(const char *xmlconfig, int x, int y, int z, unsigned char *buf, size_t sz)
28{
29    char path[PATH_MAX];
30    int meta_offset, fd;
31    unsigned int pos;
32    char header[4096];
33    struct meta_layout *m = (struct meta_layout *)header;
34    size_t file_offset, tile_size;
35
36    meta_offset = xyz_to_meta(path, sizeof(path), HASH_PATH, xmlconfig, x, y, z);
37
38    fd = open(path, O_RDONLY);
39    if (fd < 0)
40        return -1;
41
42    pos = 0;
43    while (pos < sizeof(header)) {
44        size_t len = sizeof(header) - pos;
45        int got = read(fd, header + pos, len);
46        if (got < 0) {
47            close(fd);
48            return -2;
49        } else if (got > 0) {
50            pos += got;
51        } else {
52            break;
53        }
54    }
55    if (pos < sizeof(struct meta_layout)) {
56        fprintf(stderr, "Meta file %s too small to contain header\n", path);
57        return -3;
58    }
59    if (memcmp(m->magic, META_MAGIC, strlen(META_MAGIC))) {
60        fprintf(stderr, "Meta file %s header magic mismatch\n", path);
61        return -4;
62    }
63#if 1
64    // Currently this code only works with fixed metatile sizes (due to xyz_to_meta above)
65    if (m->count != (METATILE * METATILE)) {
66        fprintf(stderr, "Meta file %s header bad count %d != %d\n", path, m->count, METATILE * METATILE);
67        return -5;
68    }
69#else
70    if (m->count < 0 || m->count > 256) {
71        fprintf(stderr, "Meta file %s header bad count %d\n", path, m->count);
72        return -5;
73    }
74#endif
75    file_offset = m->index[meta_offset].offset;
76    tile_size   = m->index[meta_offset].size;
77
78    if (lseek(fd, file_offset, SEEK_SET) < 0) {
79        fprintf(stderr, "Meta file %s seek error %d\n", path, m->count);
80        return -6;
81    }
82    if (tile_size > sz) {
83        fprintf(stderr, "Truncating tile %zd to fit buffer of %zd\n", tile_size, sz);
84        tile_size = sz;
85    }
86    pos = 0;
87    while (pos < tile_size) {
88        size_t len = tile_size - pos;
89        int got = read(fd, buf + pos, len);
90        if (got < 0) {
91            close(fd);
92            return -7;
93        } else if (got > 0) {
94            pos += got;
95        } else {
96            break;
97        }
98    }
99    close(fd);
100    return pos;
101}
102#endif
103
104int read_from_file(const char *xmlconfig, int x, int y, int z, unsigned char *buf, size_t sz)
105{
106    char path[PATH_MAX];
107    int fd;
108    size_t pos;
109
110    xyz_to_path(path, sizeof(path), HASH_PATH, xmlconfig, x, y, z);
111
112    fd = open(path, O_RDONLY);
113    if (fd < 0)
114        return -1;
115
116    pos = 0;
117    while (pos < sz) {
118        size_t len = sz - pos;
119        int got = read(fd, buf + pos, len);
120        if (got < 0) {
121            close(fd);
122            return -2;
123        } else if (got > 0) {
124            pos += got;
125        } else {
126            break;
127        }
128    }
129    if (pos == sz) {
130        fprintf(stderr, "file %s truncated at %zd bytes\n", path, sz);
131    }
132    close(fd);
133    return pos;
134}
135
136int tile_read(const char *xmlconfig, int x, int y, int z, unsigned char *buf, int sz)
137{
138#ifdef METATILE
139    int r;
140
141    r = read_from_meta(xmlconfig, x, y, z, buf, sz);
142    if (r >= 0)
143        return r;
144#endif
145    return read_from_file(xmlconfig, x, y, z, buf, sz);
146}
147
148#ifdef METATILE
149void process_meta(const char *xmlconfig, int x, int y, int z)
150{
151    int fd;
152    int ox, oy, limit;
153    size_t offset, pos;
154    const int buf_len = 10 * MAX_SIZE; // To store all tiles in this .meta
155    unsigned char *buf;
156    struct meta_layout *m;
157    char meta_path[PATH_MAX];
158    char tmp[PATH_MAX];
159    struct stat s;
160
161    buf = (unsigned char *)malloc(buf_len);
162    if (!buf)
163        return;
164
165    m = (struct meta_layout *)buf;
166    offset = sizeof(struct meta_layout) + (sizeof(struct entry) * (METATILE * METATILE));
167    memset(buf, 0, offset);
168
169    limit = (1 << z);
170    limit = MIN(limit, METATILE);
171
172    for (ox=0; ox < limit; ox++) {
173        for (oy=0; oy < limit; oy++) {
174            //fprintf(stderr, "Process %d/%d/%d\n", num, ox, oy);
175            int len = read_from_file(xmlconfig, x + ox, y + oy, z, buf + offset, buf_len - offset);
176            int mt = xyz_to_meta(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x + ox, y + oy, z);
177            if (len <= 0) {
178#if 1
179                fprintf(stderr, "Problem reading sub tiles for metatile xml(%s) x(%d) y(%d) z(%d), got %d\n", xmlconfig, x, y, z, len);
180                free(buf);
181                return;
182#else
183                 m->index[mt].offset = 0;
184                 m->index[mt].size = 0;
185#endif
186            } else {
187                 m->index[mt].offset = offset;
188                 m->index[mt].size = len;
189                 offset += len;
190            }
191        }
192    }
193    m->count = METATILE * METATILE;
194    memcpy(m->magic, META_MAGIC, strlen(META_MAGIC));
195    m->x = x;
196    m->y = y;
197    m->z = z;
198
199    xyz_to_meta(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x, y, z);
200    snprintf(tmp, sizeof(tmp), "%s.tmp.%d", meta_path, getpid());
201
202    fd = open(tmp, O_WRONLY | O_TRUNC | O_CREAT, 0666);
203    if (fd < 0) {
204        fprintf(stderr, "Error creating file: %s\n", meta_path);
205        free(buf);
206        return;
207    }
208
209    pos = 0;
210    while (pos < offset) {
211        int len = write(fd, buf + pos, offset - pos);
212        if (len < 0) {
213            perror("Writing file");
214            free(buf);
215            close(fd);
216            return;
217        } else if (len > 0) {
218            pos += len;
219        } else {
220            break;
221        }
222    }
223    close(fd);
224    free(buf);
225
226    // Reset meta timestamp to match one of the original tiles
227    xyz_to_path(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x, y, z);
228    if (stat(meta_path, &s) == 0) {
229        struct utimbuf b;
230        b.actime = s.st_atime;
231        b.modtime = s.st_mtime;
232        xyz_to_meta(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x, y, z);
233        utime(tmp, &b);
234    }
235    rename(tmp, meta_path);
236    printf("Produced .meta: %s\n", meta_path);
237
238    // Remove raw .png's
239    for (ox=0; ox < limit; ox++) {
240        for (oy=0; oy < limit; oy++) {
241            xyz_to_path(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x + ox, y + oy, z);
242            if (unlink(meta_path)<0)
243                perror(meta_path);
244        }
245    }
246}
247
248void process_pack(const char *name)
249{
250    char meta_path[PATH_MAX];
251    char xmlconfig[XMLCONFIG_MAX];
252    int x, y, z;
253    int meta_offset;
254
255    if (path_to_xyz(name, xmlconfig, &x, &y, &z))
256        return;
257 
258    // Launch the .meta creation for only 1 tile of the whole block
259    meta_offset = xyz_to_meta(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x, y, z);
260    //fprintf(stderr,"Requesting x(%d) y(%d) z(%d) - mo(%d)\n", x, y, z, meta_offset);
261
262    if (meta_offset == 0)
263        process_meta(xmlconfig, x, y, z);
264}
265
266static void write_tile(const char *xmlconfig, int x, int y, int z, const unsigned char *buf, size_t sz)
267{
268    int fd;
269    char path[PATH_MAX];
270    size_t pos;
271
272    xyz_to_path(path, sizeof(path), HASH_PATH, xmlconfig, x, y, z);
273    fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
274    if (fd < 0) {
275        fprintf(stderr, "Error creating file: %s\n", path);
276        return;
277    }
278
279    pos = 0;
280    while (pos < sz) {
281        int len = write(fd, buf + pos, sz - pos);
282        if (len < 0) {
283            perror("Writing file");
284            close(fd);
285            return;
286        } else if (len > 0) {
287            pos += len;
288        } else {
289            break;
290        }
291    }
292    close(fd);
293    printf("Produced tile: %s\n", path);
294}
295
296void process_unpack(const char *name)
297{
298    char meta_path[PATH_MAX];
299    char xmlconfig[XMLCONFIG_MAX];
300    int x, y, z;
301    int ox, oy, limit;
302    const int buf_len = 1024 * 1024;
303    unsigned char *buf;
304    struct stat s;
305
306    // path_to_xyz is valid for meta tile names as well
307    if (path_to_xyz(name, xmlconfig, &x, &y, &z))
308        return;
309
310    buf = (unsigned char *)malloc(buf_len);
311    if (!buf)
312        return;
313
314
315    limit = (1 << z);
316    limit = MIN(limit, METATILE);
317
318    for (ox=0; ox < limit; ox++) {
319        for (oy=0; oy < limit; oy++) {
320            int len = read_from_meta(xmlconfig, x + ox, y + oy, z, buf, buf_len);
321
322            if (len <= 0)
323                fprintf(stderr, "Failed to get tile x(%d) y(%d) z(%d)\n", x + ox, y + oy, z);
324            else
325                write_tile(xmlconfig, x + ox, y + oy, z, buf, len);
326        }
327    }
328
329    // Grab timestamp of the meta file and update tile timestamps
330    if (stat(name, &s) == 0) {
331        struct utimbuf b;
332        b.actime = s.st_atime;
333        b.modtime = s.st_mtime;
334        for (ox=0; ox < limit; ox++) {
335            for (oy=0; oy < limit; oy++) {
336                xyz_to_path(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x+ox, y+oy, z);
337                utime(meta_path, &b);
338            }
339        }
340    }
341
342    // Remove the .meta file
343    xyz_to_meta(meta_path, sizeof(meta_path), HASH_PATH, xmlconfig, x, y, z);
344    if (unlink(meta_path)<0)
345        perror(meta_path);
346}
347#endif
Note: See TracBrowser for help on using the repository browser.