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

Last change on this file since 8646 was 8425, checked in by jonb, 11 years ago

mod_tile: Move map style & font location into render_config.h. Fix up operation with non-metatile rendering. Several utilities are not implemented for non-metatile (render_list, render_old, speedtest).

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