Beispiel #1
0
/*
 * 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;

}
Beispiel #3
0
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);
}
Beispiel #4
0
/**
 * 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);

}