static CircTreeGeomCache* GetCircTreeGeomCache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2) { return (CircTreeGeomCache*)GetGeomCache(fcinfo, &CircTreeCacheMethods, g1, g2); }
/* ** GetPrepGeomCache ** ** Pull the current prepared geometry from the cache or make ** one if there is not one available. Only prepare geometry ** if we are seeing a key for the second time. That way rapidly ** cycling keys don't cause too much preparing. */ PrepGeomCache* GetPrepGeomCache(FunctionCallInfoData *fcinfo, GSERIALIZED *pg_geom1, GSERIALIZED *pg_geom2) { MemoryContext old_context; GeomCache* supercache = GetGeomCache(fcinfo); PrepGeomCache* cache = supercache->prep; int copy_keys = 1; size_t pg_geom1_size = 0; size_t pg_geom2_size = 0; assert ( ! cache || cache->type == 2 ); if (!PrepGeomHash) CreatePrepGeomHash(); if ( pg_geom1 ) pg_geom1_size = VARSIZE(pg_geom1); if ( pg_geom2 ) pg_geom2_size = VARSIZE(pg_geom2); if ( cache == NULL) { /* ** Cache requested, but the cache isn't set up yet. ** Set it up, but don't prepare the geometry yet. ** That way if the next call is a cache miss we haven't ** wasted time preparing a geometry we don't need. */ PrepGeomHashEntry pghe; old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); cache = palloc(sizeof(PrepGeomCache)); MemoryContextSwitchTo(old_context); cache->type = 2; cache->prepared_geom = 0; cache->geom = 0; cache->argnum = 0; cache->pg_geom1 = 0; cache->pg_geom2 = 0; cache->pg_geom1_size = 0; cache->pg_geom2_size = 0; cache->context = MemoryContextCreate(T_AllocSetContext, 8192, &PreparedCacheContextMethods, fcinfo->flinfo->fn_mcxt, "PostGIS Prepared Geometry Context"); POSTGIS_DEBUGF(3, "GetPrepGeomCache: creating cache: %p", cache); pghe.context = cache->context; pghe.geom = 0; pghe.prepared_geom = 0; AddPrepGeomHashEntry( pghe ); supercache->prep = cache; POSTGIS_DEBUGF(3, "GetPrepGeomCache: adding context to hash: %p", cache); } else if ( pg_geom1 && cache->argnum != 2 && cache->pg_geom1_size == pg_geom1_size && memcmp(cache->pg_geom1, pg_geom1, pg_geom1_size) == 0) { if ( !cache->prepared_geom ) { /* ** Cache hit, but we haven't prepared our geometry yet. ** Prepare it. */ PrepGeomHashEntry* pghe; cache->geom = POSTGIS2GEOS( pg_geom1 ); cache->prepared_geom = GEOSPrepare( cache->geom ); cache->argnum = 1; POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 1"); pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = cache->geom; pghe->prepared_geom = cache->prepared_geom; POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 1"); } else { /* ** Cache hit, and we're good to go. Do nothing. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 1"); } /* We don't need new keys until we have a cache miss */ copy_keys = 0; } else if ( pg_geom2 && cache->argnum != 1 && cache->pg_geom2_size == pg_geom2_size && memcmp(cache->pg_geom2, pg_geom2, pg_geom2_size) == 0) { if ( !cache->prepared_geom ) { /* ** Cache hit on arg2, but we haven't prepared our geometry yet. ** Prepare it. */ PrepGeomHashEntry* pghe; cache->geom = POSTGIS2GEOS( pg_geom2 ); cache->prepared_geom = GEOSPrepare( cache->geom ); cache->argnum = 2; POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 2"); pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = cache->geom; pghe->prepared_geom = cache->prepared_geom; POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 2"); } else { /* ** Cache hit, and we're good to go. Do nothing. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 2"); } /* We don't need new keys until we have a cache miss */ copy_keys = 0; } else if ( cache->prepared_geom ) { /* ** No cache hits, so this must be a miss. ** Destroy the GEOS objects, empty the cache. */ PrepGeomHashEntry* pghe; pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = 0; pghe->prepared_geom = 0; POSTGIS_DEBUGF(3, "GetPrepGeomCache: cache miss, argument %d", cache->argnum); GEOSPreparedGeom_destroy( cache->prepared_geom ); GEOSGeom_destroy( (GEOSGeometry *)cache->geom ); cache->prepared_geom = 0; cache->geom = 0; cache->argnum = 0; } if ( copy_keys && pg_geom1 ) { /* ** If this is a new key (cache miss) we flip into the function ** manager memory context and make a copy. We can't just store a pointer ** because this copy will be pfree'd at the end of this function ** call. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom1 into cache"); old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); if ( cache->pg_geom1 ) pfree(cache->pg_geom1); cache->pg_geom1 = palloc(pg_geom1_size); MemoryContextSwitchTo(old_context); memcpy(cache->pg_geom1, pg_geom1, pg_geom1_size); cache->pg_geom1_size = pg_geom1_size; } if ( copy_keys && pg_geom2 ) { POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom2 into cache"); old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); if ( cache->pg_geom2 ) pfree(cache->pg_geom2); cache->pg_geom2 = palloc(pg_geom2_size); MemoryContextSwitchTo(old_context); memcpy(cache->pg_geom2, pg_geom2, pg_geom2_size); cache->pg_geom2_size = pg_geom2_size; } return cache; }