Salome HOME
Merge from V6_3_BR 15/07/2011
[modules/kernel.git] / src / ResourcesManager / ResourcesManager.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "ResourcesManager.hxx" 
24 #include <Basics_Utils.hxx>
25 #include <fstream>
26 #include <iostream>
27 #include <sstream>
28 #include <string.h>
29 #include <map>
30 #include <list>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifdef WNT
34 #else
35 #include <unistd.h>
36 #endif
37 #include <libxml/parser.h>
38
39 #include <algorithm>
40
41 #define MAX_SIZE_FOR_HOSTNAME 256;
42
43 static LoadRateManagerFirst first;
44 static LoadRateManagerCycl cycl;
45 static LoadRateManagerAltCycl altcycl;
46 //=============================================================================
47 /*!
48  * just for test
49  */ 
50 //=============================================================================
51
52 ResourcesManager_cpp::
53 ResourcesManager_cpp(const char *xmlFilePath)
54 {
55   _path_resources.push_back(xmlFilePath);
56 #if defined(_DEBUG_) || defined(_DEBUG)
57   std::cerr << "ResourcesManager_cpp constructor" << std::endl;
58 #endif
59   _resourceManagerMap["first"]=&first;
60   _resourceManagerMap["cycl"]=&cycl;
61   _resourceManagerMap["altcycl"]=&altcycl;
62   _resourceManagerMap["best"]=&altcycl;
63   _resourceManagerMap[""]=&altcycl;
64 }
65
66 //=============================================================================
67 /*!
68  *  Standard constructor, parse resource file.
69  *  - if ${APPLI} exists in environment,
70  *    look for ${HOME}/${APPLI}/CatalogResources.xml
71  *  - else look for default:
72  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
73  *  - parse XML resource file.
74  */ 
75 //=============================================================================
76
77 ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
78 {
79   RES_MESSAGE("ResourcesManager_cpp constructor");
80
81   _resourceManagerMap["first"]=&first;
82   _resourceManagerMap["cycl"]=&cycl;
83   _resourceManagerMap["altcycl"]=&altcycl;
84   _resourceManagerMap["best"]=&altcycl;
85   _resourceManagerMap[""]=&altcycl;
86
87   bool default_catalog_resource = true;
88   if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
89   {
90     default_catalog_resource = false;
91     std::string user_file("");
92     user_file = getenv("USER_CATALOG_RESOURCES_FILE");
93     std::ifstream ifile(user_file.c_str(), std::ifstream::in );
94     if (ifile) {
95       // The file exists, and is open for input
96       _path_resources.push_back(user_file);
97     }
98     else {
99       default_catalog_resource = true;
100       RES_INFOS("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
101     }
102   }
103   if (default_catalog_resource)
104   {
105     std::string default_file("");
106     if (getenv("APPLI") != 0)
107     {
108       default_file += getenv("HOME");
109       default_file += "/";
110       default_file += getenv("APPLI");
111       default_file += "/CatalogResources.xml";
112       _path_resources.push_back(default_file);
113     }
114     else
115     {
116       if(!getenv("KERNEL_ROOT_DIR"))
117         throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
118       default_file = getenv("KERNEL_ROOT_DIR");
119       default_file += "/share/salome/resources/kernel/CatalogResources.xml";
120       _path_resources.push_back(default_file);
121     }
122   }
123
124   _lasttime=0;
125
126   ParseXmlFiles();
127   RES_MESSAGE("ResourcesManager_cpp constructor end");
128 }
129
130 //=============================================================================
131 /*!
132  *  Standard Destructor
133  */ 
134 //=============================================================================
135
136 ResourcesManager_cpp::~ResourcesManager_cpp()
137 {
138   RES_MESSAGE("ResourcesManager_cpp destructor");
139 }
140
141 //=============================================================================
142 //! get the list of resource names fitting constraints given by params
143 /*!
144  * Steps:
145  * 1: Restrict list with resourceList if defined
146  * 2: If name is defined -> check resource list
147  * 3: If not 2:, if hostname is defined -> check resource list
148  * 4: If not 3:, sort resource with nb_proc, etc...
149  * 5: In all cases remove resource that does not correspond with OS
150  * 6: And remove resource with componentList - if list is empty ignored it...
151  */ 
152 //=============================================================================
153
154 std::vector<std::string> 
155 ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(ResourcesException)
156 {
157   RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
158   RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
159   RES_MESSAGE("[GetFittingResources] with hostname: "<< params.hostname);
160
161   // Result
162   std::vector<std::string> vec;
163
164   // Parse Again CalatogResource File
165   ParseXmlFiles();
166
167   // Steps:
168   // 1: If name is defined -> check resource list
169   // 2: Restrict list with resourceList if defined
170   // 3: If not 2:, if hostname is defined -> check resource list
171   // 4: If not 3:, sort resource with nb_proc, etc...
172   // 5: In all cases remove resource that does not correspond with OS
173   // 6: And remove resource with componentList - if list is empty ignored it...
174
175   // Step 1
176   if (params.name != "")
177   {
178     RES_MESSAGE("[GetFittingResources] name parameter found !");
179     if (_resourcesList.find(params.name) != _resourcesList.end())
180     {
181       vec.push_back(params.name);
182       return vec;
183     }
184     else
185       RES_MESSAGE("[GetFittingResources] resource name was not found on resource list ! name requested was " << params.name);
186       std::string error("[GetFittingResources] resource name was not found on resource list ! name requested was " + params.name);
187       throw ResourcesException(error);
188   }
189
190   MapOfParserResourcesType local_resourcesList = _resourcesList;
191   // Step 2
192   if (params.resourceList.size() > 0)
193   {
194     RES_MESSAGE("[GetFittingResources] Restricted resource list found !");
195     local_resourcesList.clear();
196     std::vector<std::string>::size_type sz = params.resourceList.size();
197
198     for (unsigned int i=0; i < sz; i++)
199     {
200       if (_resourcesList.find(params.resourceList[i]) != _resourcesList.end())
201         local_resourcesList[params.resourceList[i]] = _resourcesList[params.resourceList[i]];
202     }
203   }
204
205   // Step 3
206   if (params.hostname != "")
207   {
208     RES_MESSAGE("[GetFittingResources] Entering in hostname case !");
209
210     std::string hostname = params.hostname;
211     if (hostname ==  "localhost")
212       hostname = Kernel_Utils::GetHostname().c_str();
213
214     std::map<std::string, ParserResourcesType>::const_iterator iter = _resourcesList.begin();
215     for (; iter != _resourcesList.end(); iter++)
216     {
217       if ((*iter).second.HostName == hostname)
218         vec.push_back((*iter).first);
219     }
220   }
221   // Step 4
222   else
223   {
224     // --- Search for available resources sorted by priority
225     MapOfParserResourcesType_it i = local_resourcesList.begin();
226     for (; i != local_resourcesList.end(); ++i)
227       vec.push_back(i->first);
228
229     // --- set wanted parameters
230     ResourceDataToSort::_nbOfProcWanted = params.nb_proc;
231     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
232     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
233     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
234     ResourceDataToSort::_memInMBWanted = params.mem_mb;
235     // --- end of set
236         
237     // Sort
238     std::list<ResourceDataToSort> li;
239     std::vector<std::string>::iterator iter = vec.begin();
240     for (; iter != vec.end(); iter++)
241       li.push_back(local_resourcesList[(*iter)].DataForSort);
242     li.sort();
243
244     vec.clear();
245     for (std::list<ResourceDataToSort>::iterator iter2 = li.begin(); iter2 != li.end(); iter2++)
246       vec.push_back((*iter2)._Name);
247   }
248
249   // Step 5
250   SelectOnlyResourcesWithOS(vec, params.OS.c_str());
251     
252   // Step 6
253   std::vector<std::string> vec_save(vec);
254   KeepOnlyResourcesWithComponent(vec, params.componentList);
255   if (vec.size() == 0)
256     vec = vec_save;
257
258   // End
259   // Send an exception if return list is empty...
260   if (vec.size() == 0)
261   {
262     std::string error("[GetFittingResources] ResourcesManager doesn't find any resource that fits to your parameters");
263     throw ResourcesException(error);
264   }
265
266   return vec;
267 }
268
269 //=============================================================================
270 /*!
271  *  add an entry in the ressources catalog xml file.
272  */ 
273 //=============================================================================
274
275 void
276 ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resource) throw(ResourcesException)
277 {
278   // TODO - Add minimal check
279   _resourcesList[new_resource.Name] = new_resource;
280 }
281
282 //=============================================================================
283 /*!
284  *  Deletes a resource from the catalog
285  */ 
286 //=============================================================================
287
288 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
289 {
290   MapOfParserResourcesType_it it = _resourcesList.find(name);
291   if (it != _resourcesList.end())
292     _resourcesList.erase(name);
293   else
294     RES_INFOS("You try to delete a resource that does not exist... : " << name);
295 }
296
297 //=============================================================================
298 /*!
299  *  write the current data in memory in file.
300  */ 
301 //=============================================================================
302
303 void ResourcesManager_cpp::WriteInXmlFile(std::string xml_file)
304 {
305   RES_MESSAGE("WriteInXmlFile : start");
306
307   if (xml_file == "")
308   {
309     _path_resources_it = _path_resources.begin();
310     xml_file = *_path_resources_it;
311   }
312
313   const char* aFilePath = xml_file.c_str();
314   FILE* aFile = fopen(aFilePath, "w");
315
316   if (aFile == NULL)
317   {
318     std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
319     return;
320   }
321   
322   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
323   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
324
325   SALOME_ResourcesCatalog_Handler* handler =
326     new SALOME_ResourcesCatalog_Handler(_resourcesList);
327   handler->PrepareDocToXmlFile(aDoc);
328   delete handler;
329
330   int isOk = xmlSaveFormatFile(aFilePath, aDoc, 1);
331   if (!isOk) 
332      std::cerr << "Error while XML file saving : " << xml_file << std::endl;
333   
334   // Free the document
335   xmlFreeDoc(aDoc);
336   fclose(aFile);
337   RES_MESSAGE("WriteInXmlFile : WRITING DONE!");
338 }
339
340 //=============================================================================
341 /*!
342  *  parse the data type catalog
343  */ 
344 //=============================================================================
345
346 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
347 {
348   // Parse file only if its modification time is greater than lasttime (last registered modification time)
349   bool to_parse = false;
350   for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
351   {
352     struct stat statinfo;
353     int result = stat((*_path_resources_it).c_str(), &statinfo);
354     if (result < 0)
355     {
356       std::cerr << "Error in method stat for file : " << (*_path_resources_it).c_str() << " no new xml file is parsed" << std::endl;
357       return _resourcesList;
358     }
359
360     if(statinfo.st_mtime > _lasttime)
361     {
362       to_parse = true;
363       _lasttime = statinfo.st_mtime;
364     }
365   }
366
367   if (to_parse)
368   {
369     _resourcesList.clear();
370     // On parse tous les fichiers
371     for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
372     {
373       MapOfParserResourcesType _resourcesList_tmp;
374       MapOfParserResourcesType _resourcesBatchList_tmp;
375       SALOME_ResourcesCatalog_Handler* handler =
376         new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp);
377       const char* aFilePath = (*_path_resources_it).c_str();
378       FILE* aFile = fopen(aFilePath, "r");
379
380       if (aFile != NULL)
381       {
382         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
383         if (aDoc != NULL)
384         {
385           handler->ProcessXmlDocument(aDoc);
386
387           // adding new resources to the file
388           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
389           {
390             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
391             if (j == _resourcesList.end())
392             {
393               _resourcesList[i->first] = i->second;
394             }
395             else
396             {
397               std::cerr << "ParseXmlFiles Warning, two resources with the same name were found, taking the first declaration : " << i->first << std::endl;
398             }
399           }
400         }
401         else
402           std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
403         // Free the document
404         xmlFreeDoc(aDoc);
405         fclose(aFile);
406       }
407       else
408         std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
409
410       delete handler;
411     }
412   }
413   return _resourcesList;
414 }
415
416 //=============================================================================
417 /*!
418  *   consult the content of the list
419  */ 
420 //=============================================================================
421
422 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
423 {
424   return _resourcesList;
425 }
426
427 std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources)
428 {
429   if(_resourceManagerMap.count(policy)==0)
430     return _resourceManagerMap[""]->Find(listOfResources, _resourcesList);
431   return _resourceManagerMap[policy]->Find(listOfResources, _resourcesList);
432 }
433
434 //=============================================================================
435 /*!
436  *  Gives a sublist of resources with matching OS.
437  *  If parameter OS is empty, gives the complete list of resources
438  */ 
439 //=============================================================================
440 void 
441 ResourcesManager_cpp::SelectOnlyResourcesWithOS(std::vector<std::string>& resources, std::string OS)
442 {
443   if (OS != "")
444   {
445     // a computer list is given : take only resources with OS on those computers
446     std::vector<std::string> vec_tmp = resources;
447     resources.clear();
448     std::vector<std::string>::iterator iter = vec_tmp.begin();
449     for (; iter != vec_tmp.end(); iter++)
450     {
451       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
452       if(it != _resourcesList.end())
453         if ( (*it).second.OS == OS)
454           resources.push_back(*iter);
455     }
456   }
457 }
458
459
460 //=============================================================================
461 /*!
462  *  Gives a sublist of machines on which the component is known.
463  */ 
464 //=============================================================================
465 void 
466 ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& resources, 
467                                                      const std::vector<std::string>& componentList)
468 {
469   std::vector<std::string> kept_resources;
470
471   std::vector<std::string>::iterator iter = resources.begin();
472   for (; iter != resources.end(); iter++)
473   {
474     const std::vector<std::string>& mapOfComponentsOfCurrentHost = _resourcesList[*iter].ComponentsList;
475
476     bool erasedHost = false;
477     if( mapOfComponentsOfCurrentHost.size() > 0 )
478     {
479       for(unsigned int i=0; i<componentList.size(); i++)
480       {
481         std::vector<std::string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
482                                                             mapOfComponentsOfCurrentHost.end(),
483                                                             componentList[i]);
484         if (itt == mapOfComponentsOfCurrentHost.end())
485         {
486           erasedHost = true;
487           break;
488         }
489       }
490     }
491     if(!erasedHost)
492       kept_resources.push_back(*iter);
493   }
494   resources=kept_resources;
495 }
496
497
498 ParserResourcesType 
499 ResourcesManager_cpp::GetResourcesDescr(const std::string & name)
500 {
501   if (_resourcesList.find(name) != _resourcesList.end())
502     return _resourcesList[name];
503   else
504   {
505     std::string error("[GetResourcesDescr] Resource does not exist: ");
506     error += name;
507     throw ResourcesException(error);
508   }
509 }