/* * AsetDirectContextCreate * Create a new AsetDirect context. * * parent: parent context, or NULL if top-level context * name: name of context (for debugging --- string will be copied) */ MemoryContext AsetDirectContextCreate(MemoryContext parent, const char *name) { AsetDirectContext *set; Size namesize = MAXALIGN(strlen(name) + 1); Size allocsize; Size setsize; /* #bytes to request for new context */ int nareaspace; /* num of slots in areaspace array */ /* * Determine amount of memory to request for the AsetDirectContext struct. * * Assume the total allocation will be rounded up to a power of 2, and * will include the AsetDirectContext with variably sized 'areaspace' array * and the context 'name' string. Size the 'areaspace' array to use up any * extra space in the expected allocation. */ allocsize = 1 << ceil_log2_Size(MAXALIGN(sizeof(AsetDirectContext)) + namesize); nareaspace = VARELEMENTS_TO_FIT(allocsize - namesize, AsetDirectContext, areaspace); setsize = ASETDIRECTCONTEXT_BYTES(nareaspace); /* * Create the new memory context and hook up to parent context. */ set = (AsetDirectContext *)MemoryContextCreate(T_AsetDirectContext, setsize, &AsetDirectMethods, parent, name); /* * Initialize empty collection of ptrs to allocated areas. */ CdbPtrBuf_Init(&set->areas, set->areaspace, nareaspace, 50, /* num_cells_expand */ set->header.parent); return (MemoryContext)set; } /* AsetDirectContextCreate */
/* ** 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; PrepGeomCache* cache = fcinfo->flinfo->fn_extra; 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; if (!PrepGeomHash) CreatePrepGeomHash(); if ( pg_geom1 ) pg_geom1_size = VARSIZE(pg_geom1) + VARHDRSZ; if ( pg_geom2 ) pg_geom2_size = VARSIZE(pg_geom2) + VARHDRSZ; 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 ); fcinfo->flinfo->fn_extra = 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; }
static void AddToStdPortalCache(StdPortalCache *STDCache, char *lextab, char *gaztab, char *rultab) { MemoryContext STDMemoryContext; MemoryContext old_context; STANDARDIZER *std = NULL; DBG("Enter: AddToStdPortalCache"); std = CreateStd(lextab, gaztab, rultab); if (!std) elog(ERROR, "AddToStdPortalCache: could not create address standardizer for '%s', '%s', '%s'", lextab, gaztab, rultab); /* if the NextSlot in the cache is used, then delete it */ if (STDCache->StdCache[STDCache->NextSlot].std != NULL) { #ifdef DEBUG StdCacheItem *ce = &STDCache->StdCache[STDCache->NextSlot]; DBG("Removing item from STD cache ('%s', '%s', '%s') index %d", ce->lextab, ce->gaztab, ce->rultab, STDCache->NextSlot); #endif DeleteNextSlotFromStdCache(STDCache); } DBG("Adding item to STD cache ('%s', '%s', '%s') index %d", lextab, gaztab, rultab, STDCache->NextSlot); STDMemoryContext = MemoryContextCreate(T_AllocSetContext, 8192, &StdCacheContextMethods, STDCache->StdCacheContext, "PAGC STD Memory Context"); /* Create the backend hash if it doesn't already exist */ DBG("Check if StdHash exists (%p)", StdHash); if (!StdHash) CreateStdHash(); /* * Add the MemoryContext to the backend hash so we can * clean up upon portal shutdown */ DBG("Adding standardizer obj (%p) to hash table with MemoryContext key (%p)", std, STDMemoryContext); AddStdHashEntry(STDMemoryContext, std); /* change memory contexts so the pstrdup are allocated in the * context of this cache item. They will be freed when the * cache item is deleted. */ DBG("AddToStdPortalCache: changing memory context to %p", STDCache->StdCacheContext); old_context = MemoryContextSwitchTo(STDCache->StdCacheContext); DBG(" old_context= %p", old_context); STDCache->StdCache[STDCache->NextSlot].lextab = pstrdup(lextab); DBG(" pstrdup(lextab) completed"); STDCache->StdCache[STDCache->NextSlot].gaztab = pstrdup(gaztab); DBG(" pstrdup(gaztab) completed"); STDCache->StdCache[STDCache->NextSlot].rultab = pstrdup(rultab); DBG(" pstrdup(rultab) completed"); MemoryContextSwitchTo(old_context); DBG(" changed memory context to %p", old_context); STDCache->StdCache[STDCache->NextSlot].std = std; STDCache->StdCache[STDCache->NextSlot].std_mcxt = STDMemoryContext; STDCache->NextSlot = (STDCache->NextSlot + 1) % STD_CACHE_ITEMS; DBG("STDCache->NextSlot=%d", STDCache->NextSlot); }
/** * Add an entry to the local PROJ4 SRS cache. If we need to wrap around then * we must make sure the entry we choose to delete does not contain other_srid * which is the definition for the other half of the transformation. */ static void AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid) { MemoryContext PJMemoryContext; projPJ projection = NULL; char *proj_str; int* pj_errno_ref; /* ** Turn the SRID number into a proj4 string, by reading from spatial_ref_sys ** or instantiating a magical value from a negative srid. */ proj_str = GetProj4String(srid); if ( ! proj_str ) { elog(ERROR, "GetProj4String returned NULL for SRID (%d)", srid); } projection = lwproj_from_string(proj_str); pj_errno_ref = pj_get_errno_ref(); if ( (projection == NULL) || (*pj_errno_ref)) { /* we need this for error reporting */ /*pfree(projection); */ elog(ERROR, "AddToPROJ4SRSCache: couldn't parse proj4 string: '%s': %s", proj_str, pj_strerrno(*pj_errno_ref)); } /* * If the cache is already full then find the first entry * that doesn't contain other_srid and use this as the * subsequent value of PROJ4SRSCacheCount */ if (PROJ4Cache->PROJ4SRSCacheCount == PROJ4_CACHE_ITEMS) { bool found = false; int i; for (i = 0; i < PROJ4_CACHE_ITEMS; i++) { if (PROJ4Cache->PROJ4SRSCache[i].srid != other_srid && found == false) { POSTGIS_DEBUGF(3, "choosing to remove item from query cache with SRID %d and index %d", PROJ4Cache->PROJ4SRSCache[i].srid, i); DeleteFromPROJ4SRSCache(PROJ4Cache, PROJ4Cache->PROJ4SRSCache[i].srid); PROJ4Cache->PROJ4SRSCacheCount = i; found = true; } } } /* * Now create a memory context for this projection and * store it in the backend hash */ POSTGIS_DEBUGF(3, "adding SRID %d with proj4text \"%s\" to query cache at index %d", srid, proj_str, PROJ4Cache->PROJ4SRSCacheCount); PJMemoryContext = MemoryContextCreate(T_AllocSetContext, 8192, &PROJ4SRSCacheContextMethods, PROJ4Cache->PROJ4SRSCacheContext, "PostGIS PROJ4 PJ Memory Context"); /* Create the backend hash if it doesn't already exist */ if (!PJHash) PJHash = CreatePJHash(); /* * Add the MemoryContext to the backend hash so we can * clean up upon portal shutdown */ POSTGIS_DEBUGF(3, "adding projection object (%p) to hash table with MemoryContext key (%p)", projection, PJMemoryContext); AddPJHashEntry(PJMemoryContext, projection); PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].srid = srid; PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection = projection; PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection_mcxt = PJMemoryContext; PROJ4Cache->PROJ4SRSCacheCount++; /* Free the projection string */ pfree(proj_str); }