Salome HOME
Successful first launch of scheme on cluster.
[modules/yacs.git] / src / evalyfx / YACSEvalResource.cxx
1 // Copyright (C) 2012-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "YACSEvalResource.hxx"
22
23 #include "DeploymentTree.hxx"
24 #include "Container.hxx"
25 #include "Exception.hxx"
26
27 #include "SalomeContainer.hxx"
28 #include "SalomeHPContainer.hxx"
29 #include "ComponentInstance.hxx"
30
31 #include "ResourcesManager.hxx"
32
33 #include <set>
34 #include <queue>
35 #include <sstream>
36 #include <iterator>
37 #include <algorithm>
38
39 const char YACSEvalVirtualYACSContainer::CONTAINER_NAME_KEY[]="container_name";
40
41 const char YACSEvalVirtualYACSContainer::CPU_CLOCK_KEY[]="cpu_clock";
42
43 const char YACSEvalVirtualYACSContainer::HOSTNAME_KEY[]="hostname";
44
45 const char YACSEvalVirtualYACSContainer::MEM_KEY[]="mem_mb";
46
47 const char YACSEvalVirtualYACSContainer::NB_NODE_KEY[]="nb_node";
48
49 const char YACSEvalVirtualYACSContainer::NB_PROC_PER_NODE_KEY[]="nb_proc_per_node";
50
51 const char YACSEvalVirtualYACSContainer::NB_RESOURCE_PROCS_KEY[]="nb_resource_procs";
52
53 const char YACSEvalVirtualYACSContainer::POLICY_KEY[]="policy";
54
55 const char YACSEvalVirtualYACSContainer::OS_KEY[]="OS";
56
57 /*!
58  * This class is here only to avoid "friend class YACSEvalListOfResources".
59  */
60 class YACSEvalResourceEff : public YACSEvalResource
61 {
62 public:
63   YACSEvalResourceEff(YACSEvalListOfResources *gf, const std::vector< YACS::ENGINE::Container * >& conts);
64 };
65
66 YACSEvalResourceEff::YACSEvalResourceEff(YACSEvalListOfResources *gf, const std::vector< YACS::ENGINE::Container * >& conts):YACSEvalResource(gf,conts)
67 {
68 }
69
70 void YACSEvalNonConstLocker::checkNonLocked() const
71 {
72   if(_isLocked)
73     throw YACS::Exception("YACSEvalNonConstLocker::checkNonLocked : this is locked and trying to invoke non-const method !");
74 }
75
76 void YACSEvalNonConstLocker::checkLocked() const
77 {
78   if(!_isLocked)
79     throw YACS::Exception("YACSEvalNonConstLocker::checkLocked : this is NOT locked whereas it should be !");
80 }
81
82 YACSEvalVirtualYACSContainer::YACSEvalVirtualYACSContainer():_gf(0),_cont(0)
83 {
84 }
85
86 void YACSEvalVirtualYACSContainer::set(YACSEvalResource *gf, YACS::ENGINE::Container *cont)
87 {
88   checkNonLocked();
89   _gf=gf;
90   if(_cont==cont)
91     return ;
92   if(_cont)
93     _cont->decrRef();
94   _cont=cont;
95   if(_cont)
96     _cont->incrRef();
97   _propertyMap=listOfPropertiesInYACSContainer();
98 }
99
100 YACSEvalVirtualYACSContainer::YACSEvalVirtualYACSContainer(YACSEvalResource *gf, YACS::ENGINE::Container *cont):_gf(gf),_cont(cont)
101 {
102   if(_cont)
103     _cont->incrRef();
104   _propertyMap=listOfPropertiesInYACSContainer();
105 }
106
107 YACSEvalVirtualYACSContainer::~YACSEvalVirtualYACSContainer()
108 {
109   if(_cont)
110     _cont->decrRef();
111 }
112
113 /*!
114  * \param [in,out] entry - Resource type instance to be updated with \a this.
115  */
116 void YACSEvalVirtualYACSContainer::aggregate(ParserResourcesType& entry) const
117 {
118   if(entry.HostName.empty())
119     entry.HostName=getHostName();
120   entry.DataForSort._memInMB=std::max(entry.DataForSort._memInMB,getMem());
121   entry.DataForSort._nbOfProcPerNode=std::max(entry.DataForSort._nbOfProcPerNode,getNbProcPerNode());
122   entry.DataForSort._nbOfNodes=std::max(entry.DataForSort._nbOfNodes,getNbNodes());
123   entry.DataForSort._CPUFreqMHz=std::max(entry.DataForSort._CPUFreqMHz,getCPUFreq());
124   std::vector<YACS::ENGINE::ComponentInstance *> comps(_gf->getGodFather()->getDeploymentTree()->getComponentsLinkedToContainer(_cont));
125   std::set<std::string> compNames;
126   for(std::vector<YACS::ENGINE::ComponentInstance *>::const_iterator it=comps.begin();it!=comps.end();it++)
127     {
128       YACS::ENGINE::ComponentInstance *elt(*it);
129       if(elt)
130         compNames.insert(elt->getCompoName());
131     }
132   compNames.insert(entry.ComponentsList.begin(),entry.ComponentsList.end());
133   compNames.erase(std::string());
134   std::vector<std::string> compNames2(compNames.begin(),compNames.end());
135   entry.ComponentsList=compNames2;
136 }
137
138 std::string YACSEvalVirtualYACSContainer::findDefault(bool isInteractive) const
139 {
140   std::vector<std::string> possibleHosts(_gf->getAllFittingMachines());
141   for(std::vector<std::string>::const_iterator it=possibleHosts.begin();it!=possibleHosts.end();it++)
142     {
143       if(_gf->getGodFather()->hasRightInteractiveStatus(*it,isInteractive))
144         return *it;
145     }
146   throw YACS::Exception("YACSEvalVirtualYACSContainer::findDefault : impossible to find a right machine with requested interactive status !");
147 }
148
149 void YACSEvalVirtualYACSContainer::setWantedMachine(const std::string& machine)
150 {
151   checkNonLocked();
152   std::vector<std::string> possibleHosts(_gf->getAllFittingMachines());
153   if(std::find(possibleHosts.begin(),possibleHosts.end(),machine)==possibleHosts.end())
154     throw YACS::Exception("YACSEvalVirtualYACSContainer::setWantedMachine : the specified machine is not in the list of available !");
155   std::string oldMachine(getChosenMachine());
156   setMachineNoCheck(machine);
157   try
158   {
159       _gf->notifyWantedMachine(this,oldMachine,machine);
160   }
161   catch(YACS::Exception& e)
162   {
163       setMachineNoCheck(oldMachine);
164       throw e;
165   }
166 }
167
168 std::vector<std::string> YACSEvalVirtualYACSContainer::listOfPropertyKeys() const
169 {
170   std::set<std::string> s;
171   std::map<std::string,std::string>::const_iterator it;
172   for(it=_overloadedPropertyMap.begin();it!=_overloadedPropertyMap.end();it++)
173     s.insert((*it).first);
174   for(it=_propertyMap.begin();it!=_propertyMap.end();it++)
175     s.insert((*it).first);
176   std::vector<std::string> ret(s.begin(),s.end());
177   return ret;
178 }
179
180 std::string YACSEvalVirtualYACSContainer::getValueOfKey(const char *key) const
181 {
182   std::string skey(key);
183   if(skey==HOSTNAME_KEY)
184     return _chosenHost;
185   std::map<std::string,std::string>::const_iterator it;
186   it=_overloadedPropertyMap.find(skey);
187   if(it!=_overloadedPropertyMap.end())
188     return (*it).second;
189   it=_propertyMap.find(skey);
190   if(it!=_propertyMap.end())
191     return (*it).second;
192   return std::string();
193 }
194
195 void YACSEvalVirtualYACSContainer::setProperty(const std::string& key, const std::string &value)
196 {
197   checkNonLocked();
198   if(key==HOSTNAME_KEY)
199     setWantedMachine(value);
200   else
201     _overloadedPropertyMap[key]=value;
202 }
203
204 void YACSEvalVirtualYACSContainer::apply(bool interactiveStatus)
205 {
206   YACS::ENGINE::SalomeContainer *cont0(dynamic_cast<YACS::ENGINE::SalomeContainer *>(_cont));
207   YACS::ENGINE::SalomeHPContainer *cont1(dynamic_cast<YACS::ENGINE::SalomeHPContainer *>(_cont));
208   if(!cont0 && !cont1)
209     throw YACS::Exception("YACSEvalVirtualYACSContainer::apply : unrecognized container !");
210   if(interactiveStatus)
211     _cont->setProperty(HOSTNAME_KEY,getValueOfKey(HOSTNAME_KEY));
212   else
213     {// in cluster mode no hostname and policy set to cycl by default
214       _cont->setProperty(HOSTNAME_KEY,std::string());
215       _cont->setProperty("policy","cycl");
216     }
217 }
218
219 std::string YACSEvalVirtualYACSContainer::getName() const
220 {
221   checkNotNullYACSContainer();
222   return _cont->getName();
223 }
224
225 unsigned int YACSEvalVirtualYACSContainer::getValueOfKeyUInt(const char *key) const
226 {
227   std::string v(getValueOfKey(key));
228   unsigned int ret(0);
229   if(v.empty())
230     return ret;
231   std::istringstream iss(v);
232   iss >> ret;
233   return ret;
234 }
235
236 std::map<std::string,std::string> YACSEvalVirtualYACSContainer::listOfPropertiesInYACSContainer() const
237 {
238   YACS::ENGINE::SalomeContainer *cont0(dynamic_cast<YACS::ENGINE::SalomeContainer *>(_cont));
239   YACS::ENGINE::SalomeHPContainer *cont1(dynamic_cast<YACS::ENGINE::SalomeHPContainer *>(_cont));
240   std::map<std::string,std::string> props;
241   if(cont0)
242     props=cont0->getProperties();
243   else if(cont1)
244     props=cont1->getProperties();
245   return props;
246 }
247
248 void YACSEvalVirtualYACSContainer::checkNotNullYACSContainer() const
249 {
250   if(!_cont)
251     throw YACS::Exception("YACSEvalVirtualYACSContainer::checkNotNullYACSContainer : internal YACS container is NULL !");
252 }
253
254 YACSEvalResource::~YACSEvalResource()
255 {
256 }
257
258 std::vector<std::string> YACSEvalResource::getAllChosenMachines() const
259 {
260   std::set<std::string> s;
261   for(std::vector< YACSEvalVirtualYACSContainer >::const_iterator it=_containers.begin();it!=_containers.end();it++)
262     s.insert((*it).getChosenMachine());
263   std::vector<std::string> ret(s.begin(),s.end());
264   return ret;
265 }
266
267 std::vector<std::string> YACSEvalResource::getAllFittingMachines() const
268 {
269   ParserResourcesType ref;
270   aggregate(ref);
271   return _gf->getFittingResources(&ref);
272 }
273
274 void YACSEvalResource::setWantedMachine(const std::string& machine)
275 {
276   checkNonLocked();
277   std::vector<std::string> possibleHosts(getAllFittingMachines());
278   if(std::find(possibleHosts.begin(),possibleHosts.end(),machine)==possibleHosts.end())
279     throw YACS::Exception("YACSEvalResource::setWantedMachine : the specified machine is not in the list of available !");
280   for(std::vector< YACSEvalVirtualYACSContainer >::iterator it=_containers.begin();it!=_containers.end();it++)
281     (*it).setMachineNoCheck(machine);
282 }
283
284 YACSEvalVirtualYACSContainer *YACSEvalResource::at(std::size_t i) const
285 {
286   if(i>=_containers.size())
287     throw YACS::Exception("YACSEvalResource::at : invalid input ! must be < size !");
288   return const_cast<YACSEvalVirtualYACSContainer *>(&_containers[i]);
289 }
290
291 void YACSEvalResource::apply(bool interactiveStatus)
292 {
293   for(std::vector< YACSEvalVirtualYACSContainer >::iterator it=_containers.begin();it!=_containers.end();it++)
294     (*it).apply(interactiveStatus);
295 }
296
297 void YACSEvalResource::fitWithCurrentCatalogAbs()
298 {
299   std::vector<std::string> ress(getAllFittingMachines());
300   if(ress.empty())
301     throw YACS::Exception("YACSEvalResource::fitWithCurrentCatalogAbs : no suitable host in your catalog of resource !");
302   setMachineNoCheck(ress.front());
303 }
304
305 void YACSEvalResource::aggregate(ParserResourcesType& entry) const
306 {
307   for(std::vector< YACSEvalVirtualYACSContainer >::const_iterator it=_containers.begin();it!=_containers.end();it++)
308     (*it).aggregate(entry);
309 }
310
311 void YACSEvalResource::notifyWantedMachine(YACSEvalVirtualYACSContainer *sender, const std::string& oldMachine, const std::string& newMachine)
312 {
313   _gf->notifyWantedMachine(sender,oldMachine,newMachine);
314 }
315
316 void YACSEvalResource::setMachineNoCheck(const std::string& machine)
317 {
318   for(std::vector< YACSEvalVirtualYACSContainer >::iterator it=_containers.begin();it!=_containers.end();it++)
319     (*it).setMachineNoCheck(machine);
320 }
321
322 YACSEvalResource::YACSEvalResource(YACSEvalListOfResources *gf, const std::vector< YACS::ENGINE::Container * >& conts):_gf(gf)
323 {
324   std::size_t sz(conts.size());
325   _containers.resize(sz);
326   for(std::size_t i=0;i<sz;i++)
327     _containers[i].set(this,conts[i]);
328 }
329
330 void YACSEvalParamsForCluster::setExclusiveness(bool newStatus)
331 {
332   if(newStatus)
333     throw YACS::Exception("YACSEvalParamsForCluster::setExclusiveness : exclusive mode set to true is not implemented yet !");
334 }
335
336 void YACSEvalParamsForCluster::checkConsistency() const
337 {
338   if(_remoteWorkingDir.empty())
339     throw YACS::Exception("YACSEvalParamsForCluster::checkConsistency : remote work dir is not set !");
340   if(_localWorkingDir.empty())
341     throw YACS::Exception("YACSEvalParamsForCluster::checkConsistency : local work dir is not set !");
342   if(_wcKey.empty())
343     throw YACS::Exception("YACSEvalParamsForCluster::checkConsistency : WC key is not set !");
344   if(_nbOfProcs==0)
345     throw YACS::Exception("YACSEvalParamsForCluster::checkConsistency : nb procs must be != 0 !");
346 }
347
348 YACSEvalListOfResources::YACSEvalListOfResources(int maxLevOfPara, ResourcesManager_cpp *rm, const YACS::ENGINE::DeploymentTree& dt):_maxLevOfPara(maxLevOfPara),_rm(rm),_dt(new YACS::ENGINE::DeploymentTree(dt))
349 {
350   std::vector<YACS::ENGINE::Container *> conts(_dt->getAllContainers());
351   std::map<std::string, std::vector<YACS::ENGINE::Container *> > listOfHosts;
352   for(std::vector<YACS::ENGINE::Container *>::const_iterator it=conts.begin();it!=conts.end();it++)
353     {
354       std::vector<YACS::ENGINE::ComponentInstance *> cis(dt.getComponentsLinkedToContainer(*it));
355       YACS::ENGINE::SalomeContainer *c1(dynamic_cast<YACS::ENGINE::SalomeContainer *>(*it));
356       YACS::ENGINE::SalomeHPContainer *c2(dynamic_cast<YACS::ENGINE::SalomeHPContainer *>(*it));
357       std::string zeHost;
358       if(c1)
359         zeHost=c1->getProperty(YACSEvalVirtualYACSContainer::HOSTNAME_KEY);
360       if(c2)
361         zeHost=c2->getProperty(YACSEvalVirtualYACSContainer::HOSTNAME_KEY);
362       listOfHosts[zeHost].push_back(*it);
363     }
364   for(std::map<std::string, std::vector<YACS::ENGINE::Container *> >::const_iterator it=listOfHosts.begin();it!=listOfHosts.end();it++)
365     _resources.push_back(new YACSEvalResourceEff(this,(*it).second));
366   fitWithCurrentCatalog();
367 }
368
369 std::vector<std::string> YACSEvalListOfResources::getAllChosenMachines() const
370 {
371   std::set<std::string> s;
372   for(std::vector<YACSEvalResource *>::const_iterator it=_resources.begin();it!=_resources.end();it++)
373     {
374       std::vector<std::string> tmp((*it)->getAllChosenMachines());
375       s.insert(tmp.begin(),tmp.end());
376     }
377   std::vector<std::string> ret(s.begin(),s.end());
378   return ret;
379 }
380
381 std::vector<std::string> YACSEvalListOfResources::getAllFittingMachines() const
382 {
383   ParserResourcesType ref;
384   for(std::vector<YACSEvalResource *>::const_iterator it=_resources.begin();it!=_resources.end();it++)
385     (*it)->aggregate(ref);
386   return getFittingResources(&ref);
387 }
388
389 void YACSEvalListOfResources::setWantedMachine(const std::string& machine)
390 {
391   checkNonLocked();
392   std::vector<std::string> possibleHosts(getAllFittingMachines());
393   if(std::find(possibleHosts.begin(),possibleHosts.end(),machine)==possibleHosts.end())
394     throw YACS::Exception("YACSEvalResource::setWantedMachine : the specified machine is not in the list of available !");
395   for(std::vector<YACSEvalResource *>::iterator it=_resources.begin();it!=_resources.end();it++)
396     (*it)->setMachineNoCheck(machine);
397 }
398
399 YACSEvalResource *YACSEvalListOfResources::at(std::size_t i) const
400 {
401   if(i>=size())
402     throw YACS::Exception("YACSEvalListOfResources::at : invalid id !");
403   return _resources[i];
404 }
405
406 bool YACSEvalListOfResources::isInteractive() const
407 {
408   const MapOfParserResourcesType& zeList(_rm->GetList());
409   std::vector<std::string> allMachines(getAllChosenMachines());
410   if(allMachines.empty())
411     return true;
412   std::size_t ii(0),sz(allMachines.size());
413   std::vector<bool> status(sz);
414   for(std::vector<std::string>::const_iterator it=allMachines.begin();it!=allMachines.end();it++,ii++)
415     {
416       std::map<std::string, ParserResourcesType>::const_iterator it2(zeList.find(*it));
417       if(it2==zeList.end())
418         {
419           std::ostringstream oss; oss << "YACSEvalListOfResources::isInteractive : presence of non existing \"" << *it << "\" !";
420           throw YACS::Exception(oss.str());
421         }
422       const ParserResourcesType& elt((*it2).second);
423       status[ii]=(elt.Batch==none);
424     }
425   std::size_t trueRet(std::count(status.begin(),status.end(),true)),falseRet(std::count(status.begin(),status.end(),false));
426   if(trueRet==sz && falseRet==0)
427     return true;
428   else if(trueRet==0 && falseRet==sz)
429     return false;
430   throw YACS::Exception("YACSEvalListOfResources::isInteractive : mix of interactive and non interactive ! internal error !");
431 }
432
433 unsigned int YACSEvalListOfResources::getNumberOfProcsDeclared() const
434 {
435   if(isInteractive())
436     {
437       std::vector<std::string> chosen(getAllChosenMachines());
438       unsigned int ret(0);
439       for(std::vector<std::string>::const_iterator it=chosen.begin();it!=chosen.end();it++)
440         ret+=getNumberOfProcOfResource(*it);
441       return ret;
442     }
443   else
444     return _paramsInCaseOfCluster.getNbProcs();
445 }
446
447 void YACSEvalListOfResources::checkOKForRun() const
448 {
449   if(!isInteractive())
450     _paramsInCaseOfCluster.checkConsistency();
451 }
452
453 void YACSEvalListOfResources::apply()
454 {
455   bool interactiveSt(isInteractive());
456   for(std::vector<YACSEvalResource *>::iterator it=_resources.begin();it!=_resources.end();it++)
457     (*it)->apply(interactiveSt);
458 }
459
460 YACSEvalListOfResources::~YACSEvalListOfResources()
461 {
462   delete _dt;
463   for(std::vector<YACSEvalResource *>::iterator it=_resources.begin();it!=_resources.end();it++)
464     delete *it;
465 }
466
467 class EffectiveComparator
468 {
469 public:
470   virtual ~EffectiveComparator() { }
471   virtual EffectiveComparator *copy() const = 0;
472   virtual bool compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const = 0;
473 };
474
475 // comparator for a null request in scheme
476 class BasicComparator : public EffectiveComparator
477 {
478 public:
479   EffectiveComparator *copy() const { return new BasicComparator; }
480   bool compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const;
481 };
482
483 class MemAwareComparator : public EffectiveComparator
484 {
485 public:
486   EffectiveComparator *copy() const { return new MemAwareComparator; }
487   bool compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const;
488 };
489
490 class CompromiseComparator : public EffectiveComparator
491 {
492 public:
493   CompromiseComparator(int memMB, int nbProcs):_memMB(memMB),_nbProcs(nbProcs) { }
494   EffectiveComparator *copy() const { return new CompromiseComparator(_memMB,_nbProcs); }
495   bool compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const;
496 private:
497   int _memMB;
498   int _nbProcs;
499 };
500
501 class CompareRes
502 {
503 public:
504   CompareRes(const ParserResourcesType *request, const MapOfParserResourcesType& zeCatalog);
505   CompareRes(const CompareRes& other);
506   bool operator()(const std::string& res1, const std::string& res2);
507   ~CompareRes() { delete _comp; }
508 private:
509   EffectiveComparator *_comp;
510   const ParserResourcesType *_request;
511   const MapOfParserResourcesType& _zeCatalog;
512 };
513
514 bool BasicComparator::compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const
515 {
516   int nbOfProcs1(elt1._nbOfNodes*elt1._nbOfProcPerNode),nbOfProcs2(elt2._nbOfNodes*elt2._nbOfProcPerNode);
517   return nbOfProcs1<nbOfProcs2;
518 }
519
520 bool MemAwareComparator::compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const
521 {
522   return elt1._memInMB<elt2._memInMB;
523 }
524
525 bool CompromiseComparator::compare(const ResourceDataToSort& elt1, const ResourceDataToSort& elt2) const
526 {
527   double v1a(elt1._memInMB/_memMB),v1b(elt1._nbOfNodes*elt1._nbOfProcPerNode/_nbProcs);
528   double v2a(elt2._memInMB/_memMB),v2b(elt2._nbOfNodes*elt2._nbOfProcPerNode/_nbProcs);
529   return std::min(v1a,v1b)<std::min(v2a,v2b);
530 }
531
532 CompareRes::CompareRes(const ParserResourcesType *request, const MapOfParserResourcesType& zeCatalog):_comp(0),_request(request),_zeCatalog(zeCatalog)
533 {
534   const ResourceDataToSort& tmp(_request->DataForSort);
535   // all request items are set to default -> Basic comparison on procs
536   if(request->DataForSort._nbOfNodes==1 && request->DataForSort._nbOfProcPerNode==1 && request->DataForSort._memInMB==0)
537     _comp=new BasicComparator;
538   // all items are set to default except memory -> Memory aware only
539   else if(request->DataForSort._memInMB!=0 && request->DataForSort._nbOfNodes==1 && request->DataForSort._nbOfProcPerNode==1)
540     _comp=new MemAwareComparator;
541   // memory and procs are set by the user -> do the best possible.
542   else if(request->DataForSort._memInMB!=0 && ( request->DataForSort._nbOfNodes!=1 || request->DataForSort._nbOfProcPerNode!=1 ) )
543     _comp=new CompromiseComparator(request->DataForSort._memInMB,request->DataForSort._nbOfNodes*request->DataForSort._nbOfProcPerNode);
544   else
545     _comp=new BasicComparator;
546 }
547
548 CompareRes::CompareRes(const CompareRes& other):_comp(other._comp->copy()),_request(other._request),_zeCatalog(other._zeCatalog)
549 {
550 }
551
552 bool CompareRes::operator()(const std::string& res1, const std::string& res2)
553 {
554   std::map<std::string, ParserResourcesType>::const_iterator it1(_zeCatalog.find(res1)),it2(_zeCatalog.find(res2));
555   if(it1==_zeCatalog.end() || it2==_zeCatalog.end())
556     throw YACS::Exception("Internal error during comparison !");
557   const ParserResourcesType& elt1((*it1).second);
558   const ParserResourcesType& elt2((*it2).second);
559   return _comp->compare(elt1.DataForSort,elt2.DataForSort);
560 }
561
562 /*!
563  * Implements an another alg than those proposed by default in ResourcesManager_cpp in "ResourcesManager.hxx".
564  */
565 std::vector<std::string> YACSEvalListOfResources::getFittingResources(ParserResourcesType *request) const
566 {
567   int mlop(getMaxLevelOfParallelism());
568   request->DataForSort._memInMB*=mlop;
569   request->DataForSort._nbOfNodes*=mlop;
570   //
571   const MapOfParserResourcesType& zeListInCatalog(_rm->GetList());
572   std::vector<std::string> list0;
573   // first keep those having relevant components
574   const std::vector<std::string>& listExpected(request->ComponentsList);
575   std::set<std::string> listExpected2(listExpected.begin(),listExpected.end());
576   for(std::map<std::string, ParserResourcesType>::const_iterator it=zeListInCatalog.begin();it!=zeListInCatalog.end();it++)
577     {
578       const std::vector<std::string>& compoList((*it).second.ComponentsList);
579       std::set<std::string> s1(compoList.begin(),compoList.end());
580       std::vector<std::string> diff;
581       std::set_difference(listExpected2.begin(),listExpected2.end(),s1.begin(),s1.end(),std::inserter(diff,diff.begin()));
582       if(diff.empty())
583         list0.push_back((*it).first);
584     }
585   // sort list0 regarding request
586   std::sort(list0.begin(),list0.end(),CompareRes(request,zeListInCatalog));
587   // if HostName in request is defined and in list0 put it first.
588   std::string tmp(request->HostName);
589   if(!tmp.empty())
590     {
591       std::vector<std::string>::iterator it1(std::find(list0.begin(),list0.end(),tmp));
592       if(it1!=list0.end())
593         {// HostName in list0 so put it in first place.
594           list0.erase(it1);
595           list0.insert(list0.begin(),tmp);
596         }
597     }
598   return list0;
599 }
600
601 void YACSEvalListOfResources::notifyWantedMachine(YACSEvalVirtualYACSContainer *sender, const std::string& oldMachine, const std::string& newMachine)
602 {
603   const MapOfParserResourcesType& zeList(_rm->GetList());
604   std::map<std::string, ParserResourcesType>::const_iterator itOld(zeList.find(oldMachine)),itNew(zeList.find(newMachine));
605   if(itOld==zeList.end() || itNew==zeList.end())
606     throw YACS::Exception("YACSEvalListOfResources::notifyWantedMachine : internal error !");
607   const ParserResourcesType& oldPRT((*itOld).second);
608   const ParserResourcesType& newPRT((*itNew).second);
609   bool oldISt(oldPRT.Batch==none),newISt(newPRT.Batch==none);//interactive status
610   if(oldISt==newISt)
611     return ;
612   // the batch/interactive mode has changed -> try to change for all.
613   std::queue<std::string> sts;
614   try
615   {
616     if(newISt)
617       {// switching from interactive to batch -> In batch every YACSEvalVirtualYACSContainer instances in this must lie on newMachine.
618         for(std::vector<YACSEvalResource *>::const_iterator it=_resources.begin();it!=_resources.end();it++)
619           {
620             std::vector<std::string> fms((*it)->getAllFittingMachines());
621             std::vector<std::string>::iterator it0(std::find(fms.begin(),fms.end(),newMachine));
622             if(it0==fms.end())
623               {
624                 std::ostringstream oss; oss << "In the context of switch to batch the requested cluster machine \"" << newMachine << "\" is not compatible for following list of containers : " << std::endl;
625                 std::size_t sz((*it)->size());
626                 for(std::size_t i=0;i<sz;i++)
627                   {
628                     YACSEvalVirtualYACSContainer *cont((*it)->at(i));
629                     if(cont)
630                       oss << " \"" << cont->getName() << "\", ";
631                   }
632                 throw YACS::Exception(oss.str());
633               }
634             std::size_t sz((*it)->size());
635             for(std::size_t i=0;i<sz;i++)
636               {
637                 std::size_t sz((*it)->size());
638                 for(std::size_t i=0;i<sz;i++)
639                   {
640                     YACSEvalVirtualYACSContainer *cont((*it)->at(i));
641                     if(cont==sender)
642                       continue;
643                     sts.push(newMachine);
644                   }
645               }
646           }
647       }
648     else
649       {
650         for(std::vector<YACSEvalResource *>::const_iterator it=_resources.begin();it!=_resources.end();it++)
651           {
652             std::size_t sz((*it)->size());
653             for(std::size_t i=0;i<sz;i++)
654               {
655                 YACSEvalVirtualYACSContainer *cont((*it)->at(i));
656                 if(cont==sender)
657                   continue;
658                 sts.push(cont->findDefault(false));
659               }
660           }
661       }
662   }
663   catch(YACS::Exception& e)
664   {
665       std::ostringstream oss; oss << "YACSEvalListOfResources::notifyWantedMachine : switching from interactive/batch must be global ! " << e.what();
666       throw YACS::Exception(oss.str());
667   }
668   for(std::vector<YACSEvalResource *>::const_iterator it=_resources.begin();it!=_resources.end();it++)
669     {
670       std::size_t sz((*it)->size());
671       for(std::size_t i=0;i<sz;i++)
672         {
673           YACSEvalVirtualYACSContainer *cont((*it)->at(i));
674           if(cont==sender)
675             continue;
676           cont->setMachineNoCheck(sts.front());
677           sts.pop();
678         }
679     }
680 }
681
682 bool YACSEvalListOfResources::hasRightInteractiveStatus(const std::string& machineToTest, bool isInteractive) const
683 {
684   const MapOfParserResourcesType& zeList(_rm->GetList());
685   std::map<std::string, ParserResourcesType>::const_iterator it(zeList.find(machineToTest));
686   if(it==zeList.end())
687     throw YACS::Exception("YACSEvalListOfResources::hasRightInteractiveStatus : internal error !");
688   const ParserResourcesType& elt((*it).second);
689   bool myStatus(elt.Batch==none);
690   return myStatus==isInteractive;
691 }
692
693 void YACSEvalListOfResources::fitWithCurrentCatalog()
694 {
695   std::vector<std::string> ress(getAllFittingMachines());
696   if(ress.empty())
697     throw YACS::Exception("YACSEvalListOfResources::fitWithCurrentCatalog : no available resource in your catalog !");
698   for(std::vector<YACSEvalResource *>::iterator it=_resources.begin();it!=_resources.end();it++)
699     (*it)->setMachineNoCheck(ress.front());
700 }
701
702 unsigned int YACSEvalListOfResources::getNumberOfProcOfResource(const std::string& machine) const
703 {
704   const MapOfParserResourcesType& zeList(_rm->GetList());
705   std::map<std::string, ParserResourcesType>::const_iterator it(zeList.find(machine));
706   if(it==zeList.end())
707     throw YACS::Exception("YACSEvalListOfResources::getNumberOfProcOfResource : internal error !");
708   const ParserResourcesType& PRT((*it).second);
709   const ResourceDataToSort& RDT(PRT.DataForSort);
710   unsigned int ret(RDT._nbOfNodes*RDT._nbOfProcPerNode);
711   return ret;
712 }