//============================================================================
//  NAClusterInfo constructor.
//
// Input: heap pointer(should always be context heap
//  
//
// Output: Retrieves information for the local cluster. This includes information
// regarding its CPUs as well as for the dp2s. All these information will be cached
// in the appropriate structure.
//
// Return:
//  none
//
//==============================================================================
NAClusterInfo::NAClusterInfo(CollHeap * heap)
 : heap_(heap), 
   maxOSV_(COM_VERS_UNKNOWN),
   maxOSVName_(heap),
   inTestMode_(FALSE),
   useAggregationNodesOnly_(FALSE)
{
  OptimizerSimulator::osimMode mode = OptimizerSimulator::OFF;

  if(CURRCONTEXT_OPTSIMULATOR && 
     !CURRCONTEXT_OPTSIMULATOR->isCallDisabled(9))
    mode = CURRCONTEXT_OPTSIMULATOR->getOsimMode();

  // Check for OSIM mode
  switch (mode)
  {
    case OptimizerSimulator::OFF:
    case OptimizerSimulator::LOAD:
    case OptimizerSimulator::CAPTURE:
    {
      // Hash Map to store NodeName and NoideIds
      nodeNameToNodeIdMap_ = new (heap) NAHashDictionary<NAString, Int32>
          (NAString::hash, 101, TRUE, heap_);
          
      clusterToCPUMap_ = new(heap) NAHashDictionary<CollIndex,maps>
                                                          (&clusterNumHashFunc,17,TRUE, heap);
                                                          
      nodeIdToNodeNameMap_ = new(heap) NAHashDictionary<Int32, NAString>
                                                          (&intHashFunc, 101,TRUE,heap);
                                                          
      activeClusters_= NULL;
      smpCount_ = -1;

      NADefaults::getNodeAndClusterNumbers(localSMP_ , localCluster_);

      Int32 nodeCount = 0;
      Int32 nodeMax = 0;
      MS_Mon_Node_Info_Entry_Type *nodeInfo = NULL;

      // Get the number of nodes to know how much info space to allocate
      Int32 error = msg_mon_get_node_info(&nodeCount, 0, NULL);
      CMPASSERT(error == 0);
      CMPASSERT(nodeCount > 0);

      // Allocate the space for node info entries
      nodeInfo = (MS_Mon_Node_Info_Entry_Type *) new(heap) 
                  char[nodeCount * sizeof(MS_Mon_Node_Info_Entry_Type)];
      CMPASSERT(nodeInfo);


      // Get the node info
      memset(nodeInfo, 0, sizeof(nodeInfo));
      nodeMax = nodeCount;
      error = msg_mon_get_node_info(&nodeCount, nodeMax, nodeInfo);
      CMPASSERT(error == 0);

      maps *cpuList=new(heap) maps(heap);
      smpCount_ = 0;

      NAList<CollIndex> storageList(nodeCount);

      for (Int32 i = 0; i < nodeCount; i++)
      {
        if (nodeInfo[i].spare_node)
          continue;

        // The zone type must either be an aggregation node or storage node
        // to be included in the list of CPUs.
        if ((nodeInfo[i].type & MS_Mon_ZoneType_Aggregation) != 0 ||
            ((nodeInfo[i].type & MS_Mon_ZoneType_Storage) != 0 ))
        {
          if ( (nodeInfo[i].type & MS_Mon_ZoneType_Storage) != 0 )
            storageList.insert(nodeInfo[i].nid);

          if ( (nodeInfo[i].type & MS_Mon_ZoneType_Storage) == 0 )
            cpuList->insertToAggregationNodeList(nodeInfo[i].nid);

          if (!nodeInfo[i].spare_node)
             smpCount_++;

          // store nodeName-nodeId pairs
          NAString *key_nodeName = new (heap_) NAString(nodeInfo[i].node_name, heap_);
          size_t pos = key_nodeName->index('.');
          if (pos && pos != NA_NPOS)
            key_nodeName->remove(pos);
#ifdef _DEBUG
          else {
             // The node names for virtual nodes seen with workstations are of
             // format <nodeName>:0, <nodeName>:1 etc. In debug mode, we work with
             // such node names by removing all substrings starting at ':' and 
             // insert the node name into the nodeIdToNodeNameMap_.
             pos = key_nodeName->index(':');
             if (pos && pos != NA_NPOS)
               key_nodeName->remove(pos);
          }
#endif

          Int32 *val_nodeId = new Int32(nodeInfo[i].nid);
          nodeNameToNodeIdMap_->insert(key_nodeName, val_nodeId);

          // store nodeId->nadeName 
          //share the same memory with nodeNameToNodeIdMap_
          nodeIdToNodeNameMap_->insert(val_nodeId, key_nodeName);
        }
      }

      // Fix Bugzilla #1210. Put the aggregation nodes at the beginning of 
      // the list. ESP logical node map synthesization code can take the 
      // advantage of this and place more ESPs on aggregation nodes when 
      // the node map size is less than the total number of SQL nodes.
      *(cpuList->list) = *(cpuList->listOfAggregationOnlyNodes);
      cpuList->list->insert(storageList);

      // if there exists no aggregation only nodes, allow all nodes to
      // host esps.
      if (cpuList->listOfAggregationOnlyNodes->entries() == 0) {
        for (Int32 i = 0; i<cpuList->list->entries(); i++)
          cpuList->insertToAggregationNodeList((*(cpuList->list))[i]);
      }

      NADELETEBASIC(nodeInfo, heap);


      CollIndex *ptrClusterNum = new(heap) CollIndex(localCluster_);
      CollIndex *cluster=clusterToCPUMap_->insert(ptrClusterNum,cpuList); 

      CMPASSERT(cluster);

      break;
    }
    case OptimizerSimulator::SIMULATE:

      clusterToCPUMap_ = NULL;
      nodeIdToNodeNameMap_ = NULL;
      activeClusters_= NULL;
      smpCount_ = -1;
      //load NAClusterInfo from OSIM file
      simulateNAClusterInfo();
      break;
    default:
      // The OSIM must run under OFF (normal), CAPTURE or SIMULATE mode.
      OSIM_errorMessage("Invalid OSIM mode - It must be OFF or CAPTURE or SIMULATE.");
      break;
  }
} // NAClusterInfo::NAClusterInfo()
//============================================================================
//  NAClusterInfo constructor.
//
// Input: heap pointer(should always be context heap
//  
//
// Output: Retrieves information for the local cluster. This includes information
// regarding its CPUs as well as for the dp2s. All these information will be cached
// in the appropriate structure.
//
// Return:
//  none
//
//==============================================================================
NAClusterInfo::NAClusterInfo(CollHeap * heap)
 : heap_(heap), 
   cpuArray_(heap),
   inTestMode_(FALSE)
{
  OptimizerSimulator::osimMode mode = OptimizerSimulator::OFF;

  if(CURRCONTEXT_OPTSIMULATOR && 
     !CURRCONTEXT_OPTSIMULATOR->isCallDisabled(9))
    mode = CURRCONTEXT_OPTSIMULATOR->getOsimMode();

  // Check for OSIM mode
  switch (mode)
  {
    case OptimizerSimulator::OFF:
    case OptimizerSimulator::LOAD:
    case OptimizerSimulator::CAPTURE:
    {
      Int32 dummyClusterNum;

      // Hash Map to store NodeName and NoideIds
      nodeNameToNodeIdMap_ = new (heap) NAHashDictionary<NAString, Int32>
          (NAString::hash, 101, TRUE, heap_);
      nodeIdToNodeNameMap_ = new(heap) NAHashDictionary<Int32, NAString>
                                                          (&intHashFunc, 101,TRUE,heap);
                                                          
      NADefaults::getNodeAndClusterNumbers(localSMP_ , dummyClusterNum);

      Int32 nodeCount = 0;
      Int32 nodeMax = 0;
      MS_Mon_Node_Info_Entry_Type *nodeInfo = NULL;

      // Get the number of nodes to know how much info space to allocate
      Int32 error = msg_mon_get_node_info(&nodeCount, 0, NULL);
      CMPASSERT(error == 0);
      CMPASSERT(nodeCount > 0);

      // Allocate the space for node info entries
      nodeInfo = (MS_Mon_Node_Info_Entry_Type *) new(heap) 
                  char[nodeCount * sizeof(MS_Mon_Node_Info_Entry_Type)];
      CMPASSERT(nodeInfo);


      // Get the node info
      memset(nodeInfo, 0, sizeof(nodeInfo));
      nodeMax = nodeCount;
      error = msg_mon_get_node_info(&nodeCount, nodeMax, nodeInfo);
      CMPASSERT(error == 0);

      for (Int32 i = 0; i < nodeCount; i++)
      {
        if (nodeInfo[i].spare_node)
          continue;

        // The zone type must either be an aggregation node or storage node
        // to be included in the list of CPUs.
        if ((nodeInfo[i].type & MS_Mon_ZoneType_Aggregation) != 0 ||
            ((nodeInfo[i].type & MS_Mon_ZoneType_Storage) != 0 ))
        {
          cpuArray_.insertAt(cpuArray_.entries(),
                             nodeInfo[i].nid);

          // store nodeName-nodeId pairs
          NAString *key_nodeName = new (heap_) NAString(nodeInfo[i].node_name, heap_);
          size_t pos = key_nodeName->index('.');
          if (pos && pos != NA_NPOS)
            key_nodeName->remove(pos);
#ifdef _DEBUG
          else {
             // The node names for virtual nodes seen with workstations are of
             // format <nodeName>:0, <nodeName>:1 etc. In debug mode, we work with
             // such node names by removing all substrings starting at ':' and 
             // insert the node name into the nodeIdToNodeNameMap_.
             pos = key_nodeName->index(':');
             if (pos && pos != NA_NPOS)
               key_nodeName->remove(pos);
          }
#endif

          Int32 *val_nodeId = new Int32(nodeInfo[i].nid);
          nodeNameToNodeIdMap_->insert(key_nodeName, val_nodeId);

          // store nodeId->nadeName 
          //share the same memory with nodeNameToNodeIdMap_
          nodeIdToNodeNameMap_->insert(val_nodeId, key_nodeName);
        }
      }

      NADELETEBASIC(nodeInfo, heap);

      break;
    }
    case OptimizerSimulator::SIMULATE:

      nodeIdToNodeNameMap_ = NULL;
      cpuArray_.clear();
      //load NAClusterInfo from OSIM file
      simulateNAClusterInfo();
      break;
    default:
      // The OSIM must run under OFF (normal), CAPTURE or SIMULATE mode.
      OSIM_errorMessage("Invalid OSIM mode - It must be OFF or CAPTURE or SIMULATE.");
      break;
  }
} // NAClusterInfo::NAClusterInfo()