示例#1
0
static int _mapcache_cache_sqlite_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
{
    mapcache_cache_sqlite *cache = (mapcache_cache_sqlite*) pcache;
    struct sqlite_conn *conn;
    sqlite3_stmt *stmt;
    int ret;
    mapcache_pooled_connection *pc = mapcache_sqlite_get_conn(ctx,cache,tile,1);
    if (GC_HAS_ERROR(ctx)) {
        if(tile->tileset->read_only || !tile->tileset->source) {
            mapcache_sqlite_release_conn(ctx, pc);
            return MAPCACHE_FAILURE;
        } else {
            /* not an error in this case, as the db file may not have been created yet */
            ctx->clear_errors(ctx);
            mapcache_sqlite_release_conn(ctx, pc);
            return MAPCACHE_CACHE_MISS;
        }
    }
    conn = SQLITE_CONN(pc);
    stmt = conn->prepared_statements[GET_TILE_STMT_IDX];
    if(!stmt) {
        sqlite3_prepare(conn->handle, cache->get_stmt.sql, -1, &conn->prepared_statements[GET_TILE_STMT_IDX], NULL);
        stmt = conn->prepared_statements[GET_TILE_STMT_IDX];
    }
    cache->bind_stmt(ctx, stmt, cache, tile);
    do {
        ret = sqlite3_step(stmt);
        if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_BUSY && ret != SQLITE_LOCKED) {
            ctx->set_error(ctx, 500, "sqlite backend failed on get: %s", sqlite3_errmsg(conn->handle));
            sqlite3_reset(stmt);
            mapcache_sqlite_release_conn(ctx, pc);
            return MAPCACHE_FAILURE;
        }
    } while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED);
    if (ret == SQLITE_DONE) {
        sqlite3_reset(stmt);
        mapcache_sqlite_release_conn(ctx, pc);
        return MAPCACHE_CACHE_MISS;
    } else {
        const void *blob = sqlite3_column_blob(stmt, 0);
        int size = sqlite3_column_bytes(stmt, 0);
        if(size>0 && ((char*)blob)[0] == '#') {
            tile->encoded_data = mapcache_empty_png_decode(ctx,tile->grid_link->grid->tile_sx, tile->grid_link->grid->tile_sy ,blob,&tile->nodata);
        } else {
            tile->encoded_data = mapcache_buffer_create(size, ctx->pool);
            memcpy(tile->encoded_data->buf, blob, size);
            tile->encoded_data->size = size;
        }
        if (sqlite3_column_count(stmt) > 1) {
            time_t mtime = sqlite3_column_int64(stmt, 1);
            apr_time_ansi_put(&(tile->mtime), mtime);
        }
        sqlite3_reset(stmt);
        mapcache_sqlite_release_conn(ctx, pc);
        return MAPCACHE_SUCCESS;
    }
}
示例#2
0
/**
 * \brief get content of given tile
 *
 * fills the mapcache_tile::data of the given tile with content stored on the memcache server
 * \private \memberof mapcache_cache_memcache
 * \sa mapcache_cache::tile_get()
 */
