bool disk_storage::put_meta(const tile_protocol &tile, const std::string &buf) const { pair<string, int> foo = xyz_to_meta(dir_, tile.x, tile.y, tile.z, tile.style); if (foo.second == 0) { fs::path tmp = fs::path(dir_) / fs::unique_path(); try { fs::path p(foo.first); // create directory for metatile to go in. fs::create_directories(p.parent_path()); // write first to temporary location { fs::ofstream out(tmp); out << buf; } // now copy that file atomically into position fs::rename(tmp, p); return true; } catch (const fs::filesystem_error &e) { LOG_ERROR(boost::format("Filesystem error: %1%") % e.what()); } } else { #ifdef RENDERMQ_DEBUG LOG_ERROR("Attempt to save tile at non-metatile boundary."); #endif } return false; }
shared_ptr<tile_storage::handle> disk_storage::get(const tile_protocol &tile) const { if (data_locked) { throw runtime_error("Multiple use of disk_storage::data_cache not allowed."); } pair<string, int> foo = xyz_to_meta(dir_, tile.x, tile.y, tile.z, tile.style); try { fs::path p(foo.first); if (fs::exists(p)) { std::time_t t = fs::last_write_time(p); int ret = read_from_meta(dir_, tile.x, tile.y, tile.z, tile.style, data_cache.c_array(), data_cache.size(), tile.format); if (ret > 0) { return shared_ptr<tile_storage::handle>(new handle(t, ret, *this)); } } } catch (const fs::filesystem_error &e) { LOG_ERROR(boost::format("Filesystem error: %1%") % e.what()); } return shared_ptr<tile_storage::handle>(new null_handle()); }
void metaTile::save(std::string const& tile_dir, std::string const& hostname) { int ox, oy, limit; size_t offset; struct entry offsets[METATILE * METATILE]; struct meta_layout m; memset(&m, 0, sizeof(m)); memset(&offsets, 0, sizeof(offsets)); std::pair<std::string, int> metatile = xyz_to_meta(tile_dir, x_, y_, z_, style_); std::stringstream ss; ss << metatile.first << "." << std::string(hostname) << "." << pthread_self(); std::string tmp(ss.str()); boost::filesystem::path p0(tmp); boost::filesystem::create_directories(p0.parent_path()); std::ofstream file(tmp.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); // Create and write header m.count = METATILE * METATILE; memcpy(m.magic, META_MAGIC, strlen(META_MAGIC)); m.x = x_; m.y = y_; m.z = z_; file.write((const char *)&m, sizeof(m)); offset = header_size; limit = get_meta_dimensions(z_); // Generate offset table for(ox = 0; ox < limit; ox++) { for(oy = 0; oy < limit; oy++) { int mt = xyz_to_meta_offset(x_ + ox, y_ + oy, z_); offsets[mt].offset = offset; offsets[mt].size = tile[ox][oy].size(); offset += offsets[mt].size; } } file.write((const char *)&offsets, sizeof(offsets)); // Write tiles for(ox = 0; ox < limit; ox++) { for(oy = 0; oy < limit; oy++) { file.write((const char *)tile[ox][oy].data(), tile[ox][oy].size()); } } file.close(); rename(tmp.c_str(), metatile.first.c_str()); }
void item_load(struct item *item, const struct protocol *req) { char path[PATH_MAX]; struct stat buf; xyz_to_meta(path, sizeof(path), HASH_PATH, req->xmlname, req->x, req->y, req->z); if(!stat(path, &buf)) { // save time of old tile item->old_mtime=buf.st_mtime; } else { // no tile item->old_mtime=0; } }
bool disk_storage::expire(const tile_protocol &tile) const { pair<string, int> foo = xyz_to_meta(dir_, tile.x, tile.y, tile.z, tile.style); try { fs::path p(foo.first); if (fs::exists(p)) { // indicate that a tile has expired by setting its time to the // unix epoch. it's not perfect, but things very rarely are. fs::last_write_time(p, std::time_t(0)); return true; } } catch (const fs::filesystem_error &e) { LOG_ERROR(boost::format("Filesystem error: %1%") % e.what()); } return false; }
bool disk_storage::get_meta(const tile_protocol &tile, std::string &data) const { pair<string, int> foo = xyz_to_meta(dir_, tile.x, tile.y, tile.z, tile.style); try { fs::path p(foo.first); if (fs::exists(p) && fs::is_regular_file(p)) { // if its expired we signal as such std::time_t t = fs::last_write_time(p); if(t == 0) return false; uintmax_t size = fs::file_size(p); fs::ifstream in(p); data.resize(size); // ooh, evil. cast away the const... in.read((char *)data.data(), size); return bool(in); } } catch (const fs::filesystem_error &e) { LOG_ERROR(boost::format("Filesystem error: %1%") % e.what()); } return false; }
int read_from_meta(std::string const& tile_dir, int x, int y, int z, std::string const &style, unsigned char* buf, size_t sz, int fmt) { char header[4096]; std::pair<std::string, int> metatile = xyz_to_meta(tile_dir, x, y, z, style); int fd = open(metatile.first.c_str(), O_RDONLY); if(fd < 0) return -1; unsigned pos = 0; while(pos < sizeof(header)) { size_t len = sizeof(header) - pos; int got = read(fd, header + pos, len); if(got < 0) { close(fd); return -2; } else if(got > 0) { pos += got; } else { break; } } // search for the correct format metatile header. size_t n_header = 0; struct meta_layout *m = NULL; do { m = (struct meta_layout *)(header + n_header * metaTile::header_size); if(pos < (n_header + 1) * metaTile::header_size) { LOG_ERROR(boost::format("Meta file %1% too small to contain header") % metatile.first); return -3; } if(memcmp(m->magic, META_MAGIC, strlen(META_MAGIC))) { LOG_WARNING(boost::format("Meta file %1% header magic mismatch") % metatile.first); return -4; } ++n_header; }while(m->fmt != fmt); // Currently this code only works with fixed metatile sizes (due to xyz_to_meta above) if(m->count != (METATILE * METATILE)) { LOG_WARNING(boost::format("Meta file %1% header bad count %2% != %3%") % metatile.first % m->count % (METATILE * METATILE)); return -5; } size_t file_offset = m->index[metatile.second].offset; size_t tile_size = m->index[metatile.second].size; if(lseek(fd, file_offset, SEEK_SET) < 0) { LOG_ERROR(boost::format("Meta file %1% seek error %2%") % metatile.first % m->count); return -6; } if(tile_size > sz) { LOG_WARNING(boost::format("Truncating tile %1% to fit buffer of %1%") % tile_size % sz); tile_size = sz; } pos = 0; while(pos < tile_size) { size_t len = tile_size - pos; int got = read(fd, buf + pos, len); if(got < 0) { close(fd); return -7; } else if(got > 0) { pos += got; } else { break; } } close(fd); return pos; }
int main(int argc, char **argv) { const char *spath = RENDER_SOCKET; int fd; struct sockaddr_un addr; int ret=0; int z; int c; char name[PATH_MAX]; struct timeval start, end; struct timeval start_all, end_all; int num, num_all = 0; const char * mapname = "default"; int verbose = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"socket", 1, 0, 's'}, {"map", 1, 0, 'm'}, {"verbose", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hvs:m:", long_options, &option_index); if (c == -1) break; switch (c) { case 's': /* -s, --socket */ spath = strdup(optarg); break; case 'm': /* -m, --map */ mapname=strdup(optarg); break; case 'v': /* -v, --verbose */ verbose=1; break; case 'h': /* -h, --help */ fprintf(stderr, "Usage: speedtest [OPTION] ...\n"); fprintf(stderr, " -m, --map=MAP render tiles in this map (defaults to '" XMLCONFIG_DEFAULT "')\n"); fprintf(stderr, " -s, --socket=SOCKET unix domain socket name for contacting renderd\n"); return -1; default: fprintf(stderr, "unhandled char '%c'\n", c); break; } } fprintf(stderr, "Rendering client\n"); fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "failed to create unix socket\n"); exit(2); } bzero(&addr, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, spath, sizeof(addr.sun_path)); if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { fprintf(stderr, "socket connect failed for: %s\n", spath); close(fd); exit(3); } // Render something to counter act the startup costs // of obtaining the Postgis table extents printf("Initial startup costs\n"); gettimeofday(&start, NULL); process_loop(fd, 0,0,0,mapname); gettimeofday(&end, NULL); display_rate(start, end, 1); gettimeofday(&start_all, NULL); for (z=minZoom; z<=maxZoom; z++) { double px0 = boundx0; double py0 = boundy1; double px1 = boundx1; double py1 = boundy0; gprj.fromLLtoPixel(px0, py0, z); gprj.fromLLtoPixel(px1, py1, z); int x, xmin, xmax; xmin = (int)(px0/256.0); xmax = (int)(px1/256.0); int y, ymin, ymax; ymin = (int)(py0/256.0); ymax = (int)(py1/256.0); num = (xmax - xmin + 1) * (ymax - ymin + 1); // if (!num) { // printf("No tiles at zoom(%d)\n", z); // continue; // } printf("\nZoom(%d) Now rendering %d tiles\n", z, num); num_all += num; gettimeofday(&start, NULL); for (x=xmin; x<=xmax; x++) { for (y=ymin; y<=ymax; y++) { struct stat s; xyz_to_meta(name, sizeof(name), HASH_PATH, XMLCONFIG_DEFAULT, x, y, z); if (stat(name, &s) < 0) { // File doesn't exist ret = process_loop(fd, x, y, z, mapname); } //printf("."); fflush(NULL); } } //printf("\n"); gettimeofday(&end, NULL); display_rate(start, end, num); } gettimeofday(&end_all, NULL); printf("\nTotal for all tiles rendered\n"); display_rate(start_all, end_all, num_all); close(fd); return ret; }