source: subversion/applications/utils/mod_tile/mod_tile.c @ 17688

Last change on this file since 17688 was 17688, checked in by apmon, 10 years ago

[mod_tile / renderd] Add two more priority levels into the queues of renderd

In addition to the request queue and the dirty queue, there are now also a requestPrio and requestBulk queue.
The rendering order now is first render requests from requestPrio, then from request followed by the
dirty queue and finally if no other requests are queued, render from the requestBulk queue.

RequestPrio?, Request and RequestBulk? all block, whereas Diry immediately returns with NotDoneYet?.

This also changes mod_tile to submit requests that if not rendered in time would result in 404 errors as high priority.

prioBulk should be useful for things like rerendering all the outdated tiles in the background, but this patch
does not include those changes.

File size: 47.3 KB
Line 
1#include "apr.h"
2#include "apr_strings.h"
3#include "apr_thread_proc.h"    /* for RLIMIT stuff */
4#include "apr_optional.h"
5#include "apr_buckets.h"
6#include "apr_lib.h"
7#include "apr_poll.h"
8
9#define APR_WANT_STRFUNC
10#define APR_WANT_MEMFUNC
11#include "apr_want.h"
12
13#include "util_filter.h"
14#include "ap_config.h"
15#include "httpd.h"
16#include "http_config.h"
17#include "http_request.h"
18#include "http_core.h"
19#include "http_protocol.h"
20#include "http_main.h"
21#include "http_log.h"
22#include "util_script.h"
23#include "ap_mpm.h"
24#include "mod_core.h"
25#include "mod_cgi.h"
26#include "util_md5.h"
27
28module AP_MODULE_DECLARE_DATA tile_module;
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <stdarg.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <limits.h>
41#include <time.h>
42
43#include "gen_tile.h"
44#include "protocol.h"
45#include "render_config.h"
46#include "store.h"
47#include "dir_utils.h"
48
49#define INILINE_MAX 256
50
51#define FRESH 1
52#define OLD 2
53#define FRESH_RENDER 3
54#define OLD_RENDER 4
55
56typedef struct stats_data {
57    apr_uint64_t noResp200;
58    apr_uint64_t noResp304;
59    apr_uint64_t noResp404;
60    apr_uint64_t noResp5XX;
61    apr_uint64_t noRespOther;
62    apr_uint64_t noFreshCache;
63    apr_uint64_t noFreshRender;
64    apr_uint64_t noOldCache;
65    apr_uint64_t noOldRender;
66} stats_data;
67
68typedef struct {
69    char xmlname[XMLCONFIG_MAX];
70    char baseuri[PATH_MAX];
71    int minzoom;
72    int maxzoom;
73} tile_config_rec;
74
75typedef struct {
76    apr_array_header_t *configs;
77    int request_timeout;
78    int max_load_old;
79    int max_load_missing;
80    int cache_duration_dirty;
81    int cache_duration_max;
82    int cache_duration_minimum;
83    int cache_duration_low_zoom;
84    int cache_level_low_zoom;
85    int cache_duration_medium_zoom;
86    int cache_level_medium_zoom;
87    double cache_duration_last_modified_factor;
88    char renderd_socket_name[PATH_MAX];
89    char tile_dir[PATH_MAX];
90    int mincachetime[MAX_ZOOM + 1];
91    int enableGlobalStats;
92} tile_server_conf;
93
94enum tileState { tileMissing, tileOld, tileCurrent };
95
96static int error_message(request_rec *r, const char *format, ...)
97                 __attribute__ ((format (printf, 2, 3)));
98
99static int error_message(request_rec *r, const char *format, ...)
100{
101    va_list ap;
102    va_start(ap, format);
103    int len;
104    char *msg;
105
106    len = vasprintf(&msg, format, ap);
107
108    if (msg) {
109        //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", msg);
110        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "%s", msg);
111        r->content_type = "text/plain";
112        if (!r->header_only)
113            ap_rputs(msg, r);
114        free(msg);
115    }
116
117    return OK;
118}
119
120#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
121#include "unixd.h"
122#define MOD_TILE_SET_MUTEX_PERMS /* XXX Apache should define something */
123#endif
124
125/* Number of microseconds to camp out on the mutex */
126#define CAMPOUT 10
127/* Maximum number of times we camp out before giving up */
128#define MAXCAMP 10
129
130apr_shm_t *stats_shm;
131char *shmfilename;
132apr_global_mutex_t *stats_mutex;
133char *mutexfilename;
134
135int socket_init(request_rec *r)
136{
137    ap_conf_vector_t *sconf = r->server->module_config;
138    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
139
140    int fd;
141    struct sockaddr_un addr;
142
143    fd = socket(PF_UNIX, SOCK_STREAM, 0);
144    if (fd < 0) {
145        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "failed to create unix socket");
146        return FD_INVALID;
147    }
148
149    bzero(&addr, sizeof(addr));
150    addr.sun_family = AF_UNIX;
151    strncpy(addr.sun_path, scfg->renderd_socket_name, sizeof(addr.sun_path));
152
153    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
154        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "socket connect failed for: %s", scfg->renderd_socket_name);
155        close(fd);
156        return FD_INVALID;
157    }
158    return fd;
159}
160
161int request_tile(request_rec *r, struct protocol *cmd, int renderImmediately)
162{
163    int fd;
164    int ret = 0;
165    int retry = 1;
166    struct protocol resp;
167
168    ap_conf_vector_t *sconf = r->server->module_config;
169    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
170
171    fd = socket_init(r);
172
173    if (fd == FD_INVALID) {
174        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Failed to connect to renderer");
175        return 0;
176    }
177
178    // cmd has already been partial filled, fill in the rest
179    cmd->ver = PROTO_VER;
180    switch (renderImmediately) {
181    case 0: { cmd->cmd = cmdDirty; break;}
182    case 1: { cmd->cmd = cmdRender; break;}
183    case 2: { cmd->cmd = cmdRenderPrio; break;}
184    }
185
186    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Requesting xml(%s) z(%d) x(%d) y(%d)", cmd->xmlname, cmd->z, cmd->x, cmd->y);
187    do {
188        ret = send(fd, cmd, sizeof(struct protocol), 0);
189
190        if (ret == sizeof(struct protocol))
191            break;
192
193        close(fd);
194        if (errno != EPIPE)
195            return 0;
196
197        fd = socket_init(r);
198        if (fd == FD_INVALID)
199            return 0;
200    } while (retry--);
201
202    if (renderImmediately) {
203        struct timeval tv = {scfg->request_timeout, 0 };
204        fd_set rx;
205        int s;
206
207        while (1) {
208            FD_ZERO(&rx);
209            FD_SET(fd, &rx);
210            s = select(fd+1, &rx, NULL, NULL, &tv);
211            if (s == 1) {
212                bzero(&resp, sizeof(struct protocol));
213                ret = recv(fd, &resp, sizeof(struct protocol), 0);
214                if (ret != sizeof(struct protocol)) {
215                    //perror("recv error");
216                    break;
217                }
218
219                if (cmd->x == resp.x && cmd->y == resp.y && cmd->z == resp.z && !strcmp(cmd->xmlname, resp.xmlname)) {
220                    close(fd);
221                    if (resp.cmd == cmdDone)
222                        return 1;
223                    else
224                        return 0;
225                } else {
226                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
227                       "Response does not match request: xml(%s,%s) z(%d,%d) x(%d,%d) y(%d,%d)", cmd->xmlname,
228                       resp.xmlname, cmd->z, resp.z, cmd->x, resp.x, cmd->y, resp.y);
229                }
230            } else {
231                break;
232            }
233        }
234    }
235
236    close(fd);
237    return 0;
238}
239
240static apr_time_t getPlanetTime(request_rec *r)
241{
242    static apr_time_t last_check;
243    static apr_time_t planet_timestamp;
244    static pthread_mutex_t planet_lock = PTHREAD_MUTEX_INITIALIZER;
245    apr_time_t now = r->request_time;
246    struct apr_finfo_t s;
247
248    pthread_mutex_lock(&planet_lock);
249    // Only check for updates periodically
250    if (now < last_check + apr_time_from_sec(300)) {
251        pthread_mutex_unlock(&planet_lock);
252        return planet_timestamp;
253    }
254
255    ap_conf_vector_t *sconf = r->server->module_config;
256    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
257    char filename[PATH_MAX];
258    snprintf(filename, PATH_MAX-1, "%s/%s", scfg->tile_dir, PLANET_TIMESTAMP);
259
260    last_check = now;
261    if (apr_stat(&s, filename, APR_FINFO_MIN, r->pool) != APR_SUCCESS) {
262        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Planet timestamp file (%s) is missing", filename);
263        // Make something up
264        planet_timestamp = now - apr_time_from_sec(3 * 24 * 60 * 60);
265    } else {
266        if (s.mtime != planet_timestamp) {
267            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Planet file updated");
268            planet_timestamp = s.mtime;
269        }
270    }
271    pthread_mutex_unlock(&planet_lock);
272    return planet_timestamp;
273}
274
275static enum tileState tile_state_once(request_rec *r)
276{
277    apr_status_t rv;
278    apr_finfo_t *finfo = &r->finfo;
279
280    if (!(finfo->valid & APR_FINFO_MTIME)) {
281        rv = apr_stat(finfo, r->filename, APR_FINFO_MIN, r->pool);
282        if (rv != APR_SUCCESS)
283            return tileMissing;
284    }
285
286    if (finfo->mtime < getPlanetTime(r))
287        return tileOld;
288
289    return tileCurrent;
290}
291
292static enum tileState tile_state(request_rec *r, struct protocol *cmd)
293{
294    enum tileState state = tile_state_once(r);
295#ifdef METATILEFALLBACK
296    if (state == tileMissing) {
297        ap_conf_vector_t *sconf = r->server->module_config;
298        tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
299
300        // Try fallback to plain PNG
301        char path[PATH_MAX];
302        xyz_to_path(path, sizeof(path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
303        r->filename = apr_pstrdup(r->pool, path);
304        state = tile_state_once(r);
305        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "png fallback %d/%d/%d",x,y,z);
306
307        if (state == tileMissing) {
308            // PNG not available either, if it gets rendered, it'll now be a .meta
309            xyz_to_meta(path, sizeof(path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
310            r->filename = apr_pstrdup(r->pool, path);
311        }
312    }
313#endif
314    return state;
315}
316
317static void add_expiry(request_rec *r, struct protocol * cmd)
318{
319    apr_time_t holdoff;
320    apr_table_t *t = r->headers_out;
321    enum tileState state = tile_state(r, cmd);
322    apr_finfo_t *finfo = &r->finfo;
323    char *timestr;
324    long int planetTimestamp, maxAge, minCache, lastModified;
325
326    ap_conf_vector_t *sconf = r->server->module_config;
327    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
328
329    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "expires(%s), uri(%s), filename(%s), path_info(%s)\n",
330                  r->handler, r->uri, r->filename, r->path_info);
331
332    /* Test if the tile we are serving is out of date, then set a low maxAge*/
333    if (state == tileOld) {
334        holdoff = (scfg->cache_duration_dirty /2) * (rand() / (RAND_MAX + 1.0));
335        maxAge = scfg->cache_duration_dirty + holdoff;
336    } else {
337        // cache heuristic based on zoom level
338        if (cmd->z > MAX_ZOOM) {
339            minCache = 0;
340            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
341                                    "z (%i) is larger than MAXZOOM %i\n",
342                                    cmd->z, MAX_ZOOM);
343        } else {
344            minCache = scfg->mincachetime[cmd->z];
345        }
346        // Time to the next known complete rerender
347        planetTimestamp = apr_time_sec(getPlanetTime(r) + apr_time_from_sec(PLANET_INTERVAL) - r->request_time) ;
348        // Time since the last render of this tile
349        lastModified = (int)(((double)apr_time_sec(r->request_time - finfo->mtime)) * scfg->cache_duration_last_modified_factor);
350        // Add a random jitter of 3 hours to space out cache expiry
351        holdoff = (3 * 60 * 60) * (rand() / (RAND_MAX + 1.0));
352
353        maxAge = MAX(minCache, planetTimestamp);
354        maxAge = MAX(maxAge,lastModified);
355        maxAge += holdoff;
356
357        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
358                        "caching heuristics: next planet render %ld; zoom level based %ld; last modified %ld\n",
359                        planetTimestamp, minCache, lastModified);
360    }
361
362    maxAge = MIN(maxAge, scfg->cache_duration_max);
363
364    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Setting tiles maxAge to %ld\n", maxAge);
365
366    apr_table_mergen(t, "Cache-Control",
367                     apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT,
368                     maxAge));
369    timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
370    apr_rfc822_date(timestr, (apr_time_from_sec(maxAge) + r->request_time));
371    apr_table_setn(t, "Expires", timestr);
372}
373
374double get_load_avg(request_rec *r)
375{
376    double loadavg[1];
377    int n = getloadavg(loadavg, 1);
378
379    if (n < 1)
380        return 1000;
381    else
382        return loadavg[0];
383}
384
385static int get_global_lock(request_rec *r) {
386    apr_status_t rs;
387    int camped;
388
389    for (camped = 0; camped < MAXCAMP; camped++) {
390        rs = apr_global_mutex_trylock(stats_mutex);
391        if (APR_STATUS_IS_EBUSY(rs)) {
392            apr_sleep(CAMPOUT);
393        } else if (rs == APR_SUCCESS) {
394            return 1;
395        } else if (APR_STATUS_IS_ENOTIMPL(rs)) {
396            /* If it's not implemented, just hang in the mutex. */
397            rs = apr_global_mutex_lock(stats_mutex);
398            if (rs == APR_SUCCESS) {
399                return 1;
400            } else {
401                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Could not get hardlock");
402                return 0;
403            }
404        } else {
405            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Unknown return status from trylock");
406            return 0;
407        }
408    }
409    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Timedout trylock");
410    return 0;
411}
412
413static int incRespCounter(int resp, request_rec *r) {
414    stats_data *stats;
415
416    ap_conf_vector_t *sconf = r->server->module_config;
417    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
418
419    if (!scfg->enableGlobalStats) {
420        /* If tile stats reporting is not enable
421         * pretend we correctly updated the counter to
422         * not fill the logs with warnings about failed
423         * stats
424         */
425        return 1;
426    }
427
428    if (get_global_lock(r) != 0) {
429        stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
430        switch (resp) {
431        case OK: {
432            stats->noResp200++;
433            break;
434        }
435        case HTTP_NOT_MODIFIED: {
436            stats->noResp304++;
437            break;
438        }
439        case HTTP_NOT_FOUND: {
440            stats->noResp404++;
441            break;
442        }
443        case HTTP_INTERNAL_SERVER_ERROR: {
444            stats->noResp5XX++;
445            break;
446        }
447        default: {
448            stats->noRespOther++;
449        }
450
451        }
452        apr_global_mutex_unlock(stats_mutex);
453        /* Swallowing the result because what are we going to do with it at
454         * this stage?
455         */
456        return 1;
457    } else {
458        return 0;
459    }
460}
461
462static int incFreshCounter(int status, request_rec *r) {
463    stats_data *stats;
464
465    ap_conf_vector_t *sconf = r->server->module_config;
466    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
467
468    if (!scfg->enableGlobalStats) {
469        /* If tile stats reporting is not enable
470         * pretend we correctly updated the counter to
471         * not fill the logs with warnings about failed
472         * stats
473         */
474        return 1;
475    }
476
477    if (get_global_lock(r) != 0) {
478        stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
479        switch (status) {
480        case FRESH: {
481            stats->noFreshCache++;
482            break;
483        }
484        case FRESH_RENDER: {
485            stats->noFreshRender++;
486            break;
487        }
488        case OLD: {
489            stats->noOldCache++;
490            break;
491        }
492        case OLD_RENDER: {
493            stats->noOldRender++;
494            break;
495        }
496        }
497        apr_global_mutex_unlock(stats_mutex);
498        /* Swallowing the result because what are we going to do with it at
499         * this stage?
500         */
501        return 1;
502    } else {
503        return 0;
504    }
505}
506
507static int tile_handler_dirty(request_rec *r)
508{
509    if(strcmp(r->handler, "tile_dirty"))
510        return DECLINED;
511
512    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
513    if (cmd == NULL)
514        return DECLINED;
515
516    request_tile(r, cmd, 0);
517    return error_message(r, "Tile submitted for rendering\n");
518}
519
520static int tile_storage_hook(request_rec *r)
521{
522//    char abs_path[PATH_MAX];
523    int avg;
524    int renderPrio = 0;
525    enum tileState state;
526
527    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_storage_hook: handler(%s), uri(%s), filename(%s), path_info(%s)",
528                  r->handler, r->uri, r->filename, r->path_info);
529
530    if (!r->handler)
531        return DECLINED;
532
533    // Any status request is OK
534    if (!strcmp(r->handler, "tile_status"))
535        return OK;
536
537    if (strcmp(r->handler, "tile_serve") && strcmp(r->handler, "tile_dirty"))
538        return DECLINED;
539
540    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
541    if (cmd == NULL)
542        return DECLINED;
543/*
544should already be done
545    // Generate the tile filename
546#ifdef METATILE
547    ap_conf_vector_t *sconf = r->server->module_config;
548    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
549    xyz_to_meta(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
550#else
551    xyz_to_path(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
552#endif
553    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "abs_path(%s)", abs_path);
554    r->filename = apr_pstrdup(r->pool, abs_path);
555*/
556    avg = get_load_avg(r);
557    state = tile_state(r, cmd);
558
559    ap_conf_vector_t *sconf = r->server->module_config;
560    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
561
562    switch (state) {
563        case tileCurrent:
564            if (!incFreshCounter(FRESH, r)) {
565                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
566                    "Failed to increase fresh stats counter");
567            }
568            return OK;
569            break;
570        case tileOld:
571            if (avg > scfg->max_load_old) {
572               // Too much load to render it now, mark dirty but return old tile
573               request_tile(r, cmd, 0);
574               ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Load larger max_load_old (%d). Mark dirty and deliver from cache.", scfg->max_load_old);
575               if (!incFreshCounter(OLD, r)) {
576                   ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
577                        "Failed to increase fresh stats counter");
578               }
579               return OK;
580            }
581            renderPrio = 1;
582            break;
583        case tileMissing:
584            if (avg > scfg->max_load_missing) {
585               request_tile(r, cmd, 0);
586               ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Load larger max_load_missing (%d). Return HTTP_NOT_FOUND.", scfg->max_load_missing);
587               if (!incRespCounter(HTTP_NOT_FOUND, r)) {
588                   ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
589                        "Failed to increase response stats counter");
590               }
591               return HTTP_NOT_FOUND;
592            }
593            renderPrio = 2;
594            break;
595    }
596
597    if (request_tile(r, cmd, renderPrio)) {
598        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Update file info abs_path(%s)", r->filename);
599        // Need to update fileinfo for new rendered tile
600        apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool);
601        if (!incFreshCounter(FRESH_RENDER, r)) {
602            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
603                    "Failed to increase fresh stats counter");
604        }
605        return OK;
606    }
607
608    if (state == tileOld) {
609        if (!incFreshCounter(OLD_RENDER, r)) {
610            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
611                    "Failed to increase fresh stats counter");
612        }
613        return OK;
614    }
615    if (!incRespCounter(HTTP_NOT_FOUND, r)) {
616        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
617                "Failed to increase response stats counter");
618    }
619
620    return HTTP_NOT_FOUND;
621}
622
623static int tile_handler_status(request_rec *r)
624{
625    enum tileState state;
626    char time_str[APR_CTIME_LEN];
627
628    if(strcmp(r->handler, "tile_status"))
629        return DECLINED;
630
631    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
632    if (cmd == NULL){
633        sleep(CLIENT_PENALTY);
634        return HTTP_NOT_FOUND;
635    }
636
637    state = tile_state(r, cmd);
638    if (state == tileMissing)
639        return error_message(r, "Unable to find a tile at %s\n", r->filename);
640    apr_ctime(time_str, r->finfo.mtime);
641
642    return error_message(r, "Tile is %s. Last rendered at %s\n", (state == tileOld) ? "due to be rendered" : "clean", time_str);
643}
644
645static int tile_handler_mod_stats(request_rec *r)
646{
647    stats_data * stats;
648    stats_data local_stats;
649
650    if (strcmp(r->handler, "tile_mod_stats"))
651        return DECLINED;
652
653    ap_conf_vector_t *sconf = r->server->module_config;
654    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
655
656    if (!scfg->enableGlobalStats) {
657        return error_message(r, "Stats are not enabled for this server");
658    }
659
660    if (get_global_lock(r) != 0) {
661        //Copy over the global counter variable into
662        //local variables, that we can immediately
663        //release the lock again
664        stats = (stats_data *) apr_shm_baseaddr_get(stats_shm);
665        memcpy(&local_stats, stats, sizeof(stats_data));
666        apr_global_mutex_unlock(stats_mutex);
667    } else {
668        return error_message(r, "Failed to acquire lock, can't display stats");
669    }
670
671    ap_rprintf(r, "NoResp200: %li\n", local_stats.noResp200);
672    ap_rprintf(r, "NoResp304: %li\n", local_stats.noResp304);
673    ap_rprintf(r, "NoResp404: %li\n", local_stats.noResp404);
674    ap_rprintf(r, "NoResp5XX: %li\n", local_stats.noResp5XX);
675    ap_rprintf(r, "NoRespOther: %li\n", local_stats.noRespOther);
676    ap_rprintf(r, "NoFreshCache: %li\n", local_stats.noFreshCache);
677    ap_rprintf(r, "NoOldCache: %li\n", local_stats.noOldCache);
678    ap_rprintf(r, "NoFreshRender: %li\n", local_stats.noFreshRender);
679    ap_rprintf(r, "NoOldRender: %li\n", local_stats.noOldRender);
680
681
682    return OK;
683}
684
685static int tile_handler_serve(request_rec *r)
686{
687    const int tile_max = MAX_SIZE;
688    unsigned char *buf;
689    int len;
690    apr_status_t errstatus;
691
692    if(strcmp(r->handler, "tile_serve"))
693        return DECLINED;
694
695    struct protocol * cmd = (struct protocol *)ap_get_module_config(r->request_config, &tile_module);
696    if (cmd == NULL){
697        sleep(CLIENT_PENALTY);
698        if (!incRespCounter(HTTP_NOT_FOUND, r)) {
699            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
700                    "Failed to increase response stats counter");
701        }
702        return HTTP_NOT_FOUND;
703    }
704
705    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_handler_serve: xml(%s) z(%d) x(%d) y(%d)", cmd->xmlname, cmd->z, cmd->x, cmd->y);
706
707    // FIXME: It is a waste to do the malloc + read if we are fulfilling a HEAD or returning a 304.
708    buf = malloc(tile_max);
709    if (!buf) {
710        if (!incRespCounter(HTTP_INTERNAL_SERVER_ERROR, r)) {
711            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
712                    "Failed to increase response stats counter");
713        }
714        return HTTP_INTERNAL_SERVER_ERROR;
715    }
716
717    len = tile_read(cmd->xmlname, cmd->x, cmd->y, cmd->z, buf, tile_max);
718    if (len > 0) {
719#if 0
720        // Set default Last-Modified and Etag headers
721        ap_update_mtime(r, r->finfo.mtime);
722        ap_set_last_modified(r);
723        ap_set_etag(r);
724#else
725        // Use MD5 hash as only cache attribute.
726        // If a tile is re-rendered and produces the same output
727        // then we can continue to use the previous cached copy
728        char *md5 = ap_md5_binary(r->pool, buf, len);
729        apr_table_setn(r->headers_out, "ETag",
730                        apr_psprintf(r->pool, "\"%s\"", md5));
731#endif
732        ap_set_content_type(r, "image/png");
733        ap_set_content_length(r, len);
734        add_expiry(r, cmd);
735        if ((errstatus = ap_meets_conditions(r)) != OK) {
736            free(buf);
737            if (!incRespCounter(errstatus, r)) {
738                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
739                        "Failed to increase response stats counter");
740            }
741            return errstatus;
742        } else {
743            ap_rwrite(buf, len, r);
744            free(buf);
745            if (!incRespCounter(errstatus, r)) {
746                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
747                        "Failed to increase response stats counter");
748            }
749            return OK;
750        }
751    }
752    free(buf);
753    //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "len = %d", len);
754    if (!incRespCounter(HTTP_NOT_FOUND, r)) {
755        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
756                "Failed to increase response stats counter");
757    }
758    return DECLINED;
759}
760
761static int tile_translate(request_rec *r)
762{
763    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: uri(%s)", r->uri);
764
765    int i,n,limit,oob;
766    char option[11];
767
768    ap_conf_vector_t *sconf = r->server->module_config;
769    tile_server_conf *scfg = ap_get_module_config(sconf, &tile_module);
770
771    tile_config_rec *tile_configs = (tile_config_rec *) scfg->configs->elts;
772
773    /*
774     * The page /mod_tile returns global stats about the number of tiles
775     * handled and in what state those tiles were.
776     * This should probably not be hard coded
777     */
778    if (!strncmp("/mod_tile", r->uri, strlen("/mod_tile"))) {
779        r->handler = "tile_mod_stats";
780        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
781                "tile_translate: retrieving global mod_tile stats");
782        return OK;
783    }
784
785    for (i = 0; i < scfg->configs->nelts; ++i) {
786        tile_config_rec *tile_config = &tile_configs[i];
787
788        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: baseuri(%s) name(%s)", tile_config->baseuri, tile_config->xmlname);
789
790        if (!strncmp(tile_config->baseuri, r->uri, strlen(tile_config->baseuri))) {
791
792            struct protocol * cmd = (struct protocol *) apr_pcalloc(r->pool, sizeof(struct protocol));
793            bzero(cmd, sizeof(struct protocol));
794
795            n = sscanf(r->uri+strlen(tile_config->baseuri), "%d/%d/%d.png/%10s", &(cmd->z), &(cmd->x), &(cmd->y), option);
796            if (n < 3) return DECLINED;
797
798            oob = (cmd->z < 0 || cmd->z > MAX_ZOOM);
799            if (!oob) {
800                 // valid x/y for tiles are 0 ... 2^zoom-1
801                 limit = (1 << cmd->z) - 1;
802                 oob =  (cmd->x < 0 || cmd->x > limit || cmd->y < 0 || cmd->y > limit);
803            }
804
805            if (oob) {
806                sleep(CLIENT_PENALTY);
807                //Don't increase stats counter here,
808                //As we are interested in valid tiles only
809                return HTTP_NOT_FOUND;
810            }
811
812            strcpy(cmd->xmlname, tile_config->xmlname);
813
814            // Store a copy for later
815            ap_set_module_config(r->request_config, &tile_module, cmd);
816
817            // Generate the tile filename?
818            char abs_path[PATH_MAX];
819#ifdef METATILE
820            xyz_to_meta(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
821#else
822            xyz_to_path(abs_path, sizeof(abs_path), scfg->tile_dir, cmd->xmlname, cmd->x, cmd->y, cmd->z);
823#endif
824            r->filename = apr_pstrdup(r->pool, abs_path);
825
826            if (n == 4) {
827                if (!strcmp(option, "status")) r->handler = "tile_status";
828                else if (!strcmp(option, "dirty")) r->handler = "tile_dirty";
829                else return DECLINED;
830            } else {
831                r->handler = "tile_serve";
832            }
833
834            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "tile_translate: op(%s) xml(%s) z(%d) x(%d) y(%d)", r->handler , cmd->xmlname, cmd->z, cmd->x, cmd->y);
835
836            return OK;
837        }
838    }
839    return DECLINED;
840}
841
842/*
843 * This routine is called in the parent, so we'll set up the shared
844 * memory segment and mutex here.
845 */
846
847static int mod_tile_post_config(apr_pool_t *pconf, apr_pool_t *plog,
848                             apr_pool_t *ptemp, server_rec *s)
849{
850    void *data; /* These two help ensure that we only init once. */
851    const char *userdata_key = "mod_tile_init_module";
852    apr_status_t rs;
853    stats_data *stats;
854
855
856    /*
857     * The following checks if this routine has been called before.
858     * This is necessary because the parent process gets initialized
859     * a couple of times as the server starts up, and we don't want
860     * to create any more mutexes and shared memory segments than
861     * we're actually going to use.
862     */
863    apr_pool_userdata_get(&data, userdata_key, s->process->pool);
864    if (!data) {
865        apr_pool_userdata_set((const void *) 1, userdata_key,
866                              apr_pool_cleanup_null, s->process->pool);
867        return OK;
868    } /* Kilroy was here */
869
870    /* Create the shared memory segment */
871
872    /*
873     * Create a unique filename using our pid. This information is
874     * stashed in the global variable so the children inherit it.
875     * TODO get the location from the environment $TMPDIR or somesuch.
876     */
877    shmfilename = apr_psprintf(pconf, "/tmp/httpd_shm.%ld", (long int)getpid());
878
879    /* Now create that segment */
880    rs = apr_shm_create(&stats_shm, sizeof(stats_data),
881                        (const char *) shmfilename, pconf);
882    if (rs != APR_SUCCESS) {
883        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
884                     "Failed to create shared memory segment on file %s",
885                     shmfilename);
886        return HTTP_INTERNAL_SERVER_ERROR;
887    }
888
889    /* Created it, now let's zero it out */
890    stats = (stats_data *)apr_shm_baseaddr_get(stats_shm);
891    stats->noResp200 = 0;
892    stats->noResp304 = 0;
893    stats->noResp404 = 0;
894    stats->noResp5XX = 0;
895    stats->noRespOther = 0;
896    stats->noFreshCache = 0;
897    stats->noFreshRender = 0;
898    stats->noOldCache = 0;
899    stats->noOldRender = 0;
900
901    /* Create global mutex */
902
903    /*
904     * Create another unique filename to lock upon. Note that
905     * depending on OS and locking mechanism of choice, the file
906     * may or may not be actually created.
907     */
908    mutexfilename = apr_psprintf(pconf, "/tmp/httpd_mutex.%ld",
909                                 (long int) getpid());
910
911    rs = apr_global_mutex_create(&stats_mutex, (const char *) mutexfilename,
912                                 APR_LOCK_DEFAULT, pconf);
913    if (rs != APR_SUCCESS) {
914        ap_log_error(APLOG_MARK, APLOG_ERR, rs, s,
915                     "Failed to create mutex on file %s",
916                     mutexfilename);
917        return HTTP_INTERNAL_SERVER_ERROR;
918    }
919
920#ifdef MOD_TILE_SET_MUTEX_PERMS
921    rs = unixd_set_global_mutex_perms(stats_mutex);
922    if (rs != APR_SUCCESS) {
923        ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
924                     "Parent could not set permissions on mod_tile "
925                     "mutex: check User and Group directives");
926        return HTTP_INTERNAL_SERVER_ERROR;
927    }
928#endif /* MOD_TILE_SET_MUTEX_PERMS */
929
930    return OK;
931}
932
933
934/*
935 * This routine gets called when a child inits. We use it to attach
936 * to the shared memory segment, and reinitialize the mutex.
937 */
938
939static void mod_tile_child_init(apr_pool_t *p, server_rec *s)
940{
941    apr_status_t rs;
942
943     /*
944      * Re-open the mutex for the child. Note we're reusing
945      * the mutex pointer global here.
946      */
947     rs = apr_global_mutex_child_init(&stats_mutex,
948                                      (const char *) mutexfilename,
949                                      p);
950     if (rs != APR_SUCCESS) {
951         ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s,
952                     "Failed to reopen mutex on file %s",
953                     shmfilename);
954         /* There's really nothing else we can do here, since
955          * This routine doesn't return a status. */
956         exit(1); /* Ugly, but what else? */
957     }
958}
959
960static void register_hooks(__attribute__((unused)) apr_pool_t *p)
961{
962    ap_hook_post_config(mod_tile_post_config, NULL, NULL, APR_HOOK_MIDDLE);
963    ap_hook_child_init(mod_tile_child_init, NULL, NULL, APR_HOOK_MIDDLE);
964    ap_hook_handler(tile_handler_serve, NULL, NULL, APR_HOOK_MIDDLE);
965    ap_hook_handler(tile_handler_dirty, NULL, NULL, APR_HOOK_MIDDLE);
966    ap_hook_handler(tile_handler_status, NULL, NULL, APR_HOOK_MIDDLE);
967    ap_hook_handler(tile_handler_mod_stats, NULL, NULL, APR_HOOK_MIDDLE);
968    ap_hook_translate_name(tile_translate, NULL, NULL, APR_HOOK_MIDDLE);
969    ap_hook_map_to_storage(tile_storage_hook, NULL, NULL, APR_HOOK_FIRST);
970}
971
972static const char *_add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name, int minzoom, int maxzoom)
973{
974    if (strlen(name) == 0) {
975        return "ConfigName value must not be null";
976    }
977
978    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
979    tile_config_rec *tilecfg = apr_array_push(scfg->configs);
980
981    strncpy(tilecfg->baseuri, baseuri, PATH_MAX-1);
982    tilecfg->baseuri[PATH_MAX-1] = 0;
983    strncpy(tilecfg->xmlname, name, XMLCONFIG_MAX-1);
984    tilecfg->xmlname[XMLCONFIG_MAX-1] = 0;
985    tilecfg->minzoom = minzoom;
986    tilecfg->maxzoom = maxzoom;
987
988
989    return NULL;
990}
991
992static const char *add_tile_config(cmd_parms *cmd, void *mconfig, const char *baseuri, const char *name)
993{
994    return _add_tile_config(cmd, mconfig, baseuri, name, 0, MAX_ZOOM);
995}
996
997static const char *load_tile_config(cmd_parms *cmd, void *mconfig, const char *conffile)
998{
999    FILE * hini ;
1000    char filename[PATH_MAX];
1001    char xmlname[XMLCONFIG_MAX];
1002    char line[INILINE_MAX];
1003    char key[INILINE_MAX];
1004    char value[INILINE_MAX];
1005    const char * result;
1006
1007    if (strlen(conffile) == 0) {
1008        strcpy(filename, RENDERD_CONFIG);
1009    } else {
1010        strcpy(filename, conffile);
1011    }
1012
1013    // Load the config
1014    if ((hini=fopen(filename, "r"))==NULL) {
1015        return "Unable to open config file";
1016    }
1017
1018    while (fgets(line, INILINE_MAX, hini)!=NULL) {
1019        if (line[0] == '#') continue;
1020        if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
1021        if (line[0] == '[') {
1022            if (strlen(line) >= XMLCONFIG_MAX){
1023                return "XML name too long";
1024            }
1025            sscanf(line, "[%[^]]", xmlname);
1026        } else if (sscanf(line, "%[^=]=%[^;#]", key, value) == 2
1027               ||  sscanf(line, "%[^=]=\"%[^\"]\"", key, value) == 2) {
1028
1029            if (!strcmp(key, "URI")){
1030                if (strlen(value) >= PATH_MAX){
1031                    return "URI too long";
1032                }
1033                result = add_tile_config(cmd, mconfig, value, xmlname);
1034                if (result != NULL) return result;
1035            }
1036        }
1037    }
1038    fclose(hini);
1039    return NULL;
1040}
1041
1042static const char *mod_tile_request_timeout_config(cmd_parms *cmd, void *mconfig, const char *request_timeout_string)
1043{
1044    int request_timeout;
1045
1046    if (sscanf(request_timeout_string, "%d", &request_timeout) != 1) {
1047        return "ModTileRequestTimeout needs integer argument";
1048    }
1049
1050    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1051    scfg->request_timeout = request_timeout;
1052    return NULL;
1053}
1054
1055static const char *mod_tile_max_load_old_config(cmd_parms *cmd, void *mconfig, const char *max_load_old_string)
1056{
1057    int max_load_old;
1058
1059    if (sscanf(max_load_old_string, "%d", &max_load_old) != 1) {
1060        return "ModTileMaxLoadOld needs integer argument";
1061    }
1062
1063    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1064    scfg->max_load_old = max_load_old;
1065    return NULL;
1066}
1067
1068static const char *mod_tile_max_load_missing_config(cmd_parms *cmd, void *mconfig, const char *max_load_missing_string)
1069{
1070    int max_load_missing;
1071
1072    if (sscanf(max_load_missing_string, "%d", &max_load_missing) != 1) {
1073        return "ModTileMaxLoadMissing needs integer argument";
1074    }
1075
1076    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1077    scfg->max_load_missing = max_load_missing;
1078    return NULL;
1079}
1080
1081static const char *mod_tile_renderd_socket_name_config(cmd_parms *cmd, void *mconfig, const char *renderd_socket_name_string)
1082{
1083    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1084    strncpy(scfg->renderd_socket_name, renderd_socket_name_string, PATH_MAX-1);
1085    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1086    return NULL;
1087}
1088
1089static const char *mod_tile_tile_dir_config(cmd_parms *cmd, void *mconfig, const char *tile_dir_string)
1090{
1091    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1092    strncpy(scfg->tile_dir, tile_dir_string, PATH_MAX-1);
1093    scfg->tile_dir[PATH_MAX-1] = 0;
1094    return NULL;
1095}
1096
1097static const char *mod_tile_cache_lastmod_factor_config(cmd_parms *cmd, void *mconfig, const char *modified_factor_string)
1098{
1099    float modified_factor;
1100    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1101            &tile_module);
1102    if (sscanf(modified_factor_string, "%f", &modified_factor) != 1) {
1103        return "ModTileCacheLastModifiedFactor needs float argument";
1104    }
1105    scfg->cache_duration_last_modified_factor = modified_factor;
1106    return NULL;
1107}
1108
1109static const char *mod_tile_cache_duration_max_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1110{
1111    int cache_duration;
1112    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1113            &tile_module);
1114    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1115        return "ModTileCacheDurationMax needs integer argument";
1116    }
1117    scfg->cache_duration_max = cache_duration;
1118    return NULL;
1119}
1120
1121static const char *mod_tile_cache_duration_dirty_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1122{
1123    int cache_duration;
1124    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1125            &tile_module);
1126    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1127        return "ModTileCacheDurationDirty needs integer argument";
1128    }
1129    scfg->cache_duration_dirty = cache_duration;
1130    return NULL;
1131}
1132
1133static const char *mod_tile_cache_duration_minimum_config(cmd_parms *cmd, void *mconfig, const char *cache_duration_string)
1134{
1135    int cache_duration;
1136    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config,
1137            &tile_module);
1138    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1139        return "ModTileCacheDurationMinimum needs integer argument";
1140    }
1141    scfg->cache_duration_minimum = cache_duration;
1142    return NULL;
1143}
1144
1145static const char *mod_tile_cache_duration_low_config(cmd_parms *cmd, void *mconfig, const char *zoom_level_string, const char *cache_duration_string)
1146{
1147    int zoom_level;
1148    int cache_duration;
1149    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1150    if (sscanf(zoom_level_string, "%d", &zoom_level) != 1) {
1151            return "ModTileCacheDurationLowZoom needs integer argument";
1152    }
1153    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1154            return "ModTileCacheDurationLowZoom needs integer argument";
1155    }
1156    scfg->cache_level_low_zoom = zoom_level;
1157    scfg->cache_duration_low_zoom = cache_duration;
1158
1159    return NULL;
1160}
1161static const char *mod_tile_cache_duration_medium_config(cmd_parms *cmd, void *mconfig, const char *zoom_level_string, const char *cache_duration_string)
1162{
1163    int zoom_level;
1164    int cache_duration;
1165    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1166    if (sscanf(zoom_level_string, "%d", &zoom_level) != 1) {
1167            return "ModTileCacheDurationMediumZoom needs integer argument";
1168    }
1169    if (sscanf(cache_duration_string, "%d", &cache_duration) != 1) {
1170            return "ModTileCacheDurationMediumZoom needs integer argument";
1171    }
1172    scfg->cache_level_medium_zoom = zoom_level;
1173    scfg->cache_duration_medium_zoom = cache_duration;
1174
1175    return NULL;
1176}
1177
1178static const char *mod_tile_enable_stats(cmd_parms *cmd, void *mconfig, int enableStats)
1179{
1180    tile_server_conf *scfg = ap_get_module_config(cmd->server->module_config, &tile_module);
1181    scfg->enableGlobalStats = enableStats;
1182    return NULL;
1183}
1184
1185static void *create_tile_config(apr_pool_t *p, server_rec *s)
1186{
1187    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
1188
1189    scfg->configs = apr_array_make(p, 4, sizeof(tile_config_rec));
1190    scfg->request_timeout = REQUEST_TIMEOUT;
1191    scfg->max_load_old = MAX_LOAD_OLD;
1192    scfg->max_load_missing = MAX_LOAD_MISSING;
1193    strncpy(scfg->renderd_socket_name, RENDER_SOCKET, PATH_MAX-1);
1194    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1195    strncpy(scfg->tile_dir, HASH_PATH, PATH_MAX-1);
1196    scfg->tile_dir[PATH_MAX-1] = 0;
1197    scfg->cache_duration_dirty = 15*60;
1198    scfg->cache_duration_last_modified_factor = 0.0;
1199    scfg->cache_duration_max = 7*24*60*60;
1200    scfg->cache_duration_minimum = 3*60*60;
1201    scfg->cache_duration_low_zoom = 6*24*60*60;
1202    scfg->cache_duration_medium_zoom = 1*24*60*60;
1203    scfg->cache_level_low_zoom = 0;
1204    scfg->cache_level_medium_zoom = 0;
1205    scfg->enableGlobalStats = 1;
1206
1207    return scfg;
1208}
1209
1210static void *merge_tile_config(apr_pool_t *p, void *basev, void *overridesv)
1211{
1212    int i;
1213    tile_server_conf * scfg = (tile_server_conf *) apr_pcalloc(p, sizeof(tile_server_conf));
1214    tile_server_conf * scfg_base = (tile_server_conf *) basev;
1215    tile_server_conf * scfg_over = (tile_server_conf *) overridesv;
1216
1217    scfg->configs = apr_array_append(p, scfg_base->configs, scfg_over->configs);
1218    scfg->request_timeout = scfg_over->request_timeout;
1219    scfg->max_load_old = scfg_over->max_load_old;
1220    scfg->max_load_missing = scfg_over->max_load_missing;
1221    strncpy(scfg->renderd_socket_name, scfg_over->renderd_socket_name, PATH_MAX-1);
1222    scfg->renderd_socket_name[PATH_MAX-1] = 0;
1223    strncpy(scfg->tile_dir, scfg_over->tile_dir, PATH_MAX-1);
1224    scfg->tile_dir[PATH_MAX-1] = 0;
1225    scfg->cache_duration_dirty = scfg_over->cache_duration_dirty;
1226    scfg->cache_duration_last_modified_factor = scfg_over->cache_duration_last_modified_factor;
1227    scfg->cache_duration_max = scfg_over->cache_duration_max;
1228    scfg->cache_duration_minimum = scfg_over->cache_duration_minimum;
1229    scfg->cache_duration_low_zoom = scfg_over->cache_duration_low_zoom;
1230    scfg->cache_duration_medium_zoom = scfg_over->cache_duration_medium_zoom;
1231    scfg->cache_level_low_zoom = scfg_over->cache_level_low_zoom;
1232    scfg->cache_level_medium_zoom = scfg_over->cache_level_medium_zoom;
1233    scfg->enableGlobalStats = scfg_over->enableGlobalStats;
1234
1235    //Construct a table of minimum cache times per zoom level
1236    for (i = 0; i <= MAX_ZOOM; i++) {
1237        if (i <= scfg->cache_level_low_zoom) {
1238            scfg->mincachetime[i] = scfg->cache_duration_low_zoom;
1239        } else if (i <= scfg->cache_level_medium_zoom) {
1240            scfg->mincachetime[i] = scfg->cache_duration_medium_zoom;
1241        } else {
1242            scfg->mincachetime[i] = scfg->cache_duration_minimum;
1243        }
1244    }
1245
1246    return scfg;
1247}
1248
1249static const command_rec tile_cmds[] =
1250{
1251    AP_INIT_TAKE1(
1252        "LoadTileConfigFile",            /* directive name */
1253        load_tile_config,                /* config action routine */
1254        NULL,                            /* argument to include in call */
1255        OR_OPTIONS,                      /* where available */
1256        "load an entire renderd config file"  /* directive description */
1257    ),
1258    AP_INIT_TAKE2(
1259        "AddTileConfig",                 /* directive name */
1260        add_tile_config,                 /* config action routine */
1261        NULL,                            /* argument to include in call */
1262        OR_OPTIONS,                      /* where available */
1263        "path and name of renderd config to use"  /* directive description */
1264    ),
1265    AP_INIT_TAKE1(
1266        "ModTileRequestTimeout",         /* directive name */
1267        mod_tile_request_timeout_config, /* config action routine */
1268        NULL,                            /* argument to include in call */
1269        OR_OPTIONS,                      /* where available */
1270        "Set timeout in seconds on mod_tile requests"  /* directive description */
1271    ),
1272    AP_INIT_TAKE1(
1273        "ModTileMaxLoadOld",             /* directive name */
1274        mod_tile_max_load_old_config,    /* config action routine */
1275        NULL,                            /* argument to include in call */
1276        OR_OPTIONS,                      /* where available */
1277        "Set max load for rendering old tiles"  /* directive description */
1278    ),
1279    AP_INIT_TAKE1(
1280        "ModTileMaxLoadMissing",         /* directive name */
1281        mod_tile_max_load_missing_config, /* config action routine */
1282        NULL,                            /* argument to include in call */
1283        OR_OPTIONS,                      /* where available */
1284        "Set max load for rendering missing tiles"  /* directive description */
1285    ),
1286    AP_INIT_TAKE1(
1287        "ModTileRenderdSocketName",      /* directive name */
1288        mod_tile_renderd_socket_name_config, /* config action routine */
1289        NULL,                            /* argument to include in call */
1290        OR_OPTIONS,                      /* where available */
1291        "Set name of unix domain socket for connecting to rendering daemon"  /* directive description */
1292    ),
1293    AP_INIT_TAKE1(
1294        "ModTileTileDir",                /* directive name */
1295        mod_tile_tile_dir_config,        /* config action routine */
1296        NULL,                            /* argument to include in call */
1297        OR_OPTIONS,                      /* where available */
1298        "Set name of tile cache directory"  /* directive description */
1299    ),
1300    AP_INIT_TAKE1(
1301        "ModTileCacheDurationMax",                /* directive name */
1302        mod_tile_cache_duration_max_config,        /* config action routine */
1303        NULL,                            /* argument to include in call */
1304        OR_OPTIONS,                      /* where available */
1305        "Set the maximum cache expiry in seconds"  /* directive description */
1306    ),
1307    AP_INIT_TAKE1(
1308        "ModTileCacheDurationDirty",                    /* directive name */
1309        mod_tile_cache_duration_dirty_config,           /* config action routine */
1310        NULL,                                           /* argument to include in call */
1311        OR_OPTIONS,                                     /* where available */
1312        "Set the cache expiry for serving dirty tiles"  /* directive description */
1313    ),
1314    AP_INIT_TAKE1(
1315        "ModTileCacheDurationMinimum",          /* directive name */
1316        mod_tile_cache_duration_minimum_config, /* config action routine */
1317        NULL,                                   /* argument to include in call */
1318        OR_OPTIONS,                             /* where available */
1319        "Set the minimum cache expiry"          /* directive description */
1320    ),
1321    AP_INIT_TAKE1(
1322        "ModTileCacheLastModifiedFactor",       /* directive name */
1323        mod_tile_cache_lastmod_factor_config,   /* config action routine */
1324        NULL,                                   /* argument to include in call */
1325        OR_OPTIONS,                             /* where available */
1326        "Set the factor by which the last modified determins cache expiry" /* directive description */
1327    ),
1328    AP_INIT_TAKE2(
1329        "ModTileCacheDurationLowZoom",       /* directive name */
1330        mod_tile_cache_duration_low_config,                 /* config action routine */
1331        NULL,                            /* argument to include in call */
1332        OR_OPTIONS,                      /* where available */
1333        "Set the minimum cache duration and zoom level for low zoom tiles"  /* directive description */
1334    ),
1335    AP_INIT_TAKE2(
1336        "ModTileCacheDurationMediumZoom",       /* directive name */
1337        mod_tile_cache_duration_medium_config,                 /* config action routine */
1338        NULL,                            /* argument to include in call */
1339        OR_OPTIONS,                      /* where available */
1340        "Set the minimum cache duration and zoom level for medium zoom tiles"  /* directive description */
1341    ),
1342    AP_INIT_FLAG(
1343        "ModTileEnableStats",       /* directive name */
1344        mod_tile_enable_stats,                 /* config action routine */
1345        NULL,                            /* argument to include in call */
1346        OR_OPTIONS,                      /* where available */
1347        "On Off - enable of keeping stats about what mod_tile is serving"  /* directive description */
1348    ),
1349    {NULL}
1350};
1351
1352module AP_MODULE_DECLARE_DATA tile_module =
1353{
1354    STANDARD20_MODULE_STUFF,
1355    NULL,                                /* dir config creater */
1356    NULL,                                /* dir merger --- default is to override */
1357    create_tile_config,                  /* server config */
1358    merge_tile_config,                   /* merge server config */
1359    tile_cmds,                           /* command apr_table_t */
1360    register_hooks                       /* register hooks */
1361};
1362
Note: See TracBrowser for help on using the repository browser.