@@ -795,11 +795,42 @@ int mapcache_tileset_tile_get_readonly(mapcache_context *ctx, mapcache_tile *til
795795
796796typedef struct {
797797 mapcache_tile * tile ;
798- int cache_status ;
798+ int isFetched ;
799799} mapcache_subtile ;
800800
801801static void mapcache_tileset_tile_get_without_subdimensions (mapcache_context * ctx , mapcache_tile * tile , int read_only );
802802
803+ #if APR_HAS_THREADS
804+ /* use a thread pool if using 1.3.12 or higher apu */
805+ #include "apu_version.h"
806+ #if (APU_MAJOR_VERSION <= 1 && APU_MINOR_VERSION <= 3 )
807+ #define USE_THREADPOOL 0
808+ #include <apr_thread_proc.h>
809+ #else
810+ #define USE_THREADPOOL 1
811+ #include <apr_thread_pool.h>
812+ #endif
813+
814+ typedef struct {
815+ mapcache_subtile * subtile ;
816+ mapcache_tile * tile ;
817+ mapcache_context * ctx ;
818+ } _thread_subtile ;
819+ static void * APR_THREAD_FUNC _thread_get_subtile (apr_thread_t * thread , void * data )
820+ {
821+ _thread_subtile * t = (_thread_subtile * )data ;
822+ /* creates the tile from the source, takes care of metatiling */
823+ mapcache_tileset_tile_get_without_subdimensions (t -> ctx , t -> subtile -> tile ,
824+ (t -> tile -> tileset -> subdimension_read_only || !t -> tile -> tileset -> source )?1 :0 );
825+ t -> subtile -> isFetched = MAPCACHE_TRUE ;
826+ #if !USE_THREADPOOL
827+ apr_thread_exit (thread , APR_SUCCESS );
828+ #endif
829+ return NULL ;
830+ }
831+ #endif // APR_HAS_THREADS
832+
833+
803834void mapcache_tileset_tile_set_get_with_subdimensions (mapcache_context * ctx , mapcache_tile * tile ) {
804835 apr_array_header_t * subtiles ;
805836 mapcache_extent extent ;
@@ -813,6 +844,7 @@ void mapcache_tileset_tile_set_get_with_subdimensions(mapcache_context *ctx, map
813844 */
814845 subtiles = apr_array_make (ctx -> pool ,1 ,sizeof (mapcache_subtile ));
815846 st .tile = tile ;
847+ st .isFetched = MAPCACHE_FALSE ;
816848 APR_ARRAY_PUSH (subtiles ,mapcache_subtile ) = st ;
817849 mapcache_grid_get_tile_extent (ctx ,tile -> grid_link -> grid ,tile -> x ,tile -> y ,tile -> z ,& extent );
818850 if (GC_HAS_ERROR (ctx )) goto cleanup ;
@@ -856,6 +888,7 @@ void mapcache_tileset_tile_set_get_with_subdimensions(mapcache_context *ctx, map
856888 /* clone the existing subtiles if we have more than one sub-dimension to assemble for the the current dimension */
857889 for (k = 1 ;k < single_subdimension -> nelts ;k ++ ) {
858890 st .tile = mapcache_tileset_tile_clone (ctx -> pool ,APR_ARRAY_IDX (subtiles ,j ,mapcache_subtile ).tile );
891+ st .isFetched = MAPCACHE_FALSE ;
859892 APR_ARRAY_PUSH (subtiles ,mapcache_subtile )= st ;
860893 }
861894 }
@@ -872,10 +905,50 @@ void mapcache_tileset_tile_set_get_with_subdimensions(mapcache_context *ctx, map
872905
873906 /* our subtiles array now contains a list of tiles with subdimensions split up, we now need to fetch them from the cache */
874907 /* note that subtiles[0].tile == tile */
908+ #if APR_HAS_THREADS
909+ {
910+ apr_thread_t * * threads ;
911+ apr_threadattr_t * thread_attrs ;
912+ int nthreads ;
913+ _thread_subtile * thread_subtiles ;
914+
915+ nthreads = 0 ;
916+ apr_threadattr_create (& thread_attrs , ctx -> pool );
917+ thread_subtiles = (_thread_subtile * )apr_pcalloc (ctx -> pool ,subtiles -> nelts * sizeof (_thread_subtile ));
918+ threads = (apr_thread_t * * )apr_pcalloc (ctx -> pool ,subtiles -> nelts * sizeof (apr_thread_t * ));
919+ for (i = subtiles -> nelts - 1 ; i >=0 ; i -- ) {
920+ int rv ;
921+ thread_subtiles [i ].subtile = & (APR_ARRAY_IDX (subtiles ,i ,mapcache_subtile ));
922+ thread_subtiles [i ].tile = tile ;
923+ thread_subtiles [i ].ctx = ctx -> clone (ctx );
924+ rv = apr_thread_create (& threads [i ], thread_attrs , _thread_get_subtile ,
925+ (void * )& (thread_subtiles [i ]), thread_subtiles [i ].ctx -> pool );
926+ if (rv != APR_SUCCESS ) {
927+ // In case of failure creating a thread, the subtile will be fetched in the main loop below
928+ break ;
929+ }
930+ nthreads ++ ;
931+ }
932+ for (i = 0 ; i < nthreads ; i ++ ) {
933+ int rv ;
934+ apr_thread_join (& rv , threads [i ]);
935+ if (rv != APR_SUCCESS ) {
936+ ctx -> set_error (ctx ,500 , "thread %d of %d failed on exit\n" ,i ,nthreads );
937+ }
938+ if (GC_HAS_ERROR (thread_subtiles [i ].ctx )) {
939+ /* transfer error message from child thread to main context */
940+ ctx -> set_error (ctx ,thread_subtiles [i ].ctx -> get_error (thread_subtiles [i ].ctx ),
941+ thread_subtiles [i ].ctx -> get_error_message (thread_subtiles [i ].ctx ));
942+ }
943+ }
944+ }
945+ #endif // APR_HAS_THREADS
875946
876947 for (i = subtiles -> nelts - 1 ; i >=0 ; i -- ) {
877948 mapcache_tile * subtile = APR_ARRAY_IDX (subtiles ,i ,mapcache_subtile ).tile ;
878- mapcache_tileset_tile_get_without_subdimensions (ctx , subtile , (tile -> tileset -> subdimension_read_only || !tile -> tileset -> source )?1 :0 ); /* creates the tile from the source, takes care of metatiling */
949+ if (!APR_ARRAY_IDX (subtiles ,i ,mapcache_subtile ).isFetched ) {
950+ mapcache_tileset_tile_get_without_subdimensions (ctx , subtile , (tile -> tileset -> subdimension_read_only || !tile -> tileset -> source )?1 :0 ); /* creates the tile from the source, takes care of metatiling */
951+ }
879952 if (GC_HAS_ERROR (ctx ))
880953 goto cleanup ;
881954 if (!subtile -> nodata ) {
0 commit comments