static int _mapcache_cache_memcache_get(mapcache_context *ctx, mapcache_cache *pcache, mapcache_tile *tile)
{
  char *key;
  int rv;
  mapcache_cache_memcache *cache = (mapcache_cache_memcache*)pcache;
  mapcache_pooled_connection *pc;
  mapcache_buffer *encoded_data;
  struct mapcache_memcache_pooled_connection *mpc;
  pc = _mapcache_memcache_get_conn(ctx,cache,tile);
  if(GC_HAS_ERROR(ctx)) {
    return MAPCACHE_FAILURE;
  }
  mpc = pc->connection;
  key = mapcache_util_get_tile_key(ctx, tile,NULL," \r\n\t\f\e\a\b","#");
  if(GC_HAS_ERROR(ctx)) {
    rv = MAPCACHE_FAILURE;
    goto cleanup;
  }
  encoded_data = mapcache_buffer_create(0,ctx->pool);
  rv = apr_memcache_getp(mpc->memcache,ctx->pool,key,(char**)&encoded_data->buf,&encoded_data->size,NULL);
  if(rv != APR_SUCCESS) {
    rv = MAPCACHE_CACHE_MISS;
    goto cleanup;
  }
  if(encoded_data->size == 0) {
    ctx->set_error(ctx,500,"memcache cache returned 0-length data for tile %d %d %d\n",tile->x,tile->y,tile->z);
    rv = MAPCACHE_FAILURE;
    goto cleanup;
  }
  /* extract the tile modification time from the end of the data returned */
  memcpy(
    &tile->mtime,
    &(((char*)encoded_data->buf)[encoded_data->size-sizeof(apr_time_t)]),
    sizeof(apr_time_t));
  
  ((char*)encoded_data->buf)[encoded_data->size+sizeof(apr_time_t)]='\0';
  encoded_data->avail = encoded_data->size;
  encoded_data->size -= sizeof(apr_time_t);
  if(((char*)encoded_data->buf)[0] == '#' && encoded_data->size > 1) {
    tile->encoded_data = mapcache_empty_png_decode(ctx,tile->grid_link->grid->tile_sx, tile->grid_link->grid->tile_sy ,encoded_data->buf,&tile->nodata);
  } else {
    tile->encoded_data = encoded_data;
  }
  rv = MAPCACHE_SUCCESS;
  
cleanup:
  _mapcache_memcache_release_conn(ctx,pc);
  
  return rv;
}
示例#3
0
文件: core.c 项目: MiniHero/mapcache
mapcache_http_response *mapcache_core_get_tile(mapcache_context *ctx, mapcache_request_get_tile *req_tile)
{
  int expires = 0;
  mapcache_http_response *response;
  int i,is_empty=1 /* response image is initially empty */;
  char *timestr;
  mapcache_image *base=NULL;
  mapcache_image_format *format = NULL;

#ifdef DEBUG
  if(req_tile->ntiles ==0) {
    ctx->set_error(ctx,500,"BUG: get_tile called with 0 tiles");
    return NULL;
  }
#endif
  response = mapcache_http_response_create(ctx->pool);


  mapcache_prefetch_tiles(ctx,req_tile->tiles,req_tile->ntiles);
  if(GC_HAS_ERROR(ctx))
    return NULL;

  /* loop through tiles, and eventually merge them vertically together */
  for(i=0; i<req_tile->ntiles; i++) {
    mapcache_tile *tile = req_tile->tiles[i]; /* shortcut */
    if(tile->mtime && (tile->mtime < response->mtime || response->mtime == 0))
      response->mtime = tile->mtime;
    if(tile->expires && (tile->expires < expires || expires == 0)) {
      expires = tile->expires;
    }
    
    if(tile->nodata) {
      /* treat the special case where the cache explicitely stated that the
       tile was empty, and we don't have any vertical merging to do */
      if(tile->encoded_data && req_tile->ntiles == 1) {
        response->data = tile->encoded_data;
        /* we don't touch is_empty, as we have access to the encoded empty image, but the
         resulting tile is empty */
      }
      continue;
    }
    
    /* treat the most common case: 
     - we have a single tile request (i.e. isempty is true)
     - the cache returned the encoded image
     */
    if(is_empty && tile->encoded_data) {
      response->data = tile->encoded_data;
      /* just in case we also have the raw image data available, keep a ref to it
       if we need to merge another tile ontop of it*/
      if(tile->raw_image) {
        base = tile->raw_image;
      }
      is_empty = 0; /* we now know we might need to do some vertical merging */
      continue;
    }

    /* if we're here, either
     * - we need to merge the current tile onto the previous one(s), or
     * - we only have the tile's raw data available
     */

    if(!is_empty) {
      /* we have an existing tile, so we know we need to merge the current one into it */
      if(!base) {
        /* the existing tile has not been decoded yet, but we need the access to the raw pixels*/
        base = mapcache_imageio_decode(ctx, response->data);
        if(!base) return NULL;
      }
      response->data = NULL; /* the encoded data is now obsolete, as we will be merging the current tile */

      /* we need to access the current tile's pixel data */
      if(!tile->raw_image) {
        tile->raw_image = mapcache_imageio_decode(ctx,tile->encoded_data);
        if(!tile->raw_image) return NULL;
      }
      mapcache_image_merge(ctx, base, tile->raw_image);
    } else {
      /* we don't need to merge onto an existing tile and don't have access to the tile's encoded data.
       * 
       * we don't encode the tile's raw image data just yet because we might need to merge another one on top
       * of it later.
       */
      base = tile->raw_image;
      is_empty = 0;
    }
  }

  if(!response->data) {
    /* we need to encode the raw image data*/
    if(base) {
      if(req_tile->format) {
        format = req_tile->format;
      } else {
        format = req_tile->tiles[0]->tileset->format;
        if(!format) {
          format = ctx->config->default_image_format; /* this one is always defined */
        }
      }
      response->data = format->write(ctx, base, format);
      if(GC_HAS_ERROR(ctx)) {
        return NULL;
      }
    } else {
#ifdef DEBUG
      if(!is_empty) {
        ctx->set_error(ctx,500,"BUG: no image data to encode, but tile not marked as empty");
        return NULL;
      }
#endif
      unsigned char empty[5] = {'#',0,0,0,0};
      response->data = mapcache_empty_png_decode(ctx,empty,&is_empty); /* is_empty is unchanged and left to 1 */
      format = mapcache_configuration_get_image_format(ctx->config,"PNG8");
    }
  }
  
  /* compute the content-type */
  mapcache_image_format_type t = mapcache_imageio_header_sniff(ctx,response->data);
  if(t == GC_PNG)
    apr_table_set(response->headers,"Content-Type","image/png");
  else if(t == GC_JPEG)
    apr_table_set(response->headers,"Content-Type","image/jpeg");

  /* compute expiry headers */
  if(expires) {
    apr_time_t now = apr_time_now();
    apr_time_t additional = apr_time_from_sec(expires);
    apr_time_t texpires = now + additional;
    apr_table_set(response->headers, "Cache-Control",apr_psprintf(ctx->pool, "max-age=%d", expires));
    timestr = apr_palloc(ctx->pool, APR_RFC822_DATE_LEN);
    apr_rfc822_date(timestr, texpires);
    apr_table_setn(response->headers, "Expires", timestr);
  }

  return response;
}