1 /******************************************************************************
2  *
3  * Project:  MapServer
4  * Purpose:  MapCache tile caching: multitier cache backend.
5  * Author:   Thomas Bonfort and the MapServer team.
6  *
7  ******************************************************************************
8  * Copyright (c) 1996-2011 Regents of the University of Minnesota.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without multitierriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies of this Software or works derived from this Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *****************************************************************************/
28 
29 #include "mapcache.h"
30 
31 typedef struct mapcache_cache_multitier mapcache_cache_multitier;
32 
33 struct mapcache_cache_multitier {
34   mapcache_cache cache;
35   apr_array_header_t *caches;
36 };
37 
38 
_mapcache_cache_multitier_tile_exists(mapcache_context * ctx,mapcache_cache * pcache,mapcache_tile * tile)39 static int _mapcache_cache_multitier_tile_exists(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
40 {
41   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
42   int i;
43   for(i=0; i<cache->caches->nelts; i++) {
44     mapcache_cache *subcache = APR_ARRAY_IDX(cache->caches,i,mapcache_cache*);
45     if(mapcache_cache_tile_exists(ctx, subcache, tile) == MAPCACHE_TRUE) {
46       return MAPCACHE_TRUE;
47     }
48   }
49   return MAPCACHE_FALSE;
50 }
51 
_mapcache_cache_multitier_tile_delete(mapcache_context * ctx,mapcache_cache * pcache,mapcache_tile * tile)52 static void _mapcache_cache_multitier_tile_delete(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
53 {
54   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
55   int i;
56   for(i=0; i<cache->caches->nelts; i++) {
57     mapcache_cache *subcache = APR_ARRAY_IDX(cache->caches,i,mapcache_cache*);
58     mapcache_cache_tile_delete(ctx, subcache, tile);
59     ctx->clear_errors(ctx); /* ignore errors */
60   }
61 }
62 
63 /**
64  * \brief get content of given tile
65  *
66  * fills the mapcache_tile::data of the given tile with content stored on the multitier server
67  * \private \memberof mapcache_cache_multitier
68  * \sa mapcache_cache::tile_get()
69  */
_mapcache_cache_multitier_tile_get(mapcache_context * ctx,mapcache_cache * pcache,mapcache_tile * tile)70 static int _mapcache_cache_multitier_tile_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
71 {
72   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
73   mapcache_cache *subcache;
74   int i,ret;
75   subcache = APR_ARRAY_IDX(cache->caches,0,mapcache_cache*);
76   ret = mapcache_cache_tile_get(ctx, subcache, tile);
77 
78   if(ret == MAPCACHE_CACHE_MISS) {
79     for(i=1; i<cache->caches->nelts; i++) {
80       subcache = APR_ARRAY_IDX(cache->caches,i,mapcache_cache*);
81       if(mapcache_cache_tile_get(ctx, subcache, tile) == MAPCACHE_SUCCESS) {
82         ctx->log(ctx,MAPCACHE_DEBUG,"got tile (%s,z=%d,y=%d,x=%d) from secondary cache (%s)",tile->tileset->name, tile->z, tile->y, tile->x, subcache->name);
83         for(--i;i>=0;i--) {
84           subcache = APR_ARRAY_IDX(cache->caches,i,mapcache_cache*);
85           mapcache_cache_tile_set(ctx, subcache, tile);
86           ctx->clear_errors(ctx); /* silently ignore these errors */
87           ctx->log(ctx,MAPCACHE_DEBUG,"transferring tile (%s,z=%d,y=%d,x=%d) to cache (%s)",tile->tileset->name, tile->z, tile->y, tile->x, subcache->name);
88         }
89         return MAPCACHE_SUCCESS;
90       }
91     }
92     return MAPCACHE_CACHE_MISS;
93   } else {
94     //ctx->log(ctx,MAPCACHE_DEBUG,"got tile (%s,z=%d,y=%d,x=%d) from primary cache (%s)",tile->tileset->name, tile->z, tile->y, tile->x, subcache->name);
95     return ret;
96   }
97 }
98 
_mapcache_cache_multitier_tile_set(mapcache_context * ctx,mapcache_cache * pcache,mapcache_tile * tile)99 static void _mapcache_cache_multitier_tile_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
100 {
101   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
102   mapcache_cache *subcache = APR_ARRAY_IDX(cache->caches,cache->caches->nelts-1,mapcache_cache*);
103   return mapcache_cache_tile_set(ctx, subcache, tile);
104 }
105 
_mapcache_cache_multitier_tile_multi_set(mapcache_context * ctx,mapcache_cache * pcache,mapcache_tile * tiles,int ntiles)106 static void _mapcache_cache_multitier_tile_multi_set(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tiles, int ntiles)
107 {
108   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
109   mapcache_cache *subcache = APR_ARRAY_IDX(cache->caches,cache->caches->nelts-1,mapcache_cache*);
110   return mapcache_cache_tile_multi_set(ctx, subcache, tiles, ntiles);
111 }
112 
113 /**
114  * \private \memberof mapcache_cache_multitier
115  */
_mapcache_cache_multitier_configuration_parse_xml(mapcache_context * ctx,ezxml_t node,mapcache_cache * pcache,mapcache_cfg * config)116 static void _mapcache_cache_multitier_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_cache *pcache, mapcache_cfg *config)
117 {
118   ezxml_t cur_node;
119   mapcache_cache_multitier *cache = (mapcache_cache_multitier*)pcache;
120   cache->caches = apr_array_make(ctx->pool,3,sizeof(mapcache_cache*));
121   for(cur_node = ezxml_child(node,"cache"); cur_node; cur_node = cur_node->next) {
122     mapcache_cache *refcache = mapcache_configuration_get_cache(config, cur_node->txt);
123     if(!refcache) {
124       ctx->set_error(ctx, 400, "multitier cache \"%s\" references cache \"%s\","
125                      " but it is not configured (hint:referenced caches must be declared before this multitier cache in the xml file)", pcache->name, cur_node->txt);
126       return;
127     }
128     APR_ARRAY_PUSH(cache->caches,mapcache_cache*) = refcache;
129   }
130   if(cache->caches->nelts == 0) {
131     ctx->set_error(ctx,400,"multitier cache \"%s\" does not reference any child caches", pcache->name);
132   }
133 }
134 
135 /**
136  * \private \memberof mapcache_cache_multitier
137  */
_mapcache_cache_multitier_configuration_post_config(mapcache_context * ctx,mapcache_cache * cache,mapcache_cfg * cfg)138 static void _mapcache_cache_multitier_configuration_post_config(mapcache_context *ctx, mapcache_cache *cache,
139     mapcache_cfg *cfg)
140 {
141 }
142 
143 
144 /**
145  * \brief creates and initializes a mapcache_cache_multitier
146  */
mapcache_cache_multitier_create(mapcache_context * ctx)147 mapcache_cache* mapcache_cache_multitier_create(mapcache_context *ctx)
148 {
149   mapcache_cache_multitier *cache = apr_pcalloc(ctx->pool,sizeof(mapcache_cache_multitier));
150   if(!cache) {
151     ctx->set_error(ctx, 500, "failed to allocate multitier cache");
152     return NULL;
153   }
154   cache->cache.metadata = apr_table_make(ctx->pool,3);
155   cache->cache.type = MAPCACHE_CACHE_COMPOSITE;
156   cache->cache._tile_delete = _mapcache_cache_multitier_tile_delete;
157   cache->cache._tile_get = _mapcache_cache_multitier_tile_get;
158   cache->cache._tile_exists = _mapcache_cache_multitier_tile_exists;
159   cache->cache._tile_set = _mapcache_cache_multitier_tile_set;
160   cache->cache._tile_multi_set = _mapcache_cache_multitier_tile_multi_set;
161   cache->cache.configuration_post_config = _mapcache_cache_multitier_configuration_post_config;
162   cache->cache.configuration_parse_xml = _mapcache_cache_multitier_configuration_parse_xml;
163   return (mapcache_cache*)cache;
164 }
165 
166