Skip to content

Commit e8d538d

Browse files
ohanssentbonfort
authored andcommitted
return stale tile in case an error occured re-reading an expired tile (#125)
1 parent 69c3aca commit e8d538d

File tree

2 files changed

+60
-44
lines changed

2 files changed

+60
-44
lines changed

include/mapcache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
#define MAPCACHE_TILESET_WRONG_EXTENT 4
8585
#define MAPCACHE_CACHE_MISS 5
8686
#define MAPCACHE_FILE_LOCKED 6
87+
#define MAPCACHE_CACHE_RELOAD 7
88+
8789
#define MAPCACHE_MAX_NUM_TILES 1000
8890

8991
#define MAPCACHE_USERAGENT "mod-mapcache/"MAPCACHE_VERSION

lib/tileset.c

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -780,15 +780,12 @@ void mapcache_tileset_tile_get(mapcache_context *ctx, mapcache_tile *tile)
780780
apr_time_t now = apr_time_now();
781781
apr_time_t stale = tile->mtime + apr_time_from_sec(tile->tileset->auto_expire);
782782
if(stale<now) {
783-
mapcache_tileset_tile_delete(ctx,tile,MAPCACHE_TRUE);
784-
GC_CHECK_ERROR(ctx);
785-
ret = MAPCACHE_CACHE_MISS;
783+
/* Indicate that we need to re-render the tile */
784+
ret = MAPCACHE_CACHE_RELOAD;
786785
}
787786
}
788787

789-
if(ret == MAPCACHE_CACHE_MISS) {
790-
int isLocked;
791-
void *lock;
788+
if (ret == MAPCACHE_CACHE_MISS) {
792789
/* bail out straight away if the tileset has no source or is read-only */
793790
if(tile->tileset->read_only || !tile->tileset->source) {
794791
/* there is no source configured for this tile. not an error, let caller now*/
@@ -805,54 +802,71 @@ void mapcache_tileset_tile_get(mapcache_context *ctx, mapcache_tile *tile)
805802
ctx->set_error(ctx,404,"tile not in cache, and configured for readonly mode");
806803
return;
807804
}
805+
}
806+
807+
808+
if (ret == MAPCACHE_CACHE_MISS || ret == MAPCACHE_CACHE_RELOAD) {
809+
int isLocked;
810+
void *lock;
808811

809-
/* the tile does not exist, we must take action before re-asking for it */
810-
/*
811-
* is the tile already being rendered by another thread ?
812-
* the call is protected by the same mutex that sets the lock on the tile,
813-
* so we can assure that:
814-
* - if the lock does not exist, then this thread should do the rendering
815-
* - if the lock exists, we should wait for the other thread to finish
816-
*/
812+
/* If the tile does not exist or stale, we must take action before re-asking for it */
813+
if( !tile->tileset->read_only && tile->tileset->source && !ctx->config->non_blocking) {
814+
/*
815+
* is the tile already being rendered by another thread ?
816+
* the call is protected by the same mutex that sets the lock on the tile,
817+
* so we can assure that:
818+
* - if the lock does not exist, then this thread should do the rendering
819+
* - if the lock exists, we should wait for the other thread to finish
820+
*/
817821

818-
/* aquire a lock on the metatile */
819-
mt = mapcache_tileset_metatile_get(ctx, tile);
820-
isLocked = mapcache_lock_or_wait_for_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), &lock);
821-
GC_CHECK_ERROR(ctx);
822+
/* aquire a lock on the metatile */
823+
mt = mapcache_tileset_metatile_get(ctx, tile);
824+
isLocked = mapcache_lock_or_wait_for_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), &lock);
825+
GC_CHECK_ERROR(ctx);
822826

823827

824-
if(isLocked == MAPCACHE_TRUE) {
825-
/* no other thread is doing the rendering, do it ourselves */
828+
if(isLocked == MAPCACHE_TRUE) {
829+
/* no other thread is doing the rendering, do it ourselves */
826830
#ifdef DEBUG
827-
ctx->log(ctx, MAPCACHE_DEBUG, "cache miss: tileset %s - tile %d %d %d",
828-
tile->tileset->name,tile->x, tile->y,tile->z);
831+
ctx->log(ctx, MAPCACHE_DEBUG, "cache miss/reload: tileset %s - tile %d %d %d",
832+
tile->tileset->name,tile->x, tile->y,tile->z);
829833
#endif
830-
/* this will query the source to create the tiles, and save them to the cache */
831-
mapcache_tileset_render_metatile(ctx, mt);
832-
833-
if(GC_HAS_ERROR(ctx)) {
834-
/* temporarily clear error state so we don't mess up with error handling in the locker */
835-
void *error;
836-
ctx->pop_errors(ctx,&error);
837-
mapcache_unlock_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), lock);
838-
ctx->push_errors(ctx,error);
839-
} else {
840-
mapcache_unlock_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), lock);
834+
/* this will query the source to create the tiles, and save them to the cache */
835+
mapcache_tileset_render_metatile(ctx, mt);
836+
837+
if(GC_HAS_ERROR(ctx)) {
838+
/* temporarily clear error state so we don't mess up with error handling in the locker */
839+
void *error;
840+
ctx->pop_errors(ctx,&error);
841+
mapcache_unlock_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), lock);
842+
ctx->push_errors(ctx,error);
843+
} else {
844+
mapcache_unlock_resource(ctx, ctx->config->locker, mapcache_tileset_metatile_resource_key(ctx,mt), lock);
845+
}
841846
}
842847
}
843-
GC_CHECK_ERROR(ctx);
844848

845-
/* the previous step has successfully finished, we can now query the cache to return the tile content */
846-
ret = tile->tileset->_cache->tile_get(ctx, tile->tileset->_cache, tile);
847-
GC_CHECK_ERROR(ctx);
849+
if (ret == MAPCACHE_CACHE_RELOAD && GC_HAS_ERROR(ctx))
850+
/* If we tried to reload a stale tile but failed, we know we have already
851+
* fetched it from the cache. We can then ignore errors and just use old tile.
852+
*/
853+
ctx->clear_errors(ctx);
848854

849-
if(ret != MAPCACHE_SUCCESS) {
850-
if(isLocked == MAPCACHE_FALSE) {
851-
ctx->set_error(ctx, 500, "tileset %s: unknown error (another thread/process failed to create the tile I was waiting for)",
852-
tile->tileset->name);
853-
} else {
854-
/* shouldn't really happen, as the error ought to have been caught beforehand */
855-
ctx->set_error(ctx, 500, "tileset %s: failed to re-get tile %d %d %d from cache after set", tile->tileset->name,tile->x,tile->y,tile->z);
855+
else {
856+
/* Else, check for errors and try to fetch the tile from the cache.
857+
*/
858+
GC_CHECK_ERROR(ctx);
859+
ret = tile->tileset->_cache->tile_get(ctx, tile->tileset->_cache, tile);
860+
GC_CHECK_ERROR(ctx);
861+
862+
if(ret != MAPCACHE_SUCCESS) {
863+
if(isLocked == MAPCACHE_FALSE) {
864+
ctx->set_error(ctx, 500, "tileset %s: unknown error (another thread/process failed to create the tile I was waiting for)",
865+
tile->tileset->name);
866+
} else {
867+
/* shouldn't really happen, as the error ought to have been caught beforehand */
868+
ctx->set_error(ctx, 500, "tileset %s: failed to re-get tile %d %d %d from cache after set", tile->tileset->name,tile->x,tile->y,tile->z);
869+
}
856870
}
857871
}
858872
}

0 commit comments

Comments
 (0)