Skip to content

Commit f595e91

Browse files
committed
PROJ6: make sure that the projection context is reused by all FastCGI/MapScript requests of the same thread
1 parent aed7223 commit f595e91

File tree

6 files changed

+174
-17
lines changed

6 files changed

+174
-17
lines changed

Diff for: mapfile.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -5848,6 +5848,7 @@ int msUpdateWebFromString(webObj *web, char *string, int url_string)
58485848
** This really belongs in mapobject.c, but currently it also depends on
58495849
** lots of other init methods in this file.
58505850
*/
5851+
58515852
int initMap(mapObj *map)
58525853
{
58535854
int i=0;
@@ -5925,18 +5926,21 @@ int initMap(mapObj *map)
59255926
initQueryMap(&map->querymap);
59265927

59275928
#ifdef USE_PROJ
5929+
map->projContext = msProjectionContextGetFromPool();
5930+
59285931
if(msInitProjection(&(map->projection)) == -1)
59295932
return(-1);
59305933
if(msInitProjection(&(map->latlon)) == -1)
59315934
return(-1);
59325935

5936+
msProjectionSetContext(&(map->projection), map->projContext);
5937+
msProjectionSetContext(&(map->latlon), map->projContext);
5938+
59335939
/* initialize a default "geographic" projection */
59345940
map->latlon.numargs = 2;
59355941
map->latlon.args[0] = msStrdup("proj=latlong");
59365942
map->latlon.args[1] = msStrdup("ellps=WGS84"); /* probably want a different ellipsoid */
59375943
if(msProcessProjection(&(map->latlon)) == -1) return(-1);
5938-
5939-
msProjectionInheritContextFrom(&(map->projection), &(map->latlon));
59405944
#endif
59415945

59425946
map->templatepattern = map->datapattern = NULL;
@@ -6314,7 +6318,7 @@ static int loadMapInternal(mapObj *map)
63146318
if((map->interlace = getSymbol(2, MS_ON,MS_OFF)) == -1) return MS_FAILURE;
63156319
break;
63166320
case(LATLON):
6317-
msFreeProjection(&map->latlon);
6321+
msFreeProjectionExceptContext(&map->latlon);
63186322
if(loadProjection(&map->latlon) == -1) return MS_FAILURE;
63196323
break;
63206324
case(LAYER):
@@ -6486,7 +6490,7 @@ mapObj *msLoadMapFromString(char *buffer, char *new_mappath)
64866490
/*
64876491
** Sets up file-based mapfile loading and calls loadMapInternal to do the work.
64886492
*/
6489-
mapObj *msLoadMap(char *filename, char *new_mappath)
6493+
mapObj *msLoadMap(const char *filename, const char *new_mappath)
64906494
{
64916495
mapObj *map;
64926496
struct mstimeval starttime, endtime;

Diff for: mapobject.c

+3
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,11 @@ void msFreeMap(mapObj *map)
9393
msFree(map->shapepath);
9494
msFree(map->mappath);
9595

96+
#ifdef USE_PROJ
9697
msFreeProjection(&(map->projection));
9798
msFreeProjection(&(map->latlon));
99+
msProjectionContextReleaseToPool(map->projContext);
100+
#endif
98101

99102
msFreeLabelCache(&(map->labelcache));
100103

Diff for: mapproject.c

+151-9
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,26 @@
3838

3939
#ifdef USE_PROJ
4040
static char *ms_proj_lib = NULL;
41+
#if PROJ_VERSION_MAJOR >= 6
42+
static unsigned ms_proj_lib_change_counter = 0;
43+
#endif
44+
45+
typedef struct LinkedListOfProjContext LinkedListOfProjContext;
46+
struct LinkedListOfProjContext
47+
{
48+
LinkedListOfProjContext* next;
49+
projectionContext* context;
50+
};
51+
52+
static LinkedListOfProjContext* headOfLinkedListOfProjContext = NULL;
4153

4254
static int msTestNeedWrap( pointObj pt1, pointObj pt2, pointObj pt2_geo,
4355
reprojectionObj* reprojector );
4456

57+
58+
static projectionContext* msProjectionContextCreate(void);
59+
static void msProjectionContextUnref(projectionContext* ctx);
60+
4561
#if defined(USE_PROJ) && PROJ_VERSION_MAJOR >= 6
4662

4763
#include "proj_experimental.h"
@@ -69,6 +85,7 @@ typedef struct
6985
struct projectionContext
7086
{
7187
PJ_CONTEXT* proj_ctx;
88+
unsigned ms_proj_lib_change_counter;
7289
int ref_count;
7390
pjCacheEntry pj_cache[PJ_CACHE_ENTRY_SIZE];
7491
int pj_cache_size;
@@ -253,7 +270,6 @@ static void msProjErrorLogger(void * user_data,
253270
/* msProjectionContextCreate() */
254271
/************************************************************************/
255272

256-
static
257273
projectionContext* msProjectionContextCreate(void)
258274
{
259275
projectionContext* ctx = (projectionContext*)msSmallCalloc(1, sizeof(projectionContext));
@@ -265,11 +281,6 @@ projectionContext* msProjectionContextCreate(void)
265281
}
266282
ctx->ref_count = 1;
267283
proj_context_use_proj4_init_rules(ctx->proj_ctx, TRUE);
268-
if( ms_proj_lib )
269-
{
270-
const char* const paths[1] = { ms_proj_lib };
271-
proj_context_set_search_paths(ctx->proj_ctx, 1, paths);
272-
}
273284
proj_log_func (ctx->proj_ctx, NULL, msProjErrorLogger);
274285
return ctx;
275286
}
@@ -278,7 +289,6 @@ projectionContext* msProjectionContextCreate(void)
278289
/* msProjectionContextUnref() */
279290
/************************************************************************/
280291

281-
static
282292
void msProjectionContextUnref(projectionContext* ctx)
283293
{
284294
if( !ctx )
@@ -409,6 +419,24 @@ int msProjectTransformPoints( reprojectionObj* reprojector,
409419

410420
#else
411421

422+
/************************************************************************/
423+
/* msProjectionContextCreate() */
424+
/************************************************************************/
425+
426+
projectionContext* msProjectionContextCreate(void)
427+
{
428+
return NULL;
429+
}
430+
431+
/************************************************************************/
432+
/* msProjectionContextUnref() */
433+
/************************************************************************/
434+
435+
void msProjectionContextUnref(projectionContext* ctx)
436+
{
437+
(void)ctx;
438+
}
439+
412440
struct reprojectionObj
413441
{
414442
projectionObj* in;
@@ -564,6 +592,25 @@ void msProjectionInheritContextFrom(projectionObj *pDst, projectionObj* pSrc)
564592
#endif
565593
}
566594

595+
/************************************************************************/
596+
/* msProjectionSetContext() */
597+
/************************************************************************/
598+
599+
void msProjectionSetContext(projectionObj *p, projectionContext* ctx)
600+
{
601+
#if !defined(USE_PROJ)
602+
/* do nothing */
603+
#elif PROJ_VERSION_MAJOR >= 6
604+
if( p->proj_ctx == NULL && ctx != NULL)
605+
{
606+
p->proj_ctx = ctx;
607+
p->proj_ctx->ref_count ++;
608+
}
609+
#else
610+
/* do nothing */
611+
#endif
612+
}
613+
567614
/*
568615
** Handle OGC WMS/WFS AUTO projection in the format:
569616
** "AUTO:proj_id,units_id,lon0,lat0"
@@ -728,6 +775,16 @@ int msProcessProjection(projectionObj *p)
728775
return -1;
729776
}
730777
}
778+
if( p->proj_ctx->ms_proj_lib_change_counter != ms_proj_lib_change_counter )
779+
{
780+
msAcquireLock( TLOCK_PROJ );
781+
p->proj_ctx->ms_proj_lib_change_counter = ms_proj_lib_change_counter;
782+
{
783+
const char* const paths[1] = { ms_proj_lib };
784+
proj_context_set_search_paths(p->proj_ctx->proj_ctx, 1, ms_proj_lib ? paths : NULL);
785+
}
786+
msReleaseLock( TLOCK_PROJ );
787+
}
731788
#endif
732789

733790
if (strncasecmp(p->args[0], "AUTO:", 5) == 0 ||
@@ -2259,8 +2316,21 @@ void msSetPROJ_LIB( const char *proj_lib, const char *pszRelToPath )
22592316

22602317
msAcquireLock( TLOCK_PROJ );
22612318
#if PROJ_VERSION_MAJOR >= 6
2262-
free( ms_proj_lib );
2263-
ms_proj_lib = proj_lib ? msStrdup(proj_lib) : NULL;
2319+
if( proj_lib == NULL && ms_proj_lib == NULL )
2320+
{
2321+
/* do nothing */
2322+
}
2323+
else if( proj_lib != NULL && ms_proj_lib != NULL &&
2324+
strcmp(proj_lib, ms_proj_lib) == 0 )
2325+
{
2326+
/* do nothing */
2327+
}
2328+
else
2329+
{
2330+
ms_proj_lib_change_counter++;
2331+
free( ms_proj_lib );
2332+
ms_proj_lib = proj_lib ? msStrdup(proj_lib) : NULL;
2333+
}
22642334
#else
22652335
{
22662336
static int finder_installed = 0;
@@ -2589,3 +2659,75 @@ int GetMapserverUnitUsingProj(projectionObj *psProj)
25892659
return -1;
25902660
}
25912661

2662+
/************************************************************************/
2663+
/* msProjectionContextGetFromPool() */
2664+
/* */
2665+
/* Returns a projection context from the pool, or create a new */
2666+
/* one if the pool is empty. */
2667+
/* After use, it should normally be returned with */
2668+
/* msProjectionContextReleaseToPool() */
2669+
/************************************************************************/
2670+
2671+
projectionContext* msProjectionContextGetFromPool()
2672+
{
2673+
#ifdef USE_PROJ
2674+
projectionContext* context;
2675+
msAcquireLock( TLOCK_PROJ );
2676+
2677+
if( headOfLinkedListOfProjContext )
2678+
{
2679+
LinkedListOfProjContext* next = headOfLinkedListOfProjContext->next;
2680+
context = headOfLinkedListOfProjContext->context;
2681+
msFree(headOfLinkedListOfProjContext);
2682+
headOfLinkedListOfProjContext = next;
2683+
}
2684+
else
2685+
{
2686+
context = msProjectionContextCreate();
2687+
}
2688+
2689+
msReleaseLock( TLOCK_PROJ );
2690+
return context;
2691+
#else
2692+
return NULL;
2693+
#endif
2694+
}
2695+
2696+
/************************************************************************/
2697+
/* msProjectionContextReleaseToPool() */
2698+
/************************************************************************/
2699+
2700+
void msProjectionContextReleaseToPool(projectionContext* ctx)
2701+
{
2702+
#ifdef USE_PROJ
2703+
LinkedListOfProjContext* link =
2704+
(LinkedListOfProjContext*)msSmallMalloc(sizeof(LinkedListOfProjContext));
2705+
link->context = ctx;
2706+
msAcquireLock( TLOCK_PROJ );
2707+
link->next = headOfLinkedListOfProjContext;
2708+
headOfLinkedListOfProjContext = link;
2709+
msReleaseLock( TLOCK_PROJ );
2710+
#endif
2711+
}
2712+
2713+
/************************************************************************/
2714+
/* msProjectionContextPoolCleanup() */
2715+
/************************************************************************/
2716+
2717+
void msProjectionContextPoolCleanup()
2718+
{
2719+
#ifdef USE_PROJ
2720+
LinkedListOfProjContext* link;
2721+
msAcquireLock( TLOCK_PROJ );
2722+
link = headOfLinkedListOfProjContext;
2723+
while( link )
2724+
{
2725+
LinkedListOfProjContext* next = link->next;
2726+
msProjectionContextUnref(link->context);
2727+
msFree(link);
2728+
link = next;
2729+
}
2730+
headOfLinkedListOfProjContext = NULL;
2731+
msReleaseLock( TLOCK_PROJ );
2732+
#endif
2733+
}

Diff for: mapproject.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ extern "C" {
5555
#define wkp_lonlat 1
5656
#define wkp_gmerc 2
5757

58-
#ifndef SWIG
59-
typedef struct projectionContext projectionContext;
60-
#endif
58+
typedef struct projectionContext projectionContext;
6159

6260
typedef struct {
6361
#ifdef SWIG
@@ -94,6 +92,10 @@ extern "C" {
9492
MS_DLL_EXPORT reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* out);
9593
MS_DLL_EXPORT void msProjectDestroyReprojector(reprojectionObj* reprojector);
9694

95+
MS_DLL_EXPORT projectionContext* msProjectionContextGetFromPool(void);
96+
MS_DLL_EXPORT void msProjectionContextReleaseToPool(projectionContext* ctx);
97+
MS_DLL_EXPORT void msProjectionContextPoolCleanup(void);
98+
9799
MS_DLL_EXPORT int msIsAxisInverted(int epsg_code);
98100
MS_DLL_EXPORT int msProjectPoint(projectionObj *in, projectionObj *out, pointObj *point); /* legacy interface */
99101
MS_DLL_EXPORT int msProjectPointEx(reprojectionObj* reprojector, pointObj *point);
@@ -111,6 +113,7 @@ extern "C" {
111113
MS_DLL_EXPORT void msFreeProjectionExceptContext(projectionObj *p);
112114
MS_DLL_EXPORT int msInitProjection(projectionObj *p);
113115
MS_DLL_EXPORT void msProjectionInheritContextFrom(projectionObj *pDst, projectionObj* pSrc);
116+
MS_DLL_EXPORT void msProjectionSetContext(projectionObj *p, projectionContext* ctx);
114117
MS_DLL_EXPORT int msProcessProjection(projectionObj *p);
115118
MS_DLL_EXPORT int msLoadProjectionString(projectionObj *p, const char *value);
116119
MS_DLL_EXPORT int msLoadProjectionStringEPSG(projectionObj *p, const char *value);

Diff for: mapserver.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,10 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char
19621962
#ifdef USE_V8_MAPSCRIPT
19631963
void *v8context;
19641964
#endif
1965+
1966+
#ifndef SWIG
1967+
projectionContext* projContext;
1968+
#endif
19651969
};
19661970

19671971
/************************************************************************/
@@ -2120,7 +2124,7 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char
21202124
MS_DLL_EXPORT int msValidateParameter(const char *value, const char *pattern1, const char *pattern2, const char *pattern3, const char *pattern4);
21212125
MS_DLL_EXPORT int msGetLayerIndex(mapObj *map, const char *name);
21222126
MS_DLL_EXPORT int msGetSymbolIndex(symbolSetObj *set, char *name, int try_addimage_if_notfound);
2123-
MS_DLL_EXPORT mapObj *msLoadMap(char *filename, char *new_mappath);
2127+
MS_DLL_EXPORT mapObj *msLoadMap(const char *filename, const char *new_mappath);
21242128
MS_DLL_EXPORT int msTransformXmlMapfile(const char *stylesheet, const char *xmlMapfile, FILE *tmpfile);
21252129
MS_DLL_EXPORT int msSaveMap(mapObj *map, char *filename);
21262130
MS_DLL_EXPORT void msFreeCharArray(char **array, int num_items);

Diff for: maputil.c

+1
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,7 @@ void msCleanup()
20802080
pj_deallocate_grids();
20812081
#endif
20822082
msSetPROJ_LIB( NULL, NULL );
2083+
msProjectionContextPoolCleanup();
20832084
#endif
20842085
#if defined(USE_CURL)
20852086
msHTTPCleanup();

0 commit comments

Comments
 (0)