1 /******************************************************************************
2  *
3  * Project:  MapServer
4  * Purpose:  MapCache tile caching: generic cache access
5  * Author:   Thomas Bonfort and the MapServer team.
6  *
7  ******************************************************************************
8  * Copyright (c) 1996-2015 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 compositeriction, 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 #include "mapcache.h"
29 #include <apr_time.h>
30 
mapcache_cache_tile_get(mapcache_context * ctx,mapcache_cache * cache,mapcache_tile * tile)31 int mapcache_cache_tile_get(mapcache_context *ctx, mapcache_cache *cache, mapcache_tile *tile) {
32   int i,rv;
33   mapcache_rule *rule = mapcache_ruleset_rule_get(tile->grid_link->rules, tile->z);
34 #ifdef DEBUG
35   ctx->log(ctx,MAPCACHE_DEBUG,"calling tile_get on cache (%s): (tileset=%s, grid=%s, z=%d, x=%d, y=%d",cache->name,tile->tileset->name,tile->grid_link->grid->name,tile->z,tile->x, tile->y);
36 #endif
37 
38   /* if tile is outside visible limits, return a blank tile */
39   if (mapcache_ruleset_is_visible_tile(rule, tile) == MAPCACHE_FALSE) {
40     tile->encoded_data = mapcache_buffer_create(0, ctx->pool);
41     mapcache_buffer_append(tile->encoded_data, rule->hidden_tile->size, rule->hidden_tile->buf);
42     return MAPCACHE_SUCCESS;
43   }
44 
45   for(i=0;i<=cache->retry_count;i++) {
46     if(i) {
47       ctx->log(ctx,MAPCACHE_INFO,"cache (%s) get retry %d of %d. previous try returned error: %s",cache->name,i,cache->retry_count,ctx->get_error_message(ctx));
48       ctx->clear_errors(ctx);
49       if(cache->retry_delay > 0) {
50         double wait = cache->retry_delay;
51         int j = 0;
52         for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
53           wait *= 2;
54         apr_sleep((int)(wait*1000000));  /* apr_sleep expects microseconds */
55       }
56     }
57     rv = cache->_tile_get(ctx,cache,tile);
58     if(!GC_HAS_ERROR(ctx))
59       break;
60   }
61   return rv;
62 }
63 
mapcache_cache_tile_delete(mapcache_context * ctx,mapcache_cache * cache,mapcache_tile * tile)64 void mapcache_cache_tile_delete(mapcache_context *ctx, mapcache_cache *cache, mapcache_tile *tile) {
65   int i;
66 #ifdef DEBUG
67   ctx->log(ctx,MAPCACHE_DEBUG,"calling tile_delete on cache (%s): (tileset=%s, grid=%s, z=%d, x=%d, y=%d",cache->name,tile->tileset->name,tile->grid_link->grid->name,tile->z,tile->x, tile->y);
68 #endif
69   if(tile->tileset->read_only)
70     return;
71   for(i=0;i<=cache->retry_count;i++) {
72     if(i) {
73       ctx->log(ctx,MAPCACHE_INFO,"cache (%s) delete retry %d of %d. previous try returned error: %s",cache->name,i,cache->retry_count,ctx->get_error_message(ctx));
74       ctx->clear_errors(ctx);
75       if(cache->retry_delay > 0) {
76         double wait = cache->retry_delay;
77         int j = 0;
78         for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
79           wait *= 2;
80         apr_sleep((int)(wait*1000000));  /* apr_sleep expects microseconds */
81       }
82     }
83     cache->_tile_delete(ctx,cache,tile);
84     if(!GC_HAS_ERROR(ctx))
85       break;
86   }
87 }
88 
mapcache_cache_tile_exists(mapcache_context * ctx,mapcache_cache * cache,mapcache_tile * tile)89 int mapcache_cache_tile_exists(mapcache_context *ctx, mapcache_cache *cache, mapcache_tile *tile) {
90   int i,rv;
91   mapcache_rule *rule = mapcache_ruleset_rule_get(tile->grid_link->rules, tile->z);
92 #ifdef DEBUG
93   ctx->log(ctx,MAPCACHE_DEBUG,"calling tile_exists on cache (%s): (tileset=%s, grid=%s, z=%d, x=%d, y=%d",cache->name,tile->tileset->name,tile->grid_link->grid->name,tile->z,tile->x, tile->y);
94 #endif
95 
96   /* if tile is outside visible limits return TRUE
97      a blank tile will be returned on subsequent get call on cache */
98   if (mapcache_ruleset_is_visible_tile(rule, tile) == MAPCACHE_FALSE) {
99     return MAPCACHE_TRUE;
100   }
101 
102   for(i=0;i<=cache->retry_count;i++) {
103     if(i) {
104       ctx->log(ctx,MAPCACHE_INFO,"cache (%s) exists retry %d of %d. previous try returned error: %s",cache->name,i,cache->retry_count,ctx->get_error_message(ctx));
105       ctx->clear_errors(ctx);
106       if(cache->retry_delay > 0) {
107         double wait = cache->retry_delay;
108         int j = 0;
109         for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
110           wait *= 2;
111         apr_sleep((int)(wait*1000000));  /* apr_sleep expects microseconds */
112       }
113     }
114     rv = cache->_tile_exists(ctx,cache,tile);
115     if(!GC_HAS_ERROR(ctx))
116       break;
117   }
118   return rv;
119 }
120 
mapcache_cache_tile_set(mapcache_context * ctx,mapcache_cache * cache,mapcache_tile * tile)121 void mapcache_cache_tile_set(mapcache_context *ctx, mapcache_cache *cache, mapcache_tile *tile) {
122   int i;
123 #ifdef DEBUG
124   ctx->log(ctx,MAPCACHE_DEBUG,"calling tile_set on cache (%s): (tileset=%s, grid=%s, z=%d, x=%d, y=%d",cache->name,tile->tileset->name,tile->grid_link->grid->name,tile->z,tile->x, tile->y);
125 #endif
126   if(tile->tileset->read_only)
127     return;
128   for(i=0;i<=cache->retry_count;i++) {
129     if(i) {
130       ctx->log(ctx,MAPCACHE_INFO,"cache (%s) set retry %d of %d. previous try returned error: %s",cache->name,i,cache->retry_count,ctx->get_error_message(ctx));
131       ctx->clear_errors(ctx);
132       if(cache->retry_delay > 0) {
133         double wait = cache->retry_delay;
134         int j = 0;
135         for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
136           wait *= 2;
137         apr_sleep((int)(wait*1000000));  /* apr_sleep expects microseconds */
138       }
139     }
140     cache->_tile_set(ctx,cache,tile);
141     if(!GC_HAS_ERROR(ctx))
142       break;
143   }
144 }
145 
mapcache_cache_tile_multi_set(mapcache_context * ctx,mapcache_cache * cache,mapcache_tile * tiles,int ntiles)146 void mapcache_cache_tile_multi_set(mapcache_context *ctx, mapcache_cache *cache, mapcache_tile *tiles, int ntiles) {
147   int i;
148 #ifdef DEBUG
149   ctx->log(ctx,MAPCACHE_DEBUG,"calling tile_multi_set on cache (%s): (tileset=%s, grid=%s, first tile: z=%d, x=%d, y=%d",cache->name,tiles[0].tileset->name,tiles[0].grid_link->grid->name,
150       tiles[0].z,tiles[0].x, tiles[0].y);
151 #endif
152   if((&tiles[0])->tileset->read_only)
153     return;
154   if(cache->_tile_multi_set) {
155     for(i=0;i<=cache->retry_count;i++) {
156       if(i) {
157         ctx->log(ctx,MAPCACHE_INFO,"cache (%s) multi-set retry %d of %d. previous try returned error: %s",cache->name,i,cache->retry_count,ctx->get_error_message(ctx));
158         ctx->clear_errors(ctx);
159         if(cache->retry_delay > 0) {
160           double wait = cache->retry_delay;
161           int j = 0;
162           for(j=1;j<i;j++) /* sleep twice as long as before previous retry */
163             wait *= 2;
164           apr_sleep((int)(wait*1000000));  /* apr_sleep expects microseconds */
165         }
166       }
167       cache->_tile_multi_set(ctx,cache,tiles,ntiles);
168       if(!GC_HAS_ERROR(ctx))
169         break;
170     }
171   } else {
172     for( i=0;i<ntiles;i++ ) {
173       mapcache_cache_tile_set(ctx, cache, tiles+i);
174     }
175   }
176 }
177