1
/******************************************************************************
5
* Purpose: MapCache tile caching: filesytem cache backend.
6
* Author: Thomas Bonfort and the MapServer team.
8
******************************************************************************
9
* Copyright (c) 1996-2011 Regents of the University of Minnesota.
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:
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.
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
*****************************************************************************/
31
#include <apr_file_info.h>
32
#include <apr_strings.h>
33
#include <apr_file_io.h>
43
* \brief computes the relative path between two destinations
45
* \param tilename the absolute filename of the tile
46
* \param blankname the absolute path of the blank tile image
49
char* relative_path(mapcache_context *ctx, char* tilename, char* blankname)
54
/* work up the directory paths of the tile and blank filename to find the common
56
char *tile_it = tilename, *blank_it = blankname;
57
if(*tile_it != *blank_it) {
58
/* the two files have no common root.
59
* This really shouldn't happen on a unix FS hierarchy, and symbolic linking
60
* is enabled only on these platforms, so this case should in practice never
62
* we return the absolute path, and should probably set a warning message
64
return apr_pstrdup(ctx->pool, blankname);
66
while(*(tile_it+1) && *(blank_it+1) && *(tile_it+1) == *(blank_it+1)) {
71
/* tile_it and blank_it point on the last common character of the two filenames,
72
which should be a '/'. If not, return the full blank name
73
* (and set a warning message? )*/
74
if(*tile_it != *blank_it || *tile_it != '/') {
75
return apr_pstrdup(ctx->pool, blankname);
79
while(*tile_it == '/') tile_it++; /*skip leading '/'s*/
81
/* blank_it now contains the path that must be appended after the relative
82
part of the constructed path,e.g.:
83
- tilename = "/basepath/tilesetname/gridname/03/000/05/08.png"
84
- blankname = "/basepath/tilesetname/gridname/blanks/005599FF.png"
86
- tile_it is "03/000/05/08.png"
87
- blank_it is "blanks/005599FF.png"
90
/* we now count the number of '/' in the remaining tilename */
94
/* also skip consecutive '/'s */
95
while(*(tile_it+1)=='/') tile_it++;
101
blank_rel = apr_pstrcat(ctx->pool, blank_rel, "../", NULL);
103
blank_rel = apr_pstrcat(ctx->pool,blank_rel,blank_it,NULL);
108
* \brief returns base path for given tile
110
* \param tile the tile to get base path from
111
* \param path pointer to a char* that will contain the filename
112
* \private \memberof mapcache_cache_disk
114
static void _mapcache_cache_disk_base_tile_key(mapcache_context *ctx, mapcache_tile *tile, char **path)
116
*path = apr_pstrcat(ctx->pool,
117
((mapcache_cache_disk*)tile->tileset->cache)->base_directory,"/",
118
tile->tileset->name,"/",
119
tile->grid_link->grid->name,
121
if(tile->dimensions) {
122
const apr_array_header_t *elts = apr_table_elts(tile->dimensions);
125
apr_table_entry_t *entry = &(APR_ARRAY_IDX(elts,i,apr_table_entry_t));
126
const char *dimval = mapcache_util_str_sanitize(ctx->pool,entry->val,"/.",'#');
127
*path = apr_pstrcat(ctx->pool,*path,"/",dimval,NULL);
132
static void _mapcache_cache_disk_blank_tile_key(mapcache_context *ctx, mapcache_tile *tile, unsigned char *color, char **path)
134
/* not implemented for template caches, as symlink_blank will never be set */
135
*path = apr_psprintf(ctx->pool,"%s/%s/%s/blanks/%02X%02X%02X%02X.%s",
136
((mapcache_cache_disk*)tile->tileset->cache)->base_directory,
138
tile->grid_link->grid->name,
143
tile->tileset->format?tile->tileset->format->extension:"png");
145
ctx->set_error(ctx,500, "failed to allocate blank tile key");
150
* \brief return filename for given tile
152
* \param tile the tile to get the key from
153
* \param path pointer to a char* that will contain the filename
155
* \private \memberof mapcache_cache_disk
157
static void _mapcache_cache_disk_tilecache_tile_key(mapcache_context *ctx, mapcache_tile *tile, char **path)
159
mapcache_cache_disk *dcache = (mapcache_cache_disk*)tile->tileset->cache;
160
if(dcache->base_directory) {
162
_mapcache_cache_disk_base_tile_key(ctx, tile, &start);
163
*path = apr_psprintf(ctx->pool,"%s/%02d/%03d/%03d/%03d/%03d/%03d/%03d.%s",
167
(tile->x / 1000) % 1000,
170
(tile->y / 1000) % 1000,
172
tile->tileset->format?tile->tileset->format->extension:"png");
174
*path = dcache->filename_template;
175
*path = mapcache_util_str_replace(ctx->pool,*path, "{tileset}", tile->tileset->name);
176
*path = mapcache_util_str_replace(ctx->pool,*path, "{grid}", tile->grid_link->grid->name);
177
*path = mapcache_util_str_replace(ctx->pool,*path, "{ext}",
178
tile->tileset->format?tile->tileset->format->extension:"png");
179
if(strstr(*path,"{x}"))
180
*path = mapcache_util_str_replace(ctx->pool,*path, "{x}",
181
apr_psprintf(ctx->pool,"%d",tile->x));
183
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_x}",
184
apr_psprintf(ctx->pool,"%d",
185
tile->grid_link->grid->levels[tile->z]->maxx - tile->x - 1));
186
if(strstr(*path,"{y}"))
187
*path = mapcache_util_str_replace(ctx->pool,*path, "{y}",
188
apr_psprintf(ctx->pool,"%d",tile->y));
190
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_y}",
191
apr_psprintf(ctx->pool,"%d",
192
tile->grid_link->grid->levels[tile->z]->maxy - tile->y - 1));
193
if(strstr(*path,"{z}"))
194
*path = mapcache_util_str_replace(ctx->pool,*path, "{z}",
195
apr_psprintf(ctx->pool,"%d",tile->z));
197
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_z}",
198
apr_psprintf(ctx->pool,"%d",
199
tile->grid_link->grid->nlevels - tile->z - 1));
200
if(tile->dimensions) {
202
const apr_array_header_t *elts = apr_table_elts(tile->dimensions);
205
apr_table_entry_t *entry = &(APR_ARRAY_IDX(elts,i,apr_table_entry_t));
206
char *dimval = apr_pstrdup(ctx->pool,entry->val);
209
/* replace dangerous characters by '#' */
210
if(*iter == '.' || *iter == '/') {
215
dimstring = apr_pstrcat(ctx->pool,dimstring,"#",entry->key,"#",dimval,NULL);
217
*path = mapcache_util_str_replace(ctx->pool,*path, "{dim}", dimstring);
221
ctx->set_error(ctx,500, "failed to allocate tile key");
225
static void _mapcache_cache_disk_template_tile_key(mapcache_context *ctx, mapcache_tile *tile, char **path)
227
mapcache_cache_disk *dcache = (mapcache_cache_disk*)tile->tileset->cache;
229
*path = dcache->filename_template;
230
*path = mapcache_util_str_replace(ctx->pool,*path, "{tileset}", tile->tileset->name);
231
*path = mapcache_util_str_replace(ctx->pool,*path, "{grid}", tile->grid_link->grid->name);
232
*path = mapcache_util_str_replace(ctx->pool,*path, "{ext}",
233
tile->tileset->format?tile->tileset->format->extension:"png");
235
if(strstr(*path,"{x}"))
236
*path = mapcache_util_str_replace(ctx->pool,*path, "{x}",
237
apr_psprintf(ctx->pool,"%d",tile->x));
239
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_x}",
240
apr_psprintf(ctx->pool,"%d",
241
tile->grid_link->grid->levels[tile->z]->maxx - tile->x - 1));
242
if(strstr(*path,"{y}"))
243
*path = mapcache_util_str_replace(ctx->pool,*path, "{y}",
244
apr_psprintf(ctx->pool,"%d",tile->y));
246
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_y}",
247
apr_psprintf(ctx->pool,"%d",
248
tile->grid_link->grid->levels[tile->z]->maxy - tile->y - 1));
249
if(strstr(*path,"{z}"))
250
*path = mapcache_util_str_replace(ctx->pool,*path, "{z}",
251
apr_psprintf(ctx->pool,"%d",tile->z));
253
*path = mapcache_util_str_replace(ctx->pool,*path, "{inv_z}",
254
apr_psprintf(ctx->pool,"%d",
255
tile->grid_link->grid->nlevels - tile->z - 1));
256
if(tile->dimensions) {
258
const apr_array_header_t *elts = apr_table_elts(tile->dimensions);
261
apr_table_entry_t *entry = &(APR_ARRAY_IDX(elts,i,apr_table_entry_t));
262
char *dimval = apr_pstrdup(ctx->pool,entry->val);
265
/* replace dangerous characters by '#' */
266
if(*iter == '.' || *iter == '/') {
271
dimstring = apr_pstrcat(ctx->pool,dimstring,"#",entry->key,"#",dimval,NULL);
273
*path = mapcache_util_str_replace(ctx->pool,*path, "{dim}", dimstring);
277
ctx->set_error(ctx,500, "failed to allocate tile key");
281
static void _mapcache_cache_disk_arcgis_tile_key(mapcache_context *ctx, mapcache_tile *tile, char **path)
283
mapcache_cache_disk *dcache = (mapcache_cache_disk*)tile->tileset->cache;
284
if(dcache->base_directory) {
286
_mapcache_cache_disk_base_tile_key(ctx, tile, &start);
287
*path = apr_psprintf(ctx->pool,"%s/L%02d/R%08x/C%08x.%s" ,
292
tile->tileset->format?tile->tileset->format->extension:"png");
296
ctx->set_error(ctx,500, "failed to allocate tile key");
301
static int _mapcache_cache_disk_has_tile(mapcache_context *ctx, mapcache_tile *tile)
306
((mapcache_cache_disk*)tile->tileset->cache)->tile_key(ctx, tile, &filename);
307
if(GC_HAS_ERROR(ctx)) {
308
return MAPCACHE_FALSE;
310
rv = apr_stat(&finfo,filename,0,ctx->pool);
311
if(rv != APR_SUCCESS) {
312
return MAPCACHE_FALSE;
314
return MAPCACHE_TRUE;
318
static void _mapcache_cache_disk_delete(mapcache_context *ctx, mapcache_tile *tile)
323
((mapcache_cache_disk*)tile->tileset->cache)->tile_key(ctx, tile, &filename);
326
ret = apr_file_remove(filename,ctx->pool);
327
if(ret != APR_SUCCESS && !APR_STATUS_IS_ENOENT(ret)) {
328
ctx->set_error(ctx, 500, "failed to remove file %s: %s",filename, apr_strerror(ret,errmsg,120));
334
* \brief get file content of given tile
336
* fills the mapcache_tile::data of the given tile with content stored in the file
337
* \private \memberof mapcache_cache_disk
338
* \sa mapcache_cache::tile_get()
340
static int _mapcache_cache_disk_get(mapcache_context *ctx, mapcache_tile *tile)
347
apr_mmap_t *tilemmap;
349
((mapcache_cache_disk*)tile->tileset->cache)->tile_key(ctx, tile, &filename);
350
if(GC_HAS_ERROR(ctx)) {
351
return MAPCACHE_FAILURE;
353
if((rv=apr_file_open(&f, filename,
355
APR_FOPEN_READ, APR_UREAD | APR_GREAD,
357
APR_FOPEN_READ|APR_FOPEN_BUFFERED|APR_FOPEN_BINARY,APR_OS_DEFAULT,
359
ctx->pool)) == APR_SUCCESS) {
360
rv = apr_file_info_get(&finfo, APR_FINFO_SIZE|APR_FINFO_MTIME, f);
362
ctx->set_error(ctx, 500, "tile %s has no data",filename);
363
return MAPCACHE_FAILURE;
368
* at this stage, we have a handle to an open file that contains data.
369
* idealy, we should aquire a read lock, in case the data contained inside the file
370
* is incomplete (i.e. if another process is currently writing to the tile).
371
* currently such a lock is not set, as we don't want to loose performance on tile accesses.
372
* any error that might happen at this stage should only occur if the tile isn't already cached,
373
* i.e. normally only once.
375
tile->mtime = finfo.mtime;
376
tile->encoded_data = mapcache_buffer_create(size,ctx->pool);
380
rv = apr_mmap_create(&tilemmap,f,0,finfo.size,APR_MMAP_READ,ctx->pool);
381
if(rv != APR_SUCCESS) {
383
ctx->set_error(ctx, 500, "mmap error: %s",apr_strerror(rv,errmsg,120));
384
return MAPCACHE_FAILURE;
386
tile->encoded_data->buf = tilemmap->mm;
387
tile->encoded_data->size = tile->encoded_data->avail = finfo.size;
389
//manually add the data to our buffer
390
apr_file_read(f,(void*)tile->encoded_data->buf,&size);
391
tile->encoded_data->size = size;
392
tile->encoded_data->avail = size;
395
if(tile->encoded_data->size != finfo.size) {
396
ctx->set_error(ctx, 500, "failed to copy image data, got %d of %d bytes",(int)size, (int)finfo.size);
397
return MAPCACHE_FAILURE;
399
return MAPCACHE_SUCCESS;
401
if(APR_STATUS_IS_ENOENT(rv)) {
402
/* the file doesn't exist on the disk */
403
return MAPCACHE_CACHE_MISS;
405
char *error = strerror(rv);
406
ctx->set_error(ctx, 500, "failed to open file %s: %s",filename, error);
407
return MAPCACHE_FAILURE;
413
* \brief write tile data to disk
415
* writes the content of mapcache_tile::data to disk.
416
* \returns MAPCACHE_FAILURE if there is no data to write, or if the tile isn't locked
417
* \returns MAPCACHE_SUCCESS if the tile has been successfully written to disk
418
* \private \memberof mapcache_cache_disk
419
* \sa mapcache_cache::tile_set()
421
static void _mapcache_cache_disk_set(mapcache_context *ctx, mapcache_tile *tile)
427
char *filename, *hackptr1, *hackptr2=NULL;
428
const int creation_retry = ((mapcache_cache_disk*)tile->tileset->cache)->creation_retry;
429
int retry_count_create_file = 0;
432
/* all this should be checked at a higher level */
433
if(!tile->encoded_data && !tile->raw_image) {
434
ctx->set_error(ctx,500,"attempting to write empty tile to disk");
437
if(!tile->encoded_data && !tile->tileset->format) {
438
ctx->set_error(ctx,500,"received a raw tile image for a tileset with no format");
443
((mapcache_cache_disk*)tile->tileset->cache)->tile_key(ctx, tile, &filename);
446
/* find the location of the last '/' in the string */
455
if(APR_SUCCESS != (ret = apr_dir_make_recursive(filename,APR_OS_DEFAULT,ctx->pool))) {
457
* apr_dir_make_recursive sometimes sends back this error, although it should not.
460
if(!APR_STATUS_IS_EEXIST(ret)) {
461
ctx->set_error(ctx, 500, "failed to create directory %s: %s",filename, apr_strerror(ret,errmsg,120));
467
ret = apr_file_remove(filename,ctx->pool);
468
if(ret != APR_SUCCESS && !APR_STATUS_IS_ENOENT(ret)) {
469
ctx->set_error(ctx, 500, "failed to remove file %s: %s",filename, apr_strerror(ret,errmsg,120));
474
if(((mapcache_cache_disk*)tile->tileset->cache)->symlink_blank) {
475
if(!tile->raw_image) {
476
tile->raw_image = mapcache_imageio_decode(ctx, tile->encoded_data);
479
if(mapcache_image_blank_color(tile->raw_image) != MAPCACHE_FALSE) {
481
_mapcache_cache_disk_blank_tile_key(ctx,tile,tile->raw_image->data,&blankname);
482
if(apr_file_open(&f, blankname, APR_FOPEN_READ, APR_OS_DEFAULT, ctx->pool) != APR_SUCCESS) {
483
if(!tile->encoded_data) {
484
tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format);
487
/* create the blank file */
488
char *blankdirname = apr_psprintf(ctx->pool, "%s/%s/%s/blanks",
489
((mapcache_cache_disk*)tile->tileset->cache)->base_directory,
491
tile->grid_link->grid->name);
492
if(APR_SUCCESS != (ret = apr_dir_make_recursive(
493
blankdirname, APR_OS_DEFAULT,ctx->pool))) {
494
if(!APR_STATUS_IS_EEXIST(ret)) {
495
ctx->set_error(ctx, 500, "failed to create directory %s for blank tiles",blankdirname, apr_strerror(ret,errmsg,120));
500
/* aquire a lock on the blank file */
501
int isLocked = mapcache_lock_or_wait_for_resource(ctx,blankname);
503
if(isLocked == MAPCACHE_TRUE) {
505
if((ret = apr_file_open(&f, blankname,
506
APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BUFFERED|APR_FOPEN_BINARY,
507
APR_OS_DEFAULT, ctx->pool)) != APR_SUCCESS) {
508
ctx->set_error(ctx, 500, "failed to create file %s: %s",blankname, apr_strerror(ret,errmsg,120));
509
mapcache_unlock_resource(ctx,blankname);
510
return; /* we could not create the file */
513
bytes = (apr_size_t)tile->encoded_data->size;
514
ret = apr_file_write(f,(void*)tile->encoded_data->buf,&bytes);
515
if(ret != APR_SUCCESS) {
516
ctx->set_error(ctx, 500, "failed to write data to file %s (wrote %d of %d bytes): %s",blankname, (int)bytes, (int)tile->encoded_data->size, apr_strerror(ret,errmsg,120));
517
mapcache_unlock_resource(ctx,blankname);
518
return; /* we could not create the file */
521
if(bytes != tile->encoded_data->size) {
522
ctx->set_error(ctx, 500, "failed to write image data to %s, wrote %d of %d bytes", blankname, (int)bytes, (int)tile->encoded_data->size);
523
mapcache_unlock_resource(ctx,blankname);
527
mapcache_unlock_resource(ctx,blankname);
529
ctx->log(ctx,MAPCACHE_DEBUG,"created blank tile %s",blankname);
536
int retry_count_create_symlink = 0;
539
* compute the relative path between tile and blank tile
541
char *blankname_rel = NULL;
542
blankname_rel = relative_path(ctx,filename, blankname);
546
* depending on configuration symlink creation will retry if it fails.
547
* this can happen on nfs mounted network storage.
548
* the solution is to create the containing directory again and retry the symlink creation.
550
while(symlink(blankname_rel, filename) != 0) {
551
retry_count_create_symlink++;
553
if(retry_count_create_symlink > creation_retry) {
554
char *error = strerror(errno);
555
ctx->set_error(ctx, 500, "failed to link tile %s to %s: %s",filename, blankname_rel, error);
556
return; /* we could not create the file */
561
if(APR_SUCCESS != (ret = apr_dir_make_recursive(filename,APR_OS_DEFAULT,ctx->pool))) {
562
if(!APR_STATUS_IS_EEXIST(ret)) {
563
ctx->set_error(ctx, 500, "failed to create symlink, can not create directory %s: %s",filename, apr_strerror(ret,errmsg,120));
564
return; /* we could not create the file */
571
ctx->log(ctx, MAPCACHE_DEBUG, "linked blank tile %s to %s",filename,blankname);
576
#endif /*HAVE_SYMLINK*/
578
/* go the normal way: either we haven't configured blank tile detection, or the tile was not blank */
580
if(!tile->encoded_data) {
581
tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format);
586
* depending on configuration file creation will retry if it fails.
587
* this can happen on nfs mounted network storage.
588
* the solution is to create the containing directory again and retry the file creation.
590
while((ret = apr_file_open(&f, filename,
591
APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BUFFERED|APR_FOPEN_BINARY,
592
APR_OS_DEFAULT, ctx->pool)) != APR_SUCCESS) {
594
retry_count_create_file++;
596
if(retry_count_create_file > creation_retry) {
597
ctx->set_error(ctx, 500, "failed to create file %s: %s",filename, apr_strerror(ret,errmsg,120));
598
return; /* we could not create the file */
603
if(APR_SUCCESS != (ret = apr_dir_make_recursive(filename,APR_OS_DEFAULT,ctx->pool))) {
604
if(!APR_STATUS_IS_EEXIST(ret)) {
605
ctx->set_error(ctx, 500, "failed to create file, can not create directory %s: %s",filename, apr_strerror(ret,errmsg,120));
606
return; /* we could not create the file */
613
bytes = (apr_size_t)tile->encoded_data->size;
614
ret = apr_file_write(f,(void*)tile->encoded_data->buf,&bytes);
615
if(ret != APR_SUCCESS) {
616
ctx->set_error(ctx, 500, "failed to write data to file %s (wrote %d of %d bytes): %s",filename, (int)bytes, (int)tile->encoded_data->size, apr_strerror(ret,errmsg,120));
617
return; /* we could not create the file */
620
if(bytes != tile->encoded_data->size) {
621
ctx->set_error(ctx, 500, "failed to write image data to %s, wrote %d of %d bytes", filename, (int)bytes, (int)tile->encoded_data->size);
623
ret = apr_file_close(f);
624
if(ret != APR_SUCCESS) {
625
ctx->set_error(ctx, 500, "failed to close file %s:%s",filename, apr_strerror(ret,errmsg,120));
626
return; /* we could not create the file */
632
* \private \memberof mapcache_cache_disk
634
static void _mapcache_cache_disk_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_cache *cache, mapcache_cfg *config)
637
mapcache_cache_disk *dcache = (mapcache_cache_disk*)cache;
639
int template_layout = MAPCACHE_FALSE;
641
layout = (char*)ezxml_attr(node,"layout");
642
if (!layout || !strlen(layout) || !strcmp(layout,"tilecache")) {
643
dcache->tile_key = _mapcache_cache_disk_tilecache_tile_key;
644
} else if(!strcmp(layout,"arcgis")) {
645
dcache->tile_key = _mapcache_cache_disk_arcgis_tile_key;
646
} else if (!strcmp(layout,"template")) {
647
dcache->tile_key = _mapcache_cache_disk_template_tile_key;
648
template_layout = MAPCACHE_TRUE;
649
if ((cur_node = ezxml_child(node,"template")) != NULL) {
650
dcache->filename_template = apr_pstrdup(ctx->pool,cur_node->txt);
652
ctx->set_error(ctx, 400, "no template specified for cache \"%s\"", cache->name);
656
ctx->set_error(ctx, 400, "unknown layout type %s for cache \"%s\"", layout, cache->name);
660
if (!template_layout && (cur_node = ezxml_child(node,"base")) != NULL) {
661
dcache->base_directory = apr_pstrdup(ctx->pool,cur_node->txt);
664
if (!template_layout && (cur_node = ezxml_child(node,"symlink_blank")) != NULL) {
665
if(strcasecmp(cur_node->txt,"false")) {
667
dcache->symlink_blank=1;
669
ctx->set_error(ctx,400,"cache %s: host system does not support file symbolic linking",cache->name);
675
if ((cur_node = ezxml_child(node,"creation_retry")) != NULL) {
676
dcache->creation_retry = atoi(cur_node->txt);
681
* \private \memberof mapcache_cache_disk
683
static void _mapcache_cache_disk_configuration_post_config(mapcache_context *ctx, mapcache_cache *cache,
686
mapcache_cache_disk *dcache = (mapcache_cache_disk*)cache;
687
/* check all required parameters are configured */
688
if((!dcache->base_directory || !strlen(dcache->base_directory)) &&
689
(!dcache->filename_template || !strlen(dcache->filename_template))) {
690
ctx->set_error(ctx, 400, "disk cache %s has no base directory or template",dcache->cache.name);
696
* \brief creates and initializes a mapcache_disk_cache
698
mapcache_cache* mapcache_cache_disk_create(mapcache_context *ctx)
700
mapcache_cache_disk *cache = apr_pcalloc(ctx->pool,sizeof(mapcache_cache_disk));
702
ctx->set_error(ctx, 500, "failed to allocate disk cache");
705
cache->symlink_blank = 0;
706
cache->creation_retry = 0;
707
cache->cache.metadata = apr_table_make(ctx->pool,3);
708
cache->cache.type = MAPCACHE_CACHE_DISK;
709
cache->cache.tile_delete = _mapcache_cache_disk_delete;
710
cache->cache.tile_get = _mapcache_cache_disk_get;
711
cache->cache.tile_exists = _mapcache_cache_disk_has_tile;
712
cache->cache.tile_set = _mapcache_cache_disk_set;
713
cache->cache.configuration_post_config = _mapcache_cache_disk_configuration_post_config;
714
cache->cache.configuration_parse_xml = _mapcache_cache_disk_configuration_parse_xml;
715
return (mapcache_cache*)cache;
718
/* vim: ts=2 sts=2 et sw=2