* GeomCache entry from the generic cache if one exists.
* If it doesn't exist, make a new empty one and return it.
*/
+#if 0
GeomCache*
GetGeomCache(FunctionCallInfoData* fcinfo, int cache_entry)
{
return cache;
}
+#endif
+GeomCache*
+GetGeomCache2(FunctionCallInfoData* fcinfo, const GeomCacheMethods* cache_methods, const GSERIALIZED* g1, const GSERIALIZED* g2)
+{
+ GeomCache* cache;
+ int cache_hit = 0;
+ MemoryContext old_context;
+ const GSERIALIZED *geom;
+ GenericCacheCollection* generic_cache = GetGenericCacheCollection(fcinfo);
+ int entry_number = cache_methods->entry_number;
+
+ Assert(entry_number >= 0);
+ Assert(entry_number < NUM_CACHE_ENTRIES);
+
+ cache = (GeomCache*)(generic_cache->entry[entry_number]);
+
+ if ( ! cache )
+ {
+ old_context = MemoryContextSwitchTo(FIContext(fcinfo));
+ /* Allocate in the upper context */
+ cache = cache_methods->GeomCacheAllocator();
+ MemoryContextSwitchTo(old_context);
+ /* Store the pointer in GenericCache */
+ cache->type = entry_number;
+ generic_cache->entry[entry_number] = (GenericCache*)cache;
+ }
+
+ /* Cache hit on the first argument */
+ if ( g1 &&
+ cache->argnum != 2 &&
+ cache->geom1_size == VARSIZE(g1) &&
+ memcmp(cache->geom1, g1, cache->geom1_size) == 0 )
+ {
+ cache_hit = 1;
+ geom = g1;
+
+ }
+ /* Cache hit on second argument */
+ else if ( g2 &&
+ cache->argnum != 1 &&
+ cache->geom2_size == VARSIZE(g2) &&
+ memcmp(cache->geom2, g2, cache->geom2_size) == 0 )
+ {
+ cache_hit = 2;
+ geom = g2;
+ }
+ /* No cache hit. If we have a tree, free it. */
+ else
+ {
+ cache_hit = 0;
+ if ( cache->argnum )
+ {
+ cache_methods->GeomIndexFreer(cache);
+ cache->argnum = 0;
+ }
+ }
+
+ /* Cache hit, but no tree built yet, build it! */
+ if ( cache_hit && ! cache->argnum )
+ {
+ int rv;
+ LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
+
+ /* Can't build a tree on a NULL or empty */
+ if ( (!lwgeom) || lwgeom_is_empty(lwgeom) )
+ return NULL;
+
+ old_context = MemoryContextSwitchTo(FIContext(fcinfo));
+ rv = cache_methods->GeomIndexBuilder(lwgeom, cache);
+ MemoryContextSwitchTo(old_context);
+ cache->argnum = cache_hit;
+
+ /* Something went awry in the tree build phase */
+ if ( ! rv )
+ {
+ cache->argnum = 0;
+ return NULL;
+ }
+
+ }
+
+ /* We have a hit and a calculated tree, we're done */
+ if ( cache_hit && cache->argnum )
+ return cache;
+
+ /* Argument one didn't match, so copy the new value in. */
+ if ( g1 && cache_hit != 1 )
+ {
+ if ( cache->geom1 ) pfree(cache->geom1);
+ cache->geom1_size = VARSIZE(g1);
+ cache->geom1 = MemoryContextAlloc(FIContext(fcinfo), cache->geom1_size);
+ memcpy(cache->geom1, g1, cache->geom1_size);
+ }
+ /* Argument two didn't match, so copy the new value in. */
+ if ( g2 && cache_hit != 2 )
+ {
+ if ( cache->geom2 ) pfree(cache->geom2);
+ cache->geom2_size = VARSIZE(g2);
+ cache->geom2 = MemoryContextAlloc(FIContext(fcinfo), cache->geom2_size);
+ memcpy(cache->geom2, g2, cache->geom2_size);
+ }
+
+ return NULL;
+}
* and the geometry values. Checks for a cache, checks for cache hits,
* returns a built tree if one exists.
*/
+#if 0
void*
GetGeomIndex(FunctionCallInfoData* fcinfo, int cache_entry, GeomIndexBuilder index_build, GeomIndexFreer index_free, const GSERIALIZED* geom1, const GSERIALIZED* geom2, int* argnum)
{
return NULL;
}
-
+#endif
/**
* Builder, freeer and public accessor for cached CIRC_NODE trees
static int
CircTreeBuilder(const LWGEOM* lwgeom, GeomCache* cache)
{
+ CircTreeGeomCache* circ_cache = (CircTreeGeomCache*)cache;
CIRC_NODE* tree = lwgeom_calculate_circ_tree(lwgeom);
- if ( cache->index )
+
+ if ( circ_cache->index )
{
- circ_tree_free((CIRC_NODE*)(cache->index));
- cache->index = 0;
+ circ_tree_free(circ_cache->index);
+ circ_cache->index = 0;
}
if ( ! tree )
return LW_FAILURE;
- cache->index = (void*)tree;
+ circ_cache->index = tree;
return LW_SUCCESS;
}
static int
CircTreeFreer(GeomCache* cache)
{
- CIRC_NODE* tree = (CIRC_NODE*)(cache->index);
- if ( tree )
+ CircTreeGeomCache* circ_cache = (CircTreeGeomCache*)cache;
+ if ( circ_cache->index )
{
- circ_tree_free(tree);
- cache->index = 0;
+ circ_tree_free(circ_cache->index);
+ circ_cache->index = 0;
+ circ_cache->argnum = 0;
}
return LW_SUCCESS;
}
+static GeomCache*
+CircTreeAllocator(void)
+{
+ CircTreeGeomCache* cache = palloc(sizeof(CircTreeGeomCache));
+ memset(cache, 0, sizeof(CircTreeGeomCache));
+ return (GeomCache*)cache;
+}
+
+static GeomCacheMethods CircTreeCacheMethods =
+{
+ CIRC_CACHE_ENTRY,
+ CircTreeBuilder,
+ CircTreeFreer,
+ CircTreeAllocator
+};
+
CIRC_NODE*
-GetCircTree(FunctionCallInfoData* fcinfo, GSERIALIZED* g1, GSERIALIZED* g2, int* argnum_of_cache)
+GetCircTree(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, int* argnum_of_cache)
{
- int argnum = 0;
- CIRC_NODE* tree = NULL;
+ CircTreeGeomCache* cache = (CircTreeGeomCache*)GetGeomCache2(fcinfo, &CircTreeCacheMethods, g1, g2);
- tree = (CIRC_NODE*)GetGeomIndex(fcinfo, CIRC_CACHE_ENTRY, CircTreeBuilder, CircTreeFreer, g1, g2, &argnum);
+ if ( ! cache )
+ return NULL;
if ( argnum_of_cache )
- *argnum_of_cache = argnum;
+ *argnum_of_cache = cache->argnum;
- return tree;
+ return cache->index;
+}
+
+CircTreeGeomCache*
+GetCircTreeGeomCache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2)
+{
+ return (CircTreeGeomCache*)GetGeomCache2(fcinfo, &CircTreeCacheMethods, g1, g2);
}
#define RTREE_CACHE_ENTRY 2
#define CIRC_CACHE_ENTRY 3
#define RECT_CACHE_ENTRY 4
+
#define NUM_CACHE_ENTRIES 5
* argument the tree is built for.
*/
typedef struct {
- int type;
- GSERIALIZED* geom1;
- GSERIALIZED* geom2;
- size_t geom1_size;
- size_t geom2_size;
- int32 argnum;
- MemoryContext context_statement;
- MemoryContext context_callback;
- void* index;
+ int type;
+ GSERIALIZED* geom1;
+ GSERIALIZED* geom2;
+ size_t geom1_size;
+ size_t geom2_size;
+ int32 argnum;
} GeomCache;
+typedef struct {
+ int type; // <GeomCache>
+ GSERIALIZED* geom1; //
+ GSERIALIZED* geom2; //
+ size_t geom1_size; //
+ size_t geom2_size; //
+ int32 argnum; // </GeomCache>
+ CIRC_NODE* index;
+} CircTreeGeomCache;
+
/* An entry in the PROJ4 SRS cache */
typedef struct struct_PROJ4SRSCacheItem
* geometry and return a tree structure for fast edge
* access.
*/
+#if 0
typedef int (*GeomIndexBuilder)(const LWGEOM* lwgeom, GeomCache* cache);
typedef int (*GeomIndexFreer)(GeomCache* cache);
+typedef GeomCache* (*GeomCacheAllocator)(void);
+#endif
+
+typedef struct
+{
+ int entry_number;
+ int (*GeomIndexBuilder)(const LWGEOM* lwgeom, GeomCache* cache);
+ int (*GeomIndexFreer)(GeomCache* cache);
+ GeomCache* (*GeomCacheAllocator)(void);
+} GeomCacheMethods;
/*
* Cache retrieval functions
*/
-PROJ4PortalCache* GetPROJ4SRSCache(FunctionCallInfoData *fcinfo);
-GeomCache* GetGeomCache(FunctionCallInfoData *fcinfo, int cache_entry);
-CIRC_NODE* GetCircTree(FunctionCallInfoData* fcinfo, GSERIALIZED* g1, GSERIALIZED* g2, int* argnum_of_cache);
+PROJ4PortalCache* GetPROJ4SRSCache(FunctionCallInfoData *fcinfo);
+GeomCache* GetGeomCache2(FunctionCallInfoData *fcinfo, const GeomCacheMethods* cache_methods, const GSERIALIZED* g1, const GSERIALIZED* g2);
+CIRC_NODE* GetCircTree(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, int* argnum_of_cache);
+CircTreeGeomCache* GetCircTreeGeomCache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2);
/*
* Given candidate geometries, a builer function and an entry type, cache and/or return an
* appropriate tree.
*/
-void* GetGeomIndex(FunctionCallInfoData* fcinfo, int cache_entry, GeomIndexBuilder index_build, GeomIndexFreer tree_free, const GSERIALIZED* g1, const GSERIALIZED* g2, int* argnum);
+//void* GetGeomIndex(FunctionCallInfoData* fcinfo, int cache_entry, GeomIndexBuilder index_build, GeomIndexFreer tree_free, const GSERIALIZED* g1, const GSERIALIZED* g2, int* argnum);
#endif /* LWGEOM_CACHE_H_ */
static int
PrepGeomCacheBuilder(const LWGEOM *lwgeom, GeomCache *cache)
{
- PrepGeomCache* prepcache;
+ PrepGeomCache* prepcache = (PrepGeomCache*)cache;
PrepGeomHashEntry* pghe;
/*
/*
* No callback entry for this statement context yet? Set it up
*/
- if ( ! cache->context_callback )
+ if ( ! prepcache->context_callback )
{
PrepGeomHashEntry pghe;
- cache->context_callback = MemoryContextCreate(T_AllocSetContext, 8192,
+ prepcache->context_callback = MemoryContextCreate(T_AllocSetContext, 8192,
&PreparedCacheContextMethods,
- cache->context_statement,
+ prepcache->context_statement,
"PostGIS Prepared Geometry Context");
- pghe.context = cache->context_callback;
+ pghe.context = prepcache->context_callback;
pghe.geom = 0;
pghe.prepared_geom = 0;
AddPrepGeomHashEntry( pghe );
* Hum, we shouldn't be asked to build a new cache on top of
* an existing one. Error.
*/
- if ( cache->index )
+ if ( prepcache->argnum || prepcache->geom || prepcache->prepared_geom )
{
lwerror("PrepGeomCacheBuilder asked to build new prepcache where one already exists.");
return LW_FAILURE;
}
- /*
- * Allocate a new index structure
- */
- cache->index = MemoryContextAlloc(cache->context_statement, sizeof(PrepGeomCache));
- memset(cache->index, 0, sizeof(PrepGeomCache));
- prepcache = (PrepGeomCache*)(cache->index);
-
prepcache->geom = LWGEOM2GEOS( lwgeom );
if ( ! prepcache->geom ) return LW_FAILURE;
prepcache->prepared_geom = GEOSPrepare( prepcache->geom );
* In order to find the objects we need to destroy, we keep
* extra references in a global hash object.
*/
- pghe = GetPrepGeomHashEntry(cache->context_callback);
+ pghe = GetPrepGeomHashEntry(prepcache->context_callback);
if ( ! pghe )
{
- lwerror("PrepGeomCacheBuilder failed to find hash entry for context %p", cache->context_callback);
+ lwerror("PrepGeomCacheBuilder failed to find hash entry for context %p", prepcache->context_callback);
return LW_FAILURE;
}
PrepGeomCacheCleaner(GeomCache *cache)
{
PrepGeomHashEntry* pghe = 0;
- PrepGeomCache* prepcache = (PrepGeomCache*)(cache->index);
+ PrepGeomCache* prepcache = (PrepGeomCache*)cache;
if ( ! prepcache )
return LW_FAILURE;
* Clear out the references to the soon-to-be-freed GEOS objects
* from the callback hash entry
*/
- pghe = GetPrepGeomHashEntry(cache->context_callback);
+ pghe = GetPrepGeomHashEntry(prepcache->context_callback);
if ( ! pghe )
{
- lwerror("PrepGeomCacheCleaner failed to find hash entry for context %p", cache->context_callback);
+ lwerror("PrepGeomCacheCleaner failed to find hash entry for context %p", prepcache->context_callback);
return LW_FAILURE;
}
pghe->geom = 0;
POSTGIS_DEBUGF(3, "PrepGeomCacheFreeer: freeing %p argnum %d", prepcache, prepcache->argnum);
GEOSPreparedGeom_destroy( prepcache->prepared_geom );
GEOSGeom_destroy( (GEOSGeometry *)prepcache->geom );
- pfree(cache->index);
- cache->index = 0;
+ prepcache->argnum = 0;
+ prepcache->prepared_geom = 0;
+ prepcache->geom = 0;
return LW_SUCCESS;
}
+static GeomCache*
+PrepGeomCacheAllocator()
+{
+ PrepGeomCache* prepcache = palloc(sizeof(PrepGeomCache));
+ memset(prepcache, 0, sizeof(PrepGeomCache));
+ prepcache->context_statement = CurrentMemoryContext;
+ prepcache->type = PREP_CACHE_ENTRY;
+ return (GeomCache*)prepcache;
+}
+
+static GeomCacheMethods PrepGeomCacheMethods =
+{
+ PREP_CACHE_ENTRY,
+ PrepGeomCacheBuilder,
+ PrepGeomCacheCleaner,
+ PrepGeomCacheAllocator
+};
+
+
/**
* Given a couple potential geometries and a function
* call context, return a prepared structure for one
PrepGeomCache*
GetPrepGeomCache(FunctionCallInfoData* fcinfo, GSERIALIZED* g1, GSERIALIZED* g2)
{
- int argnum = 0;
- PrepGeomCache* prepcache = NULL;
-
- prepcache = (PrepGeomCache*)GetGeomIndex(fcinfo, PREP_CACHE_ENTRY, PrepGeomCacheBuilder, PrepGeomCacheCleaner, g1, g2, &argnum);
-
- return prepcache;
+ return (PrepGeomCache*)GetGeomCache2(fcinfo, &PrepGeomCacheMethods, g1, g2);
}
}
PrepGeomCache;
*/
-
+/*
typedef struct
{
int argnum;
const GEOSGeometry *geom;
}
PrepGeomCache;
+*/
+typedef struct {
+ int type; // <GeomCache>
+ GSERIALIZED* geom1; //
+ GSERIALIZED* geom2; //
+ size_t geom1_size; //
+ size_t geom2_size; //
+ int32 argnum; // </GeomCache>
+ MemoryContext context_statement;
+ MemoryContext context_callback;
+ const GEOSPreparedGeometry* prepared_geom;
+ const GEOSGeometry* geom;
+} PrepGeomCache;
+
/*
** Get the current cache, given the input geometries.
LWMPOLY *mpoly;
LWPOLY *poly;
int nrings;
+ RTreeGeomCache* rtree_cache = (RTreeGeomCache*)cache;
RTREE_POLY_CACHE* currentCache;
if ( ! cache )
return LW_FAILURE;
+
+ if ( rtree_cache->index )
+ {
+ lwerror("RTreeBuilder asked to build index where one already exists.");
+ return LW_FAILURE;
+ }
if (lwgeom->type == MULTIPOLYGONTYPE)
{
i++;
}
}
- cache->index = (void*)currentCache;
+ rtree_cache->index = currentCache;
}
else if ( lwgeom->type == POLYGONTYPE )
{
{
currentCache->ringIndices[i] = RTreeCreate(poly->rings[i]);
}
- cache->index = (void*)currentCache;
+ rtree_cache->index = currentCache;
}
else
{
static int
RTreeFreer(GeomCache* cache)
{
+ RTreeGeomCache* rtree_cache = (RTreeGeomCache*)cache;
+
if ( ! cache )
return LW_FAILURE;
- if ( cache->index )
+ if ( rtree_cache->index )
{
- RTREE_POLY_CACHE* currentCache = (RTREE_POLY_CACHE*)(cache->index);
- RTreeCacheClear(currentCache);
- lwfree(currentCache);
- cache->index = 0;
+ RTreeCacheClear(rtree_cache->index);
+ lwfree(rtree_cache->index);
+ rtree_cache->index = 0;
+ rtree_cache->argnum = 0;
}
return LW_SUCCESS;
}
+static GeomCache*
+RTreeAllocator(void)
+{
+ RTreeGeomCache* cache = palloc(sizeof(RTreeGeomCache));
+ memset(cache, 0, sizeof(RTreeGeomCache));
+ return (GeomCache*)cache;
+}
+
+static GeomCacheMethods RTreeCacheMethods =
+{
+ RTREE_CACHE_ENTRY,
+ RTreeBuilder,
+ RTreeFreer,
+ RTreeAllocator
+};
+
RTREE_POLY_CACHE*
GetRtreeCache(FunctionCallInfoData* fcinfo, GSERIALIZED* g1)
{
- int argnum = 0;
+ RTreeGeomCache* cache = (RTreeGeomCache*)GetGeomCache2(fcinfo, &RTreeCacheMethods, g1, NULL);
RTREE_POLY_CACHE* index = NULL;
- index = (RTREE_POLY_CACHE*)GetGeomIndex(fcinfo, RTREE_CACHE_ENTRY, RTreeBuilder, RTreeFreer, g1, 0, &argnum);
+ if ( cache )
+ index = cache->index;
return index;
}
}
RTREE_POLY_CACHE;
+
+
+typedef struct {
+ int type; // <GeomCache>
+ GSERIALIZED* geom1; //
+ GSERIALIZED* geom2; //
+ size_t geom1_size; //
+ size_t geom2_size; //
+ int32 argnum; // </GeomCache>
+ RTREE_POLY_CACHE* index;
+} RTreeGeomCache;
+
+
/**
* Retrieves a collection of line segments given the root and crossing value.
*/