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

Last change on this file since 28681 was 28516, checked in by Dirk Stoecker, 7 years ago

finally remove hardcoded tile path and replace it by config option

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