Skip to content

Commit 60e3633

Browse files
committed
Add fallback source type to handle errors
1 parent 26916de commit 60e3633

File tree

9 files changed

+221
-21
lines changed

9 files changed

+221
-21
lines changed

include/mapcache.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ typedef enum {
265265
MAPCACHE_SOURCE_WMS,
266266
MAPCACHE_SOURCE_MAPSERVER,
267267
MAPCACHE_SOURCE_DUMMY,
268-
MAPCACHE_SOURCE_GDAL
268+
MAPCACHE_SOURCE_GDAL,
269+
MAPCACHE_SOURCE_FALLBACK
269270
} mapcache_source_type;
270271

271272
/**\interface mapcache_source
@@ -285,11 +286,11 @@ struct mapcache_source {
285286
*
286287
* sets the mapcache_metatile::tile::data for the given tile
287288
*/
288-
void (*_render_map)(mapcache_context *ctx, mapcache_map *map);
289+
void (*_render_map)(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map);
289290

290-
void (*query_info)(mapcache_context *ctx, mapcache_feature_info *fi);
291+
void (*_query_info)(mapcache_context *ctx, mapcache_source *psource, mapcache_feature_info *fi);
291292

292-
void (*configuration_parse_xml)(mapcache_context *ctx, ezxml_t xml, mapcache_source * source);
293+
void (*configuration_parse_xml)(mapcache_context *ctx, ezxml_t xml, mapcache_source * source, mapcache_cfg *config);
293294
void (*configuration_check)(mapcache_context *ctx, mapcache_cfg *cfg, mapcache_source * source);
294295
};
295296

@@ -907,12 +908,19 @@ void mapcache_source_init(mapcache_context *ctx, mapcache_source *source);
907908
* \memberof mapcache_source
908909
*/
909910
void mapcache_source_render_map(mapcache_context *ctx, mapcache_source *source, mapcache_map *map);
911+
void mapcache_source_query_info(mapcache_context *ctx, mapcache_source *source,
912+
mapcache_feature_info *fi);
910913

911914
/**
912915
* \memberof mapcache_source_gdal
913916
*/
914917
mapcache_source* mapcache_source_gdal_create(mapcache_context *ctx);
915918

919+
/**
920+
* \memberof mapcache_source_fallback
921+
*/
922+
mapcache_source* mapcache_source_fallback_create(mapcache_context *ctx);
923+
916924
/**
917925
* \memberof mapcache_source_wms
918926
*/

lib/configuration_xml.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ void parseSource(mapcache_context *ctx, ezxml_t node, mapcache_cfg *config)
342342
source = mapcache_source_gdal_create(ctx);
343343
} else if(!strcmp(type,"dummy")) {
344344
source = mapcache_source_dummy_create(ctx);
345+
} else if(!strcmp(type,"fallback")) {
346+
source = mapcache_source_fallback_create(ctx);
345347
} else {
346348
ctx->set_error(ctx, 400, "unknown source type %s for source \"%s\"", type, name);
347349
return;
@@ -371,7 +373,7 @@ void parseSource(mapcache_context *ctx, ezxml_t node, mapcache_cfg *config)
371373
}
372374
}
373375

374-
source->configuration_parse_xml(ctx,node,source);
376+
source->configuration_parse_xml(ctx,node,source, config);
375377
GC_CHECK_ERROR(ctx);
376378
source->configuration_check(ctx,config,source);
377379
GC_CHECK_ERROR(ctx);

lib/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ mapcache_http_response *mapcache_core_get_featureinfo(mapcache_context *ctx,
579579
ctx->set_error(ctx,404, "unsupported feature info format %s",fi->format);
580580
return NULL;
581581
}
582-
tileset->source->query_info(ctx,fi);
582+
mapcache_source_query_info(ctx, tileset->source, fi);
583583
if(GC_HAS_ERROR(ctx)) return NULL;
584584
response = mapcache_http_response_create(ctx->pool);
585585
response->data = fi->data;

