Salome HOME
Direct manipulation of resource map singleton
[modules/kernel.git] / src / ResourcesManager / ResourcesManager.cxx
index 1aed4d065e5a13450778ee5de2039cfc9794bb48..fc55861785f9652f41dbdb5456dbb457df8cf95b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
 
 #include "ResourcesManager.hxx" 
+
 #include "SALOME_ResourcesCatalog_Handler.hxx"
 #include <Basics_Utils.hxx>
+#include <Basics_DirUtils.hxx>
+#include "utilities.h"
+
 #include <fstream>
 #include <iostream>
 #include <sstream>
@@ -38,8 +42,7 @@
 #include <libxml/parser.h>
 
 #include <algorithm>
-
-#include "Utils_SALOME_Exception.hxx"
+#include <memory>
 
 #define MAX_SIZE_FOR_HOSTNAME 256;
 
@@ -55,7 +58,7 @@ resourceParams::resourceParams()
 : can_launch_batch_jobs(false),
   can_run_containers(false),
   nb_proc(-1),
-  nb_node(-1),
+  nb_node(0),
   nb_proc_per_node(-1),
   cpu_clock(-1),
   mem_mb(-1)
@@ -82,6 +85,7 @@ ResourcesManager_cpp(const char *xmlFilePath)
   _resourceManagerMap[""]=&altcycl;
 
   AddDefaultResourceInCatalog();
+  ParseXmlFiles();
 }
 
 //=============================================================================
@@ -95,7 +99,7 @@ ResourcesManager_cpp(const char *xmlFilePath)
  */ 
 //=============================================================================
 
-ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
+ResourcesManager_cpp::ResourcesManager_cpp()
 {
   RES_MESSAGE("ResourcesManager_cpp constructor");
 
@@ -116,18 +120,19 @@ ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
     std::ifstream ifile(user_file.c_str(), std::ifstream::in );
     if (ifile) {
       // The file exists, and is open for input
+      DEBUG_MESSAGE("USER_CATALOG_RESOURCES_FILE positioned -> add it into resourcefiles list");
       _path_resources.push_back(user_file);
     }
     else {
       default_catalog_resource = false;
-      RES_INFOS("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
-      RES_INFOS("Warning: That's why we try to create a new one.")
+      WARNING_MESSAGE("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
+      WARNING_MESSAGE("Warning: That's why we try to create a new one.")
       std::ofstream user_catalog_file;
       user_catalog_file.open(user_file.c_str());
       if (user_catalog_file.fail())
       {
-        RES_INFOS("Error: cannot write in the user catalog resouces files");
-        RES_INFOS("Error: using default CatalogResources.xml file");
+        WARNING_MESSAGE("Error: cannot write in the user catalog resources files");
+        WARNING_MESSAGE("Error: using default CatalogResources.xml file");
         default_catalog_resource = true;
       }
       else
@@ -146,23 +151,29 @@ ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
     std::string default_file("");
     if (getenv("APPLI") != 0)
     {
-      default_file += getenv("HOME");
+      default_file += Kernel_Utils::HomePath();
       default_file += "/";
       default_file += getenv("APPLI");
       default_file += "/CatalogResources.xml";
-      _path_resources.push_back(default_file);
-    }
-    else
-    {
-      if(!getenv("KERNEL_ROOT_DIR"))
-        throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
-      default_file = getenv("KERNEL_ROOT_DIR");
-      default_file += "/share/salome/resources/kernel/CatalogResources.xml";
-      _path_resources.push_back(default_file);
+      std::ifstream ifile(default_file.c_str(), std::ifstream::in );
+      if (ifile) {
+        // The file exists, and is open for input
+        DEBUG_MESSAGE("${APPLI}/CatalogResources.xml exists -> add it into resourcefiles list");
+        _path_resources.push_back(default_file);
+        default_catalog_resource=false;
+      }
     }
   }
-
-  _lasttime=0;
+  if (default_catalog_resource)
+  {
+    std::string default_file("");
+    if(!getenv("KERNEL_ROOT_DIR"))
+      throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
+    default_file = getenv("KERNEL_ROOT_DIR");
+    default_file += "/share/salome/resources/kernel/CatalogResources.xml";
+    DEBUG_MESSAGE("${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml -> add it into resourcefiles list");
+    _path_resources.push_back(default_file);
+  }
 
   ParseXmlFiles();
   RES_MESSAGE("ResourcesManager_cpp constructor end");
@@ -193,7 +204,7 @@ ResourcesManager_cpp::~ResourcesManager_cpp()
 //=============================================================================
 
 std::vector<std::string> 
-ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(ResourcesException)
+ResourcesManager_cpp::GetFittingResources(const resourceParams& params) 
 {
   RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
   RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
@@ -319,20 +330,44 @@ ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(Re
   return vec;
 }
 
+void ResourcesManager_cpp::AddResourceInCatalogNoQuestion (const ParserResourcesType & new_resource)
+{
+  _resourcesList[new_resource.Name] = new_resource;
+}
+
 //=============================================================================
 /*!
- *  add an entry in the ressources catalog xml file.
+ *  add an entry in the resources catalog xml file.
  */ 
 //=============================================================================
 
 void
 ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resource)
 {
-  if (new_resource.Name == DEFAULT_RESOURCE_NAME)
-    throw SALOME_Exception((string("Cannot modify default local resource \"") +
-                            DEFAULT_RESOURCE_NAME + "\"").c_str());
+  if (new_resource.Name == DEFAULT_RESOURCE_NAME){
+    ParserResourcesType default_resource = _resourcesList[DEFAULT_RESOURCE_NAME];
+    // some of the properties of the default resource shouldn't be modified
+    std::string check;
+    if( default_resource.HostName != new_resource.HostName)
+      check += "The Hostname property of the default resource can not be modified.\n";
+    if( default_resource.AppliPath != new_resource.AppliPath)
+      check += "The Applipath property of the default resource can not be modified.\n";
+    if( !new_resource.can_run_containers)
+      check += "The default resource should be able to run containers.\n";
+    if( !new_resource.can_launch_batch_jobs)
+      check += "The default resource should be able to launch batch jobs.\n";
+    if( default_resource.Protocol != new_resource.Protocol)
+      check += "The Protocol property of the default resource can not be modified.\n";
+    if(!check.empty())
+      throw ResourcesException(check);
+  }
   // TODO - Add minimal check
-  _resourcesList[new_resource.Name] = new_resource;
+  this->AddResourceInCatalogNoQuestion( new_resource );
+}
+
+void ResourcesManager_cpp::DeleteAllResourcesInCatalog()
+{
+  _resourcesList.clear();
 }
 
 //=============================================================================
@@ -343,9 +378,10 @@ ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resou
 
 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
 {
-  if (DEFAULT_RESOURCE_NAME == name)
-    throw SALOME_Exception((string("Cannot delete default local resource \"") +
-                            DEFAULT_RESOURCE_NAME + "\"").c_str());
+  if (DEFAULT_RESOURCE_NAME == name){
+    std::string error("Cannot delete default local resource \"" + DEFAULT_RESOURCE_NAME + "\"");
+    throw ResourcesException(error);
+  }
   MapOfParserResourcesType_it it = _resourcesList.find(name);
   if (it != _resourcesList.end())
     _resourcesList.erase(name);
@@ -364,12 +400,9 @@ void ResourcesManager_cpp::WriteInXmlFile(std::string xml_file)
   RES_MESSAGE("WriteInXmlFile : start");
 
   MapOfParserResourcesType resourceListToSave(_resourcesList);
-  // We do not save default local resource because it is automatically created at startup
-  resourceListToSave.erase(DEFAULT_RESOURCE_NAME);
   if (resourceListToSave.empty())
   {
-    RES_MESSAGE("WriteInXmlFile: nothing to do, no resource except default \"" <<
-                DEFAULT_RESOURCE_NAME << "\"");
+    RES_MESSAGE("WriteInXmlFile: nothing to do, no resource to save!");
     return;
   }
 
@@ -422,12 +455,13 @@ const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
     int result = stat((*_path_resources_it).c_str(), &statinfo);
     if (result < 0)
     {
-      RES_MESSAGE("Resource file " << *_path_resources_it << " does not exist");
+      WARNING_MESSAGE("Resource file " << *_path_resources_it << " does not exist -> no parsing");
       return _resourcesList;
     }
 
-    if(statinfo.st_mtime > _lasttime)
+    if(_lasttime == 0 || statinfo.st_mtime > _lasttime)
     {
+      DEBUG_MESSAGE("Resource file " << *_path_resources_it << " has been detected to be present and newer than Resources in memory");
       to_parse = true;
       _lasttime = statinfo.st_mtime;
     }
@@ -435,6 +469,7 @@ const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
 
   if (to_parse)
   {
+    DEBUG_MESSAGE("After analyze of resoure files time meta data, a load of resources from scratch from files is necessary.");
     _resourcesList.clear();
     AddDefaultResourceInCatalog();
     // On parse tous les fichiers
@@ -442,48 +477,55 @@ const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
     {
       MapOfParserResourcesType _resourcesList_tmp;
       MapOfParserResourcesType _resourcesBatchList_tmp;
-      SALOME_ResourcesCatalog_Handler* handler =
-        new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp);
-      const char* aFilePath = (*_path_resources_it).c_str();
+      std::unique_ptr<SALOME_ResourcesCatalog_Handler> handler( new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp) );
+      const char *aFilePath( (*_path_resources_it).c_str() );
       FILE* aFile = fopen(aFilePath, "r");
-
       if (aFile != NULL)
       {
         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
         if (aDoc != NULL)
         {
+          DEBUG_MESSAGE("XML parsing of Resource file \"" << aFilePath << "\"");
           handler->ProcessXmlDocument(aDoc);
 
           // adding new resources to the file
           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
           {
             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
-            if (i->second.HostName == "localhost" || i->second.HostName == Kernel_Utils::GetHostname())
+            if (i->second.HostName == DEFAULT_RESOURCE_NAME || i->second.HostName == Kernel_Utils::GetHostname())
             {
-              RES_MESSAGE("Resource " << i->first << " is not added because it is the same "
-                          "machine as default local resource \"" << DEFAULT_RESOURCE_NAME << "\"");
+              DEBUG_MESSAGE("Resource \"" << i->first << "\" in file \"" << aFilePath << "\" is detected as localhost");
+              MapOfParserResourcesType_it it0(_resourcesList.find(DEFAULT_RESOURCE_NAME));
+              if(it0!=_resourcesList.end())
+                {
+                  DEBUG_MESSAGE("Resource \"" << i->first << "\" in file \"" << aFilePath << "\" detected as localhost is already in memory -> update resource with content in file ( for attributes : nbOfNodes, nbOfProcPerNode, CPUFreqMHz and memInMB)");
+                  ParserResourcesType& localhostElt((*it0).second);
+                  localhostElt.DataForSort._nbOfNodes=(*i).second.DataForSort._nbOfNodes;
+                  localhostElt.DataForSort._nbOfProcPerNode=(*i).second.DataForSort._nbOfProcPerNode;
+                  localhostElt.DataForSort._CPUFreqMHz=(*i).second.DataForSort._CPUFreqMHz;
+                  localhostElt.DataForSort._memInMB=(*i).second.DataForSort._memInMB;
+                }
+              DEBUG_MESSAGE("Resource \"" << i->first << "\" is not added because it is the same machine as default local resource \"" << DEFAULT_RESOURCE_NAME << "\"");
             }
             else if (j != _resourcesList.end())
             {
-              cerr << "ParseXmlFiles Warning, two resources with the same name were found, "
-                      "taking the first declaration : " << i->first << endl;
+              WARNING_MESSAGE("ParseXmlFiles Warning, two resources with the same name were found, taking the first declaration : " << i->first );
             }
             else
             {
+              DEBUG_MESSAGE("Resource \"" << i->first << "\" added");
               _resourcesList[i->first] = i->second;
             }
           }
         }
         else
-          std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
+          ERROR_MESSAGE( "ResourcesManager_cpp: could not parse file " << aFilePath );
         // Free the document
         xmlFreeDoc(aDoc);
         fclose(aFile);
       }
       else
-        std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
-
-      delete handler;
+        ERROR_MESSAGE( "ResourcesManager_cpp: file " << aFilePath << " is not readable." );
     }
   }
   return _resourcesList;
@@ -500,11 +542,16 @@ const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
   return _resourcesList;
 }
 
-std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources)
+//! threadsafe
+std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources) const
 {
-  if(_resourceManagerMap.count(policy)==0)
-    return _resourceManagerMap[""]->Find(listOfResources, _resourcesList);
-  return _resourceManagerMap[policy]->Find(listOfResources, _resourcesList);
+  std::map<std::string , LoadRateManager*>::const_iterator it(_resourceManagerMap.find(policy));
+  if(it==_resourceManagerMap.end())
+       {
+         it=_resourceManagerMap.find("");
+         return ((*it).second)->Find(listOfResources, _resourcesList);
+       }
+  return ((*it).second)->Find(listOfResources, _resourcesList);
 }
 
 //=============================================================================
