source: XIOS/dev/XIOS_DEV_CMIP6/src/node/context.cpp @ 1378

Last change on this file since 1378 was 1378, checked in by ymipsl, 5 years ago

Attemping to solve a dead-lock rising at finalize :
Server 1 must be able receive buffer of on other context (ie from server2) when awaiting free buffer.
To be tested extensively...

YM


  • 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: 69.5 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#include <limits>
19#include <fstream>
20#include "server.hpp"
21#include "distribute_file_server2.hpp"
22
23namespace xios {
24
25  shared_ptr<CContextGroup> CContext::root;
26
27   /// ////////////////////// Définitions ////////////////////// ///
28
29   CContext::CContext(void)
30      : CObjectTemplate<CContext>(), CContextAttributes()
31      , calendar(), hasClient(false), hasServer(false)
32      , isPostProcessed(false), finalized(false)
33      , idServer_(), client(0), server(0)
34      , allProcessed(false), countChildCtx_(0)
35   { /* Ne rien faire de plus */ }
36
37   CContext::CContext(const StdString & id)
38      : CObjectTemplate<CContext>(id), CContextAttributes()
39      , calendar(), hasClient(false), hasServer(false)
40      , isPostProcessed(false), finalized(false)
41      , idServer_(), client(0), server(0)
42      , allProcessed(false), countChildCtx_(0)
43   { /* Ne rien faire de plus */ }
44
45   CContext::~CContext(void)
46   {
47     delete client;
48     delete server;
49     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
50     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
51
52   }
53
54   //----------------------------------------------------------------
55   //! Get name of context
56   StdString CContext::GetName(void)   { return (StdString("context")); }
57   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
58   ENodeType CContext::GetType(void)   { return (eContext); }
59
60   //----------------------------------------------------------------
61
62   /*!
63   \brief Get context group (context root)
64   \return Context root
65   */
66   CContextGroup* CContext::getRoot(void)
67   {
68      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
69      return root.get();
70   }
71
72   //----------------------------------------------------------------
73
74   /*!
75   \brief Get calendar of a context
76   \return Calendar
77   */
78   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
79   {
80      return (this->calendar);
81   }
82
83   //----------------------------------------------------------------
84
85   /*!
86   \brief Set a context with a calendar
87   \param[in] newCalendar new calendar
88   */
89   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
90   {
91      this->calendar = newCalendar;
92   }
93
94   //----------------------------------------------------------------
95   /*!
96   \brief Parse xml file and write information into context object
97   \param [in] node xmld node corresponding in xml file
98   */
99   void CContext::parse(xml::CXMLNode & node)
100   {
101      CContext::SuperClass::parse(node);
102
103      // PARSING POUR GESTION DES ENFANTS
104      xml::THashAttributes attributes = node.getAttributes();
105
106      if (attributes.end() != attributes.find("src"))
107      {
108         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
109         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
110            ERROR("void CContext::parse(xml::CXMLNode & node)",
111                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
112         if (!ifs.good())
113            ERROR("CContext::parse(xml::CXMLNode & node)",
114                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
115         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
116      }
117
118      if (node.getElementName().compare(CContext::GetName()))
119         DEBUG("Le noeud is wrong defined but will be considered as a context !");
120
121      if (!(node.goToChildElement()))
122      {
123         DEBUG("Le context ne contient pas d'enfant !");
124      }
125      else
126      {
127         do { // Parcours des contextes pour traitement.
128
129            StdString name = node.getElementName();
130            attributes.clear();
131            attributes = node.getAttributes();
132
133            if (attributes.end() != attributes.find("id"))
134            {
135              DEBUG(<< "Definition node has an id,"
136                    << "it will not be taking account !");
137            }
138
139#define DECLARE_NODE(Name_, name_)    \
140   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
141   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
142#define DECLARE_NODE_PAR(Name_, name_)
143#include "node_type.conf"
144
145            DEBUG(<< "The element \'"     << name
146                  << "\' in the context \'" << CContext::getCurrent()->getId()
147                  << "\' is not a definition !");
148
149         } while (node.goToNextElement());
150
151         node.goToParentElement(); // Retour au parent
152      }
153   }
154
155   //----------------------------------------------------------------
156   //! Show tree structure of context
157   void CContext::ShowTree(StdOStream & out)
158   {
159      StdString currentContextId = CContext::getCurrent() -> getId();
160      std::vector<CContext*> def_vector =
161         CContext::getRoot()->getChildList();
162      std::vector<CContext*>::iterator
163         it = def_vector.begin(), end = def_vector.end();
164
165      out << "<? xml version=\"1.0\" ?>" << std::endl;
166      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
167
168      for (; it != end; it++)
169      {
170         CContext* context = *it;
171         CContext::setCurrent(context->getId());
172         out << *context << std::endl;
173      }
174
175      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
176      CContext::setCurrent(currentContextId);
177   }
178
179
180   //----------------------------------------------------------------
181
182   //! Convert context object into string (to print)
183   StdString CContext::toString(void) const
184   {
185      StdOStringStream oss;
186      oss << "<" << CContext::GetName()
187          << " id=\"" << this->getId() << "\" "
188          << SuperClassAttribute::toString() << ">" << std::endl;
189      if (!this->hasChild())
190      {
191         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
192      }
193      else
194      {
195
196#define DECLARE_NODE(Name_, name_)    \
197   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
198   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
199#define DECLARE_NODE_PAR(Name_, name_)
200#include "node_type.conf"
201
202      }
203
204      oss << "</" << CContext::GetName() << " >";
205
206      return (oss.str());
207   }
208
209   //----------------------------------------------------------------
210
211   /*!
212   \brief Find all inheritace among objects in a context.
213   \param [in] apply (true) write attributes of parent into ones of child if they are empty
214                     (false) write attributes of parent into a new container of child
215   \param [in] parent unused
216   */
217   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
218   {
219#define DECLARE_NODE(Name_, name_)    \
220   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
221     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
222#define DECLARE_NODE_PAR(Name_, name_)
223#include "node_type.conf"
224   }
225
226   //----------------------------------------------------------------
227
228   //! Verify if all root definition in the context have child.
229   bool CContext::hasChild(void) const
230   {
231      return (
232#define DECLARE_NODE(Name_, name_)    \
233   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
234#define DECLARE_NODE_PAR(Name_, name_)
235#include "node_type.conf"
236      false);
237}
238
239   //----------------------------------------------------------------
240
241   void CContext::CleanTree(void)
242   {
243#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
244#define DECLARE_NODE_PAR(Name_, name_)
245#include "node_type.conf"
246   }
247   ///---------------------------------------------------------------
248
249   //! Initialize client side
250   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
251   {
252
253     hasClient = true;
254     MPI_Comm intraCommServer, interCommServer;
255     
256
257     if (CServer::serverLevel != 1)
258      // initClient is called by client
259     {
260       client = new CContextClient(this, intraComm, interComm, cxtServer);
261       if (cxtServer) // Attached mode
262       {
263         intraCommServer = intraComm;
264         interCommServer = interComm;
265       }
266       else
267       {
268         MPI_Comm_dup(intraComm, &intraCommServer);
269         comms.push_back(intraCommServer);
270         MPI_Comm_dup(interComm, &interCommServer);
271         comms.push_back(interCommServer);
272       }
273/* for registry take the id of client context */
274/* for servers, supress the _server_ from id  */
275       string contextRegistryId=getId() ;
276       size_t pos=contextRegistryId.find("_server_") ;
277       if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
278
279       registryIn=new CRegistry(intraComm);
280       registryIn->setPath(contextRegistryId) ;
281       if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
282       registryIn->bcastRegistry() ;
283       registryOut=new CRegistry(intraComm) ;
284       
285       registryOut->setPath(contextRegistryId) ;
286
287       server = new CContextServer(this, intraCommServer, interCommServer);
288     }
289     else
290     // initClient is called by primary server
291     {
292       clientPrimServer.push_back(new CContextClient(this, intraComm, interComm));
293       MPI_Comm_dup(intraComm, &intraCommServer);
294       comms.push_back(intraCommServer);
295       MPI_Comm_dup(interComm, &interCommServer);
296       comms.push_back(interCommServer);
297       serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer));
298     }
299   }
300
301   /*!
302    Sets client buffers.
303    \param [in] contextClient
304    \param [in] bufferForWriting True if buffers are used for sending data for writing
305    This flag is only true for client and server-1 for communication with server-2
306  */
307   void CContext::setClientServerBuffer(CContextClient* contextClient, bool bufferForWriting)
308   {
309      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
310     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
311
312      // Ensure there is at least some room for 20 of such events in the buffers
313      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
314
315#define DECLARE_NODE(Name_, name_)    \
316     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
317#define DECLARE_NODE_PAR(Name_, name_)
318#include "node_type.conf"
319#undef DECLARE_NODE
320#undef DECLARE_NODE_PAR
321
322     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
323     std::map<int, StdSize> maxEventSize;
324     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient, bufferForWriting);
325     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient, bufferForWriting);
326
327     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
328     for (it = dataBufferSize.begin(); it != ite; ++it)
329       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
330
331     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
332     ite = bufferSize.end();
333     for (it = bufferSize.begin(); it != ite; ++it)
334     {
335       it->second *= CXios::bufferSizeFactor;
336       if (it->second < minBufferSize) it->second = minBufferSize;
337       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
338     }
339
340     // Leaders will have to send some control events so ensure there is some room for those in the buffers
341     if (contextClient->isServerLeader())
342     {
343       const std::list<int>& ranks = contextClient->getRanksServerLeader();
344       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
345       {
346         if (!bufferSize.count(*itRank))
347         {
348           bufferSize[*itRank] = minBufferSize;
349           maxEventSize[*itRank] = minEventSize;
350         }
351       }
352     }
353     contextClient->setBufferSize(bufferSize, maxEventSize);
354
355   }
356
357   //! Verify whether a context is initialized
358   bool CContext::isInitialized(void)
359   {
360     return hasClient;
361   }
362
363   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
364   {
365     hasServer=true;
366     server = new CContextServer(this,intraComm,interComm);
367
368/* for registry take the id of client context */
369/* for servers, supress the _server_ from id  */
370     string contextRegistryId=getId() ;
371     size_t pos=contextRegistryId.find("_server_") ;
372     if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
373       
374     registryIn=new CRegistry(intraComm);
375     registryIn->setPath(contextRegistryId) ;
376     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
377     registryIn->bcastRegistry() ;
378     registryOut=new CRegistry(intraComm) ;
379     registryOut->setPath(contextRegistryId) ;
380
381     MPI_Comm intraCommClient, interCommClient;
382     if (cxtClient) // Attached mode
383     {
384       intraCommClient = intraComm;
385       interCommClient = interComm;
386     }
387     else
388     {
389       MPI_Comm_dup(intraComm, &intraCommClient);
390       comms.push_back(intraCommClient);
391       MPI_Comm_dup(interComm, &interCommClient);
392       comms.push_back(interCommClient);
393     }
394     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
395   }
396
397   //! Try to send the buffers and receive possible answers
398  bool CContext::checkBuffersAndListen(bool enableEventsProcessing /*= true*/)
399  {
400    bool clientReady, serverFinished;
401
402    // Only classical servers are non-blocking
403    if (CServer::serverLevel == 0)
404    {
405      client->checkBuffers();
406      bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
407      if (hasTmpBufferedEvent)
408        hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
409      // Don't process events if there is a temporarily buffered event
410      return server->eventLoop(!hasTmpBufferedEvent || !enableEventsProcessing);
411    }
412    else if (CServer::serverLevel == 1)
413    {
414      if (!finalized)
415        client->checkBuffers();
416      bool serverFinished = true;
417      if (!finalized)
418        serverFinished = server->eventLoop();
419      bool serverPrimFinished = true;
420      for (int i = 0; i < clientPrimServer.size(); ++i)
421      {
422        if (!finalized)
423          clientPrimServer[i]->checkBuffers();
424        if (!finalized)
425          serverPrimFinished *= serverPrimServer[i]->eventLoop(enableEventsProcessing);
426      }
427      return ( serverFinished && serverPrimFinished);
428    }
429
430    else if (CServer::serverLevel == 2)
431    {
432      client->checkBuffers();
433      return server->eventLoop(enableEventsProcessing);
434    }
435  }
436
437   //! Terminate a context
438   void CContext::finalize(void)
439   {
440     // Send registry upon calling the function the first time
441     if (countChildCtx_ == 0)
442       if (hasClient) sendRegistry() ;
443
444     // Client:
445     // (1) blocking send context finalize to its server
446     // (2) blocking receive context finalize from its server
447     // (3) some memory deallocations
448     if (CXios::isClient)
449     {
450       // Make sure that client (model) enters the loop only once
451       if (countChildCtx_ < 1)
452       {
453         ++countChildCtx_;
454
455         client->finalize();
456         while (client->havePendingRequests())
457            client->checkBuffers();
458
459         while (!server->hasFinished())
460           server->eventLoop();
461
462         if (hasServer) // Mode attache
463         {
464           closeAllFile();
465           registryOut->hierarchicalGatherRegistry() ;
466           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
467         }
468
469         //! Deallocate client buffers
470         client->releaseBuffers();
471
472         //! Free internally allocated communicators
473         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
474           MPI_Comm_free(&(*it));
475         comms.clear();
476
477         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
478       }
479     }
480     else if (CXios::isServer)
481     {
482       // First context finalize message received from a model
483       // Send context finalize to its child contexts (if any)
484       if (countChildCtx_ == 0)
485         for (int i = 0; i < clientPrimServer.size(); ++i)
486           clientPrimServer[i]->finalize();
487
488       // (Last) context finalized message received
489       if (countChildCtx_ == clientPrimServer.size())
490       {
491         // Blocking send of context finalize message to its client (e.g. primary server or model)
492         info(100)<<"DEBUG: context "<<getId()<<" Send client finalize<<"<<endl ;
493         client->finalize();
494         bool bufferReleased;
495         do
496         {
497           client->checkBuffers();
498           bufferReleased = !client->havePendingRequests();
499         } while (!bufferReleased);
500         finalized = true;
501
502         closeAllFile(); // Just move to here to make sure that server-level 1 can close files
503         if (hasServer && !hasClient)
504         {           
505           registryOut->hierarchicalGatherRegistry() ;
506           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
507         }
508
509         //! Deallocate client buffers
510         client->releaseBuffers();
511         for (int i = 0; i < clientPrimServer.size(); ++i)
512           clientPrimServer[i]->releaseBuffers();
513
514         //! Free internally allocated communicators
515         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
516           MPI_Comm_free(&(*it));
517         comms.clear();
518
519         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
520       }
521
522       ++countChildCtx_;
523     }
524   }
525
526   //! Free internally allocated communicators
527   void CContext::freeComms(void)
528   {
529     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
530       MPI_Comm_free(&(*it));
531     comms.clear();
532   }
533
534   //! Deallocate buffers allocated by clientContexts
535   void CContext::releaseClientBuffers(void)
536   {
537     client->releaseBuffers();
538     for (int i = 0; i < clientPrimServer.size(); ++i)
539       clientPrimServer[i]->releaseBuffers();
540   }
541
542   void CContext::postProcessingGlobalAttributes()
543   {
544     if (allProcessed) return; 
545     
546     // After xml is parsed, there are some more works with post processing
547     postProcessing();
548
549     // Check grid and calculate its distribution
550     checkGridEnabledFields();
551 
552     // Distribute files between secondary servers according to the data size
553     distributeFiles();
554
555     setClientServerBuffer(client, (hasClient && !hasServer));
556     for (int i = 0; i < clientPrimServer.size(); ++i)
557         setClientServerBuffer(clientPrimServer[i], true);
558
559     if (hasClient)
560     {
561      // Send all attributes of current context to server
562      this->sendAllAttributesToServer();
563
564      // Send all attributes of current calendar
565      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
566
567      // We have enough information to send to server
568      // First of all, send all enabled files
569      sendEnabledFiles(this->enabledWriteModeFiles);
570      // We only use server-level 1 (for now) to read data
571      if (!hasServer)
572        sendEnabledFiles(this->enabledReadModeFiles);
573
574      // Then, send all enabled fields     
575      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
576      if (!hasServer)
577        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
578
579      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
580      // If any, so send them to server
581       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
582      if (!hasServer)
583        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
584
585       // Check whether enabled fields have grid_ref, if any, send this info to server
586      sendRefGrid(this->enabledFiles);
587      // This code may be useful in the future when we want to seperate completely read and write
588      // sendRefGrid(this->enabledWriteModeFiles);
589      // if (!hasServer)
590      //   sendRefGrid(this->enabledReadModeFiles);
591     
592      // A grid of enabled fields composed of several components which must be checked then their
593      // checked attributes should be sent to server
594      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
595
596       // We have a xml tree on the server side and now, it should be also processed
597      sendPostProcessing();
598       
599      // Finally, we send information of grid itself to server
600      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
601      if (!hasServer)
602        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
603     }
604     allProcessed = true;
605   }
606
607   void CContext::sendPostProcessingGlobalAttributes()
608   {
609      // Use correct context client to send message
610     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
611    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
612     for (int i = 0; i < nbSrvPools; ++i)
613     {
614       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
615       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
616
617       if (contextClientTmp->isServerLeader())
618       {
619         CMessage msg;
620         if (hasServer)
621           msg<<this->getIdServer(i);
622         else
623           msg<<this->getIdServer();
624         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
625         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
626           event.push(*itRank,1,msg);
627         contextClientTmp->sendEvent(event);
628       }
629       else contextClientTmp->sendEvent(event);
630     }
631   }
632
633   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
634   {
635      CBufferIn* buffer=event.subEvents.begin()->buffer;
636      string id;
637      *buffer>>id;
638      get(id)->recvPostProcessingGlobalAttributes(*buffer);
639   }
640
641   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
642   {     
643      postProcessingGlobalAttributes();
644   }
645
646   /*!
647   \brief Close all the context defintion and do processing data
648      After everything is well defined on client side, they will be processed and sent to server
649   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
650   all necessary information to server, from which each server can build its own database.
651   Because the role of server is to write out field data on a specific netcdf file,
652   the only information that it needs is the enabled files
653   and the active fields (fields will be written onto active files)
654   */
655   void CContext::closeDefinition(void)
656   {
657    CTimer::get("Context : close definition").resume() ;
658    postProcessingGlobalAttributes();
659
660    if (hasClient) sendPostProcessingGlobalAttributes();
661
662    // There are some processings that should be done after all of above. For example: check mask or index
663    this->buildFilterGraphOfEnabledFields();
664   
665     if (hasClient && !hasServer)
666    {
667      buildFilterGraphOfFieldsWithReadAccess();
668      postProcessFilterGraph();
669    }
670   
671    checkGridEnabledFields();   
672
673    if (hasClient) this->sendProcessingGridOfEnabledFields();
674    if (hasClient) this->sendCloseDefinition();
675
676    // Nettoyage de l'arborescence
677    if (hasClient) CleanTree(); // Only on client side??
678
679    if (hasClient)
680    {
681      sendCreateFileHeader();
682      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
683    }
684    CTimer::get("Context : close definition").suspend() ;
685   }
686
687   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
688   {
689     for (unsigned int i = 0; i < activeFiles.size(); i++)
690     (void)activeFiles[i]->getEnabledFields();
691   }
692
693   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
694   {
695      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
696        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
697   }
698
699   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
700   {
701     int size = activeFiles.size();
702     for (int i = 0; i < size; ++i)
703     {       
704       activeFiles[i]->sendGridComponentOfEnabledFields();
705     }
706   }
707
708   /*!
709      Send active (enabled) fields in file from a client to others
710      \param [in] activeFiles files contains enabled fields to send
711   */
712   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
713   {
714     int size = activeFiles.size();
715     for (int i = 0; i < size; ++i)
716     {       
717       activeFiles[i]->sendGridOfEnabledFields();
718     }
719   }
720
721   void CContext::checkGridEnabledFields()
722   {
723     int size = enabledFiles.size();
724     for (int i = 0; i < size; ++i)
725     {
726       enabledFiles[i]->checkGridOfEnabledFields();       
727     }
728   }
729
730   /*!
731      Check grid of active (enabled) fields in file
732      \param [in] activeFiles files contains enabled fields whose grid needs checking
733   */
734   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
735   {
736     int size = activeFiles.size();
737     for (int i = 0; i < size; ++i)
738     {
739       activeFiles[i]->checkGridOfEnabledFields();       
740     }
741   }
742
743    /*!
744      Go up the hierachical tree via field_ref and do check of attributes of fields
745      This can be done in a client then all computed information will be sent from this client to others
746      \param [in] sendToServer Flag to indicate whether calculated information will be sent
747   */
748   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
749   {
750     int size = this->enabledFiles.size();
751     for (int i = 0; i < size; ++i)
752     {
753       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
754     }
755
756     for (int i = 0; i < size; ++i)
757     {
758       this->enabledFiles[i]->generateNewTransformationGridDest();
759     }
760   }
761
762    /*!
763      Go up the hierachical tree via field_ref and do check of attributes of fields.
764      The transformation can be done in this step.
765      All computed information will be sent from this client to others.
766      \param [in] sendToServer Flag to indicate whether calculated information will be sent
767   */
768   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
769   {
770     int size = this->enabledFiles.size();
771     for (int i = 0; i < size; ++i)
772     {
773       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
774     }
775   }
776
777   void CContext::buildFilterGraphOfEnabledFields()
778   {
779     int size = this->enabledFiles.size();
780     for (int i = 0; i < size; ++i)
781     {
782       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
783     }
784   }
785
786   void CContext::postProcessFilterGraph()
787   {
788     int size = enabledFiles.size();
789     for (int i = 0; i < size; ++i)
790     {
791        enabledFiles[i]->postProcessFilterGraph();
792     }
793   }
794
795   void CContext::startPrefetchingOfEnabledReadModeFiles()
796   {
797     int size = enabledReadModeFiles.size();
798     for (int i = 0; i < size; ++i)
799     {
800        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
801     }
802   }
803
804   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
805   {
806     int size = enabledReadModeFiles.size();
807     for (int i = 0; i < size; ++i)
808     {
809        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
810     }
811   }
812
813   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
814   {
815     int size = enabledReadModeFiles.size();
816     for (int i = 0; i < size; ++i)
817     {
818        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
819     }
820   }
821
822  void CContext::findFieldsWithReadAccess(void)
823  {
824    fieldsWithReadAccess.clear();
825    const vector<CField*> allFields = CField::getAll();
826    for (size_t i = 0; i < allFields.size(); ++i)
827    {
828      CField* field = allFields[i];
829
830      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
831        field->read_access = true;
832      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
833        fieldsWithReadAccess.push_back(field);
834    }
835  }
836
837  void CContext::solveAllRefOfFieldsWithReadAccess()
838  {
839    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
840      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
841  }
842
843  void CContext::buildFilterGraphOfFieldsWithReadAccess()
844  {
845    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
846      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
847  }
848
849   void CContext::solveAllInheritance(bool apply)
850   {
851     // Résolution des héritages descendants (càd des héritages de groupes)
852     // pour chacun des contextes.
853      solveDescInheritance(apply);
854
855     // Résolution des héritages par référence au niveau des fichiers.
856      const vector<CFile*> allFiles=CFile::getAll();
857      const vector<CGrid*> allGrids= CGrid::getAll();
858
859      if (hasClient && !hasServer)
860      //if (hasClient)
861      {
862        for (unsigned int i = 0; i < allFiles.size(); i++)
863          allFiles[i]->solveFieldRefInheritance(apply);
864      }
865
866      unsigned int vecSize = allGrids.size();
867      unsigned int i = 0;
868      for (i = 0; i < vecSize; ++i)
869        allGrids[i]->solveDomainAxisRefInheritance(apply);
870
871   }
872
873   void CContext::findEnabledFiles(void)
874   {
875      const std::vector<CFile*> allFiles = CFile::getAll();
876      const CDate& initDate = calendar->getInitDate();
877
878      for (unsigned int i = 0; i < allFiles.size(); i++)
879         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
880         {
881            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
882            {
883              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
884              {
885                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
886                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
887                    <<"\" is less than the time step. File will not be written."<<endl;
888              }
889              else
890               enabledFiles.push_back(allFiles[i]);
891            }
892         }
893         else
894         {
895           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
896           {
897             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
898                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
899                 <<"\" is less than the time step. File will not be written."<<endl;
900           }
901           else
902             enabledFiles.push_back(allFiles[i]); // otherwise true by default
903         }
904
905      if (enabledFiles.size() == 0)
906         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
907               << getId() << "\" !");
908
909   }
910
911   void CContext::distributeFiles(void)
912   {
913     bool distFileMemory=false ;
914     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
915
916     if (distFileMemory) distributeFileOverMemoryBandwith() ;
917     else distributeFileOverBandwith() ;
918   }
919
920
921   void CContext::distributeFileOverBandwith(void)
922   {
923     double eps=std::numeric_limits<double>::epsilon()*10 ;
924     
925     // If primary server
926     if (hasServer && hasClient)
927     {
928       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
929       int nbPools = clientPrimServer.size();
930
931       // (1) Find all enabled files in write mode
932       // for (int i = 0; i < this->enabledFiles.size(); ++i)
933       // {
934       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
935       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
936       // }
937
938       // (2) Estimate the data volume for each file
939       int size = this->enabledWriteModeFiles.size();
940       std::vector<std::pair<double, CFile*> > dataSizeMap;
941       double dataPerPool = 0;
942       int nfield=0 ;
943       ofs<<size<<endl ;
944       for (size_t i = 0; i < size; ++i)
945       {
946         CFile* file = this->enabledWriteModeFiles[i];
947         ofs<<file->getId()<<endl ;
948         StdSize dataSize=0;
949         std::vector<CField*> enabledFields = file->getEnabledFields();
950         size_t numEnabledFields = enabledFields.size();
951         ofs<<numEnabledFields<<endl ;
952         for (size_t j = 0; j < numEnabledFields; ++j)
953         {
954           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
955           ofs<<enabledFields[j]->grid->getId()<<endl ;
956           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
957         }
958         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
959         double dataSizeSec= dataSize/ outFreqSec;
960         ofs<<dataSizeSec<<endl ;
961         nfield++ ;
962// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
963         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
964         dataPerPool += dataSizeSec;
965       }
966       dataPerPool /= nbPools;
967       std::sort(dataSizeMap.begin(), dataSizeMap.end());
968
969       // (3) Assign contextClient to each enabled file
970
971       std::multimap<double,int> poolDataSize ;
972// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
973
974       int j;
975       double dataSize ;
976       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
977             
978       for (int i = dataSizeMap.size()-1; i >= 0; --i)
979       {
980         dataSize=(*poolDataSize.begin()).first ;
981         j=(*poolDataSize.begin()).second ;
982         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
983         dataSize+=dataSizeMap[i].first;
984         poolDataSize.erase(poolDataSize.begin()) ;
985         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
986       }
987
988       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it) info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
989 
990       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
991       {
992         enabledReadModeFiles[i]->setContextClient(client);         
993       }
994     }
995     else
996     {
997       for (int i = 0; i < this->enabledFiles.size(); ++i)
998         enabledFiles[i]->setContextClient(client);
999     }
1000   }
1001
1002   void CContext::distributeFileOverMemoryBandwith(void)
1003   {
1004     // If primary server
1005     if (hasServer && hasClient)
1006     {
1007       int nbPools = clientPrimServer.size();
1008       double ratio=0.5 ;
1009       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1010
1011       int nFiles = this->enabledWriteModeFiles.size();
1012       vector<SDistFile> files(nFiles);
1013       vector<SDistGrid> grids;
1014       map<string,int> gridMap ;
1015       string gridId; 
1016       int gridIndex=0 ;
1017
1018       for (size_t i = 0; i < nFiles; ++i)
1019       {
1020         StdSize dataSize=0;
1021         CFile* file = this->enabledWriteModeFiles[i];
1022         std::vector<CField*> enabledFields = file->getEnabledFields();
1023         size_t numEnabledFields = enabledFields.size();
1024
1025         files[i].id_=file->getId() ;
1026         files[i].nbGrids_=numEnabledFields;
1027         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1028         
1029         for (size_t j = 0; j < numEnabledFields; ++j)
1030         {
1031           gridId=enabledFields[j]->grid->getId() ;
1032           if (gridMap.find(gridId)==gridMap.end())
1033           {
1034              gridMap[gridId]=gridIndex  ;
1035              SDistGrid newGrid; 
1036              grids.push_back(newGrid) ;
1037              gridIndex++ ;
1038           }
1039           files[i].assignedGrid_[j]=gridMap[gridId] ;
1040           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1041           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1042         }
1043         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1044         files[i].bandwith_= dataSize/ outFreqSec ;
1045       }
1046
1047       double bandwith=0 ;
1048       double memory=0 ;
1049   
1050       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1051       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1052
1053       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1054       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1055       
1056       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1057
1058       vector<double> memorySize(nbPools,0.) ;
1059       vector< set<int> > serverGrids(nbPools) ;
1060       vector<double> bandwithSize(nbPools,0.) ;
1061       
1062       for (size_t i = 0; i < nFiles; ++i)
1063       {
1064         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1065         for(int j=0 ; j<files[i].nbGrids_;j++)
1066         {
1067           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1068           {
1069             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1070             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1071           }
1072         }
1073         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1074         delete [] files[i].assignedGrid_ ;
1075       }
1076
1077       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned file bandwith "<<bandwithSize[i]*86400.*4./1024/1024.<<" Mb / days"<<endl ;
1078       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1079
1080
1081       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1082       {
1083         enabledReadModeFiles[i]->setContextClient(client);         
1084       }
1085
1086   }
1087   else
1088   {
1089     for (int i = 0; i < this->enabledFiles.size(); ++i)
1090        enabledFiles[i]->setContextClient(client);
1091   }
1092}
1093
1094
1095
1096   /*!
1097      Find all files in write mode
1098   */
1099   void CContext::findEnabledWriteModeFiles(void)
1100   {
1101     int size = this->enabledFiles.size();
1102     for (int i = 0; i < size; ++i)
1103     {
1104       if (enabledFiles[i]->mode.isEmpty() || 
1105          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1106        enabledWriteModeFiles.push_back(enabledFiles[i]);
1107     }
1108   }
1109
1110   /*!
1111      Find all files in read mode
1112   */
1113   void CContext::findEnabledReadModeFiles(void)
1114   {
1115     int size = this->enabledFiles.size();
1116     for (int i = 0; i < size; ++i)
1117     {
1118       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1119        enabledReadModeFiles.push_back(enabledFiles[i]);
1120     }
1121   }
1122
1123   void CContext::closeAllFile(void)
1124   {
1125     std::vector<CFile*>::const_iterator
1126            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
1127
1128     for (; it != end; it++)
1129     {
1130       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1131       (*it)->close();
1132     }
1133   }
1134
1135   /*!
1136   \brief Dispatch event received from client
1137      Whenever a message is received in buffer of server, it will be processed depending on
1138   its event type. A new event type should be added in the switch list to make sure
1139   it processed on server side.
1140   \param [in] event: Received message
1141   */
1142   bool CContext::dispatchEvent(CEventServer& event)
1143   {
1144
1145      if (SuperClass::dispatchEvent(event)) return true;
1146      else
1147      {
1148        switch(event.type)
1149        {
1150           case EVENT_ID_CLOSE_DEFINITION :
1151             recvCloseDefinition(event);
1152             return true;
1153             break;
1154           case EVENT_ID_UPDATE_CALENDAR:
1155             recvUpdateCalendar(event);
1156             return true;
1157             break;
1158           case EVENT_ID_CREATE_FILE_HEADER :
1159             recvCreateFileHeader(event);
1160             return true;
1161             break;
1162           case EVENT_ID_POST_PROCESS:
1163             recvPostProcessing(event);
1164             return true;
1165            case EVENT_ID_SEND_REGISTRY:
1166             recvRegistry(event);
1167             return true;
1168             break;
1169            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1170             recvPostProcessingGlobalAttributes(event);
1171             return true;
1172             break;
1173            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1174             recvProcessingGridOfEnabledFields(event);
1175             return true;
1176             break;
1177           default :
1178             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1179                    <<"Unknown Event");
1180           return false;
1181         }
1182      }
1183   }
1184
1185   //! Client side: Send a message to server to make it close
1186   void CContext::sendCloseDefinition(void)
1187   {
1188     // Use correct context client to send message
1189     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1190     for (int i = 0; i < nbSrvPools; ++i)
1191     {
1192       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1193       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1194       if (contextClientTmp->isServerLeader())
1195       {
1196         CMessage msg;
1197         if (hasServer)
1198           msg<<this->getIdServer(i);
1199         else
1200           msg<<this->getIdServer();
1201         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1202         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1203           event.push(*itRank,1,msg);
1204         contextClientTmp->sendEvent(event);
1205       }
1206       else contextClientTmp->sendEvent(event);
1207     }
1208   }
1209
1210   //! Server side: Receive a message of client announcing a context close
1211   void CContext::recvCloseDefinition(CEventServer& event)
1212   {
1213      CBufferIn* buffer=event.subEvents.begin()->buffer;
1214      string id;
1215      *buffer>>id;
1216      get(id)->closeDefinition();
1217   }
1218
1219   //! Client side: Send a message to update calendar in each time step
1220   void CContext::sendUpdateCalendar(int step)
1221   {
1222     // Use correct context client to send message
1223    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1224     for (int i = 0; i < nbSrvPools; ++i)
1225     {
1226       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1227       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1228
1229         if (contextClientTmp->isServerLeader())
1230         {
1231           CMessage msg;
1232           if (hasServer)
1233             msg<<this->getIdServer(i)<<step;
1234           else
1235             msg<<this->getIdServer()<<step;
1236           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1237           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1238             event.push(*itRank,1,msg);
1239           contextClientTmp->sendEvent(event);
1240         }
1241         else contextClientTmp->sendEvent(event);
1242     }
1243   }
1244
1245   //! Server side: Receive a message of client annoucing calendar update
1246   void CContext::recvUpdateCalendar(CEventServer& event)
1247   {
1248      CBufferIn* buffer=event.subEvents.begin()->buffer;
1249      string id;
1250      *buffer>>id;
1251      get(id)->recvUpdateCalendar(*buffer);
1252   }
1253
1254   //! Server side: Receive a message of client annoucing calendar update
1255   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1256   {
1257      int step;
1258      buffer>>step;
1259      updateCalendar(step);
1260      if (hasClient && hasServer)
1261      {       
1262        sendUpdateCalendar(step);
1263      }
1264   }
1265
1266   //! Client side: Send a message to create header part of netcdf file
1267   void CContext::sendCreateFileHeader(void)
1268   {
1269     // Use correct context client to send message
1270     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1271     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1272     for (int i = 0; i < nbSrvPools; ++i)
1273     {
1274       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1275       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1276
1277       if (contextClientTmp->isServerLeader())
1278       {
1279         CMessage msg;
1280         if (hasServer)
1281           msg<<this->getIdServer(i);
1282         else
1283           msg<<this->getIdServer();
1284         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1285         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1286           event.push(*itRank,1,msg) ;
1287         contextClientTmp->sendEvent(event);
1288       }
1289       else contextClientTmp->sendEvent(event);
1290     }
1291   }
1292
1293   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1294   void CContext::recvCreateFileHeader(CEventServer& event)
1295   {
1296      CBufferIn* buffer=event.subEvents.begin()->buffer;
1297      string id;
1298      *buffer>>id;
1299      get(id)->recvCreateFileHeader(*buffer);
1300   }
1301
1302   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1303   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1304   {
1305      if (!hasClient && hasServer) 
1306        createFileHeader();
1307   }
1308
1309   //! Client side: Send a message to do some post processing on server
1310   void CContext::sendProcessingGridOfEnabledFields()
1311   {
1312      // Use correct context client to send message
1313     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1314     for (int i = 0; i < nbSrvPools; ++i)
1315     {
1316       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1317       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1318
1319       if (contextClientTmp->isServerLeader())
1320       {
1321         CMessage msg;
1322         if (hasServer)
1323           msg<<this->getIdServer(i);
1324         else
1325           msg<<this->getIdServer();
1326         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1327         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1328           event.push(*itRank,1,msg);
1329         contextClientTmp->sendEvent(event);
1330       }
1331       else contextClientTmp->sendEvent(event);
1332     }
1333   }
1334
1335   //! Server side: Receive a message to do some post processing
1336   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1337   {
1338      CBufferIn* buffer=event.subEvents.begin()->buffer;
1339      string id;
1340      *buffer>>id;     
1341   }
1342
1343   //! Client side: Send a message to do some post processing on server
1344   void CContext::sendPostProcessing()
1345   {
1346      // Use correct context client to send message
1347     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1348     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1349     for (int i = 0; i < nbSrvPools; ++i)
1350     {
1351       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1352       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1353       if (contextClientTmp->isServerLeader())
1354       {
1355         CMessage msg;
1356         if (hasServer)
1357           msg<<this->getIdServer(i);
1358         else
1359           msg<<this->getIdServer();
1360         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1361         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1362         event.push(*itRank,1,msg);
1363         contextClientTmp->sendEvent(event);
1364       }
1365       else contextClientTmp->sendEvent(event);
1366     }
1367   }
1368
1369   //! Server side: Receive a message to do some post processing
1370   void CContext::recvPostProcessing(CEventServer& event)
1371   {
1372      CBufferIn* buffer=event.subEvents.begin()->buffer;
1373      string id;
1374      *buffer>>id;
1375      get(id)->recvPostProcessing(*buffer);
1376   }
1377
1378   //! Server side: Receive a message to do some post processing
1379   void CContext::recvPostProcessing(CBufferIn& buffer)
1380   {
1381      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1382      postProcessing();
1383   }
1384
1385   const StdString& CContext::getIdServer()
1386   {
1387      if (hasClient)
1388      {
1389        idServer_ = this->getId();
1390        idServer_ += "_server";
1391        return idServer_;
1392      }
1393      if (hasServer) return (this->getId());
1394   }
1395
1396   const StdString& CContext::getIdServer(const int i)
1397   {
1398     idServer_ = this->getId();
1399     idServer_ += "_server_";
1400     idServer_ += boost::lexical_cast<string>(i);
1401     return idServer_;
1402   }
1403
1404
1405   /*!
1406   \brief Do some simple post processings after parsing xml file
1407      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1408   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1409   which will be written out into netcdf files, are processed
1410   */
1411   void CContext::postProcessing()
1412   {
1413     if (isPostProcessed) return;
1414
1415      // Make sure the calendar was correctly created
1416      if (!calendar)
1417        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1418      else if (calendar->getTimeStep() == NoneDu)
1419        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1420      // Calendar first update to set the current date equals to the start date
1421      calendar->update(0);
1422
1423      // Find all inheritance in xml structure
1424      this->solveAllInheritance();
1425
1426//      ShowTree(info(10));
1427
1428      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1429      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1430      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1431
1432      // Check if some automatic time series should be generated
1433      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1434
1435      // The timeseries should only be prepared in client
1436      if (hasClient && !hasServer) prepareTimeseries();
1437
1438      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1439      findEnabledFiles();
1440      findEnabledWriteModeFiles();
1441      findEnabledReadModeFiles();
1442
1443      // For now, only read files with client and only one level server
1444      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
1445
1446      // Find all enabled fields of each file     
1447      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1448      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1449
1450      // For now, only read files with client and only one level server
1451      // if (hasClient && !hasServer)
1452      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
1453
1454      if (hasClient && !hasServer)
1455      {
1456        initReadFiles();
1457        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1458        this->readAttributesOfEnabledFieldsInReadModeFiles();
1459      }
1460
1461      // Only search and rebuild all reference objects of enable fields, don't transform
1462      this->solveOnlyRefOfEnabledFields(false);
1463
1464      // Search and rebuild all reference object of enabled fields, and transform
1465      this->solveAllRefOfEnabledFieldsAndTransform(false);
1466
1467      // Find all fields with read access from the public API
1468      if (hasClient && !hasServer) findFieldsWithReadAccess();
1469      // and solve the all reference for them
1470      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1471
1472      isPostProcessed = true;
1473   }
1474
1475   /*!
1476    * Compute the required buffer size to send the attributes (mostly those grid related).
1477    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1478    * \param [in] contextClient
1479    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1480      This flag is only true for client and server-1 for communication with server-2
1481    */
1482   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1483                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1484   {
1485         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1486     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1487     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1488
1489     std::vector<CFile*>& fileList = this->enabledFiles;
1490     size_t numEnabledFiles = fileList.size();
1491     for (size_t i = 0; i < numEnabledFiles; ++i)
1492     {
1493//         CFile* file = this->enabledWriteModeFiles[i];
1494        CFile* file = fileList[i];
1495        std::vector<CField*> enabledFields = file->getEnabledFields();
1496        size_t numEnabledFields = enabledFields.size();
1497        for (size_t j = 0; j < numEnabledFields; ++j)
1498        {
1499          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1500          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1501          for (; it != itE; ++it)
1502          {
1503                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1504                     // so we can use it safely without checking for its existence
1505             if (attributesSize[it->first] < it->second)
1506                           attributesSize[it->first] = it->second;
1507
1508                     if (maxEventSize[it->first] < it->second)
1509                           maxEventSize[it->first] = it->second;
1510          }
1511        }
1512     }
1513     return attributesSize;
1514   }
1515
1516   /*!
1517    * Compute the required buffer size to send the fields data.
1518    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1519    * \param [in] contextClient
1520    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1521      This flag is only true for client and server-1 for communication with server-2
1522    */
1523   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1524                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1525   {
1526     std::map<int, StdSize> dataSize;
1527
1528     // Find all reference domain and axis of all active fields
1529     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1530     size_t numEnabledFiles = fileList.size();
1531     for (size_t i = 0; i < numEnabledFiles; ++i)
1532     {
1533//       CFile* file = this->enabledFiles[i];
1534       CFile* file = fileList[i];
1535       if (file->getContextClient() == contextClient)
1536       {
1537         std::vector<CField*> enabledFields = file->getEnabledFields();
1538         size_t numEnabledFields = enabledFields.size();
1539         for (size_t j = 0; j < numEnabledFields; ++j)
1540         {
1541           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1542           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1543           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1544           for (; it != itE; ++it)
1545           {
1546             // If dataSize[it->first] does not exist, it will be zero-initialized
1547             // so we can use it safely without checking for its existance
1548                 if (CXios::isOptPerformance)
1549               dataSize[it->first] += it->second;
1550             else if (dataSize[it->first] < it->second)
1551               dataSize[it->first] = it->second;
1552
1553                 if (maxEventSize[it->first] < it->second)
1554               maxEventSize[it->first] = it->second;
1555           }
1556         }
1557       }
1558     }
1559     return dataSize;
1560   }
1561
1562   //! Client side: Send infomation of active files (files are enabled to write out)
1563   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1564   {
1565     int size = activeFiles.size();
1566
1567     // In a context, each type has a root definition, e.g: axis, domain, field.
1568     // Every object must be a child of one of these root definition. In this case
1569     // all new file objects created on server must be children of the root "file_definition"
1570     StdString fileDefRoot("file_definition");
1571     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1572
1573     for (int i = 0; i < size; ++i)
1574     {
1575       CFile* f = activeFiles[i];
1576       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1577       f->sendAllAttributesToServer(f->getContextClient());
1578       f->sendAddAllVariables(f->getContextClient());
1579     }
1580   }
1581
1582   //! Client side: Send information of active fields (ones are written onto files)
1583   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1584   {
1585     int size = activeFiles.size();
1586     for (int i = 0; i < size; ++i)
1587     {
1588       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1589     }
1590   }
1591
1592   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1593   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1594   {
1595     if (!hasClient) return;
1596
1597     const vector<CAxis*> allAxis = CAxis::getAll();
1598     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1599       (*it)->checkEligibilityForCompressedOutput();
1600
1601     const vector<CDomain*> allDomains = CDomain::getAll();
1602     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1603       (*it)->checkEligibilityForCompressedOutput();
1604
1605     const vector<CGrid*> allGrids = CGrid::getAll();
1606     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1607       (*it)->checkEligibilityForCompressedOutput();
1608   }
1609
1610   //! Client side: Prepare the timeseries by adding the necessary files
1611   void CContext::prepareTimeseries()
1612   {
1613     if (!hasClient) return;
1614
1615     const std::vector<CFile*> allFiles = CFile::getAll();
1616     for (size_t i = 0; i < allFiles.size(); i++)
1617     {
1618       CFile* file = allFiles[i];
1619
1620       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1621       for (size_t k = 0; k < vars.size(); k++)
1622       {
1623         CVariable* var = vars[k];
1624
1625         if (var->ts_target.isEmpty()
1626              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1627           fileVars.push_back(var);
1628
1629         if (!var->ts_target.isEmpty()
1630              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1631           fieldVars.push_back(var);
1632       }
1633
1634       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1635       {
1636         StdString fileNameStr("%file_name%") ;
1637         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1638         
1639         StdString fileName=file->getFileOutputName();
1640         size_t pos=tsPrefix.find(fileNameStr) ;
1641         while (pos!=std::string::npos)
1642         {
1643           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1644           pos=tsPrefix.find(fileNameStr) ;
1645         }
1646       
1647         const std::vector<CField*> allFields = file->getAllFields();
1648         for (size_t j = 0; j < allFields.size(); j++)
1649         {
1650           CField* field = allFields[j];
1651
1652           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1653           {
1654             CFile* tsFile = CFile::create();
1655             tsFile->duplicateAttributes(file);
1656
1657             // Add variables originating from file and targeted to timeserie file
1658             for (size_t k = 0; k < fileVars.size(); k++)
1659               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1660
1661           
1662             tsFile->name = tsPrefix + "_";
1663             if (!field->name.isEmpty())
1664               tsFile->name.get() += field->name;
1665             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1666               tsFile->name.get() += field->field_ref;
1667             else
1668               tsFile->name.get() += field->getId();
1669
1670             if (!field->ts_split_freq.isEmpty())
1671               tsFile->split_freq = field->ts_split_freq;
1672
1673             CField* tsField = tsFile->addField();
1674             tsField->field_ref = field->getId();
1675
1676             // Add variables originating from file and targeted to timeserie field
1677             for (size_t k = 0; k < fieldVars.size(); k++)
1678               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1679
1680             vars = field->getAllVariables();
1681             for (size_t k = 0; k < vars.size(); k++)
1682             {
1683               CVariable* var = vars[k];
1684
1685               // Add variables originating from field and targeted to timeserie field
1686               if (var->ts_target.isEmpty()
1687                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1688                 tsField->getVirtualVariableGroup()->addChild(var);
1689
1690               // Add variables originating from field and targeted to timeserie file
1691               if (!var->ts_target.isEmpty()
1692                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1693                 tsFile->getVirtualVariableGroup()->addChild(var);
1694             }
1695
1696             tsFile->solveFieldRefInheritance(true);
1697
1698             if (file->timeseries == CFile::timeseries_attr::exclusive)
1699               field->enabled = false;
1700           }
1701         }
1702
1703         // Finally disable the original file is need be
1704         if (file->timeseries == CFile::timeseries_attr::only)
1705          file->enabled = false;
1706       }
1707     }
1708   }
1709
1710   //! Client side: Send information of reference grid of active fields
1711   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1712   {
1713     std::set<StdString> gridIds;
1714     int sizeFile = activeFiles.size();
1715     CFile* filePtr(NULL);
1716
1717     // Firstly, find all reference grids of all active fields
1718     for (int i = 0; i < sizeFile; ++i)
1719     {
1720       filePtr = activeFiles[i];
1721       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1722       int sizeField = enabledFields.size();
1723       for (int numField = 0; numField < sizeField; ++numField)
1724       {
1725         if (0 != enabledFields[numField]->getRelGrid())
1726           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1727       }
1728     }
1729
1730     // Create all reference grids on server side
1731     StdString gridDefRoot("grid_definition");
1732     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1733     std::set<StdString>::const_iterator it, itE = gridIds.end();
1734     for (it = gridIds.begin(); it != itE; ++it)
1735     {
1736       gridPtr->sendCreateChild(*it);
1737       CGrid::get(*it)->sendAllAttributesToServer();
1738       CGrid::get(*it)->sendAllDomains();
1739       CGrid::get(*it)->sendAllAxis();
1740       CGrid::get(*it)->sendAllScalars();
1741     }
1742   }
1743
1744   //! Client side: Send information of reference domain, axis and scalar of active fields
1745   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1746   {
1747     std::set<StdString> domainIds, axisIds, scalarIds;
1748
1749     // Find all reference domain and axis of all active fields
1750     int numEnabledFiles = activeFiles.size();
1751     for (int i = 0; i < numEnabledFiles; ++i)
1752     {
1753       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1754       int numEnabledFields = enabledFields.size();
1755       for (int j = 0; j < numEnabledFields; ++j)
1756       {
1757         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1758         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1759         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1760         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1761       }
1762     }
1763
1764     // Create all reference axis on server side
1765     std::set<StdString>::iterator itDom, itAxis, itScalar;
1766     std::set<StdString>::const_iterator itE;
1767
1768     StdString scalarDefRoot("scalar_definition");
1769     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1770     itE = scalarIds.end();
1771     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1772     {
1773       if (!itScalar->empty())
1774       {
1775         scalarPtr->sendCreateChild(*itScalar);
1776         CScalar::get(*itScalar)->sendAllAttributesToServer();
1777       }
1778     }
1779
1780     StdString axiDefRoot("axis_definition");
1781     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1782     itE = axisIds.end();
1783     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1784     {
1785       if (!itAxis->empty())
1786       {
1787         axisPtr->sendCreateChild(*itAxis);
1788         CAxis::get(*itAxis)->sendAllAttributesToServer();
1789       }
1790     }
1791
1792     // Create all reference domains on server side
1793     StdString domDefRoot("domain_definition");
1794     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1795     itE = domainIds.end();
1796     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1797     {
1798       if (!itDom->empty()) {
1799          domPtr->sendCreateChild(*itDom);
1800          CDomain::get(*itDom)->sendAllAttributesToServer();
1801       }
1802     }
1803   }
1804
1805   //! Update calendar in each time step
1806   void CContext::updateCalendar(int step)
1807   {
1808      int prevStep = calendar->getStep();
1809
1810      if (prevStep < step)
1811      {
1812        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1813        {
1814          doPreTimestepOperationsForEnabledReadModeFiles();
1815        }
1816
1817        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1818        calendar->update(step);
1819        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1820  #ifdef XIOS_MEMTRACK_LIGHT
1821        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1822  #endif
1823
1824        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1825        {
1826          doPostTimestepOperationsForEnabledReadModeFiles();
1827          garbageCollector.invalidate(calendar->getCurrentDate());
1828        }
1829      }
1830      else if (prevStep == step)
1831        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
1832      else // if (prevStep > step)
1833        ERROR("void CContext::updateCalendar(int step)",
1834              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
1835   }
1836
1837   void CContext::initReadFiles(void)
1838   {
1839      vector<CFile*>::const_iterator it;
1840
1841      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1842      {
1843         (*it)->initRead();
1844      }
1845   }
1846
1847   //! Server side: Create header of netcdf file
1848   void CContext::createFileHeader(void)
1849   {
1850      vector<CFile*>::const_iterator it;
1851
1852      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1853      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
1854      {
1855         (*it)->initWrite();
1856      }
1857   }
1858
1859   //! Get current context
1860   CContext* CContext::getCurrent(void)
1861   {
1862     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1863   }
1864
1865   /*!
1866   \brief Set context with an id be the current context
1867   \param [in] id identity of context to be set to current
1868   */
1869   void CContext::setCurrent(const string& id)
1870   {
1871     CObjectFactory::SetCurrentContextId(id);
1872     CGroupFactory::SetCurrentContextId(id);
1873   }
1874
1875  /*!
1876  \brief Create a context with specific id
1877  \param [in] id identity of new context
1878  \return pointer to the new context or already-existed one with identity id
1879  */
1880  CContext* CContext::create(const StdString& id)
1881  {
1882    CContext::setCurrent(id);
1883
1884    bool hasctxt = CContext::has(id);
1885    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1886    getRoot();
1887    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1888
1889#define DECLARE_NODE(Name_, name_) \
1890    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1891#define DECLARE_NODE_PAR(Name_, name_)
1892#include "node_type.conf"
1893
1894    return (context);
1895  }
1896
1897
1898     //! Server side: Receive a message to do some post processing
1899  void CContext::recvRegistry(CEventServer& event)
1900  {
1901    CBufferIn* buffer=event.subEvents.begin()->buffer;
1902    string id;
1903    *buffer>>id;
1904    get(id)->recvRegistry(*buffer);
1905  }
1906
1907  void CContext::recvRegistry(CBufferIn& buffer)
1908  {
1909    if (server->intraCommRank==0)
1910    {
1911      CRegistry registry(server->intraComm) ;
1912      registry.fromBuffer(buffer) ;
1913      registryOut->mergeRegistry(registry) ;
1914    }
1915  }
1916
1917  void CContext::sendRegistry(void)
1918  {
1919    registryOut->hierarchicalGatherRegistry() ;
1920
1921    // Use correct context client to send message
1922    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1923    for (int i = 0; i < nbSrvPools; ++i)
1924    {
1925      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1926      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1927        if (contextClientTmp->isServerLeader())
1928        {
1929           CMessage msg ;
1930           if (hasServer)
1931             msg<<this->getIdServer(i);
1932           else
1933             msg<<this->getIdServer();
1934           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1935           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1936           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1937             event.push(*itRank,1,msg);
1938           contextClientTmp->sendEvent(event);
1939         }
1940         else contextClientTmp->sendEvent(event);
1941    }
1942  }
1943
1944  /*!
1945  * \fn bool CContext::isFinalized(void)
1946  * Context is finalized if it received context post finalize event.
1947  */
1948  bool CContext::isFinalized(void)
1949  {
1950    return finalized;
1951  }
1952
1953} // namespace xios
Note: See TracBrowser for help on using the repository browser.