source: XIOS/trunk/src/node/context.cpp @ 1448

Last change on this file since 1448 was 1358, checked in by rlacroix, 7 years ago

Support reentrant workflows and workflows with temporal integration for fields read from files.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 44.9 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18
19
20namespace xios {
21
22  shared_ptr<CContextGroup> CContext::root;
23
24   /// ////////////////////// Définitions ////////////////////// ///
25
26   CContext::CContext(void)
27      : CObjectTemplate<CContext>(), CContextAttributes()
28      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
29      , idServer_(), client(0), server(0)
30   { /* Ne rien faire de plus */ }
31
32   CContext::CContext(const StdString & id)
33      : CObjectTemplate<CContext>(id), CContextAttributes()
34      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
35      , idServer_(), client(0), server(0)
36   { /* Ne rien faire de plus */ }
37
38   CContext::~CContext(void)
39   {
40     delete client;
41     delete server;
42   }
43
44   //----------------------------------------------------------------
45   //! Get name of context
46   StdString CContext::GetName(void)   { return (StdString("context")); }
47   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
48   ENodeType CContext::GetType(void)   { return (eContext); }
49
50   //----------------------------------------------------------------
51
52   /*!
53   \brief Get context group (context root)
54   \return Context root
55   */
56   CContextGroup* CContext::getRoot(void)
57   {
58      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
59      return root.get();
60   }
61
62   //----------------------------------------------------------------
63
64   /*!
65   \brief Get calendar of a context
66   \return Calendar
67   */
68   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
69   {
70      return (this->calendar);
71   }
72
73   //----------------------------------------------------------------
74
75   /*!
76   \brief Set a context with a calendar
77   \param[in] newCalendar new calendar
78   */
79   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
80   {
81      this->calendar = newCalendar;
82   }
83
84   //----------------------------------------------------------------
85   /*!
86   \brief Parse xml file and write information into context object
87   \param [in] node xmld node corresponding in xml file
88   */
89   void CContext::parse(xml::CXMLNode & node)
90   {
91      CContext::SuperClass::parse(node);
92
93      // PARSING POUR GESTION DES ENFANTS
94      xml::THashAttributes attributes = node.getAttributes();
95
96      if (attributes.end() != attributes.find("src"))
97      {
98         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
99         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
100            ERROR("void CContext::parse(xml::CXMLNode & node)",
101                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
102         if (!ifs.good())
103            ERROR("CContext::parse(xml::CXMLNode & node)",
104                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
105         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
106      }
107
108      if (node.getElementName().compare(CContext::GetName()))
109         DEBUG("Le noeud is wrong defined but will be considered as a context !");
110
111      if (!(node.goToChildElement()))
112      {
113         DEBUG("Le context ne contient pas d'enfant !");
114      }
115      else
116      {
117         do { // Parcours des contextes pour traitement.
118
119            StdString name = node.getElementName();
120            attributes.clear();
121            attributes = node.getAttributes();
122
123            if (attributes.end() != attributes.find("id"))
124            {
125              DEBUG(<< "Definition node has an id,"
126                    << "it will not be taking account !");
127            }
128
129#define DECLARE_NODE(Name_, name_)    \
130   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
131   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
132#define DECLARE_NODE_PAR(Name_, name_)
133#include "node_type.conf"
134
135            DEBUG(<< "The element \'"     << name
136                  << "\' in the context \'" << CContext::getCurrent()->getId()
137                  << "\' is not a definition !");
138
139         } while (node.goToNextElement());
140
141         node.goToParentElement(); // Retour au parent
142      }
143   }
144
145   //----------------------------------------------------------------
146   //! Show tree structure of context
147   void CContext::ShowTree(StdOStream & out)
148   {
149      StdString currentContextId = CContext::getCurrent() -> getId();
150      std::vector<CContext*> def_vector =
151         CContext::getRoot()->getChildList();
152      std::vector<CContext*>::iterator
153         it = def_vector.begin(), end = def_vector.end();
154
155      out << "<? xml version=\"1.0\" ?>" << std::endl;
156      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
157
158      for (; it != end; it++)
159      {
160         CContext* context = *it;
161         CContext::setCurrent(context->getId());
162         out << *context << std::endl;
163      }
164
165      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
166      CContext::setCurrent(currentContextId);
167   }
168
169
170   //----------------------------------------------------------------
171
172   //! Convert context object into string (to print)
173   StdString CContext::toString(void) const
174   {
175      StdOStringStream oss;
176      oss << "<" << CContext::GetName()
177          << " id=\"" << this->getId() << "\" "
178          << SuperClassAttribute::toString() << ">" << std::endl;
179      if (!this->hasChild())
180      {
181         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
182      }
183      else
184      {
185
186#define DECLARE_NODE(Name_, name_)    \
187   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
188   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
189#define DECLARE_NODE_PAR(Name_, name_)
190#include "node_type.conf"
191
192      }
193
194      oss << "</" << CContext::GetName() << " >";
195
196      return (oss.str());
197   }
198
199   //----------------------------------------------------------------
200
201   /*!
202   \brief Find all inheritace among objects in a context.
203   \param [in] apply (true) write attributes of parent into ones of child if they are empty
204                     (false) write attributes of parent into a new container of child
205   \param [in] parent unused
206   */
207   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
208   {
209#define DECLARE_NODE(Name_, name_)    \
210   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
211     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
212#define DECLARE_NODE_PAR(Name_, name_)
213#include "node_type.conf"
214   }
215
216   //----------------------------------------------------------------
217
218   //! Verify if all root definition in the context have child.
219   bool CContext::hasChild(void) const
220   {
221      return (
222#define DECLARE_NODE(Name_, name_)    \
223   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
224#define DECLARE_NODE_PAR(Name_, name_)
225#include "node_type.conf"
226      false);
227}
228
229   //----------------------------------------------------------------
230
231   void CContext::CleanTree(void)
232   {
233#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
234#define DECLARE_NODE_PAR(Name_, name_)
235#include "node_type.conf"
236   }
237   ///---------------------------------------------------------------
238
239   //! Initialize client side
240   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
241   {
242     hasClient=true;
243     client = new CContextClient(this,intraComm, interComm, cxtServer);
244     registryIn=new CRegistry(intraComm);
245     registryIn->setPath(getId()) ;
246     if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
247     registryIn->bcastRegistry() ;
248
249     registryOut=new CRegistry(intraComm) ;
250     registryOut->setPath(getId()) ;
251
252     MPI_Comm intraCommServer, interCommServer;
253     if (cxtServer) // Attached mode
254     {
255       intraCommServer = intraComm;
256       interCommServer = interComm;
257     }
258     else
259     {
260       MPI_Comm_dup(intraComm, &intraCommServer);
261       comms.push_back(intraCommServer);
262       MPI_Comm_dup(interComm, &interCommServer);
263       comms.push_back(interCommServer);
264     }
265     server = new CContextServer(this,intraCommServer,interCommServer);
266   }
267
268   void CContext::setClientServerBuffer()
269   {
270     // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
271     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
272     // Ensure there is at least some room for 20 of such events in the buffers
273     size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
274#define DECLARE_NODE(Name_, name_)    \
275     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
276#define DECLARE_NODE_PAR(Name_, name_)
277#include "node_type.conf"
278#undef DECLARE_NODE
279#undef DECLARE_NODE_PAR
280
281     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
282     std::map<int, StdSize> maxEventSize;
283     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize);
284     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize);
285
286     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
287     for (it = dataBufferSize.begin(); it != ite; ++it)
288       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
289
290     // Apply the buffer size factor and check that we are above the minimum buffer size
291     ite = bufferSize.end();
292     for (it = bufferSize.begin(); it != ite; ++it)
293     {
294       it->second *= CXios::bufferSizeFactor;
295       if (it->second < minBufferSize) it->second = minBufferSize;
296     }
297
298     // Leaders will have to send some control events so ensure there is some room for those in the buffers
299     if (client->isServerLeader())
300     {
301       const std::list<int>& ranks = client->getRanksServerLeader();
302       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
303       {
304         if (!bufferSize.count(*itRank))
305         {
306           bufferSize[*itRank] = minBufferSize;
307           maxEventSize[*itRank] = minEventSize;
308         }
309       }
310     }
311
312     client->setBufferSize(bufferSize, maxEventSize);
313   }
314
315   //! Verify whether a context is initialized
316   bool CContext::isInitialized(void)
317   {
318     return hasClient;
319   }
320
321   //! Initialize server
322   void CContext::initServer(MPI_Comm intraComm,MPI_Comm interComm, CContext* cxtClient /*= 0*/)
323   {
324     hasServer=true;
325     server = new CContextServer(this,intraComm,interComm);
326
327     registryIn=new CRegistry(intraComm);
328     registryIn->setPath(getId()) ;
329     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
330     registryIn->bcastRegistry() ;
331     registryOut=new CRegistry(intraComm) ;
332     registryOut->setPath(getId()) ;
333
334     MPI_Comm intraCommClient, interCommClient;
335     if (cxtClient) // Attached mode
336     {
337       intraCommClient = intraComm;
338       interCommClient = interComm;
339     }
340     else
341     {
342       MPI_Comm_dup(intraComm, &intraCommClient);
343       comms.push_back(intraCommClient);
344       MPI_Comm_dup(interComm, &interCommClient);
345       comms.push_back(interCommClient);
346     }
347     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
348   }
349
350   //! Try to send the buffers and receive possible answers
351   bool CContext::checkBuffersAndListen(void)
352   {
353     client->checkBuffers();
354
355     bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
356     if (hasTmpBufferedEvent)
357       hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
358
359     // Don't process events if there is a temporarily buffered event
360     return server->eventLoop(!hasTmpBufferedEvent);
361   }
362
363   //! Terminate a context
364   void CContext::finalize(void)
365   {
366      if (!finalized)
367      {
368        finalized = true;
369        if (hasClient) sendRegistry() ;
370        client->finalize();
371        while (!server->hasFinished())
372        {
373          server->eventLoop();
374        }
375
376        if (hasServer)
377        {
378          closeAllFile();
379          registryOut->hierarchicalGatherRegistry() ;
380          if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
381        }
382
383        for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
384          MPI_Comm_free(&(*it));
385        comms.clear();
386      }
387   }
388
389   /*!
390   \brief Close all the context defintion and do processing data
391      After everything is well defined on client side, they will be processed and sent to server
392   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
393   all necessary information to server, from which each server can build its own database.
394   Because the role of server is to write out field data on a specific netcdf file,
395   the only information that it needs is the enabled files
396   and the active fields (fields will be written onto active files)
397   */
398   void CContext::closeDefinition(void)
399   {
400     CTimer::get("Context : close definition").resume() ;
401     // There is nothing client need to send to server
402     if (hasClient)
403     {
404       // After xml is parsed, there are some more works with post processing
405       postProcessing();
406     }
407     setClientServerBuffer();
408
409     if (hasClient && !hasServer)
410     {
411      // Send all attributes of current context to server
412      this->sendAllAttributesToServer();
413
414      // Send all attributes of current calendar
415      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
416
417      // We have enough information to send to server
418      // First of all, send all enabled files
419       sendEnabledFiles();
420
421      // Then, send all enabled fields
422       sendEnabledFields();
423
424      // At last, we have all info of domain and axis, then send them
425       sendRefDomainsAxis();
426
427      // After that, send all grid (if any)
428       sendRefGrid();
429    }
430
431    // We have a xml tree on the server side and now, it should be also processed
432    if (hasClient && !hasServer) sendPostProcessing();
433
434    // There are some processings that should be done after all of above. For example: check mask or index
435    if (hasClient)
436    {
437      this->buildFilterGraphOfEnabledFields();
438      buildFilterGraphOfFieldsWithReadAccess();
439      this->solveAllRefOfEnabledFields(true);
440      postProcessFilterGraph();
441    }
442
443    // Now tell server that it can process all messages from client
444    if (hasClient && !hasServer) this->sendCloseDefinition();
445
446    // Nettoyage de l'arborescence
447    if (hasClient && !hasServer) CleanTree(); // Only on client side??
448
449    if (hasClient)
450    {
451      sendCreateFileHeader();
452
453      startPrefetchingOfEnabledReadModeFiles();
454    }
455    CTimer::get("Context : close definition").suspend() ;
456   }
457
458   void CContext::findAllEnabledFields(void)
459   {
460     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
461     (void)this->enabledFiles[i]->getEnabledFields();
462   }
463
464   void CContext::findAllEnabledFieldsInReadModeFiles(void)
465   {
466     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
467     (void)this->enabledReadModeFiles[i]->getEnabledFields();
468   }
469
470   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
471   {
472      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
473        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
474   }
475
476   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
477   {
478     int size = this->enabledFiles.size();
479     for (int i = 0; i < size; ++i)
480     {
481       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
482     }
483
484     for (int i = 0; i < size; ++i)
485     {
486       this->enabledFiles[i]->generateNewTransformationGridDest();
487     }
488   }
489
490   void CContext::solveAllRefOfEnabledFields(bool sendToServer)
491   {
492     int size = this->enabledFiles.size();
493     for (int i = 0; i < size; ++i)
494     {
495       this->enabledFiles[i]->solveAllRefOfEnabledFields(sendToServer);
496     }
497   }
498
499   void CContext::buildFilterGraphOfEnabledFields()
500   {
501     int size = this->enabledFiles.size();
502     for (int i = 0; i < size; ++i)
503     {
504       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
505     }
506   }
507
508   void CContext::postProcessFilterGraph()
509   {
510     int size = enabledFiles.size();
511     for (int i = 0; i < size; ++i)
512     {
513        enabledFiles[i]->postProcessFilterGraph();
514     }
515   }
516
517   void CContext::startPrefetchingOfEnabledReadModeFiles()
518   {
519     int size = enabledReadModeFiles.size();
520     for (int i = 0; i < size; ++i)
521     {
522        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
523     }
524   }
525
526   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
527   {
528     int size = enabledReadModeFiles.size();
529     for (int i = 0; i < size; ++i)
530     {
531        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
532     }
533   }
534
535   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
536   {
537     int size = enabledReadModeFiles.size();
538     for (int i = 0; i < size; ++i)
539     {
540        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
541     }
542   }
543
544  void CContext::findFieldsWithReadAccess(void)
545  {
546    fieldsWithReadAccess.clear();
547    const vector<CField*> allFields = CField::getAll();
548    for (size_t i = 0; i < allFields.size(); ++i)
549    {
550      CField* field = allFields[i];
551
552      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
553        field->read_access = true;
554      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
555        fieldsWithReadAccess.push_back(field);
556    }
557  }
558
559  void CContext::solveAllRefOfFieldsWithReadAccess()
560  {
561    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
562      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
563  }
564
565  void CContext::buildFilterGraphOfFieldsWithReadAccess()
566  {
567    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
568      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
569  }
570
571   void CContext::solveAllInheritance(bool apply)
572   {
573     // Résolution des héritages descendants (càd des héritages de groupes)
574     // pour chacun des contextes.
575      solveDescInheritance(apply);
576
577     // Résolution des héritages par référence au niveau des fichiers.
578      const vector<CFile*> allFiles=CFile::getAll();
579      const vector<CGrid*> allGrids= CGrid::getAll();
580
581     //if (hasClient && !hasServer)
582      if (hasClient)
583      {
584        for (unsigned int i = 0; i < allFiles.size(); i++)
585          allFiles[i]->solveFieldRefInheritance(apply);
586      }
587
588      unsigned int vecSize = allGrids.size();
589      unsigned int i = 0;
590      for (i = 0; i < vecSize; ++i)
591        allGrids[i]->solveDomainAxisRefInheritance(apply);
592
593   }
594
595   void CContext::findEnabledFiles(void)
596   {
597      const std::vector<CFile*> allFiles = CFile::getAll();
598      const CDate& initDate = calendar->getInitDate();
599
600      for (unsigned int i = 0; i < allFiles.size(); i++)
601         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
602         {
603            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
604            {
605              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
606              {
607                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
608                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
609                    <<"\" is less than the time step. File will not be written."<<endl;
610              }
611              else
612               enabledFiles.push_back(allFiles[i]);
613            }
614         }
615         else
616         {
617           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
618           {
619             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
620                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
621                 <<"\" is less than the time step. File will not be written."<<endl;
622           }
623           else
624             enabledFiles.push_back(allFiles[i]); // otherwise true by default
625         }
626
627      if (enabledFiles.size() == 0)
628         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
629               << getId() << "\" !");
630   }
631
632   void CContext::findEnabledReadModeFiles(void)
633   {
634     int size = this->enabledFiles.size();
635     for (int i = 0; i < size; ++i)
636     {
637       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
638        enabledReadModeFiles.push_back(enabledFiles[i]);
639     }
640   }
641
642   void CContext::closeAllFile(void)
643   {
644     std::vector<CFile*>::const_iterator
645            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
646
647     for (; it != end; it++)
648     {
649       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
650       (*it)->close();
651     }
652   }
653
654   /*!
655   \brief Dispatch event received from client
656      Whenever a message is received in buffer of server, it will be processed depending on
657   its event type. A new event type should be added in the switch list to make sure
658   it processed on server side.
659   \param [in] event: Received message
660   */
661   bool CContext::dispatchEvent(CEventServer& event)
662   {
663
664      if (SuperClass::dispatchEvent(event)) return true;
665      else
666      {
667        switch(event.type)
668        {
669           case EVENT_ID_CLOSE_DEFINITION :
670             recvCloseDefinition(event);
671             return true;
672             break;
673           case EVENT_ID_UPDATE_CALENDAR:
674             recvUpdateCalendar(event);
675             return true;
676             break;
677           case EVENT_ID_CREATE_FILE_HEADER :
678             recvCreateFileHeader(event);
679             return true;
680             break;
681           case EVENT_ID_POST_PROCESS:
682             recvPostProcessing(event);
683             return true;
684            case EVENT_ID_SEND_REGISTRY:
685             recvRegistry(event);
686             return true;
687            break;
688
689           default :
690             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
691                    <<"Unknown Event");
692           return false;
693         }
694      }
695   }
696
697   //! Client side: Send a message to server to make it close
698   void CContext::sendCloseDefinition(void)
699   {
700     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
701     if (client->isServerLeader())
702     {
703       CMessage msg;
704       msg<<this->getIdServer();
705       const std::list<int>& ranks = client->getRanksServerLeader();
706       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
707         event.push(*itRank,1,msg);
708       client->sendEvent(event);
709     }
710     else client->sendEvent(event);
711   }
712
713   //! Server side: Receive a message of client announcing a context close
714   void CContext::recvCloseDefinition(CEventServer& event)
715   {
716
717      CBufferIn* buffer=event.subEvents.begin()->buffer;
718      string id;
719      *buffer>>id;
720      get(id)->closeDefinition();
721   }
722
723   //! Client side: Send a message to update calendar in each time step
724   void CContext::sendUpdateCalendar(int step)
725   {
726     if (!hasServer)
727     {
728       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
729       if (client->isServerLeader())
730       {
731         CMessage msg;
732         msg<<this->getIdServer()<<step;
733         const std::list<int>& ranks = client->getRanksServerLeader();
734         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
735           event.push(*itRank,1,msg);
736         client->sendEvent(event);
737       }
738       else client->sendEvent(event);
739     }
740   }
741
742   //! Server side: Receive a message of client annoucing calendar update
743   void CContext::recvUpdateCalendar(CEventServer& event)
744   {
745      CBufferIn* buffer=event.subEvents.begin()->buffer;
746      string id;
747      *buffer>>id;
748      get(id)->recvUpdateCalendar(*buffer);
749   }
750
751   //! Server side: Receive a message of client annoucing calendar update
752   void CContext::recvUpdateCalendar(CBufferIn& buffer)
753   {
754      int step;
755      buffer>>step;
756      updateCalendar(step);
757   }
758
759   //! Client side: Send a message to create header part of netcdf file
760   void CContext::sendCreateFileHeader(void)
761   {
762     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
763     if (client->isServerLeader())
764     {
765       CMessage msg;
766       msg<<this->getIdServer();
767       const std::list<int>& ranks = client->getRanksServerLeader();
768       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
769         event.push(*itRank,1,msg) ;
770       client->sendEvent(event);
771     }
772     else client->sendEvent(event);
773   }
774
775   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
776   void CContext::recvCreateFileHeader(CEventServer& event)
777   {
778      CBufferIn* buffer=event.subEvents.begin()->buffer;
779      string id;
780      *buffer>>id;
781      get(id)->recvCreateFileHeader(*buffer);
782   }
783
784   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
785   void CContext::recvCreateFileHeader(CBufferIn& buffer)
786   {
787      createFileHeader();
788   }
789
790   //! Client side: Send a message to do some post processing on server
791   void CContext::sendPostProcessing()
792   {
793     if (!hasServer)
794     {
795       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
796       if (client->isServerLeader())
797       {
798         CMessage msg;
799         msg<<this->getIdServer();
800         const std::list<int>& ranks = client->getRanksServerLeader();
801         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
802           event.push(*itRank,1,msg);
803         client->sendEvent(event);
804       }
805       else client->sendEvent(event);
806     }
807   }
808
809   //! Server side: Receive a message to do some post processing
810   void CContext::recvPostProcessing(CEventServer& event)
811   {
812      CBufferIn* buffer=event.subEvents.begin()->buffer;
813      string id;
814      *buffer>>id;
815      get(id)->recvPostProcessing(*buffer);
816   }
817
818   //! Server side: Receive a message to do some post processing
819   void CContext::recvPostProcessing(CBufferIn& buffer)
820   {
821      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
822      postProcessing();
823   }
824
825   const StdString& CContext::getIdServer()
826   {
827      if (hasClient)
828      {
829        idServer_ = this->getId();
830        idServer_ += "_server";
831        return idServer_;
832      }
833      if (hasServer) return (this->getId());
834   }
835
836   /*!
837   \brief Do some simple post processings after parsing xml file
838      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
839   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
840   which will be written out into netcdf files, are processed
841   */
842   void CContext::postProcessing()
843   {
844     if (isPostProcessed) return;
845
846      // Make sure the calendar was correctly created
847      if (!calendar)
848        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
849      else if (calendar->getTimeStep() == NoneDu)
850        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
851      // Calendar first update to set the current date equals to the start date
852      calendar->update(0);
853
854      // Find all inheritance in xml structure
855      this->solveAllInheritance();
856
857      // Check if some axis, domains or grids are eligible to for compressed indexed output.
858      // Warning: This must be done after solving the inheritance and before the rest of post-processing
859      checkAxisDomainsGridsEligibilityForCompressedOutput();
860
861      // Check if some automatic time series should be generated
862      // Warning: This must be done after solving the inheritance and before the rest of post-processing
863      prepareTimeseries();
864
865      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
866      this->findEnabledFiles();
867      this->findEnabledReadModeFiles();
868
869      // Find all enabled fields of each file
870      this->findAllEnabledFields();
871      this->findAllEnabledFieldsInReadModeFiles();
872
873     if (hasClient && !hasServer)
874     {
875      // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
876      this->readAttributesOfEnabledFieldsInReadModeFiles();
877     }
878
879      // Only search and rebuild all reference objects of enable fields, don't transform
880      this->solveOnlyRefOfEnabledFields(false);
881
882      // Search and rebuild all reference object of enabled fields
883      this->solveAllRefOfEnabledFields(false);
884
885      // Find all fields with read access from the public API
886      findFieldsWithReadAccess();
887      // and solve the all reference for them
888      solveAllRefOfFieldsWithReadAccess();
889
890      isPostProcessed = true;
891   }
892
893   /*!
894    * Compute the required buffer size to send the attributes (mostly those grid related).
895    *
896    * \param maxEventSize [in/out] the size of the bigger event for each connected server
897    */
898   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize)
899   {
900     std::map<int, StdSize> attributesSize;
901
902     if (hasClient)
903     {
904       size_t numEnabledFiles = this->enabledFiles.size();
905       for (size_t i = 0; i < numEnabledFiles; ++i)
906       {
907         CFile* file = this->enabledFiles[i];
908
909         std::vector<CField*> enabledFields = file->getEnabledFields();
910         size_t numEnabledFields = enabledFields.size();
911         for (size_t j = 0; j < numEnabledFields; ++j)
912         {
913           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
914           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
915           for (; it != itE; ++it)
916           {
917             // If attributesSize[it->first] does not exist, it will be zero-initialized
918             // so we can use it safely without checking for its existance
919             if (attributesSize[it->first] < it->second)
920               attributesSize[it->first] = it->second;
921
922             if (maxEventSize[it->first] < it->second)
923               maxEventSize[it->first] = it->second;
924           }
925         }
926       }
927     }
928
929     return attributesSize;
930   }
931
932   /*!
933    * Compute the required buffer size to send the fields data.
934    *
935    * \param maxEventSize [in/out] the size of the bigger event for each connected server
936    */
937   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize)
938   {
939     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
940
941     std::map<int, StdSize> dataSize;
942
943     // Find all reference domain and axis of all active fields
944     size_t numEnabledFiles = this->enabledFiles.size();
945     for (size_t i = 0; i < numEnabledFiles; ++i)
946     {
947       CFile* file = this->enabledFiles[i];
948       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
949
950       if (fileMode == mode)
951       {
952         std::vector<CField*> enabledFields = file->getEnabledFields();
953         size_t numEnabledFields = enabledFields.size();
954         for (size_t j = 0; j < numEnabledFields; ++j)
955         {
956           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize();
957           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
958           for (; it != itE; ++it)
959           {
960             // If dataSize[it->first] does not exist, it will be zero-initialized
961             // so we can use it safely without checking for its existance
962             if (CXios::isOptPerformance)
963               dataSize[it->first] += it->second;
964             else if (dataSize[it->first] < it->second)
965               dataSize[it->first] = it->second;
966
967             if (maxEventSize[it->first] < it->second)
968               maxEventSize[it->first] = it->second;
969           }
970         }
971       }
972     }
973
974     return dataSize;
975   }
976
977   //! Client side: Send infomation of active files (files are enabled to write out)
978   void CContext::sendEnabledFiles()
979   {
980     int size = this->enabledFiles.size();
981
982     // In a context, each type has a root definition, e.g: axis, domain, field.
983     // Every object must be a child of one of these root definition. In this case
984     // all new file objects created on server must be children of the root "file_definition"
985     StdString fileDefRoot("file_definition");
986     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
987
988     for (int i = 0; i < size; ++i)
989     {
990       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId());
991       this->enabledFiles[i]->sendAllAttributesToServer();
992       this->enabledFiles[i]->sendAddAllVariables();
993     }
994   }
995
996   //! Client side: Send information of active fields (ones are written onto files)
997   void CContext::sendEnabledFields()
998   {
999     int size = this->enabledFiles.size();
1000     for (int i = 0; i < size; ++i)
1001     {
1002       this->enabledFiles[i]->sendEnabledFields();
1003     }
1004   }
1005
1006   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1007   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1008   {
1009     if (!hasClient) return;
1010
1011     const vector<CAxis*> allAxis = CAxis::getAll();
1012     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1013       (*it)->checkEligibilityForCompressedOutput();
1014
1015     const vector<CDomain*> allDomains = CDomain::getAll();
1016     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1017       (*it)->checkEligibilityForCompressedOutput();
1018
1019     const vector<CGrid*> allGrids = CGrid::getAll();
1020     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1021       (*it)->checkEligibilityForCompressedOutput();
1022   }
1023
1024   //! Client side: Prepare the timeseries by adding the necessary files
1025   void CContext::prepareTimeseries()
1026   {
1027     if (!hasClient) return;
1028
1029     const std::vector<CFile*> allFiles = CFile::getAll();
1030     for (size_t i = 0; i < allFiles.size(); i++)
1031     {
1032       CFile* file = allFiles[i];
1033
1034       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1035       for (size_t k = 0; k < vars.size(); k++)
1036       {
1037         CVariable* var = vars[k];
1038
1039         if (var->ts_target.isEmpty()
1040              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1041           fileVars.push_back(var);
1042
1043         if (!var->ts_target.isEmpty()
1044              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1045           fieldVars.push_back(var);
1046       }
1047
1048       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1049       {
1050         StdString fileNameStr("%file_name%") ;
1051         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1052         
1053         StdString fileName=file->getFileOutputName();
1054         size_t pos=tsPrefix.find(fileNameStr) ;
1055         while (pos!=std::string::npos)
1056         {
1057           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1058           pos=tsPrefix.find(fileNameStr) ;
1059         }
1060       
1061         const std::vector<CField*> allFields = file->getAllFields();
1062         for (size_t j = 0; j < allFields.size(); j++)
1063         {
1064           CField* field = allFields[j];
1065
1066           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1067           {
1068             CFile* tsFile = CFile::create();
1069             tsFile->duplicateAttributes(file);
1070
1071             // Add variables originating from file and targeted to timeserie file
1072             for (size_t k = 0; k < fileVars.size(); k++)
1073               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1074
1075           
1076             tsFile->name = tsPrefix + "_";
1077             if (!field->name.isEmpty())
1078               tsFile->name.get() += field->name;
1079             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1080               tsFile->name.get() += field->field_ref;
1081             else
1082               tsFile->name.get() += field->getId();
1083
1084             if (!field->ts_split_freq.isEmpty())
1085               tsFile->split_freq = field->ts_split_freq;
1086
1087             CField* tsField = tsFile->addField();
1088             tsField->field_ref = field->getId();
1089
1090             // Add variables originating from file and targeted to timeserie field
1091             for (size_t k = 0; k < fieldVars.size(); k++)
1092               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1093
1094             vars = field->getAllVariables();
1095             for (size_t k = 0; k < vars.size(); k++)
1096             {
1097               CVariable* var = vars[k];
1098
1099               // Add variables originating from field and targeted to timeserie field
1100               if (var->ts_target.isEmpty()
1101                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1102                 tsField->getVirtualVariableGroup()->addChild(var);
1103
1104               // Add variables originating from field and targeted to timeserie file
1105               if (!var->ts_target.isEmpty()
1106                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1107                 tsFile->getVirtualVariableGroup()->addChild(var);
1108             }
1109
1110             tsFile->solveFieldRefInheritance(true);
1111
1112             if (file->timeseries == CFile::timeseries_attr::exclusive)
1113               field->enabled = false;
1114           }
1115         }
1116
1117         // Finally disable the original file is need be
1118         if (file->timeseries == CFile::timeseries_attr::only)
1119          file->enabled = false;
1120       }
1121     }
1122   }
1123
1124   //! Client side: Send information of reference grid of active fields
1125   void CContext::sendRefGrid()
1126   {
1127     std::set<StdString> gridIds;
1128     int sizeFile = this->enabledFiles.size();
1129     CFile* filePtr(NULL);
1130
1131     // Firstly, find all reference grids of all active fields
1132     for (int i = 0; i < sizeFile; ++i)
1133     {
1134       filePtr = this->enabledFiles[i];
1135       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1136       int sizeField = enabledFields.size();
1137       for (int numField = 0; numField < sizeField; ++numField)
1138       {
1139         if (0 != enabledFields[numField]->getRelGrid())
1140           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1141       }
1142     }
1143
1144     // Create all reference grids on server side
1145     StdString gridDefRoot("grid_definition");
1146     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1147     std::set<StdString>::const_iterator it, itE = gridIds.end();
1148     for (it = gridIds.begin(); it != itE; ++it)
1149     {
1150       gridPtr->sendCreateChild(*it);
1151       CGrid::get(*it)->sendAllAttributesToServer();
1152       CGrid::get(*it)->sendAllDomains();
1153       CGrid::get(*it)->sendAllAxis();
1154       CGrid::get(*it)->sendAllScalars();
1155     }
1156   }
1157
1158
1159   //! Client side: Send information of reference domain and axis of active fields
1160   void CContext::sendRefDomainsAxis()
1161   {
1162     std::set<StdString> domainIds, axisIds, scalarIds;
1163
1164     // Find all reference domain and axis of all active fields
1165     int numEnabledFiles = this->enabledFiles.size();
1166     for (int i = 0; i < numEnabledFiles; ++i)
1167     {
1168       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1169       int numEnabledFields = enabledFields.size();
1170       for (int j = 0; j < numEnabledFields; ++j)
1171       {
1172         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1173         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1174         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1175         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1176       }
1177     }
1178
1179     // Create all reference axis on server side
1180     std::set<StdString>::iterator itDom, itAxis, itScalar;
1181     std::set<StdString>::const_iterator itE;
1182
1183     StdString scalarDefRoot("scalar_definition");
1184     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1185     itE = scalarIds.end();
1186     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1187     {
1188       if (!itScalar->empty())
1189       {
1190         scalarPtr->sendCreateChild(*itScalar);
1191         CScalar::get(*itScalar)->sendAllAttributesToServer();
1192       }
1193     }
1194
1195     StdString axiDefRoot("axis_definition");
1196     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1197     itE = axisIds.end();
1198     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1199     {
1200       if (!itAxis->empty())
1201       {
1202         axisPtr->sendCreateChild(*itAxis);
1203         CAxis::get(*itAxis)->sendAllAttributesToServer();
1204       }
1205     }
1206
1207     // Create all reference domains on server side
1208     StdString domDefRoot("domain_definition");
1209     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1210     itE = domainIds.end();
1211     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1212     {
1213       if (!itDom->empty()) {
1214          domPtr->sendCreateChild(*itDom);
1215          CDomain::get(*itDom)->sendAllAttributesToServer();
1216       }
1217     }
1218   }
1219
1220   //! Update calendar in each time step
1221   void CContext::updateCalendar(int step)
1222   {
1223      int prevStep = calendar->getStep();
1224
1225      if (prevStep < step)
1226      {
1227        if (hasClient)
1228        {
1229          doPreTimestepOperationsForEnabledReadModeFiles();
1230        }
1231
1232        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1233        calendar->update(step);
1234        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1235  #ifdef XIOS_MEMTRACK_LIGHT
1236        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1237  #endif
1238
1239        if (hasClient)
1240        {
1241          doPostTimestepOperationsForEnabledReadModeFiles();
1242          garbageCollector.invalidate(calendar->getCurrentDate());
1243        }
1244      }
1245      else if (prevStep == step)
1246        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
1247      else // if (prevStep > step)
1248        ERROR("void CContext::updateCalendar(int step)",
1249              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
1250   }
1251
1252   //! Server side: Create header of netcdf file
1253   void CContext::createFileHeader(void )
1254   {
1255      vector<CFile*>::const_iterator it;
1256
1257      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1258      {
1259         (*it)->initFile();
1260      }
1261   }
1262
1263   //! Get current context
1264   CContext* CContext::getCurrent(void)
1265   {
1266     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1267   }
1268
1269   /*!
1270   \brief Set context with an id be the current context
1271   \param [in] id identity of context to be set to current
1272   */
1273   void CContext::setCurrent(const string& id)
1274   {
1275     CObjectFactory::SetCurrentContextId(id);
1276     CGroupFactory::SetCurrentContextId(id);
1277   }
1278
1279  /*!
1280  \brief Create a context with specific id
1281  \param [in] id identity of new context
1282  \return pointer to the new context or already-existed one with identity id
1283  */
1284  CContext* CContext::create(const StdString& id)
1285  {
1286    CContext::setCurrent(id);
1287
1288    bool hasctxt = CContext::has(id);
1289    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1290    getRoot();
1291    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1292
1293#define DECLARE_NODE(Name_, name_) \
1294    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1295#define DECLARE_NODE_PAR(Name_, name_)
1296#include "node_type.conf"
1297
1298    return (context);
1299  }
1300
1301
1302
1303     //! Server side: Receive a message to do some post processing
1304  void CContext::recvRegistry(CEventServer& event)
1305  {
1306    CBufferIn* buffer=event.subEvents.begin()->buffer;
1307    string id;
1308    *buffer>>id;
1309    get(id)->recvRegistry(*buffer);
1310  }
1311
1312  void CContext::recvRegistry(CBufferIn& buffer)
1313  {
1314    if (server->intraCommRank==0)
1315    {
1316      CRegistry registry(server->intraComm) ;
1317      registry.fromBuffer(buffer) ;
1318      registryOut->mergeRegistry(registry) ;
1319    }
1320  }
1321
1322  void CContext::sendRegistry(void)
1323  {
1324    registryOut->hierarchicalGatherRegistry() ;
1325
1326    CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1327    if (client->isServerLeader())
1328    {
1329       CMessage msg ;
1330       msg<<this->getIdServer();
1331       if (client->clientRank==0) msg<<*registryOut ;
1332       const std::list<int>& ranks = client->getRanksServerLeader();
1333       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1334         event.push(*itRank,1,msg);
1335       client->sendEvent(event);
1336     }
1337     else client->sendEvent(event);
1338  }
1339
1340} // namespace xios
Note: See TracBrowser for help on using the repository browser.