source: subversion/applications/utils/mod_tile/render_old.c @ 17661

Last change on this file since 17661 was 17476, checked in by jonb, 10 years ago

make render_old skip [renderNN] too

File size: 12.8 KB
Line 
1#define _GNU_SOURCE
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <sys/stat.h>
9#include <sys/time.h>
10#include <sys/un.h>
11#include <poll.h>
12#include <errno.h>
13#include <math.h>
14#include <getopt.h>
15#include <time.h>
16#include <sys/types.h>
17#include <dirent.h>
18#include <limits.h>
19#include <string.h>
20
21#include <pthread.h>
22
23
24#include "gen_tile.h"
25#include "protocol.h"
26#include "render_config.h"
27#include "dir_utils.h"
28
29#ifndef METATILE
30#warning("render_old not implemented for non-metatile mode. Feel free to submit fix")
31int main(int argc, char **argv)
32{
33    fprintf(stderr, "render_old not implemented for non-metatile mode. Feel free to submit fix!\n");
34    return -1;
35}
36#else
37
38#define INILINE_MAX 256
39static int minZoom = 0;
40static int maxZoom = 18;
41static int verbose = 0;
42static int num_render = 0, num_all = 0;
43static time_t planetTime;
44static struct timeval start, end;
45
46
47int work_complete;
48
49void display_rate(struct timeval start, struct timeval end, int num) 
50{
51    int d_s, d_us;
52    float sec;
53
54    d_s  = end.tv_sec  - start.tv_sec;
55    d_us = end.tv_usec - start.tv_usec;
56
57    sec = d_s + d_us / 1000000.0;
58
59    printf("Rendered %d tiles in %.2f seconds (%.2f tiles/s)\n", num, sec, num / sec);
60    fflush(NULL);
61}
62
63static time_t getPlanetTime(char *tile_dir)
64{
65    static time_t last_check;
66    static time_t planet_timestamp;
67    time_t now = time(NULL);
68    struct stat buf;
69    char filename[PATH_MAX];
70
71    snprintf(filename, PATH_MAX-1, "%s/%s", tile_dir, PLANET_TIMESTAMP);
72
73    // Only check for updates periodically
74    if (now < last_check + 300)
75        return planet_timestamp;
76
77    last_check = now;
78    if (stat(filename, &buf)) {
79        fprintf(stderr, "Planet timestamp file (%s) is missing\n", filename);
80        // Make something up
81        planet_timestamp = now - 3 * 24 * 60 * 60;
82    } else {
83        if (buf.st_mtime != planet_timestamp) {
84            printf("Planet file updated at %s", ctime(&buf.st_mtime));
85            planet_timestamp = buf.st_mtime;
86        }
87    }
88    return planet_timestamp;
89}
90
91int get_load_avg(void)
92{
93    FILE *loadavg = fopen("/proc/loadavg", "r");
94    int avg = 1000;
95
96    if (!loadavg) {
97        fprintf(stderr, "failed to read /proc/loadavg");
98        return 1000;
99    }
100    if (fscanf(loadavg, "%d", &avg) != 1) {
101        fprintf(stderr, "failed to parse /proc/loadavg");
102        fclose(loadavg);
103        return 1000;
104    }
105    fclose(loadavg);
106
107    return avg;
108}
109
110
111int process_loop(int fd, char * xmlname, int x, int y, int z)
112{
113    struct protocol cmd, rsp;
114    //struct pollfd fds[1];
115    int ret = 0;
116
117    bzero(&cmd, sizeof(cmd));
118
119    cmd.ver = 2;
120    cmd.cmd = cmdRender;
121    cmd.z = z;
122    cmd.x = x;
123    cmd.y = y;
124    strcpy(cmd.xmlname, xmlname);
125    //strcpy(cmd.path, "/tmp/foo.png");
126    //printf("Sending request\n");
127    ret = send(fd, &cmd, sizeof(cmd), 0);
128    if (ret != sizeof(cmd)) {
129        perror("send error");
130    }
131        //printf("Waiting for response\n");
132    bzero(&rsp, sizeof(rsp));
133    ret = recv(fd, &rsp, sizeof(rsp), 0);
134    if (ret != sizeof(rsp)) {
135        perror("recv error");
136        return 0;
137    }
138        //printf("Got response\n");
139
140    if (rsp.cmd != cmdDone) {
141        printf("rendering failed, pausing\n");
142        sleep(10);
143    }
144
145    if (!ret)
146        perror("Socket send error");
147    return ret;
148}
149
150void process(int fd, const char *name)
151{
152    char xmlconfig[XMLCONFIG_MAX];
153    int x, y, z;
154
155    if (path_to_xyz(name, xmlconfig, &x, &y, &z))
156        return;
157
158    printf("Requesting xml(%s) x(%d) y(%d) z(%d)\n", xmlconfig, x, y, z);
159    process_loop(fd, xmlconfig, x, y, z);
160}
161
162static void check_load(void)
163{
164    int avg = get_load_avg();
165
166    while (avg >= MAX_LOAD_OLD) {
167        printf("Load average %d, sleeping\n", avg);
168        sleep(5);
169        avg = get_load_avg();
170    }
171}
172
173#define QMAX 32
174
175pthread_mutex_t qLock;
176pthread_cond_t qCondNotEmpty;
177pthread_cond_t qCondNotFull;
178
179unsigned int qLen;
180struct qItem {
181    char *path;
182    struct qItem *next;
183};
184
185struct qItem *qHead, *qTail;
186
187char *fetch(void)
188{
189    // Fetch path to render from queue or NULL on work completion
190    // Must free() pointer after use
191    char *path;
192
193    pthread_mutex_lock(&qLock);
194
195    while (qLen == 0) {
196        if (work_complete) {
197            pthread_mutex_unlock(&qLock);
198            return NULL;
199        }
200        pthread_cond_wait(&qCondNotEmpty, &qLock);
201    }
202
203    // Fetch item from queue
204    if (!qHead) {
205        fprintf(stderr, "Queue failure, null qHead with %d items in list\n", qLen);
206        exit(1);
207    }
208    path = qHead->path;
209
210    if (qHead == qTail) {
211        free(qHead);
212        qHead = NULL;
213        qTail = NULL;
214        qLen = 0;
215    } else {
216        struct qItem *e = qHead;
217        qHead = qHead->next;
218        free(e);
219        if (qLen == QMAX)
220            pthread_cond_signal(&qCondNotFull);
221        qLen--;
222    }
223
224    pthread_mutex_unlock(&qLock);
225    return path;
226}
227
228void enqueue(const char *path)
229{
230    // Add this path in the local render queue
231    struct qItem *e = malloc(sizeof(struct qItem));
232
233    e->path = strdup(path);
234    e->next = NULL;
235
236    if (!e->path) {
237        fprintf(stderr, "Malloc failure\n");
238        exit(1);
239    }
240
241    pthread_mutex_lock(&qLock);
242
243    while (qLen == QMAX) {
244        pthread_cond_wait(&qCondNotFull, &qLock);
245    }
246
247    // Append item to end of queue
248    if (qTail)
249        qTail->next = e;
250    else
251        qHead = e;
252    qTail = e;
253    if (qLen == 0)
254        pthread_cond_signal(&qCondNotEmpty);
255    qLen++;
256
257    pthread_mutex_unlock(&qLock);
258}
259
260static void descend(const char *search)
261{
262    DIR *tiles = opendir(search);
263    struct dirent *entry;
264    char path[PATH_MAX];
265
266    if (!tiles) {
267        fprintf(stderr, "Unable to open directory: %s\n", search);
268        return;
269    }
270
271    while ((entry = readdir(tiles))) {
272        struct stat b;
273        char *p;
274
275        check_load();
276
277        if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
278            continue;
279        snprintf(path, sizeof(path), "%s/%s", search, entry->d_name);
280        if (stat(path, &b))
281            continue;
282        if (S_ISDIR(b.st_mode)) {
283            descend(path);
284            continue;
285        }
286        p = strrchr(path, '.');
287        if (p && !strcmp(p, ".meta")) {
288            num_all++;
289            if (planetTime > b.st_mtime) {
290                // request rendering of  old tile
291                enqueue(path);
292                num_render++;
293                if (!(num_render % 10)) {
294                    gettimeofday(&end, NULL);
295                    printf("\n");
296                    printf("Meta tiles rendered: ");
297                    display_rate(start, end, num_render);
298                    printf("Total tiles rendered: ");
299                    display_rate(start, end, num_render * METATILE * METATILE);
300                    printf("Total tiles handled from input: ");
301                    display_rate(start, end, num_all);
302                }
303            }
304        }
305    }
306    closedir(tiles);
307}
308
309void *thread_main(void *arg)
310{
311    const char *spath = (const char *)arg;
312    int fd;
313    struct sockaddr_un addr;
314    char *tile;
315
316    fd = socket(PF_UNIX, SOCK_STREAM, 0);
317    if (fd < 0) {
318        fprintf(stderr, "failed to create unix socket\n");
319        exit(2);
320    }
321
322    bzero(&addr, sizeof(addr));
323    addr.sun_family = AF_UNIX;
324    strncpy(addr.sun_path, spath, sizeof(addr.sun_path));
325
326    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
327        fprintf(stderr, "socket connect failed for: %s\n", spath);
328        close(fd);
329        return NULL;
330    }
331
332    while((tile = fetch())) {
333        process(fd, tile);
334        free(tile);
335    }
336
337    close(fd);
338
339    return NULL;
340}
341
342void render_layer(const char *name)
343{
344    int z;
345
346    for (z=minZoom; z<=maxZoom; z++) {
347        char path[PATH_MAX];
348        snprintf(path, PATH_MAX, HASH_PATH "/%s/%d", name, z);
349        descend(path);
350    }
351}
352
353pthread_t *workers;
354
355void spawn_workers(int num, const char *spath)
356{
357    int i;
358
359    // Setup request queue
360    pthread_mutex_init(&qLock, NULL);
361    pthread_cond_init(&qCondNotEmpty, NULL);
362    pthread_cond_init(&qCondNotFull, NULL);
363
364    printf("Starting %d rendering threads\n", num);
365    workers = calloc(sizeof(pthread_t), num);
366    if (!workers) {
367        perror("Error allocating worker memory");
368        exit(1);
369    }
370    for(i=0; i<num; i++) {
371        if (pthread_create(&workers[i], NULL, thread_main, (void *)spath)) {
372            perror("Thread creation failed");
373            exit(1);
374        }
375    }
376}
377
378void finish_workers(int num)
379{
380    int i;
381
382    printf("Waiting for rendering threads to finish\n");
383    pthread_mutex_lock(&qLock);
384    work_complete = 1;
385    pthread_mutex_unlock(&qLock);
386    pthread_cond_broadcast(&qCondNotEmpty);
387
388    for(i=0; i<num; i++)
389        pthread_join(workers[i], NULL);
390    free(workers);
391    workers = NULL;
392}
393
394
395int main(int argc, char **argv)
396{
397    char spath[PATH_MAX] = RENDER_SOCKET;
398    char *tile_dir = HASH_PATH;
399    int c;
400    int numThreads = 1;
401
402    while (1) {
403        int option_index = 0;
404        static struct option long_options[] = {
405            {"min-zoom", 1, 0, 'z'},
406            {"max-zoom", 1, 0, 'Z'},
407            {"socket", 1, 0, 's'},
408            {"num-threads", 1, 0, 'n'},
409            {"tile-dir", 1, 0, 't'},
410            {"verbose", 0, 0, 'v'},
411            {"help", 0, 0, 'h'},
412            {0, 0, 0, 0}
413        };
414
415        c = getopt_long(argc, argv, "hvz:Z:s:t:n:", long_options, &option_index);
416        if (c == -1)
417            break;
418
419        switch (c) {
420            case 's':   /* -s, --socket */
421                strncpy(spath, optarg, PATH_MAX-1);
422                spath[PATH_MAX-1] = 0;
423                break;
424            case 't':   /* -t, --tile-dir */
425                tile_dir=strdup(optarg);
426                break;
427            case 'n':   /* -n, --num-threads */
428                numThreads=atoi(optarg);
429                if (numThreads <= 0) {
430                    fprintf(stderr, "Invalid number of threads, must be at least 1\n");
431                    return 1;
432                }
433                break;
434           case 'z':   /* -z, --min-zoom */
435                        minZoom=atoi(optarg);
436                if (minZoom < 0 || minZoom > 18) {
437                    fprintf(stderr, "Invalid minimum zoom selected, must be between 0 and 18\n");
438                    return 1;
439                }
440                break;
441            case 'Z':   /* -Z, --max-zoom */
442                maxZoom=atoi(optarg);
443                if (maxZoom < 0 || maxZoom > 18) {
444                    fprintf(stderr, "Invalid maximum zoom selected, must be between 0 and 18\n");
445                    return 1;
446                }
447                break;
448            case 'v':   /* -v, --verbose */
449                verbose=1;
450                break;
451            case 'h':   /* -h, --help */
452                fprintf(stderr, "Usage: render_old [OPTION] ...\n");
453                fprintf(stderr, "Search the rendered tiles and re-render tiles which are older then the last planet import\n");
454                fprintf(stderr, "  -z, --min-zoom=ZOOM  filter input to only render tiles greater or equal to this zoom level (default 0)\n");
455                fprintf(stderr, "  -Z, --max-zoom=ZOOM  filter input to only render tiles less than or equal to this zoom level (default 18)\n");
456                fprintf(stderr, "  -s, --socket=SOCKET  unix domain socket name for contacting renderd\n");
457                return -1;
458            default:
459                fprintf(stderr, "unhandled char '%c'\n", c);
460                break;
461        }
462    }
463
464    if (maxZoom < minZoom) {
465        fprintf(stderr, "Invalid zoom range, max zoom must be greater or equal to minimum zoom\n");
466        return 1;
467    }
468
469    fprintf(stderr, "Rendering old tiles\n");
470
471    planetTime = getPlanetTime(tile_dir);
472
473    gettimeofday(&start, NULL);
474
475    FILE * hini ;
476    char line[INILINE_MAX];
477    char value[INILINE_MAX];
478
479    // Load the config
480    if ((hini=fopen(RENDERD_CONFIG, "r"))==NULL) {
481        fprintf(stderr, "Config: cannot open %s\n", RENDERD_CONFIG);
482        exit(7);
483    }
484
485    spawn_workers(numThreads, spath);
486
487    while (fgets(line, INILINE_MAX, hini)!=NULL) {
488        if (line[0] == '[') {
489            if (strlen(line) >= XMLCONFIG_MAX){
490                fprintf(stderr, "XML name too long: %s\n", line);
491                exit(7);
492            }
493            sscanf(line, "[%[^]]", value);
494            // Skip mapnik & renderd sections which are config, not tile layers
495            if (strcmp(value,"mapnik") && strncmp(value, "renderd", 7))
496                render_layer(value);
497        }
498    }
499    fclose(hini);
500
501    finish_workers(numThreads);
502
503    gettimeofday(&end, NULL);
504    printf("\nTotal for all tiles rendered\n");
505    printf("Meta tiles rendered: ");
506    display_rate(start, end, num_render);
507    printf("Total tiles rendered: ");
508    display_rate(start, end, num_render * METATILE * METATILE);
509    printf("Total tiles handled: ");
510    display_rate(start, end, num_all);
511
512    return 0;
513}
514#endif
Note: See TracBrowser for help on using the repository browser.