22 * $Id$
33 *
44 * Project: MapServer
5- * Purpose: MapCache tile caching support file: memcache cache backend.
6- * Author: Thomas Bonfort and the MapServer team.
5+ * Purpose: MapCache tile caching support file: redis cache backend.
6+ * Author: Boris Manojlovic, Thomas Bonfort and the MapServer team.
77 *
88 ******************************************************************************
99 * Copyright (c) 1996-2011 Regents of the University of Minnesota.
10+ * Copyright (c) 2021 Boris Manojlovic
1011 *
1112 * Permission is hereby granted, free of charge, to any person obtaining a
1213 * copy of this software and associated documentation files (the "Software"),
2728 * DEALINGS IN THE SOFTWARE.
2829 *****************************************************************************/
2930
30- #include "mapcache-config .h"
31+ #include "mapcache.h"
3132#ifdef USE_REDIS
3233
33- #include "mapcache.h"
3434#include <apr_strings.h>
3535#include <limits.h>
3636#include <errno.h>
3737
38- #define REDIS_GET_CACHE (t ) ((mapcache_cache_redis*)t->tileset->cache)
38+
39+ typedef struct mapcache_cache_redis mapcache_cache_redis ;
40+
41+ /**\class mapcache_cache_redis
42+ * \brief a mapcache_cache for redis
43+ * \implements mapcache_cache
44+ */
45+ struct mapcache_cache_redis {
46+ mapcache_cache cache ;
47+ char * host ;
48+ int port ;
49+ char * key_template ;
50+ char * bucket_template ;
51+ };
52+
53+ struct redis_conn_params {
54+ mapcache_cache_redis * cache ;
55+ };
56+
57+ #define REDIS_GET_CACHE (t ) ((mapcache_cache_redis*)t->tileset->_cache)
3958#define REDIS_GET_TILE_KEY (c , t ) (mapcache_util_get_tile_key(c, t, NULL, " \r\n\t\f\e\a\b", "#"))
4059#define IS_REDIS_ERROR_STATUS (r ) (r->type != REDIS_REPLY_STATUS || strncmp(r->str, "OK", 2) != 0)
4160
42- static struct redisContext * _redis_get_connection (mapcache_context * ctx ,
43- mapcache_tile * tile )
44- {
45- mapcache_cache_redis * cache = REDIS_GET_CACHE (tile );
61+
62+
63+
64+
65+ void mapcache_redis_connection_constructor (mapcache_context * ctx , void * * conn_ , void * params ) {
66+ mapcache_cache_redis * cache = ((struct redis_conn_params * )params )-> cache ;
4667 redisContext * conn = redisConnect (cache -> host , cache -> port );
4768 if (!conn || conn -> err ) {
4869 ctx -> set_error (ctx ,500 , "redis: failed to connect to server %s:%d" , cache -> host , cache -> port );
49- return NULL ;
70+ return ;
5071 }
51- return conn ;
72+ * conn_ = conn ;
73+ }
74+
75+
76+ void mapcache_redis_connection_destructor (void * conn_ ) {
77+ struct redisContext * conn ;
78+ conn = (struct redisContext * )conn_ ;
79+ redisFree (conn );
5280}
5381
54- static int _mapcache_cache_redis_has_tile (mapcache_context * ctx ,
55- mapcache_tile * tile )
82+ static mapcache_pooled_connection * _redis_get_connection (mapcache_context * ctx , mapcache_cache_redis * cache , mapcache_tile * tile )
5683{
57- char * key = REDIS_GET_TILE_KEY (ctx , tile );
84+ mapcache_pooled_connection * pc ;
85+ struct redis_conn_params params ;
86+
87+ params .cache = cache ;
88+
89+ pc = mapcache_connection_pool_get_connection (ctx ,cache -> cache .name ,mapcache_redis_connection_constructor ,
90+ mapcache_redis_connection_destructor , & params );
91+
92+ return pc ;
93+
94+ // redisContext *conn;
95+ // conn = redisConnect(cache->host, cache->port);
96+ // if (!conn || conn->err) {
97+ // ctx->set_error(ctx,500, "redis: failed to connect to server %s:%d", cache->host, cache->port);
98+ // return NULL;
99+ // }
100+ // return conn;
101+ }
102+
103+ static int _mapcache_cache_redis_has_tile (mapcache_context * ctx , mapcache_cache * pcache , mapcache_tile * tile ) {
104+ int returnValue ;
105+ redisContext * conn ;
106+ redisReply * reply ;
107+ mapcache_pooled_connection * pc ;
108+ mapcache_cache_redis * cache = (mapcache_cache_redis * )pcache ;
109+
110+ char * key = mapcache_util_get_tile_key (ctx , tile , cache -> key_template , " \r\n\t\f\e\a\b" , "#" );
58111 if (GC_HAS_ERROR (ctx )) {
59112 return MAPCACHE_FALSE ;
60113 }
61- int returnValue = MAPCACHE_TRUE ;
62- redisContext * conn = _redis_get_connection (ctx , tile );
114+ returnValue = MAPCACHE_TRUE ;
115+ pc = _redis_get_connection (ctx , cache , tile );
116+ conn = pc -> connection ;
63117 if (!conn ) {
64118 return MAPCACHE_FALSE ;
65119 }
66- redisReply * reply = redisCommand (conn , "EXISTS %s" , key );
120+ reply = redisCommand (conn , "EXISTS %s" , key );
67121 if (reply -> type != REDIS_REPLY_INTEGER ) {
68122 returnValue = MAPCACHE_FALSE ;
69123 }
@@ -75,36 +129,46 @@ static int _mapcache_cache_redis_has_tile(mapcache_context *ctx,
75129 return returnValue ;
76130}
77131
78- static void _mapcache_cache_redis_delete (mapcache_context * ctx ,
79- mapcache_tile * tile )
132+ static void _mapcache_cache_redis_delete (mapcache_context * ctx , mapcache_cache * pcache , mapcache_tile * tile )
80133{
81- char * key = REDIS_GET_TILE_KEY (ctx , tile );
134+ redisContext * conn ;
135+ redisReply * reply ;
136+ mapcache_pooled_connection * pc ;
137+ mapcache_cache_redis * cache = (mapcache_cache_redis * )pcache ;
138+
139+ char * key = mapcache_util_get_tile_key (ctx , tile , cache -> key_template , " \r\n\t\f\e\a\b" , "#" );
82140 GC_CHECK_ERROR (ctx );
83- redisContext * conn = _redis_get_connection (ctx , tile );
141+ pc = _redis_get_connection (ctx , cache , tile );
142+ conn = pc -> connection ;
84143 if (!conn ) {
85144 return ;
86145 }
87- redisReply * reply = redisCommand (conn , "DEL %s" , key );
146+ reply = redisCommand (conn , "DEL %s" , key );
88147 if (reply -> type == REDIS_REPLY_ERROR ) {
89148 ctx -> set_error (ctx , 500 , "redis: failed to delete key %s: %s" , key , reply -> str );
90149 }
91150 freeReplyObject (reply );
92151 redisFree (conn );
93152}
94153
95- static int _mapcache_cache_redis_get (mapcache_context * ctx ,
96- mapcache_tile * tile )
154+ static int _mapcache_cache_redis_get (mapcache_context * ctx , mapcache_cache * pcache , mapcache_tile * tile )
97155{
156+ redisContext * conn ;
157+ redisReply * reply ;
158+ mapcache_pooled_connection * pc ;
159+ mapcache_cache_redis * cache = (mapcache_cache_redis * )pcache ;
160+
98161 char * key = REDIS_GET_TILE_KEY (ctx , tile );
99162 if (GC_HAS_ERROR (ctx )) {
100163 return MAPCACHE_FAILURE ;
101164 }
102165 tile -> encoded_data = mapcache_buffer_create (0 , ctx -> pool );
103- redisContext * conn = _redis_get_connection (ctx , tile );
166+ pc = _redis_get_connection (ctx , cache , tile );
167+ conn = pc -> connection ;
104168 if (!conn ) {
105169 return MAPCACHE_FAILURE ;
106170 }
107- redisReply * reply = redisCommand (conn , "GET %s" , key );
171+ reply = redisCommand (conn , "GET %s" , key );
108172 if (reply -> type != REDIS_REPLY_STRING ) {
109173 freeReplyObject (reply );
110174 return MAPCACHE_CACHE_MISS ;
@@ -136,15 +200,21 @@ static int _mapcache_cache_redis_get(mapcache_context *ctx,
136200 * \private \memberof mapcache_cache_redis
137201 * \sa mapcache_cache::tile_set()
138202 */
139- static void _mapcache_cache_redis_set (mapcache_context * ctx ,
140- mapcache_tile * tile )
203+ static void _mapcache_cache_redis_set (mapcache_context * ctx , mapcache_cache * pcache , mapcache_tile * tile )
141204{
142205 /* set expiration to one day if not configured */
143206 int expires = 86400 ;
207+ mapcache_pooled_connection * pc ;
208+ mapcache_cache_redis * cache = (mapcache_cache_redis * )pcache ;
209+ char * key ;
210+ char * data ;
211+ apr_time_t now ;
212+ redisContext * conn ;
213+ redisReply * reply ;
144214 if (tile -> tileset -> auto_expire )
145215 expires = tile -> tileset -> auto_expire ;
146- mapcache_cache_redis * cache = REDIS_GET_CACHE (tile );
147- char * key = mapcache_util_get_tile_key (ctx , tile ,NULL ," \r\n\t\f\e\a\b" ,"#" );
216+ cache = REDIS_GET_CACHE (tile );
217+ key = mapcache_util_get_tile_key (ctx , tile , cache -> key_template ," \r\n\t\f\e\a\b" ,"#" );
148218 GC_CHECK_ERROR (ctx );
149219
150220 if (!tile -> encoded_data ) {
@@ -154,26 +224,21 @@ static void _mapcache_cache_redis_set(mapcache_context *ctx,
154224
155225 /* concatenate the current time to the end of the memcache data so we can extract it out
156226 * when we re-get the tile */
157- char * data = calloc (1 ,tile -> encoded_data -> size + sizeof (apr_time_t ));
158- apr_time_t now = apr_time_now ();
227+ data = calloc (1 ,tile -> encoded_data -> size + sizeof (apr_time_t ));
228+ now = apr_time_now ();
159229 apr_pool_cleanup_register (ctx -> pool , data , (void * )free , apr_pool_cleanup_null );
160230 memcpy (data ,tile -> encoded_data -> buf ,tile -> encoded_data -> size );
161231 memcpy (& (data [tile -> encoded_data -> size ]),& now ,sizeof (apr_time_t ));
162232
163- redisContext * conn = _redis_get_connection (ctx , tile );
233+ pc = _redis_get_connection (ctx , cache , tile );
234+ conn = pc -> connection ;
164235 if (!conn ) {
165236 return ;
166237 }
167- redisReply * reply = redisCommand (conn ,
168- "SETEX %s %d %b" ,
169- key ,
170- expires ,
171- data ,
172- tile -> encoded_data -> size + sizeof (apr_time_t ));
238+ reply = redisCommand (conn , "SETEX %s %d %b" , key , expires , data , tile -> encoded_data -> size + sizeof (apr_time_t ));
173239
174240 if (IS_REDIS_ERROR_STATUS (reply )) {
175- ctx -> set_error (ctx , 500 , "failed to store tile %d %d %d to redis cache %s" ,
176- tile -> x , tile -> y , tile -> z , cache -> cache .name );
241+ ctx -> set_error (ctx , 500 , "failed to store tile %d %d %d to redis cache %s" , tile -> x , tile -> y , tile -> z , cache -> cache .name );
177242 }
178243
179244 freeReplyObject (reply );
@@ -184,17 +249,13 @@ static void _mapcache_cache_redis_set(mapcache_context *ctx,
184249/**
185250 * \private \memberof mapcache_cache_redis
186251 */
187- static void _mapcache_cache_redis_configuration_parse_xml (mapcache_context * ctx ,
188- ezxml_t node ,
189- mapcache_cache * cache ,
190- mapcache_cfg * config )
191- {
252+ static void _mapcache_cache_redis_configuration_parse_xml (mapcache_context * ctx , ezxml_t node , mapcache_cache * cache , mapcache_cfg * config ) {
253+ ezxml_t xhost ,xport ;
192254 mapcache_cache_redis * dcache = (mapcache_cache_redis * )cache ;
193255 dcache -> host = NULL ;
194256 dcache -> port = 0 ;
195-
196- ezxml_t xhost = ezxml_child (node , "host" );
197- ezxml_t xport = ezxml_child (node , "port" );
257+ xhost = ezxml_child (node , "host" );
258+ xport = ezxml_child (node , "port" );
198259
199260 if (!xhost || !xhost -> txt || !* xhost -> txt ) {
200261 ctx -> set_error (ctx , 400 , "cache %s: redis cache with no <host>" , cache -> name );
@@ -222,34 +283,38 @@ static void _mapcache_cache_redis_configuration_parse_xml(mapcache_context *ctx,
222283/**
223284 * \private \memberof mapcache_cache_redis
224285 */
225- static void _mapcache_cache_redis_configuration_post_config (mapcache_context * ctx ,
226- mapcache_cache * cache ,
227- mapcache_cfg * cfg )
228- {
286+ static void _mapcache_cache_redis_configuration_post_config (mapcache_context * ctx , mapcache_cache * cache , mapcache_cfg * cfg ) {
229287}
230288
231289/**
232290 * \brief creates and initializes a mapcache_redis_cache
233291 */
234292mapcache_cache * mapcache_cache_redis_create (mapcache_context * ctx )
235293{
236- mapcache_cache_redis * cache = apr_pcalloc (ctx -> pool ,
237- sizeof (mapcache_cache_redis ));
294+ mapcache_cache_redis * cache = apr_pcalloc (ctx -> pool , sizeof (mapcache_cache_redis ));
238295 if (!cache ) {
239296 ctx -> set_error (ctx , 500 , "failed to allocate redis cache" );
240297 return NULL ;
241298 }
299+
242300 cache -> cache .metadata = apr_table_make (ctx -> pool ,3 );
243301 cache -> cache .type = MAPCACHE_CACHE_REDIS ;
244- cache -> cache .tile_get = _mapcache_cache_redis_get ;
245- cache -> cache .tile_exists = _mapcache_cache_redis_has_tile ;
246- cache -> cache .tile_set = _mapcache_cache_redis_set ;
247- cache -> cache .tile_delete = _mapcache_cache_redis_delete ;
302+ cache -> cache ._tile_get = _mapcache_cache_redis_get ;
303+ cache -> cache ._tile_exists = _mapcache_cache_redis_has_tile ;
304+ cache -> cache ._tile_set = _mapcache_cache_redis_set ;
305+ cache -> cache ._tile_delete = _mapcache_cache_redis_delete ;
248306 cache -> cache .configuration_post_config = _mapcache_cache_redis_configuration_post_config ;
249307 cache -> cache .configuration_parse_xml = _mapcache_cache_redis_configuration_parse_xml ;
308+ cache -> host = NULL ;
309+ cache -> port = 6379 ;
310+ cache -> bucket_template = NULL ;
250311 return (mapcache_cache * )cache ;
251312}
252-
313+ #else
314+ mapcache_cache * mapcache_cache_redis_create (mapcache_context * ctx ) {
315+ ctx -> set_error (ctx ,400 ,"redis support not compiled in this version" );
316+ return NULL ;
317+ }
253318#endif
254319
255320/* vim: ts=2 sts=2 et sw=2
0 commit comments