Commit 3ced96fc authored by Raúl Marín's avatar Raúl Marín

Internal cache now persists until the end of the transaction

Closes #4674
parent b28cfb9b
Pipeline #141731416 passed with stage
in 28 minutes and 18 seconds
......@@ -4,7 +4,7 @@ PostGIS 3.1.0XXXX
Only tickets not included in 3.1.0alpha1
* Breaking changes *
-
- #4674, Internal cache now persists until the end of the transaction (Raúl Marín)
* New features *
- #4656, Cast a geojson_text::geometry for implicit GeoJSON ingestion (Raúl Marín)
......
......@@ -11,7 +11,9 @@
**********************************************************************/
#include "postgres.h"
#include "executor/spi.h"
#include "fmgr.h"
#include "utils/memutils.h"
#include "../postgis_config.h"
......@@ -56,13 +58,25 @@ typedef struct {
} GenericCacheCollection;
/**
* Utility function to read the upper memory context off a function call
* info data.
*/
static MemoryContext
FIContext(FunctionCallInfo fcinfo)
* Utility function to read the upper memory context off a function call
* info data.
* This used to return flinfo->fn_mcxt (the function memory context) but that has the issue
* that is cleaned up once the function is finished, which on pure SQL functions (like ST_AsGML(geometry))
* is an issue as the cache will die after every _ST_AsGML call (thus being worthless).
* Instead we use CurTransactionContext which will live until the end of the transaction
*/
MemoryContext
PostgisCacheContext(FunctionCallInfo fcinfo)
{
return CurTransactionContext;
}
static GenericCacheCollection *internal_cache = NULL;
static void
PostgisResetInternalCache(void *v)
{
return fcinfo->flinfo->fn_mcxt;
internal_cache = NULL;
}
/**
......@@ -72,15 +86,19 @@ FIContext(FunctionCallInfo fcinfo)
static GenericCacheCollection *
GetGenericCacheCollection(FunctionCallInfo fcinfo)
{
GenericCacheCollection* cache = fcinfo->flinfo->fn_extra;
if ( ! cache )
if (!internal_cache)
{
cache = MemoryContextAlloc(FIContext(fcinfo), sizeof(GenericCacheCollection));
memset(cache, 0, sizeof(GenericCacheCollection));
fcinfo->flinfo->fn_extra = cache;
internal_cache = MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(GenericCacheCollection));
memset(internal_cache, 0, sizeof(GenericCacheCollection));
MemoryContextCallback *cb =
MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(MemoryContextCallback));
cb->func = PostgisResetInternalCache;
cb->arg = NULL;
MemoryContextRegisterResetCallback(PostgisCacheContext(fcinfo), cb);
}
return cache;
return internal_cache;
}
......@@ -97,17 +115,16 @@ GetPROJSRSCache(FunctionCallInfo fcinfo)
if ( ! cache )
{
/* Allocate in the upper context */
cache = MemoryContextAlloc(FIContext(fcinfo), sizeof(PROJPortalCache));
cache = MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(PROJPortalCache));
if (cache)
{
POSTGIS_DEBUGF(3,
"Allocating PROJCache for portal with transform() MemoryContext %p",
FIContext(fcinfo));
PostgisCacheContext(fcinfo));
memset(cache->PROJSRSCache, 0, sizeof(PROJSRSCacheItem) * PROJ_CACHE_ITEMS);
cache->type = PROJ_CACHE_ENTRY;
cache->PROJSRSCacheCount = 0;
cache->PROJSRSCacheContext = FIContext(fcinfo);
/* Store the pointer in GenericCache */
generic_cache->entry[PROJ_CACHE_ENTRY] = (GenericCache*)cache;
......@@ -142,7 +159,7 @@ GetGeomCache(FunctionCallInfo fcinfo,
if ( ! cache )
{
old_context = MemoryContextSwitchTo(FIContext(fcinfo));
old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
/* Allocate in the upper context */
cache = cache_methods->GeomCacheAllocator();
MemoryContextSwitchTo(old_context);
......@@ -201,7 +218,7 @@ GetGeomCache(FunctionCallInfo fcinfo,
/* Save the tree and supporting geometry in the cache */
/* memory context */
old_context = MemoryContextSwitchTo(FIContext(fcinfo));
old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
lwgeom = lwgeom_from_gserialized(geom);
cache->argnum = 0;
......@@ -231,7 +248,7 @@ GetGeomCache(FunctionCallInfo fcinfo,
{
if ( cache->geom1 ) pfree(cache->geom1);
cache->geom1_size = VARSIZE(g1);
cache->geom1 = MemoryContextAlloc(FIContext(fcinfo), cache->geom1_size);
cache->geom1 = MemoryContextAlloc(PostgisCacheContext(fcinfo), cache->geom1_size);
memcpy(cache->geom1, g1, cache->geom1_size);
}
/* Argument two didn't match, so copy the new value in. */
......@@ -239,7 +256,7 @@ GetGeomCache(FunctionCallInfo fcinfo,
{
if ( cache->geom2 ) pfree(cache->geom2);
cache->geom2_size = VARSIZE(g2);
cache->geom2 = MemoryContextAlloc(FIContext(fcinfo), cache->geom2_size);
cache->geom2 = MemoryContextAlloc(PostgisCacheContext(fcinfo), cache->geom2_size);
memcpy(cache->geom2, g2, cache->geom2_size);
}
......@@ -256,7 +273,7 @@ ToastCacheGet(FunctionCallInfo fcinfo)
ToastCache* cache = (ToastCache*)(generic_cache->entry[entry_number]);
if (!cache)
{
cache = MemoryContextAllocZero(FIContext(fcinfo), sizeof(ToastCache));
cache = MemoryContextAllocZero(PostgisCacheContext(fcinfo), sizeof(ToastCache));
cache->type = entry_number;
generic_cache->entry[entry_number] = (GenericCache*)cache;
}
......@@ -299,7 +316,7 @@ ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum)
return arg->geom;
/* Take a copy into the upper context */
MemoryContext old_context = MemoryContextSwitchTo(FIContext(fcinfo));
MemoryContext old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
arg->geom = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(datum);
MemoryContextSwitchTo(old_context);
return arg->geom;
......
......@@ -30,6 +30,8 @@
#define NUM_CACHE_ENTRIES 8
/* Returns the MemoryContext used to store the caches */
MemoryContext PostgisCacheContext(FunctionCallInfo fcinfo);
/*
* A generic GeomCache just needs space for the cache type,
......
......@@ -54,7 +54,8 @@ typedef struct {
} PjStrs;
/* Internal Cache API */
static LWPROJ *AddToPROJSRSCache(PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to);
static LWPROJ *
AddToPROJSRSCache(FunctionCallInfo fcinfo, PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to);
static void DeleteFromPROJSRSCache(PROJPortalCache *PROJCache, uint32_t position);
static void
......@@ -345,7 +346,7 @@ GetProj4String(int32_t srid)
* which is the definition for the other half of the transformation.
*/
static LWPROJ *
AddToPROJSRSCache(PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to)
AddToPROJSRSCache(FunctionCallInfo fcinfo, PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to)
{
MemoryContext oldContext;
......@@ -363,7 +364,7 @@ AddToPROJSRSCache(PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to
if (!pjstrs_has_entry(&to_strs))
elog(ERROR, "got NULL for SRID (%d)", srid_to);
oldContext = MemoryContextSwitchTo(PROJCache->PROJSRSCacheContext);
oldContext = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
#if POSTGIS_PROJ_VERSION < 60
PJ *projection = palloc(sizeof(PJ));
......@@ -452,10 +453,10 @@ AddToPROJSRSCache(PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to
/* We register a new callback to delete the projection on exit */
MemoryContextCallback *callback =
MemoryContextAlloc(PROJCache->PROJSRSCacheContext, sizeof(MemoryContextCallback));
MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(MemoryContextCallback));
callback->func = PROJSRSDestroyPJ;
callback->arg = (void *)projection;
MemoryContextRegisterResetCallback(PROJCache->PROJSRSCacheContext, callback);
MemoryContextRegisterResetCallback(PostgisCacheContext(fcinfo), callback);
PROJCache->PROJSRSCache[cache_position].srid_from = srid_from;
PROJCache->PROJSRSCache[cache_position].srid_to = srid_to;
......@@ -502,7 +503,7 @@ GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, LW
*pj = GetProjectionFromPROJCache(proj_cache, srid_from, srid_to);
if (*pj == NULL)
{
*pj = AddToPROJSRSCache(proj_cache, srid_from, srid_to);
*pj = AddToPROJSRSCache(fcinfo, proj_cache, srid_from, srid_to);
}
return pj != NULL;
......
......@@ -32,8 +32,6 @@ char *GetProj4String(int32_t srid);
*/
typedef void *ProjCache ;
bool IsInPROJCache(ProjCache cache, int32_t srid_from, int32_t srid_to);
PJ *GetPJFromPROJCache(ProjCache cache, int32_t srid_from, int32_t srid_to);
int GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, LWPROJ **pj);
int spheroid_init_from_srid(FunctionCallInfo fcinfo, int32_t srid, SPHEROID *s);
void srid_check_latlong(FunctionCallInfo fcinfo, int32_t srid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment