#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gen_tile.h" #include "protocol.h" #include "render_config.h" #include "store_file_utils.h" #include "render_submit_queue.h" #include "sys_utils.h" char *tile_dir = HASH_PATH; #ifndef METATILE #warning("render_old not implemented for non-metatile mode. Feel free to submit fix") int main(int argc, char **argv) { fprintf(stderr, "render_old not implemented for non-metatile mode. Feel free to submit fix!\n"); return -1; } #else #define INILINE_MAX 256 static int minZoom = 0; static int maxZoom = MAX_ZOOM; static int verbose = 0; static int num_render = 0, num_all = 0; static int max_load = MAX_LOAD_OLD; static time_t planetTime; static struct timeval start, end; int work_complete; void display_rate(struct timeval start, struct timeval end, int num) { int d_s, d_us; float sec; d_s = end.tv_sec - start.tv_sec; d_us = end.tv_usec - start.tv_usec; sec = d_s + d_us / 1000000.0; printf("%d tiles in %.2f seconds (%.2f tiles/s)\n", num, sec, num / sec); fflush(NULL); } static time_t getPlanetTime(char *tile_dir) { static time_t last_check; static time_t planet_timestamp; time_t now = time(NULL); struct stat buf; char filename[PATH_MAX]; snprintf(filename, PATH_MAX-1, "%s/%s", tile_dir, PLANET_TIMESTAMP); // Only check for updates periodically if (now < last_check + 300) return planet_timestamp; last_check = now; if (stat(filename, &buf)) { fprintf(stderr, "Planet timestamp file (%s) is missing\n", filename); // Make something up planet_timestamp = now - 3 * 24 * 60 * 60; } else { if (buf.st_mtime != planet_timestamp) { printf("Planet file updated at %s", ctime(&buf.st_mtime)); planet_timestamp = buf.st_mtime; } } return planet_timestamp; } static void check_load(void) { double avg = get_load_avg(); while (avg >= max_load) { printf("Load average %f, sleeping\n", avg); sleep(5); avg = get_load_avg(); } } static void descend(const char *search) { DIR *tiles = opendir(search); struct dirent *entry; char path[PATH_MAX]; char mapname[XMLCONFIG_MAX]; int x, y, z; if (!tiles) { fprintf(stderr, "Unable to open directory: %s\n", search); return; } while ((entry = readdir(tiles))) { struct stat b; char *p; check_load(); if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue; snprintf(path, sizeof(path), "%s/%s", search, entry->d_name); if (stat(path, &b)) continue; if (S_ISDIR(b.st_mode)) { descend(path); continue; } p = strrchr(path, '.'); if (p && !strcmp(p, ".meta")) { num_all++; if (planetTime > b.st_mtime) { // request rendering of old tile path_to_xyz(tile_dir, path, mapname, &x, &y, &z); enqueue(mapname, x, y, z); } } } closedir(tiles); } void render_layer(const char *tilepath, const char *name) { int z; for (z=minZoom; z<=maxZoom; z++) { if (verbose) printf("Rendering zoom %d\n", z); char path[PATH_MAX]; snprintf(path, PATH_MAX, "%s/%s/%d", tilepath, name, z); descend(path); } } int main(int argc, char **argv) { char spath[PATH_MAX] = RENDER_SOCKET; char *config_file = RENDERD_CONFIG; char *map = NULL; int c; int numThreads = 1; int dd, mm, yy; struct tm tm; while (1) { int option_index = 0; static struct option long_options[] = { {"config",1,0,'c'}, {"min-zoom", 1, 0, 'z'}, {"max-zoom", 1, 0, 'Z'}, {"max-load", 1, 0, 'l'}, {"socket", 1, 0, 's'}, {"num-threads", 1, 0, 'n'}, {"tile-dir", 1, 0, 't'}, {"timestamp", 1, 0, 'T'}, {"map", 1, 0, 'm'}, {"verbose", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hvz:Z:s:t:n:c:l:T:m:", long_options, &option_index); if (c == -1) break; switch (c) { case 's': /* -s, --socket */ strncpy(spath, optarg, PATH_MAX-1); spath[PATH_MAX-1] = 0; break; case 't': /* -t, --tile-dir */ tile_dir=strdup(optarg); break; case 'c': /* -c, --config */ config_file=strdup(optarg); break; case 'm': /* -m, --map */ map=strdup(optarg); break; case 'n': /* -n, --num-threads */ numThreads=atoi(optarg); if (numThreads <= 0) { fprintf(stderr, "Invalid number of threads, must be at least 1\n"); return 1; } break; case 'z': /* -z, --min-zoom */ minZoom=atoi(optarg); if (minZoom < 0 || minZoom > MAX_ZOOM) { fprintf(stderr, "Invalid minimum zoom selected, must be between 0 and %d\n", MAX_ZOOM); return 1; } break; case 'Z': /* -Z, --max-zoom */ maxZoom=atoi(optarg); if (maxZoom < 0 || maxZoom > MAX_ZOOM) { fprintf(stderr, "Invalid maximum zoom selected, must be between 0 and %d\n", MAX_ZOOM); return 1; } break; case 'l': max_load = atoi(optarg); if (max_load < 0) { fprintf(stderr, "Invalid maximum load specified, must be greater than 0\n"); return 1; } break; case 'T': if (sscanf(optarg,"%d/%d/%d", &dd, &mm, &yy) < 3) { fprintf(stderr, "Invalid planet time stamp, must be in the format dd/mm/yyyy\n"); return 1; } if (yy > 100) yy -= 1900; if (yy < 70) yy += 100; memset(&tm,0,sizeof(tm)); tm.tm_mday = dd; tm.tm_mon = mm - 1; tm.tm_year = yy; planetTime = mktime(&tm); break; case 'v': /* -v, --verbose */ verbose=1; break; case 'h': /* -h, --help */ fprintf(stderr, "Usage: render_old [OPTION] ...\n"); fprintf(stderr, "Search the rendered tiles and re-render tiles which are older then the last planet import\n"); fprintf(stderr, " -c, --config=CONFIG specify the renderd config file\n"); fprintf(stderr, " -n, --num-threads=N the number of parallel request threads (default 1)\n"); fprintf(stderr, " -t, --tile-dir tile cache directory (defaults to '" HASH_PATH "')\n"); fprintf(stderr, " -z, --min-zoom=ZOOM filter input to only render tiles greater or equal to this zoom level (default 0)\n"); fprintf(stderr, " -Z, --max-zoom=ZOOM filter input to only render tiles less than or equal to this zoom level (default %d)\n", MAX_ZOOM); fprintf(stderr, " -s, --socket=SOCKET unix domain socket name for contacting renderd\n"); fprintf(stderr, " -l, --max-load=LOAD maximum system load with which requests are submitted\n"); fprintf(stderr, " -T, --timestamp=DD/MM/YY Overwrite the assumed data of the planet import\n"); fprintf(stderr, " -m, --map=STYLE Instead of going through all styls of CONFIG, only use a specific map-style\n"); return -1; default: fprintf(stderr, "unhandled char '%c'\n", c); break; } } if (maxZoom < minZoom) { fprintf(stderr, "Invalid zoom range, max zoom must be greater or equal to minimum zoom\n"); return 1; } fprintf(stderr, "Rendering old tiles\n"); if (planetTime == 0) { planetTime = getPlanetTime(tile_dir); } else { printf("Overwriting planet file update to %s", ctime(&planetTime)); } gettimeofday(&start, NULL); FILE * hini ; char line[INILINE_MAX]; char value[INILINE_MAX]; // Load the config if ((hini=fopen(config_file, "r"))==NULL) { fprintf(stderr, "Config: cannot open %s\n", config_file); exit(7); } spawn_workers(numThreads, spath, max_load); if (map) { render_layer(tile_dir, map); } else { while (fgets(line, INILINE_MAX, hini)!=NULL) { if (line[0] == '[') { if (strlen(line) >= XMLCONFIG_MAX){ fprintf(stderr, "XML name too long: %s\n", line); exit(7); } if (sscanf(line, "[%[^]]", value) != 1) { fprintf(stderr, "Config: malformed config file on line %s\n", line); exit(7); }; // Skip mapnik & renderd sections which are config, not tile layers if (strcmp(value,"mapnik") && strncmp(value, "renderd", 7)) render_layer(tile_dir, value); } } } fclose(hini); free(map); if (tile_dir != HASH_PATH) { free(tile_dir); } finish_workers(numThreads); gettimeofday(&end, NULL); printf("\nTotal for all tiles rendered\n"); printf("Meta tiles rendered: "); display_rate(start, end, num_render); printf("Total tiles rendered: "); display_rate(start, end, num_render * METATILE * METATILE); printf("Total tiles handled: "); display_rate(start, end, num_all); return 0; } #endif