From 6ce2df051762a51454efe56390b9e88c6385e165 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Thu, 19 Jan 2012 17:15:45 +0000 Subject: [PATCH] Have both RTREE and PREPARED_GEOM caches cohexist (#547) Fixes a memory leak and improves performances when both p-i-p and other kind of overlays are requested during the same statement. git-svn-id: http://svn.osgeo.org/postgis/trunk@8877 b70326c6-7e19-0410-871a-916f4a2858ee --- postgis/Makefile.in | 1 + postgis/lwgeom_cache.c | 30 +++++++++++++ postgis/lwgeom_cache.h | 30 +++++++++++++ postgis/lwgeom_geos.c | 80 ++++++++++++---------------------- postgis/lwgeom_geos_prepared.c | 12 +++-- postgis/lwgeom_rtree.c | 5 ++- postgis/lwgeom_rtree.h | 2 + 7 files changed, 102 insertions(+), 58 deletions(-) create mode 100644 postgis/lwgeom_cache.c create mode 100644 postgis/lwgeom_cache.h diff --git a/postgis/Makefile.in b/postgis/Makefile.in index e359fb049..4e26abec8 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -33,6 +33,7 @@ PG_OBJS= \ lwgeom_btree.o \ lwgeom_box.o \ lwgeom_box3d.o \ + lwgeom_cache.o \ lwgeom_geos.o \ lwgeom_geos_prepared.o \ lwgeom_geos_clean.o \ diff --git a/postgis/lwgeom_cache.c b/postgis/lwgeom_cache.c new file mode 100644 index 000000000..9063036d0 --- /dev/null +++ b/postgis/lwgeom_cache.c @@ -0,0 +1,30 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Copyright (C) 2012 Sandro Santilli + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include "postgres.h" +#include "fmgr.h" + +#include "lwgeom_cache.h" + +GeomCache* GetGeomCache(FunctionCallInfoData *fcinfo) +{ + MemoryContext old_context; + GeomCache* cache = fcinfo->flinfo->fn_extra; + if ( ! cache ) { + old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); + cache = palloc(sizeof(GeomCache)); + MemoryContextSwitchTo(old_context); + cache->prep = 0; + cache->rtree = 0; + } +} + diff --git a/postgis/lwgeom_cache.h b/postgis/lwgeom_cache.h new file mode 100644 index 000000000..e68739859 --- /dev/null +++ b/postgis/lwgeom_cache.h @@ -0,0 +1,30 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Copyright (C) 2012 Sandro Santilli + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#ifndef LWGEOM_GEOS_CACHE_H_ +#define LWGEOM_GEOS_CACHE_H_ 1 + +#include "postgres.h" +#include "fmgr.h" + +#include "lwgeom_pg.h" +#include "lwgeom_rtree.h" +#include "lwgeom_geos_prepared.h" + +typedef struct { + PrepGeomCache* prep; + RTREE_POLY_CACHE* rtree; +} GeomCache; + +GeomCache* GetGeomCache(FunctionCallInfoData *fcinfo); + +#endif /* LWGEOM_GEOS_CACHE_H_ 1 */ diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index f81e8edc3..ce214ca34 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -3,7 +3,7 @@ * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net * - * Copyright 2009-2011 Sandro Santilli + * Copyright 2009-2012 Sandro Santilli * Copyright 2008 Paul Ramsey * Copyright 2001-2003 Refractions Research Inc. * @@ -17,6 +17,7 @@ #include "lwgeom_rtree.h" #include "lwgeom_functions_analytic.h" /* for point_in_polygon */ #include "funcapi.h" +#include "lwgeom_cache.h" /* ** GEOS prepared geometry is only available from GEOS 3.1 onwards @@ -80,11 +81,30 @@ Datum hausdorffdistancedensify(PG_FUNCTION_ARGS); Datum pgis_union_geometry_array_old(PG_FUNCTION_ARGS); Datum pgis_union_geometry_array(PG_FUNCTION_ARGS); - /* ** Prototypes end */ +static RTREE_POLY_CACHE * +GetRtreeCache(FunctionCallInfoData *fcinfo, LWGEOM *lwgeom, GSERIALIZED *poly) +{ + MemoryContext old_context; + GeomCache* supercache = GetGeomCache(fcinfo); + RTREE_POLY_CACHE *poly_cache = supercache->rtree; + + /* + * Switch the context to the function-scope context, + * retrieve the appropriate cache object, cache it for + * future use, then switch back to the local context. + */ + old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); + poly_cache = retrieveCache(lwgeom, poly, poly_cache); + supercache->rtree = poly_cache; + MemoryContextSwitchTo(old_context); + + return poly_cache; +} + PG_FUNCTION_INFO_V1(postgis_geos_version); Datum postgis_geos_version(PG_FUNCTION_ARGS) @@ -1794,7 +1814,6 @@ Datum contains(PG_FUNCTION_ARGS) LWGEOM *lwgeom; LWPOINT *point; RTREE_POLY_CACHE *poly_cache; - MemoryContext old_context; bool result; #ifdef PREPARED_GEOM PrepGeomCache *prep_cache; @@ -1841,15 +1860,7 @@ Datum contains(PG_FUNCTION_ARGS) POSTGIS_DEBUGF(3, "Precall point_in_multipolygon_rtree %p, %p", lwgeom, point); - /* - * Switch the context to the function-scope context, - * retrieve the appropriate cache object, cache it for - * future use, then switch back to the local context. - */ - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - poly_cache = retrieveCache(lwgeom, geom1, fcinfo->flinfo->fn_extra); - fcinfo->flinfo->fn_extra = poly_cache; - MemoryContextSwitchTo(old_context); + poly_cache = GetRtreeCache(fcinfo, lwgeom, geom1); if ( poly_cache->ringIndices ) { @@ -2040,7 +2051,6 @@ Datum covers(PG_FUNCTION_ARGS) LWGEOM *lwgeom; LWPOINT *point; RTREE_POLY_CACHE *poly_cache; - MemoryContext old_context; #ifdef PREPARED_GEOM PrepGeomCache *prep_cache; #endif @@ -2084,15 +2094,7 @@ Datum covers(PG_FUNCTION_ARGS) POSTGIS_DEBUGF(3, "Precall point_in_multipolygon_rtree %p, %p", lwgeom, point); - /* - * Switch the context to the function-scope context, - * retrieve the appropriate cache object, cache it for - * future use, then switch back to the local context. - */ - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - poly_cache = retrieveCache(lwgeom, geom1, fcinfo->flinfo->fn_extra); - fcinfo->flinfo->fn_extra = poly_cache; - MemoryContextSwitchTo(old_context); + poly_cache = GetRtreeCache(fcinfo, lwgeom, geom1); if ( poly_cache->ringIndices ) { @@ -2197,7 +2199,6 @@ Datum within(PG_FUNCTION_ARGS) LWGEOM *lwgeom; LWPOINT *point; int type1, type2; - MemoryContext old_context; RTREE_POLY_CACHE *poly_cache; geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); @@ -2237,15 +2238,7 @@ Datum within(PG_FUNCTION_ARGS) point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom1)); lwgeom = lwgeom_from_gserialized(geom2); - /* - * Switch the context to the function-scope context, - * retrieve the appropriate cache object, cache it for - * future use, then switch back to the local context. - */ - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - poly_cache = retrieveCache(lwgeom, geom2, fcinfo->flinfo->fn_extra); - fcinfo->flinfo->fn_extra = poly_cache; - MemoryContextSwitchTo(old_context); + poly_cache = GetRtreeCache(fcinfo, lwgeom, geom2); if ( poly_cache->ringIndices ) { @@ -2331,7 +2324,6 @@ Datum coveredby(PG_FUNCTION_ARGS) LWGEOM *lwgeom; LWPOINT *point; int type1, type2; - MemoryContext old_context; RTREE_POLY_CACHE *poly_cache; char *patt = "**F**F***"; @@ -2374,15 +2366,7 @@ Datum coveredby(PG_FUNCTION_ARGS) point = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom1)); lwgeom = lwgeom_from_gserialized(geom2); - /* - * Switch the context to the function-scope context, - * retrieve the appropriate cache object, cache it for - * future use, then switch back to the local context. - */ - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - poly_cache = retrieveCache(lwgeom, geom2, fcinfo->flinfo->fn_extra); - fcinfo->flinfo->fn_extra = poly_cache; - MemoryContextSwitchTo(old_context); + poly_cache = GetRtreeCache(fcinfo, lwgeom, geom2); if ( poly_cache->ringIndices ) { @@ -2534,7 +2518,6 @@ Datum intersects(PG_FUNCTION_ARGS) int type1, type2, polytype; LWPOINT *point; LWGEOM *lwgeom; - MemoryContext old_context; RTREE_POLY_CACHE *poly_cache; #ifdef PREPARED_GEOM PrepGeomCache *prep_cache; @@ -2589,15 +2572,8 @@ Datum intersects(PG_FUNCTION_ARGS) serialized_poly = geom1; polytype = type1; } - /* - * Switch the context to the function-scope context, - * retrieve the appropriate cache object, cache it for - * future use, then switch back to the local context. - */ - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - poly_cache = retrieveCache(lwgeom, serialized_poly, fcinfo->flinfo->fn_extra); - fcinfo->flinfo->fn_extra = poly_cache; - MemoryContextSwitchTo(old_context); + + poly_cache = GetRtreeCache(fcinfo, lwgeom, serialized_poly); if ( poly_cache->ringIndices ) { diff --git a/postgis/lwgeom_geos_prepared.c b/postgis/lwgeom_geos_prepared.c index 0e482b383..8b76b9089 100644 --- a/postgis/lwgeom_geos_prepared.c +++ b/postgis/lwgeom_geos_prepared.c @@ -3,6 +3,7 @@ * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net * + * Copyright (C) 2012 Sandro Santilli * Copyright (C) 2008 Paul Ramsey * Copyright (C) 2007 Refractions Research Inc. * @@ -11,7 +12,10 @@ * **********************************************************************/ +#include + #include "lwgeom_geos_prepared.h" +#include "lwgeom_cache.h" /*********************************************************************** ** @@ -273,13 +277,13 @@ PrepGeomCache* GetPrepGeomCache(FunctionCallInfoData *fcinfo, GSERIALIZED *pg_geom1, GSERIALIZED *pg_geom2) { MemoryContext old_context; - PrepGeomCache* cache = fcinfo->flinfo->fn_extra; + GeomCache* supercache = GetGeomCache(fcinfo); + PrepGeomCache* cache = supercache->prep; int copy_keys = 1; size_t pg_geom1_size = 0; size_t pg_geom2_size = 0; - /* Make sure this isn't someone else's cache object. */ - if ( cache && cache->type != 2 ) cache = NULL; + assert ( ! cache || cache->type == 2 ); if (!PrepGeomHash) CreatePrepGeomHash(); @@ -324,7 +328,7 @@ GetPrepGeomCache(FunctionCallInfoData *fcinfo, GSERIALIZED *pg_geom1, GSERIALIZE pghe.prepared_geom = 0; AddPrepGeomHashEntry( pghe ); - fcinfo->flinfo->fn_extra = cache; + supercache->prep = cache; POSTGIS_DEBUGF(3, "GetPrepGeomCache: adding context to hash: %p", cache); } diff --git a/postgis/lwgeom_rtree.c b/postgis/lwgeom_rtree.c index a0f43f9a3..bb9942f5a 100644 --- a/postgis/lwgeom_rtree.c +++ b/postgis/lwgeom_rtree.c @@ -9,6 +9,8 @@ * **********************************************************************/ +#include + #include "lwgeom_pg.h" #include "liblwgeom.h" #include "liblwgeom_internal.h" /* For FP comparators. */ @@ -488,8 +490,7 @@ RTREE_POLY_CACHE *retrieveCache(LWGEOM *lwgeom, GSERIALIZED *serializedPoly, RTR POSTGIS_DEBUGF(2, "retrieveCache called with %p %p %p", lwgeom, serializedPoly, currentCache); - /* Make sure this isn't someone else's cache object. */ - if ( currentCache && currentCache->type != 1 ) currentCache = NULL; + assert ( ! currentCache || currentCache->type == 1 ); if (!currentCache) { diff --git a/postgis/lwgeom_rtree.h b/postgis/lwgeom_rtree.h index be7835de3..d2e33da90 100644 --- a/postgis/lwgeom_rtree.h +++ b/postgis/lwgeom_rtree.h @@ -1,6 +1,8 @@ #ifndef _LWGEOM_RTREE_H #define _LWGEOM_RTREE_H +#include "liblwgeom.h" + typedef struct { double min; -- 2.40.0