5656#include < sstream>
5757#include < curl/curl.h>
5858#include < proj.h>
59+ #include < thread>
60+ #include < mutex>
5961
6062
6163#include " rok4/utils/TileMatrixSet.h"
@@ -470,6 +472,14 @@ class IndexCache {
470472 */
471473 static int validity;
472474
475+ /* *
476+ * \~french \brief Exclusion mutuelle
477+ * \details Pour éviter les modifications concurrentes du cache des index
478+ * \~english \brief Mutual exclusion
479+ * \details To avoid concurrent index cache updates
480+ */
481+ static std::mutex mtx;
482+
473483 /* *
474484 * \~french
475485 * \brief Constructeur
@@ -533,14 +543,16 @@ class IndexCache {
533543 // mais c'est via cette dalle symbolique que la donnée est a priori requêtée
534544 // donc c'est ce nom qu'on utilisera pour l'interrogation du cache
535545
546+ mtx.lock ();
547+
536548 IndexElement* elem = new IndexElement (origin_slab_name, data_context, data_slab_name, tiles_number, offsets, sizes);
537549
538550 // L'information n'est a priori pas dans le cache car
539- // Soit elle était dans le cache et valide, alors on aurait utiliser ce cahe et on n'aurait pas fait appel à cet ajout
551+ // Soit elle était dans le cache et valide, alors on aurait utilisé ce cache et on n'aurait pas fait appel à cet ajout
540552 // Soit elle était dans le cache mais obsolète, alors on l'aurait déjà supprimé du cache
541553
542554 if (cache.size () == size) {
543- // On réupcère le dernier élément du cache
555+ // On récupère le dernier élément du cache
544556 IndexElement* last = cache.back ();
545557 // On le vire du cache
546558 cache.pop_back ();
@@ -552,6 +564,8 @@ class IndexCache {
552564 // update reference
553565 cache.push_front (elem);
554566 map[origin_slab_name] = cache.begin ();
567+
568+ mtx.unlock ();
555569 };
556570
557571 /* * \~french
@@ -579,9 +593,19 @@ class IndexCache {
579593 // Gestion de la péremption du cache (une heure max)
580594 std::time_t now = std::time (NULL );
581595 if (now - (*(it->second ))->date > validity) {
582- delete *(it->second );
583- cache.erase (it->second );
584- map.erase (it);
596+ mtx.lock ();
597+
598+ // on le cherche à nouveau pour vérifier qu'il n'a pas déjà été supprimé par un thread concurrent
599+ it = map.find ( key );
600+
601+ if ( it != map.end () ) {
602+ delete *(it->second );
603+ cache.erase (it->second );
604+ map.erase (it);
605+ }
606+
607+ mtx.unlock ();
608+
585609 return false ;
586610 }
587611
@@ -605,11 +629,13 @@ class IndexCache {
605629 * \~english \brief Clean all element from the cache
606630 */
607631 static void cleanCache () {
632+ mtx.lock ();
608633 std::list<IndexElement*>::iterator it;
609634 for (it = cache.begin (); it != cache.end (); ++it) {
610635 delete *it;
611636 }
612637 cache.clear ();
638+ mtx.unlock ();
613639 }
614640};
615641
@@ -654,6 +680,14 @@ class TmsBook {
654680 */
655681 static std::vector<TileMatrixSet*> trash;
656682
683+ /* *
684+ * \~french \brief Exclusion mutuelle
685+ * \details Pour éviter les modifications concurrentes du cache de TMS
686+ * \~english \brief Mutual exclusion
687+ * \details To avoid concurrent TMS cache updates
688+ */
689+ static std::mutex mtx;
690+
657691public:
658692
659693
@@ -662,22 +696,26 @@ class TmsBook {
662696 * \~english \brief Empty book and put content into trash
663697 */
664698 static void send_to_trash () {
699+ mtx.lock ();
665700 std::map<std::string, TileMatrixSet*>::iterator it;
666701 for (it = book.begin (); it != book.end (); ++it) {
667702 trash.push_back (it->second );
668703 }
669704 book.empty ();
705+ mtx.unlock ();
670706 }
671707
672708 /* *
673709 * \~french \brief Vide la corbeille
674710 * \~english \brief Empty trash
675711 */
676712 static void empty_trash () {
713+ mtx.lock ();
677714 for (int i = 0 ; i < trash.size (); i++) {
678715 delete trash.at (i);
679716 }
680717 trash.empty ();
718+ mtx.unlock ();
681719 }
682720
683721
@@ -694,7 +732,7 @@ class TmsBook {
694732 }
695733
696734 /* *
697- * \~french \brief Renseigne l'ensemble de l'annuaire
735+ * \~french \brief Retourne l'ensemble de l'annuaire
698736 * \~english \brief Return the book
699737 */
700738 static std::map<std::string,TileMatrixSet*> get_book () {
@@ -731,20 +769,32 @@ class TmsBook {
731769
732770 std::string tms_path = d + " /" + id;
733771
772+ mtx.lock ();
773+ // Si on fait du cache de TMS, on revérifie que ce TMS n'a pas déjà été ajouté par un thread concurrent entre temps
774+ if (getenv (ROK4_TMS_NO_CACHE) == NULL ) {
775+ if ( it != book.end () ) {
776+ // On a effectivement depuis déjà enregistré ce TMS
777+ return it->second ;
778+ }
779+ }
780+
734781 TileMatrixSet* tms = new TileMatrixSet (tms_path);
735782 if ( ! tms->isOk () ) {
736783 BOOST_LOG_TRIVIAL (error) << tms->getErrorMessage ();
737784 delete tms;
785+ mtx.unlock ();
738786 return NULL ;
739787 }
740788
741- if (getenv (ROK4_STYLES_NO_CACHE ) == NULL ) {
742- // On veut utiliser le cache, on met donc ce nouveau TMS dans l'annuaire pour le trouver la porchaine fois
789+ if (getenv (ROK4_TMS_NO_CACHE ) == NULL ) {
790+ // On veut utiliser le cache, on met donc ce nouveau TMS dans l'annuaire pour le trouver la prochaine fois
743791 book.insert ( std::pair<std::string, TileMatrixSet*>(id, tms) );
744792 } else {
745793 // On met le TMS directement dans la corbeille, pour que le nettoyage se fasse bien
746794 trash.push_back (tms);
747795 }
796+
797+ mtx.unlock ();
748798
749799 return tms;
750800 }
@@ -816,6 +866,14 @@ class StyleBook {
816866 */
817867 static std::vector<Style*> trash;
818868
869+ /* *
870+ * \~french \brief Exclusion mutuelle
871+ * \details Pour éviter les modifications concurrentes du cache de TMS
872+ * \~english \brief Mutual exclusion
873+ * \details To avoid concurrent TMS cache updates
874+ */
875+ static std::mutex mtx;
876+
819877public:
820878
821879
@@ -824,22 +882,26 @@ class StyleBook {
824882 * \~english \brief Empty book and put content into trash
825883 */
826884 static void send_to_trash () {
885+ mtx.lock ();
827886 std::map<std::string, Style*>::iterator it;
828887 for (it = book.begin (); it != book.end (); ++it) {
829888 trash.push_back (it->second );
830889 }
831890 book.empty ();
891+ mtx.unlock ();
832892 }
833893
834894 /* *
835895 * \~french \brief Vide la corbeille
836896 * \~english \brief Empty trash
837897 */
838898 static void empty_trash () {
899+ mtx.lock ();
839900 for (int i = 0 ; i < trash.size (); i++) {
840901 delete trash.at (i);
841902 }
842903 trash.empty ();
904+ mtx.unlock ();
843905 }
844906
845907
@@ -866,7 +928,7 @@ class StyleBook {
866928
867929
868930 /* *
869- * \~french \brief Renseigne l'ensemble de l'annuaire
931+ * \~french \brief Retourne l'ensemble de l'annuaire
870932 * \~english \brief Return the book
871933 */
872934 static std::map<std::string,Style*> get_book () {
@@ -904,16 +966,27 @@ class StyleBook {
904966
905967 std::string style_path = d + " /" + id;
906968
969+ mtx.lock ();
970+ // Si on fait du cache de style, on revérifie que ce style n'a pas déjà été ajouté par un thread concurrent entre temps
971+ if (getenv (ROK4_STYLES_NO_CACHE) == NULL ) {
972+ if ( it != book.end () ) {
973+ // On a effectivement depuis déjà enregistré ce style
974+ return it->second ;
975+ }
976+ }
977+
907978 Style* style = new Style (style_path, inspire);
908979 if ( ! style->isOk () ) {
909980 BOOST_LOG_TRIVIAL (error) << style->getErrorMessage ();
910981 delete style;
982+ mtx.unlock ();
911983 return NULL ;
912984 }
913985
914986 if ( containForbiddenChars (style->getIdentifier ()) ) {
915987 BOOST_LOG_TRIVIAL (error) << " Style identifier contains forbidden chars" ;
916988 delete style;
989+ mtx.unlock ();
917990 return NULL ;
918991 }
919992
@@ -925,6 +998,7 @@ class StyleBook {
925998 trash.push_back (style);
926999 }
9271000
1001+ mtx.unlock ();
9281002 return style;
9291003 }
9301004
0 commit comments