lib/source.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,32 @@ void mapcache_source_render_map(mapcache_context *ctx, mapcache_source *source,
6262
apr_sleep((int)(wait*1000000)); /* apr_sleep expects microseconds */
6363
}
6464
}
65-
source->_render_map(ctx,map);
65+
source->_render_map(ctx, source, map);
66+
if(!GC_HAS_ERROR(ctx))
67+
break;
68+
}
69+
}
70+
71+
void mapcache_source_query_info(mapcache_context *ctx, mapcache_source *source, mapcache_feature_info *fi) {
72+
int i;
73+
#ifdef DEBUG
74+
ctx->log(ctx, MAPCACHE_DEBUG, "calling query_info on source (%s): tileset=%s, grid=%s,",
75+
source->name, fi->map.tileset->name, fi->map.grid_link->grid->name);
76+
#endif
77+
for(i=0;i<=source->retry_count;i++) {
78+
if(i) { /* not our first try */
79+
ctx->log(ctx, MAPCACHE_INFO, "source (%s) render_map retry %d of %d. previous try returned error: %s",
80+
source->name, i, source->retry_count, ctx->get_error_message(ctx));
81+
ctx->clear_errors(ctx);
82+
if(source->retry_delay > 0) {
83+
double wait = source->retry_delay;
84+
int j = 0;
85+
for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
86+
wait *= 2;
87+
apr_sleep((int)(wait*1000000)); /* apr_sleep expects microseconds */
88+
}
89+
}
90+
source->_query_info(ctx, source, fi);
6691
if(!GC_HAS_ERROR(ctx))
6792
break;
6893
}

lib/source_dummy.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct mapcache_source_dummy {
4444
* \private \memberof mapcache_source_dummy
4545
* \sa mapcache_source::render_map()
4646
*/
47-
void _mapcache_source_dummy_render_map(mapcache_context *ctx, mapcache_map *map)
47+
void _mapcache_source_dummy_render_map(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
4848
{
4949
map->raw_image = mapcache_image_create(ctx);
5050
map->raw_image->w = map->width;
@@ -55,7 +55,7 @@ void _mapcache_source_dummy_render_map(mapcache_context *ctx, mapcache_map *map)
5555
apr_pool_cleanup_register(ctx->pool, map->raw_image->data,(void*)free, apr_pool_cleanup_null);
5656
}
5757

58-
void _mapcache_source_dummy_query(mapcache_context *ctx, mapcache_feature_info *fi)
58+
void _mapcache_source_dummy_query(mapcache_context *ctx, mapcache_source *psource, mapcache_feature_info *fi)
5959
{
6060
ctx->set_error(ctx,500,"dummy source does not support queries");
6161
}
@@ -64,7 +64,7 @@ void _mapcache_source_dummy_query(mapcache_context *ctx, mapcache_feature_info *
6464
* \private \memberof mapcache_source_dummy
6565
* \sa mapcache_source::configuration_parse()
6666
*/
67-
void _mapcache_source_dummy_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *source)
67+
void _mapcache_source_dummy_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *source, mapcache_cfg *config)
6868
{
6969
}
7070

@@ -89,7 +89,7 @@ mapcache_source* mapcache_source_dummy_create(mapcache_context *ctx)
8989
source->source._render_map = _mapcache_source_dummy_render_map;
9090
source->source.configuration_check = _mapcache_source_dummy_configuration_check;
9191
source->source.configuration_parse_xml = _mapcache_source_dummy_configuration_parse_xml;
92-
source->source.query_info = _mapcache_source_dummy_query;
92+
source->source._query_info = _mapcache_source_dummy_query;
9393
return (mapcache_source*)source;
9494
}
9595

lib/source_fallback.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/******************************************************************************
2+
* $Id$
3+
*
4+
* Project: MapServer
5+
* Purpose: MapCache tile caching support file: Mapserver Mapfile datasource
6+
* Author: Thomas Bonfort and the MapServer team.
7+
*
8+
******************************************************************************
9+
* Copyright (c) 1996-2011 Regents of the University of Minnesota.
10+
*
11+
* Permission is hereby granted, free of charge, to any person obtaining a
12+
* copy of this software and associated documentation files (the "Software"),
13+
* to deal in the Software without restriction, including without limitation
14+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
15+
* and/or sell copies of the Software, and to permit persons to whom the
16+
* Software is furnished to do so, subject to the following conditions:
17+
*
18+
* The above copyright notice and this permission notice shall be included in
19+
* all copies of this Software or works derived from this Software.
20+
*
21+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27+
* DEALINGS IN THE SOFTWARE.
28+
*****************************************************************************/
29+
30+
31+
#include "mapcache.h"
32+
#include "ezxml.h"
33+
#include <apr_tables.h>
34+
#include <apr_strings.h>
35+
36+
typedef struct mapcache_source_fallback mapcache_source_fallback;
37+
struct mapcache_source_fallback {
38+
mapcache_source source;
39+
apr_array_header_t *sources;
40+
};
41+
42+
/**
43+
* \private \memberof mapcache_source_fallback
44+
* \sa mapcache_source::render_map()
45+
*/
46+
void _mapcache_source_fallback_render_map(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
47+
{
48+
mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
49+
mapcache_source *subsource;
50+
int i;
51+
subsource = APR_ARRAY_IDX(source->sources,0,mapcache_source*);
52+
mapcache_source_render_map(ctx, subsource, map);
53+
54+
if(GC_HAS_ERROR(ctx)) {
55+
int first_error = ctx->get_error(ctx);
56+
char *first_error_message = ctx->get_error_message(ctx);
57+
ctx->log(ctx,MAPCACHE_INFO,
58+
"failed render on primary source \"%s\" on tileset \"%s\". Falling back on secondary sources",
59+
subsource->name,map->tileset->name);
60+
ctx->clear_errors(ctx);
61+
for(i=1; i<source->sources->nelts; i++) {
62+
subsource = APR_ARRAY_IDX(source->sources,i,mapcache_source*);
63+
mapcache_source_render_map(ctx, subsource, map);
64+
if(GC_HAS_ERROR(ctx)) {
65+
ctx->log(ctx,MAPCACHE_INFO,
66+
"failed render on fallback source \"%s\" of tileset \"%s\". Continuing with other fallback sources if available",
67+
subsource->name,map->tileset->name);
68+
ctx->clear_errors(ctx);
69+
continue;
70+
} else {
71+
return;
72+
}
73+
}
74+
/* all backends failed, return primary error message */
75+
ctx->set_error(ctx,first_error,first_error_message);
76+
return;
77+
}
78+
}
79+
80+
void _mapcache_source_fallback_query(mapcache_context *ctx, mapcache_source *psource, mapcache_feature_info *fi)
81+
{
82+
mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
83+
mapcache_source *subsource;
84+
int i;
85+
subsource = APR_ARRAY_IDX(source->sources,0,mapcache_source*);
86+
mapcache_source_query_info(ctx, subsource, fi);
87+
88+
if(GC_HAS_ERROR(ctx)) {
89+
int first_error = ctx->get_error(ctx);
90+
char *first_error_message = ctx->get_error_message(ctx);
91+
ctx->log(ctx,MAPCACHE_INFO,
92+
"failed query_info on primary source \"%s\" on tileset \"%s\". Falling back on secondary sources",
93+
subsource->name,fi->map.tileset->name);
94+
ctx->clear_errors(ctx);
95+
for(i=1; i<source->sources->nelts; i++) {
96+
subsource = APR_ARRAY_IDX(source->sources,i,mapcache_source*);
97+
mapcache_source_query_info(ctx, subsource, fi);
98+
if(GC_HAS_ERROR(ctx)) {
99+
ctx->log(ctx,MAPCACHE_INFO,
100+
"failed query_info on fallback source \"%s\" of tileset \"%s\". Continuing with other fallback sources if available",
101+
subsource->name,fi->map.tileset->name);
102+
ctx->clear_errors(ctx);
103+
continue;
104+
} else {
105+
return;
106+
}
107+
}
108+
/* all backends failed, return primary error message */
109+
ctx->set_error(ctx,first_error,first_error_message);
110+
return;
111+
}
112+
ctx->set_error(ctx,500,"fallback source does not support queries");
113+
}
114+
115+
/**
116+
* \private \memberof mapcache_source_fallback
117+
* \sa mapcache_source::configuration_parse()
118+
*/
119+
void _mapcache_source_fallback_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *psource, mapcache_cfg *config)
120+
{
121+
ezxml_t cur_node;
122+
mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
123+
source->sources = apr_array_make(ctx->pool,3,sizeof(mapcache_source*));
124+
for(cur_node = ezxml_child(node,"source"); cur_node; cur_node = cur_node->next) {
125+
mapcache_source *refsource = mapcache_configuration_get_source(config, cur_node->txt);
126+
if(!refsource) {
127+
ctx->set_error(ctx, 400, "fallback source \"%s\" references source \"%s\","
128+
" but it is not configured (hint:referenced sources must be declared before this fallback source in the xml file)", psource->name, cur_node->txt);
129+
return;
130+
}
131+
APR_ARRAY_PUSH(source->sources,mapcache_source*) = refsource;
132+
}
133+
if(source->sources->nelts == 0) {
134+
ctx->set_error(ctx,400,"fallback source \"%s\" does not reference any child sources", psource->name);
135+
}
136+
}
137+
138+
/**
139+
* \private \memberof mapcache_source_fallback
140+
* \sa mapcache_source::configuration_check()
141+
*/
142+
void _mapcache_source_fallback_configuration_check(mapcache_context *ctx, mapcache_cfg *cfg,
143+
mapcache_source *source)
144+
{
145+
}
146+
147+
mapcache_source* mapcache_source_fallback_create(mapcache_context *ctx)
148+
{
149+
mapcache_source_fallback *source = apr_pcalloc(ctx->pool, sizeof(mapcache_source_fallback));
150+
if(!source) {
151+
ctx->set_error(ctx, 500, "failed to allocate fallback source");
152+
return NULL;
153+
}
154+
mapcache_source_init(ctx, &(source->source));
155+
source->source.type = MAPCACHE_SOURCE_FALLBACK;
156+
source->source._render_map = _mapcache_source_fallback_render_map;
157+
source->source.configuration_check = _mapcache_source_fallback_configuration_check;
158+
source->source.configuration_parse_xml = _mapcache_source_fallback_configuration_parse_xml;
159+
source->source._query_info = _mapcache_source_fallback_query;
160+
return (mapcache_source*)source;
161+
}
162+
163+
164+
/* vim: ts=2 sts=2 et sw=2
165+
*/

lib/source_gdal.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,9 @@ CreateWarpedVRT( GDALDatasetH hSrcDS,
470470
* \private \memberof mapcache_source_gdal
471471
* \sa mapcache_source::render_metatile()
472472
*/
473-
void _mapcache_source_gdal_render_metatile(mapcache_context *ctx, mapcache_map *map)
473+
void _mapcache_source_gdal_render_metatile(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
474474
{
475-
mapcache_source_gdal *gdal = (mapcache_source_gdal*)map->tileset->source;
475+
mapcache_source_gdal *gdal = (mapcache_source_gdal*)psource;
476476
gdal_connection *gdal_conn;
477477
GDALDatasetH hDstDS;
478478
GDALDatasetH hTmpDS = NULL;
@@ -604,7 +604,7 @@ void _mapcache_source_gdal_render_metatile(mapcache_context *ctx, mapcache_map *
604604
* \private \memberof mapcache_source_gdal
605605
* \sa mapcache_source::configuration_parse()
606606
*/
607-
void _mapcache_source_gdal_configuration_parse(mapcache_context *ctx, ezxml_t node, mapcache_source *source)
607+
void _mapcache_source_gdal_configuration_parse(mapcache_context *ctx, ezxml_t node, mapcache_source *source, mapcache_cfg *config)
608608
{
609609
ezxml_t cur_node;
610610
mapcache_source_gdal *src = (mapcache_source_gdal*)source;

lib/source_mapserver.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void _mapcache_source_mapserver_render_map(mapcache_context *ctx, mapcache_map *
190190

191191
}
192192

193-
void _mapcache_source_mapserver_query(mapcache_context *ctx, mapcache_feature_info *fi)
193+
void _mapcache_source_mapserver_query(mapcache_context *ctx, mapcache_source *psource, mapcache_feature_info *fi)
194194
{
195195
ctx->set_error(ctx,500,"mapserver source does not support queries");
196196
}

lib/source_wms.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ struct mapcache_source_wms {
5151
* \private \memberof mapcache_source_wms
5252
* \sa mapcache_source::render_map()
5353
*/
54-
void _mapcache_source_wms_render_map(mapcache_context *ctx, mapcache_map *map)
54+
void _mapcache_source_wms_render_map(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
5555
{
56-
mapcache_source_wms *wms = (mapcache_source_wms*)map->tileset->source;
56+
mapcache_source_wms *wms = (mapcache_source_wms*)psource;
5757
mapcache_http *http;
5858
apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params);
5959
apr_table_setn(params,"BBOX",apr_psprintf(ctx->pool,"%f,%f,%f,%f",
@@ -99,11 +99,11 @@ void _mapcache_source_wms_render_map(mapcache_context *ctx, mapcache_map *map)
9999
}
100100
}
101101

102-
void _mapcache_source_wms_query(mapcache_context *ctx, mapcache_feature_info *fi)
102+
void _mapcache_source_wms_query(mapcache_context *ctx, mapcache_source *source, mapcache_feature_info *fi)
103103
{
104104
mapcache_map *map = (mapcache_map*)fi;
105105
mapcache_http *http;
106-
mapcache_source_wms *wms = (mapcache_source_wms*)map->tileset->source;
106+
mapcache_source_wms *wms = (mapcache_source_wms*)source;
107107

108108
apr_table_t *params = apr_table_clone(ctx->pool,wms->wms_default_params);
109109
apr_table_overlap(params,wms->getmap_params,0);
@@ -144,7 +144,7 @@ void _mapcache_source_wms_query(mapcache_context *ctx, mapcache_feature_info *fi
144144
* \private \memberof mapcache_source_wms
145145
* \sa mapcache_source::configuration_parse()
146146
*/
147-
void _mapcache_source_wms_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *source)
147+
void _mapcache_source_wms_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *source, mapcache_cfg *config)
148148
{
149149
ezxml_t cur_node;
150150
mapcache_source_wms *src = (mapcache_source_wms*)source;
@@ -230,7 +230,7 @@ mapcache_source* mapcache_source_wms_create(mapcache_context *ctx)
230230
source->source._render_map = _mapcache_source_wms_render_map;
231231
source->source.configuration_check = _mapcache_source_wms_configuration_check;
232232
source->source.configuration_parse_xml = _mapcache_source_wms_configuration_parse_xml;
233-
source->source.query_info = _mapcache_source_wms_query;
233+
source->source._query_info = _mapcache_source_wms_query;
234234
source->wms_default_params = apr_table_make(ctx->pool,4);;
235235
source->getmap_params = apr_table_make(ctx->pool,4);
236236
source->getfeatureinfo_params = apr_table_make(ctx->pool,4);

0 commit comments

Comments
 (0)