@@ -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,51 @@ 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+ if (tile -> tileset -> assembly_threaded_fetching_maxzoom != -1
910+ && tile -> z <= tile -> tileset -> assembly_threaded_fetching_maxzoom ) {
911+ apr_thread_t * * threads ;
912+ apr_threadattr_t * thread_attrs ;
913+ int nthreads ;
914+ _thread_subtile * thread_subtiles ;
915+
916+ nthreads = 0 ;
917+ apr_threadattr_create (& thread_attrs , ctx -> pool );
918+ thread_subtiles = (_thread_subtile * )apr_pcalloc (ctx -> pool ,subtiles -> nelts * sizeof (_thread_subtile ));
919+ threads = (apr_thread_t * * )apr_pcalloc (ctx -> pool ,subtiles -> nelts * sizeof (apr_thread_t * ));
920+ for (i = subtiles -> nelts - 1 ; i >=0 ; i -- ) {
921+ int rv ;
922+ thread_subtiles [i ].subtile = & (APR_ARRAY_IDX (subtiles ,i ,mapcache_subtile ));
923+ thread_subtiles [i ].tile = tile ;
924+ thread_subtiles [i ].ctx = ctx -> clone (ctx );
925+ rv = apr_thread_create (& threads [i ], thread_attrs , _thread_get_subtile ,
926+ (void * )& (thread_subtiles [i ]), thread_subtiles [i ].ctx -> pool );
927+ if (rv != APR_SUCCESS ) {
928+ // In case of failure creating a thread, the subtile will be fetched in the main loop below
929+ break ;
930+ }
931+ nthreads ++ ;
932+ }
933+ for (i = 0 ; i < nthreads ; i ++ ) {
934+ int rv ;
935+ apr_thread_join (& rv , threads [i ]);
936+ if (rv != APR_SUCCESS ) {
937+ ctx -> set_error (ctx ,500 , "thread %d of %d failed on exit\n" ,i ,nthreads );
938+ }
939+ if (GC_HAS_ERROR (thread_subtiles [i ].ctx )) {
940+ /* transfer error message from child thread to main context */
941+ ctx -> set_error (ctx ,thread_subtiles [i ].ctx -> get_error (thread_subtiles [i ].ctx ),
942+ thread_subtiles [i ].ctx -> get_error_message (thread_subtiles [i ].ctx ));
943+ }
944+ }
945+ }
946+ #endif // APR_HAS_THREADS
875947
876948 for (i = subtiles -> nelts - 1 ; i >=0 ; i -- ) {
877949 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 */
950+ if (!APR_ARRAY_IDX (subtiles ,i ,mapcache_subtile ).isFetched ) {
951+ 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 */
952+ }
879953 if (GC_HAS_ERROR (ctx ))
880954 goto cleanup ;
881955 if (!subtile -> nodata ) {
0 commit comments