@@ -570,12 +617,12 @@ ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& r
   resources=kept_resources;
 }
 
-
-ParserResourcesType 
-ResourcesManager_cpp::GetResourcesDescr(const std::string & name)
+//! thread safe
+ParserResourcesType ResourcesManager_cpp::GetResourcesDescr(const std::string & name) const
 {
-  if (_resourcesList.find(name) != _resourcesList.end())
-    return _resourcesList[name];
+  MapOfParserResourcesType::const_iterator it(_resourcesList.find(name));
+  if (it != _resourcesList.end())
+    return (*it).second;
   else
   {
     std::string error("[GetResourcesDescr] Resource does not exist: ");
@@ -594,12 +641,41 @@ void ResourcesManager_cpp::AddDefaultResourceInCatalog()
   resource.DataForSort._Name = DEFAULT_RESOURCE_NAME;
   resource.Protocol = sh;
   resource.Batch = none;
-  if (getenv("HOME") != NULL && getenv("APPLI") != NULL)
+#ifndef WIN32
+  struct stat statbuf;
+  std::string aHomePath = Kernel_Utils::HomePath();
+  if (aHomePath != "" && getenv("APPLI") != NULL)
   {
-    resource.AppliPath = string(getenv("HOME")) + "/" + getenv("APPLI");
+    if (stat(getenv("APPLI"), &statbuf) ==0 &&  S_ISREG(statbuf.st_mode))
+    {
+        // if $APPLI is a regular file, we asume it's a salome Launcher file
+        resource.AppliPath = string(getenv("APPLI"));
+    }
+    else
+    {
+        resource.AppliPath = aHomePath + "/" + getenv("APPLI");
+    }
   }
-  resource.working_directory = "/tmp/salome_localres_workdir";
+  string tmpdir = "/tmp";
+  if (getenv("TMPDIR") != NULL)
+    tmpdir = getenv("TMPDIR");
+  resource.working_directory = tmpdir + "/salome_localres_workdir";
+  if (getenv("USER") != NULL)
+    resource.working_directory += string("_") + getenv("USER");
+#else
+  if (getenv("USERPROFILE") != NULL && getenv("APPLI") != NULL)
+  {
+    resource.AppliPath = string(getenv("USERPROFILE")) + "\\" + getenv("APPLI");
+  }
+  string tmpdir = "C:\\tmp";
+  if (getenv("TEMP") != NULL)
+    tmpdir = getenv("TEMP");
+  resource.working_directory = tmpdir + "\\salome_localres_workdir";
+  if (getenv("USERNAME") != NULL)
+    resource.working_directory += string("_") + getenv("USERNAME");
+#endif
   resource.can_launch_batch_jobs = true;
   resource.can_run_containers = true;
   _resourcesList[resource.Name] = resource;
+  DEBUG_MESSAGE("Put Ressource \"" << resource.Name << "\" in dictionary of resources. This resource will be present even if resource files define it later.");
 }