static int _mapcache_cache_bdb_get(mapcache_context *ctx, mapcache_tile *tile) { DBT key,data; struct bdb_env *benv = _bdb_get_conn(ctx,tile,1); mapcache_cache_bdb *cache = (mapcache_cache_bdb*)tile->tileset->cache; char *skey = mapcache_util_get_tile_key(ctx,tile,cache->key_template,NULL,NULL); if(GC_HAS_ERROR(ctx)) return MAPCACHE_FAILURE; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); data.flags = DB_DBT_MALLOC; key.data = skey; key.size = strlen(skey)+1; int ret = benv->db->get(benv->db, NULL, &key, &data, 0); if(ret == 0) { tile->encoded_data = mapcache_buffer_create(0,ctx->pool); tile->encoded_data->buf = data.data; tile->encoded_data->size = data.size-sizeof(apr_time_t); tile->encoded_data->avail = data.size; apr_pool_cleanup_register(ctx->pool, tile->encoded_data->buf,(void*)free, apr_pool_cleanup_null); tile->mtime = *((apr_time_t*)(&tile->encoded_data->buf[tile->encoded_data->size])); ret = MAPCACHE_SUCCESS; } else if(ret == DB_NOTFOUND) { ret = MAPCACHE_CACHE_MISS; } else { ctx->set_error(ctx,500,"bdb backend failure on tile_get: %s",db_strerror(ret)); ret = MAPCACHE_FAILURE; } _bdb_release_conn(ctx,tile,benv); return ret; }
void _mapcache_source_wms_query(mapcache_context *ctx, mapcache_feature_info *fi) { mapcache_map *map = (mapcache_map*)fi; mapcache_source_wms *wms = (mapcache_source_wms*)map->tileset->source; apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params); apr_table_overlap(params,wms->getmap_params,0); apr_table_setn(params,"BBOX",apr_psprintf(ctx->pool,"%f,%f,%f,%f", map->extent.minx,map->extent.miny,map->extent.maxx,map->extent.maxy)); apr_table_setn(params,"REQUEST","GetFeatureInfo"); apr_table_setn(params,"WIDTH",apr_psprintf(ctx->pool,"%d",map->width)); apr_table_setn(params,"HEIGHT",apr_psprintf(ctx->pool,"%d",map->height)); apr_table_setn(params,"SRS",map->grid_link->grid->srs); apr_table_setn(params,"X",apr_psprintf(ctx->pool,"%d",fi->i)); apr_table_setn(params,"Y",apr_psprintf(ctx->pool,"%d",fi->j)); apr_table_setn(params,"INFO_FORMAT",fi->format); apr_table_overlap(params,wms->getfeatureinfo_params,0); if(map->dimensions && !apr_is_empty_table(map->dimensions)) { const apr_array_header_t *elts = apr_table_elts(map->dimensions); int i; for(i=0; i<elts->nelts; i++) { apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t); apr_table_setn(params,entry.key,entry.val); } } fi->data = mapcache_buffer_create(30000,ctx->pool); mapcache_http_do_request_with_params(ctx,wms->http,params,fi->data,NULL,NULL); GC_CHECK_ERROR(ctx); }
/** * \brief get content of given tile * * fills the mapcache_tile::data of the given tile with content stored on the memcache server * \private \memberof mapcache_cache_memcache * \sa mapcache_cache::tile_get() */ static int _mapcache_cache_memcache_get(mapcache_context *ctx, mapcache_tile *tile) { char *key; int rv; mapcache_cache_memcache *cache = (mapcache_cache_memcache*)tile->tileset->cache; key = mapcache_util_get_tile_key(ctx, tile,NULL," \r\n\t\f\e\a\b","#"); if(GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } tile->encoded_data = mapcache_buffer_create(0,ctx->pool); rv = apr_memcache_getp(cache->memcache,ctx->pool,key,(char**)&tile->encoded_data->buf,&tile->encoded_data->size,NULL); if(rv != APR_SUCCESS) { return MAPCACHE_CACHE_MISS; } if(tile->encoded_data->size == 0) { ctx->set_error(ctx,500,"memcache cache returned 0-length data for tile %d %d %d\n",tile->x,tile->y,tile->z); return MAPCACHE_FAILURE; } /* extract the tile modification time from the end of the data returned */ memcpy( &tile->mtime, &(((char*)tile->encoded_data->buf)[tile->encoded_data->size-sizeof(apr_time_t)]), sizeof(apr_time_t)); ((char*)tile->encoded_data->buf)[tile->encoded_data->size+sizeof(apr_time_t)]='\0'; tile->encoded_data->avail = tile->encoded_data->size; tile->encoded_data->size -= sizeof(apr_time_t); return MAPCACHE_SUCCESS; }
/** * \brief encode an image to RGB(A) PNG format * \private \memberof mapcache_image_format_png * \sa mapcache_image_format::write() */ mapcache_buffer* _mapcache_imageio_png_encode(mapcache_context *ctx, mapcache_image *img, mapcache_image_format *format) { png_infop info_ptr; int color_type; size_t row; mapcache_buffer *buffer = NULL; int compression = ((mapcache_image_format_png*)format)->compression_level; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!png_ptr) { ctx->set_error(ctx, 500, "failed to allocate png_struct structure"); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); ctx->set_error(ctx, 500, "failed to allocate png_info structure"); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { ctx->set_error(ctx, 500, "failed to setjmp(png_jmpbuf(png_ptr))"); png_destroy_write_struct(&png_ptr, &info_ptr); return NULL; } buffer = mapcache_buffer_create(5000,ctx->pool); png_set_write_fn(png_ptr, buffer, _mapcache_imageio_png_write_func, _mapcache_imageio_png_flush_func); if(mapcache_image_has_alpha(img)) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, img->w, img->h, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if(compression == MAPCACHE_COMPRESSION_BEST) png_set_compression_level (png_ptr, Z_BEST_COMPRESSION); else if(compression == MAPCACHE_COMPRESSION_FAST) png_set_compression_level (png_ptr, Z_BEST_SPEED); png_write_info(png_ptr, info_ptr); if(color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 255, PNG_FILLER_AFTER); png_bytep rowptr = img->data; for(row=0;row<img->h;row++) { png_write_row(png_ptr,rowptr); rowptr += img->stride; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return buffer; }
static int _mapcache_cache_sqlite_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache; struct sqlite_conn *conn; sqlite3_stmt *stmt; int ret; mapcache_pooled_connection *pc = mapcache_sqlite_get_conn(ctx,cache,tile,1); if (GC_HAS_ERROR(ctx)) { if(tile->tileset->read_only || !tile->tileset->source) { mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_FAILURE; } else { /* not an error in this case, as the db file may not have been created yet */ ctx->clear_errors(ctx); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_CACHE_MISS; } } conn = SQLITE_CONN(pc); stmt = conn->prepared_statements[GET_TILE_STMT_IDX]; if(!stmt) { sqlite3_prepare(conn->handle, cache->get_stmt.sql, -1, &conn->prepared_statements[GET_TILE_STMT_IDX], NULL); stmt = conn->prepared_statements[GET_TILE_STMT_IDX]; } cache->bind_stmt(ctx, stmt, cache, tile); do { ret = sqlite3_step(stmt); if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_BUSY && ret != SQLITE_LOCKED) { ctx->set_error(ctx, 500, "sqlite backend failed on get: %s", sqlite3_errmsg(conn->handle)); sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_FAILURE; } } while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED); if (ret == SQLITE_DONE) { sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_CACHE_MISS; } else { const void *blob = sqlite3_column_blob(stmt, 0); int size = sqlite3_column_bytes(stmt, 0); if(size>0 && ((char*)blob)[0] == '#') { tile->encoded_data = mapcache_empty_png_decode(ctx,tile->grid_link->grid->tile_sx, tile->grid_link->grid->tile_sy ,blob,&tile->nodata); } else { tile->encoded_data = mapcache_buffer_create(size, ctx->pool); memcpy(tile->encoded_data->buf, blob, size); tile->encoded_data->size = size; } if (sqlite3_column_count(stmt) > 1) { time_t mtime = sqlite3_column_int64(stmt, 1); apr_time_ansi_put(&(tile->mtime), mtime); } sqlite3_reset(stmt); mapcache_sqlite_release_conn(ctx, pc); return MAPCACHE_SUCCESS; } }
/** * \brief push tile data to memcached * * writes the content of mapcache_tile::data to the configured memcached instance(s) * \returns MAPCACHE_FAILURE if there is no data to write, or if the tile isn't locked * \returns MAPCACHE_SUCCESS if the tile has been successfully written * \private \memberof mapcache_cache_memcache * \sa mapcache_cache::tile_set() */ static void _mapcache_cache_memcache_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { char *key; int rv; /* set no expiration if not configured */ int expires =0; mapcache_buffer *encoded_data = NULL; mapcache_cache_memcache *cache = (mapcache_cache_memcache*)pcache; mapcache_pooled_connection *pc; struct mapcache_memcache_pooled_connection *mpc; pc = _mapcache_memcache_get_conn(ctx,cache,tile); GC_CHECK_ERROR(ctx); mpc = pc->connection; key = mapcache_util_get_tile_key(ctx, tile,NULL," \r\n\t\f\e\a\b","#"); if(GC_HAS_ERROR(ctx)) goto cleanup; if(tile->tileset->auto_expire) expires = tile->tileset->auto_expire; if(cache->detect_blank) { if(!tile->raw_image) { tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data); GC_CHECK_ERROR(ctx); } if(mapcache_image_blank_color(tile->raw_image) != MAPCACHE_FALSE) { encoded_data = mapcache_buffer_create(5,ctx->pool); ((char*)encoded_data->buf)[0] = '#'; memcpy(((char*)encoded_data->buf)+1,tile->raw_image->data,4); encoded_data->size = 5; } } if(!encoded_data) { if(!tile->encoded_data) { tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format); if(GC_HAS_ERROR(ctx)) goto cleanup; } encoded_data = tile->encoded_data; } /* concatenate the current time to the end of the memcache data so we can extract it out * when we re-get the tile */ char *data = calloc(1,encoded_data->size+sizeof(apr_time_t)); apr_time_t now = apr_time_now(); apr_pool_cleanup_register(ctx->pool, data, (void*)free, apr_pool_cleanup_null); memcpy(data,encoded_data->buf,encoded_data->size); memcpy(&(data[encoded_data->size]),&now,sizeof(apr_time_t)); rv = apr_memcache_set(mpc->memcache,key,data,encoded_data->size+sizeof(apr_time_t),expires,0); if(rv != APR_SUCCESS) { ctx->set_error(ctx,500,"failed to store tile %d %d %d to memcache cache %s", tile->x,tile->y,tile->z,cache->cache.name); goto cleanup; } cleanup: _mapcache_memcache_release_conn(ctx,pc); }
static int _mapcache_cache_sqlite_get(mapcache_context *ctx, mapcache_tile *tile) { mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*)tile->tileset->cache; sqlite3 *handle; sqlite3_stmt *stmt; int ret; if(cache->hitstats) { handle = _get_conn(ctx,tile,0); } else { handle = _get_conn(ctx,tile,1); } if(GC_HAS_ERROR(ctx)) { sqlite3_close(handle); return MAPCACHE_FAILURE; } sqlite3_prepare(handle,cache->get_stmt.sql,-1,&stmt,NULL); _bind_sqlite_params(ctx,stmt,tile); do { ret = sqlite3_step(stmt); if(ret!=SQLITE_DONE && ret != SQLITE_ROW && ret!=SQLITE_BUSY && ret !=SQLITE_LOCKED) { ctx->set_error(ctx,500,"sqlite backend failed on get: %s",sqlite3_errmsg(handle)); sqlite3_finalize(stmt); sqlite3_close(handle); return MAPCACHE_FAILURE; } } while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED); if(ret == SQLITE_DONE) { sqlite3_finalize(stmt); sqlite3_close(handle); return MAPCACHE_CACHE_MISS; } else { const void *blob = sqlite3_column_blob(stmt,0); int size = sqlite3_column_bytes(stmt, 0); tile->encoded_data = mapcache_buffer_create(size,ctx->pool); memcpy(tile->encoded_data->buf, blob,size); tile->encoded_data->size = size; if(sqlite3_column_count(stmt) > 1) { time_t mtime = sqlite3_column_int64(stmt, 1); apr_time_ansi_put(&(tile->mtime),mtime); } sqlite3_finalize(stmt); /* update the hitstats if we're configured for that */ if(cache->hitstats) { sqlite3_stmt *hitstmt; sqlite3_prepare(handle,cache->hitstat_stmt.sql,-1,&hitstmt,NULL); _bind_sqlite_params(ctx,stmt,tile); sqlite3_step(hitstmt); /* we ignore the return value , TODO?*/ sqlite3_finalize(hitstmt); } sqlite3_close(handle); return MAPCACHE_SUCCESS; } }
/** * \brief get content of given tile * * fills the mapcache_tile::data of the given tile with content stored on the couchbase server * \private \memberof mapcache_cache_couchbase * \sa mapcache_cache::tile_get() */ static int _mapcache_cache_couchbase_get(mapcache_context *ctx, mapcache_tile *tile) { char *key[1]; size_t keySize[1]; libcouchbase_t *instance; libcouchbase_error_t error; getStruct_t request; key[0] = mapcache_util_get_tile_key(ctx, tile, NULL, " \r\n\t\f\e\a\b", "#"); if(GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } keySize[0] = strlen(key[0]); tile->encoded_data = mapcache_buffer_create(0, ctx->pool); libcouchbase_time_t expires = 86400; if(tile->tileset->auto_expire) expires = tile->tileset->auto_expire; instance = _couchbase_get_connection(ctx, tile); if (GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } request.tileBuffer = tile->encoded_data; error = libcouchbase_mget(*instance, &request, 1, (const void * const*)key, keySize, &expires); if (error != LIBCOUCHBASE_SUCCESS) { ctx->set_error(ctx, 500, "couchbase cache returned error on mget %s", libcouchbase_strerror(*instance, error)); _couchbase_invalidate_connection(tile, instance); return MAPCACHE_FAILURE; } libcouchbase_wait(*instance); if(request.error != LIBCOUCHBASE_SUCCESS) { _couchbase_release_connection(tile, instance); return MAPCACHE_CACHE_MISS; } if (tile->encoded_data->size == 0) { _couchbase_release_connection(tile, instance); ctx->set_error(ctx, 500, "couchbase cache returned 0-length data for tile %d %d %d", tile->x, tile->y, tile->z); return MAPCACHE_FAILURE; } apr_time_t now = apr_time_now(); tile->mtime = now; _couchbase_release_connection(tile, instance); return MAPCACHE_SUCCESS; }
/** * \brief get content of given tile * * fills the mapcache_tile::data of the given tile with content stored on the memcache server * \private \memberof mapcache_cache_memcache * \sa mapcache_cache::tile_get() */ static int _mapcache_cache_memcache_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { char *key; int rv; mapcache_cache_memcache *cache = (mapcache_cache_memcache*)pcache; mapcache_pooled_connection *pc; mapcache_buffer *encoded_data; struct mapcache_memcache_pooled_connection *mpc; pc = _mapcache_memcache_get_conn(ctx,cache,tile); if(GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } mpc = pc->connection; key = mapcache_util_get_tile_key(ctx, tile,NULL," \r\n\t\f\e\a\b","#"); if(GC_HAS_ERROR(ctx)) { rv = MAPCACHE_FAILURE; goto cleanup; } encoded_data = mapcache_buffer_create(0,ctx->pool); rv = apr_memcache_getp(mpc->memcache,ctx->pool,key,(char**)&encoded_data->buf,&encoded_data->size,NULL); if(rv != APR_SUCCESS) { rv = MAPCACHE_CACHE_MISS; goto cleanup; } if(encoded_data->size == 0) { ctx->set_error(ctx,500,"memcache cache returned 0-length data for tile %d %d %d\n",tile->x,tile->y,tile->z); rv = MAPCACHE_FAILURE; goto cleanup; } /* extract the tile modification time from the end of the data returned */ memcpy( &tile->mtime, &(((char*)encoded_data->buf)[encoded_data->size-sizeof(apr_time_t)]), sizeof(apr_time_t)); ((char*)encoded_data->buf)[encoded_data->size+sizeof(apr_time_t)]='\0'; encoded_data->avail = encoded_data->size; encoded_data->size -= sizeof(apr_time_t); if(((char*)encoded_data->buf)[0] == '#' && encoded_data->size > 1) { tile->encoded_data = mapcache_empty_png_decode(ctx,tile->grid_link->grid->tile_sx, tile->grid_link->grid->tile_sy ,encoded_data->buf,&tile->nodata); } else { tile->encoded_data = encoded_data; } rv = MAPCACHE_SUCCESS; cleanup: _mapcache_memcache_release_conn(ctx,pc); return rv; }
/** * \private \memberof mapcache_source_wms * \sa mapcache_source::render_map() */ void _mapcache_source_wms_render_map(mapcache_context *ctx, mapcache_map *map) { mapcache_source_wms *wms = (mapcache_source_wms*)map->tileset->source; mapcache_http *http; apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params); apr_table_setn(params,"BBOX",apr_psprintf(ctx->pool,"%f,%f,%f,%f", map->extent.minx,map->extent.miny,map->extent.maxx,map->extent.maxy)); apr_table_setn(params,"WIDTH",apr_psprintf(ctx->pool,"%d",map->width)); apr_table_setn(params,"HEIGHT",apr_psprintf(ctx->pool,"%d",map->height)); apr_table_setn(params,"FORMAT","image/png"); apr_table_setn(params,"SRS",map->grid_link->grid->srs); apr_table_overlap(params,wms->getmap_params,APR_OVERLAP_TABLES_SET); if(map->dimensions && !apr_is_empty_table(map->dimensions)) { const apr_array_header_t *elts = apr_table_elts(map->dimensions); int i; for(i=0; i<elts->nelts; i++) { apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t); /* set both DIM_key=val and key=val KVP params */ apr_table_setn(params,entry.key,entry.val); if(strcasecmp(entry.key,"TIME") && strcasecmp(entry.key,"ELEVATION")) { char *dim_name = apr_pstrcat(ctx->pool,"DIM_",entry.key,NULL); apr_table_setn(params,dim_name,entry.val); } } } /* if the source has no LAYERS parameter defined, then use the tileset name * as the LAYERS to request. When using mirror-mode, the source has no layers * defined, it is added based on the incoming request */ if(!apr_table_get(params,"layers")) { apr_table_set(params,"LAYERS",map->tileset->name); } map->encoded_data = mapcache_buffer_create(30000,ctx->pool); http = mapcache_http_clone(ctx, wms->http); http->url = mapcache_http_build_url(ctx,http->url,params); mapcache_http_do_request(ctx,http,map->encoded_data,NULL,NULL); GC_CHECK_ERROR(ctx); if(!mapcache_imageio_is_valid_format(ctx,map->encoded_data)) { char *returned_data = apr_pstrndup(ctx->pool,(char*)map->encoded_data->buf,map->encoded_data->size); ctx->set_error(ctx, 502, "wms request for tileset %s returned an unsupported format:\n%s", map->tileset->name, returned_data); } }
//------------------------------------------------------------------------------ void _mapcache_source_tms_render_map_elevation(mapcache_context *ctx, mapcache_map *map) { mapcache_source_tms *tms; int elevationblock; int zoom, x, y; char* url; double dx, dy; tms = (mapcache_source_tms*)map->tileset->source; elevationblock = map->grid_link->grid->elevationblock; _GetTileCoords(map, &zoom, &x, &y, tms->flipy); url = apr_psprintf(ctx->pool,"%s/1.0.0/%s/%i/%i/%i.%s", tms->url,tms->layer,zoom,x,y,tms->format); tms->http->url = apr_pstrdup(ctx->pool,url); map->encoded_data = mapcache_buffer_create(30000,ctx->pool); mapcache_http_do_request(ctx, tms->http, map->encoded_data, NULL, NULL); GC_CHECK_ERROR(ctx); if(!mapcache_imageio_is_valid_format(ctx,map->encoded_data)) { char *returned_data = apr_pstrndup(ctx->pool,(char*)map->encoded_data->buf,map->encoded_data->size); ctx->set_error(ctx, 502, "tms request for tileset %s returned an unsupported format:\n%s", map->tileset->name, returned_data); return; } map->raw_image = mapcache_imageio_decode(ctx, map->encoded_data); map->raw_image->is_elevation = MC_ELEVATION_YES; GC_CHECK_ERROR(ctx); //map->raw_image->stride = 4 * elevationblock; dx = fabs(map->grid_link->grid->extent.maxx-map->grid_link->grid->extent.minx); dy = fabs(map->grid_link->grid->extent.maxx-map->grid_link->grid->extent.minx); map->raw_image->x0 = map->extent.minx / dx * 2.0; map->raw_image->y0 = map->extent.miny / dy * 2.0; map->raw_image->x1 = map->extent.maxx / dx * 2.0; map->raw_image->y1 = map->extent.maxy / dy * 2.0; if (map->raw_image->w != elevationblock || map->raw_image->h != elevationblock) { ctx->set_error(ctx,500,"Error: size of heightmap from source is not configured propery!"); } }
//------------------------------------------------------------------------------ void _mapcache_source_tms_render_map_image(mapcache_context *ctx, mapcache_map *map) { int zoom, x, y; mapcache_source_tms *tms; char* url; tms = (mapcache_source_tms*)map->tileset->source; _GetTileCoords(map, &zoom, &x, &y, tms->flipy); url = apr_psprintf(ctx->pool,"%s/1.0.0/%s/%i/%i/%i.%s", tms->url,tms->layer,zoom,x,y,tms->format); tms->http->url = apr_pstrdup(ctx->pool,url); map->encoded_data = mapcache_buffer_create(30000,ctx->pool); mapcache_http_do_request(ctx, tms->http, map->encoded_data, NULL, NULL); GC_CHECK_ERROR(ctx); if(!mapcache_imageio_is_valid_format(ctx,map->encoded_data)) { char *returned_data = apr_pstrndup(ctx->pool,(char*)map->encoded_data->buf,map->encoded_data->size); ctx->set_error(ctx, 502, "tms request for tileset %s returned an unsupported format:\n%s", map->tileset->name, returned_data); } }
static int _mapcache_cache_tc_get(mapcache_context *ctx, mapcache_tile *tile) { int ret; struct tc_conn conn; mapcache_cache_tc *cache = (mapcache_cache_tc*)tile->tileset->cache; char *skey = mapcache_util_get_tile_key(ctx,tile,cache->key_template,NULL,NULL); conn = _tc_get_conn(ctx,tile,1); int size; if(GC_HAS_ERROR(ctx)) return MAPCACHE_FAILURE; tile->encoded_data = mapcache_buffer_create(0,ctx->pool); tile->encoded_data->buf = tcbdbget(conn.bdb, skey, strlen(skey), &size); if(tile->encoded_data->buf) { tile->encoded_data->avail = size; tile->encoded_data->size = size - sizeof(apr_time_t); apr_pool_cleanup_register(ctx->pool, tile->encoded_data->buf,(void*)free, apr_pool_cleanup_null); tile->mtime = *((apr_time_t*)(&tile->encoded_data->buf[tile->encoded_data->size])); ret = MAPCACHE_SUCCESS; } else { ret = MAPCACHE_CACHE_MISS; } _tc_release_conn(ctx,tile,conn); return ret; }
mapcache_http_response *mapcache_core_proxy_request(mapcache_context *ctx, mapcache_request_proxy *req_proxy) { mapcache_http *http; mapcache_http_response *response = mapcache_http_response_create(ctx->pool); response->data = mapcache_buffer_create(30000,ctx->pool); http = req_proxy->http; if(req_proxy->pathinfo) { http = mapcache_http_clone(ctx,http); if( (*(req_proxy->pathinfo)) == '/' || http->url[strlen(http->url)-1] == '/') http->url = apr_pstrcat(ctx->pool,http->url,req_proxy->pathinfo,NULL); else http->url = apr_pstrcat(ctx->pool,http->url,"/",req_proxy->pathinfo,NULL); } mapcache_http_do_request_with_params(ctx,http,req_proxy->params,response->data,response->headers,&response->code); if(response->code !=0 && GC_HAS_ERROR(ctx)) { /* the http request was successful, but the server returned an error */ ctx->clear_errors(ctx); } /*remove some headers that should not be sent back to the client*/ apr_table_unset(response->headers,"Transfer-Encoding"); apr_table_unset(response->headers,"Connection"); return response; }
/** * \brief get content of given tile * * fills the mapcache_tile::data of the given tile with content stored on the riak server * \private \memberof mapcache_cache_riak * \sa mapcache_cache::tile_get() */ static int _mapcache_cache_riak_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { int error; int connect_error = RIACK_SUCCESS; int retries = 3; RIACK_STRING key; struct RIACK_GET_OBJECT obj; struct RIACK_GET_PROPERTIES properties; struct RIACK_CLIENT *client; mapcache_pooled_connection *pc; mapcache_cache_riak *cache = (mapcache_cache_riak*)pcache; memset(&properties, 0, sizeof(struct RIACK_GET_PROPERTIES)); //Use Buckets defaults instead of setting the read/write attributes /* properties.r_use = 1; properties.r = 1; */ key.value = mapcache_util_get_tile_key(ctx, tile, NULL, " \r\n\t\f\e\a\b", "#"); if (GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } key.len = strlen(key.value); tile->encoded_data = mapcache_buffer_create(0, ctx->pool); pc = _riak_get_connection(ctx, cache, tile); if (GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } client = pc->connection; // If we get an error it is advised that we call reconnect. It also appears // that every now and then we get an error and need to retry once again to // get it to work. do { error = riack_get(client, cache->bucket, key, &properties, &obj); if (error != RIACK_SUCCESS) { ctx->log(ctx, MAPCACHE_WARN, "Retry %d in riak_get for tile %s from cache %s due to error %d", (4-retries), key.value, cache->cache.name, error); for (connect_error = riack_reconnect(client); connect_error != RIACK_SUCCESS && retries > 0; connect_error = riack_reconnect(client)) { --retries; } --retries; } } while (error != RIACK_SUCCESS && retries >= 0); if (error != RIACK_SUCCESS) { if (connect_error != RIACK_SUCCESS) mapcache_connection_pool_invalidate_connection(ctx,pc); else mapcache_connection_pool_release_connection(ctx,pc); ctx->set_error(ctx, 500, "Failed to get tile %s from cache %s due to error %d", key.value, cache->cache.name, error); return MAPCACHE_FAILURE; } // Check if tile exists. If it doesn't we need to return CACHE_MISS or things go wrong. // Mapcache doesn't appear to use the has_tile function and uses _get instead so we need // to do this sort of test here instead of erroring. if (obj.object.content_count < 1 || obj.object.content[0].data_len == 0) { riack_free_get_object(client, &obj); // Need to free the object here as well. mapcache_connection_pool_release_connection(ctx,pc); return MAPCACHE_CACHE_MISS; } // Copy the data into the buffer mapcache_buffer_append(tile->encoded_data, obj.object.content[0].data_len, obj.object.content[0].data); riack_free_get_object(client, &obj); // riack_get allocates the returned object so we need to deallocate it. mapcache_connection_pool_release_connection(ctx,pc); return MAPCACHE_SUCCESS; }
/** * \private \memberof mapcache_source_gdal * \sa mapcache_source::render_metatile() */ void _mapcache_source_gdal_render_metatile(mapcache_context *ctx, mapcache_metatile *tile) { mapcache_source_gdal *gdal = (mapcache_source_gdal*)tile->tile.tileset->source; char *srcSRS = "", *dstSRS; mapcache_buffer *data = mapcache_buffer_create(0,ctx->pool); GC_CHECK_ERROR(ctx); GDALDatasetH hDataset; GDALAllRegister(); OGRSpatialReferenceH hSRS; CPLErrorReset(); hSRS = OSRNewSpatialReference( NULL ); if( OSRSetFromUserInput( hSRS, tile->tile.grid->srs ) == OGRERR_NONE ) OSRExportToWkt( hSRS, &dstSRS ); else { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"failed to parse gdal srs %s",tile->tile.grid->srs); return; } OSRDestroySpatialReference( hSRS ); hDataset = GDALOpen( gdal->datastr, GA_ReadOnly ); if( hDataset == NULL ) { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"GDAL failed to open %s",gdal->datastr); return; } /* -------------------------------------------------------------------- */ /* Check that there's at least one raster band */ /* -------------------------------------------------------------------- */ if ( GDALGetRasterCount(hDataset) == 0 ) { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"raster %s has no bands",gdal->datastr); return; } if( GDALGetProjectionRef( hDataset ) != NULL && strlen(GDALGetProjectionRef( hDataset )) > 0 ) srcSRS = apr_pstrdup(ctx->pool,GDALGetProjectionRef( hDataset )); else if( GDALGetGCPProjection( hDataset ) != NULL && strlen(GDALGetGCPProjection(hDataset)) > 0 && GDALGetGCPCount( hDataset ) > 1 ) srcSRS = apr_pstrdup(ctx->pool,GDALGetGCPProjection( hDataset )); GDALDriverH hDriver = GDALGetDriverByName( "MEM" ); GDALDatasetH hDstDS; /* -------------------------------------------------------------------- */ /* Create a transformation object from the source to */ /* destination coordinate system. */ /* -------------------------------------------------------------------- */ void *hTransformArg = GDALCreateGenImgProjTransformer( hDataset, srcSRS, NULL, dstSRS, TRUE, 1000.0, 0 ); if( hTransformArg == NULL ) { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"gdal failed to create SRS transformation object"); return; } /* -------------------------------------------------------------------- */ /* Get approximate output definition. */ /* -------------------------------------------------------------------- */ int nPixels, nLines; double adfDstGeoTransform[6]; if( GDALSuggestedWarpOutput( hDataset, GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines ) != CE_None ) { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"gdal failed to create suggested warp output"); return; } GDALDestroyGenImgProjTransformer( hTransformArg ); double dfXRes = (tile->bbox[2] - tile->bbox[0]) / tile->sx; double dfYRes = (tile->bbox[3] - tile->bbox[1]) / tile->sy; adfDstGeoTransform[0] = tile->bbox[0]; adfDstGeoTransform[3] = tile->bbox[3]; adfDstGeoTransform[1] = dfXRes; adfDstGeoTransform[5] = -dfYRes; hDstDS = GDALCreate( hDriver, "tempd_gdal_image", tile->sx, tile->sy, 4, GDT_Byte, NULL ); /* -------------------------------------------------------------------- */ /* Write out the projection definition. */ /* -------------------------------------------------------------------- */ GDALSetProjection( hDstDS, dstSRS ); GDALSetGeoTransform( hDstDS, adfDstGeoTransform ); char **papszWarpOptions = NULL; papszWarpOptions = CSLSetNameValue( papszWarpOptions, "INIT", "0" ); /* -------------------------------------------------------------------- */ /* Create a transformation object from the source to */ /* destination coordinate system. */ /* -------------------------------------------------------------------- */ GDALTransformerFunc pfnTransformer = NULL; void *hGenImgProjArg=NULL, *hApproxArg=NULL; hTransformArg = hGenImgProjArg = GDALCreateGenImgProjTransformer( hDataset, srcSRS, hDstDS, dstSRS, TRUE, 1000.0, 0 ); if( hTransformArg == NULL ) exit( 1 ); pfnTransformer = GDALGenImgProjTransform; hTransformArg = hApproxArg = GDALCreateApproxTransformer( GDALGenImgProjTransform, hGenImgProjArg, 0.125 ); pfnTransformer = GDALApproxTransform; /* -------------------------------------------------------------------- */ /* Now actually invoke the warper to do the work. */ /* -------------------------------------------------------------------- */ GDALSimpleImageWarp( hDataset, hDstDS, 0, NULL, pfnTransformer, hTransformArg, GDALDummyProgress, NULL, papszWarpOptions ); CSLDestroy( papszWarpOptions ); if( hApproxArg != NULL ) GDALDestroyApproxTransformer( hApproxArg ); if( hGenImgProjArg != NULL ) GDALDestroyGenImgProjTransformer( hGenImgProjArg ); if(GDALGetRasterCount(hDstDS) != 4) { ctx->set_error(ctx,MAPCACHE_SOURCE_GDAL_ERROR,"gdal did not create a 4 band image"); return; } GDALRasterBandH *redband, *greenband, *blueband, *alphaband; redband = GDALGetRasterBand(hDstDS,1); greenband = GDALGetRasterBand(hDstDS,2); blueband = GDALGetRasterBand(hDstDS,3); alphaband = GDALGetRasterBand(hDstDS,4); unsigned char *rasterdata = apr_palloc(ctx->pool,tile->sx*tile->sy*4); data->buf = rasterdata; data->avail = tile->sx*tile->sy*4; data->size = tile->sx*tile->sy*4; GDALRasterIO(redband,GF_Read,0,0,tile->sx,tile->sy,(void*)(rasterdata),tile->sx,tile->sy,GDT_Byte,4,4*tile->sx); GDALRasterIO(greenband,GF_Read,0,0,tile->sx,tile->sy,(void*)(rasterdata+1),tile->sx,tile->sy,GDT_Byte,4,4*tile->sx); GDALRasterIO(blueband,GF_Read,0,0,tile->sx,tile->sy,(void*)(rasterdata+2),tile->sx,tile->sy,GDT_Byte,4,4*tile->sx); if(GDALGetRasterCount(hDataset)==4) GDALRasterIO(alphaband,GF_Read,0,0,tile->sx,tile->sy,(void*)(rasterdata+3),tile->sx,tile->sy,GDT_Byte,4,4*tile->sx); else { unsigned char *alphaptr; int i; for(alphaptr = rasterdata+3, i=0; i<tile->sx*tile->sy; i++, alphaptr+=4) { *alphaptr = 255; } } tile->imdata = mapcache_image_create(ctx); tile->imdata->w = tile->sx; tile->imdata->h = tile->sy; tile->imdata->stride = tile->sx * 4; tile->imdata->data = rasterdata; GDALClose( hDstDS ); GDALClose( hDataset); }
/** * \brief get file content of given tile * * fills the mapcache_tile::data of the given tile with content stored in the file * \private \memberof mapcache_cache_disk * \sa mapcache_cache::tile_get() */ static int _mapcache_cache_disk_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile) { char *filename; apr_file_t *f; apr_finfo_t finfo; apr_status_t rv; apr_size_t size; apr_mmap_t *tilemmap; mapcache_cache_disk *cache = (mapcache_cache_disk*)pcache; cache->tile_key(ctx, cache, tile, &filename); if(GC_HAS_ERROR(ctx)) { return MAPCACHE_FAILURE; } ctx->log(ctx,MAPCACHE_DEBUG,"checking for tile %s",filename); if((rv=apr_file_open(&f, filename, #ifndef NOMMAP APR_FOPEN_READ, APR_UREAD | APR_GREAD, #else APR_FOPEN_READ|APR_FOPEN_BUFFERED|APR_FOPEN_BINARY,APR_OS_DEFAULT, #endif ctx->pool)) == APR_SUCCESS) { rv = apr_file_info_get(&finfo, APR_FINFO_SIZE|APR_FINFO_MTIME, f); if(!finfo.size) { ctx->set_error(ctx, 500, "tile %s has no data",filename); return MAPCACHE_FAILURE; } size = finfo.size; /* * at this stage, we have a handle to an open file that contains data. * idealy, we should aquire a read lock, in case the data contained inside the file * is incomplete (i.e. if another process is currently writing to the tile). * currently such a lock is not set, as we don't want to loose performance on tile accesses. * any error that might happen at this stage should only occur if the tile isn't already cached, * i.e. normally only once. */ tile->mtime = finfo.mtime; tile->encoded_data = mapcache_buffer_create(size,ctx->pool); #ifndef NOMMAP rv = apr_mmap_create(&tilemmap,f,0,finfo.size,APR_MMAP_READ,ctx->pool); if(rv != APR_SUCCESS) { char errmsg[120]; ctx->set_error(ctx, 500, "mmap error: %s",apr_strerror(rv,errmsg,120)); return MAPCACHE_FAILURE; } tile->encoded_data->buf = tilemmap->mm; tile->encoded_data->size = tile->encoded_data->avail = finfo.size; #else //manually add the data to our buffer apr_file_read(f,(void*)tile->encoded_data->buf,&size); tile->encoded_data->size = size; tile->encoded_data->avail = size; #endif apr_file_close(f); if(tile->encoded_data->size != finfo.size) { ctx->set_error(ctx, 500, "failed to copy image data, got %d of %d bytes",(int)size, (int)finfo.size); return MAPCACHE_FAILURE; } return MAPCACHE_SUCCESS; } else { if(APR_STATUS_IS_ENOENT(rv)) { /* the file doesn't exist on the disk */ return MAPCACHE_CACHE_MISS; } else { char *error = strerror(rv); ctx->set_error(ctx, 500, "failed to open file %s: %s",filename, error); return MAPCACHE_FAILURE; } } }