#include "hashtable.h"
#include "hashtypes.h"
#include "groupcomm.h"

/* Log Management */
#define FATAL_GROUPCOMM
#define ERROR_GROUPCOMM
//#define INFO_GROUPCOMM
//#define WARN_GROUPCOMM
//#define DEBUG_GROUPCOMM
//#define DEBUG_GROUPCOMM_SEND
//#define DEBUG_GROUPCOMM_SENDSIZE
//#define DEBUG_GROUPCOMM_HASH
//#define DEBUG_GROUPCOMM_COMMIT
//#define MAX_COMMIT 100000
//#define DEBUG_GROUPCOMM_STATS

// i/o
#include <stdio.h>

// JM Milan
#include <string.h>

// system imports
#include <sys/time.h>
#include <sys/utsname.h>

#include "fillHash.h"
#include "tools.h"
#include "stat.h"
/************************/
/*                      */
/*       Hash Table     */
/*                      */
/************************/
void procFillHash (T_Mess);
void procInit (Opt_M);
void SendUnicastToThread (char *, hot_uint32, hot_uint32, hot_endpt_t, hot_uint32);
void responseToThread (int, char *, hot_uint32, hot_uint32, bool, hot_endpt_t);

/*****************************************************************************/
int cast_count_commit = 0; //TODO quitar
int cast_count_to = 0; //TODO quitar
int cast_count_connection = 0; //TODO quitar

/******** Order statistics     **********/
/*void PrintOrderStats() {
int tid, i, j, lastopt, f, t;
int ok=0, ko=0, lost=0;
long time, new_time, n;

  lastopt=0;
  /*
  printf("TOTAL\n");
  for (i=100;i<idx[TOTAL];i++)
    printf("%d,", disorder[TOTAL][i]);
  printf("\nFIFO\n");
  for (i=100;i<idx[FIFO];i++)
    printf("%d,", disorder[FIFO][i]);
  printf("\n");
  */
/*  for (lastopt=0;lastopt<idx[FIFO]
                 && disorder[FIFO][lastopt]!=disorder[TOTAL][WARMUP];lastopt++) {
  } // for j
  for (i=WARMUP;i<idx[TOTAL] && i<idx[FIFO];i++) {
    // is the corresponding opt before the last opt?
    for (j=0;j<lastopt && disorder[FIFO][j]!=disorder[TOTAL][i];j++) {
    } // for j
    // if so, it is misordered
    if (disorder[FIFO][j]==disorder[TOTAL][i]) {
      ko++;
    }
    else {
      // is the corresponding opt after the last opt?
      for (j=lastopt;j<idx[FIFO]
                     && disorder[FIFO][j]!=disorder[TOTAL][i];j++) {
      } // for j
      // if so, it is ordered
      if (disorder[FIFO][j]==disorder[TOTAL][i]) {
        lastopt=j;
        ok++;
      } else
        // otherwise the opt message has been lost
	lost++;
    }
  } //for i


  /*time = 0;
  for (tid=0;tid<(WARMUP+WARMUP/2+N_TXN)*100;tid++) {
    // if this tid has been processed and it is not a warmup tid
    if ((arrival_s[TOTAL][tid] > 0) &&(arrival_s[FIFO][tid] > 0)) {
      #ifdef DEBUG_GROUPCOMM
        printf("opt %d %d and to %d %d\n",
          arrival_s[FIFO][tid], arrival_us[FIFO][tid],
          arrival_s[TOTAL][tid], arrival_us[TOTAL][tid]);
        printf("opt-to: %d us\n",
          (arrival_s[TOTAL][tid]-arrival_s[FIFO][tid])*1000000L
          +(arrival_us[TOTAL][tid]-arrival_us[FIFO][tid]));
      #endif
      new_time = (arrival_s[TOTAL][tid]-arrival_s[FIFO][tid])*1000000L
	+(arrival_us[TOTAL][tid]-arrival_us[FIFO][tid]);
      if ((new_time > 0) && (new_time <30000))
         time+= new_time;
      n++;
    } //if
  } //for
  #ifdef DEBUG_GROUPCOMM
    printf("inorder = %d msg, disorder = %d msg, lost = %d\n", ok, ko, lost);
    printf("inorder = %f %%, disorder = %f %%, lost = %f %%\n", ok*100.0/(ok+ko+lost), ko*100.0/(ok+ko+lost),
      lost*100.0/(ok+ko+lost));
    printf("avg time (us) opt-to %d\n", time/n);
  #endif
  PrintAborts();*/
//}


/******** operations over context_state and view **********/
//int getRank (


/******** Multicast operations **********/
// 270603
void
MulticastCommit(char* writeset, hot_uint32 writeset_length, char* response, hot_uint32 response_length, hot_uint32 recordsUpdates, hot_uint32 tid, hot_uint32 thId) {
  // TO DO: check writeset type
  hot_err_t err;
  hot_msg_t msg;
  hot_uint32 type=COMMIT;
  int i;
  struct timeval tp1, tp2;

  // create msg
  msg = hot_msg_Create();

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) MulticastCommit fill the msg\n");
#endif

//printf("MulticastCommit writeset of %d bytes\n", writeset_length);

  // fill the msg in
  // writeset
  err=hot_msg_Write(msg, writeset, writeset_length);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) writeset\n");
#endif

  // response
  err=hot_msg_Write(msg, response, response_length);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) response\n");
#endif

  // recordsUpdates
  err = hot_msg_WriteUint32(msg, &response_length);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));


  // recordsUpdates
  err = hot_msg_WriteUint32(msg, &recordsUpdates);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) recordsUpdates\n");
#endif

  // tid
  err = hot_msg_WriteUint32(msg, &tid);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) tid\n");
#endif

  // 270603. thId
  err=hot_msg_WriteUint32(msg, &thId);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  //type
  err=hot_msg_WriteUint32(msg, &type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) casting commit message\n");
#endif
  // multicast the message
#ifdef WRITESET_FIFO
  //err = hot_ens_Cast(contexts[FIFO].gctx, msg, NULL);
#else
  err = hot_ens_Cast(contexts[TOTAL].gctx, msg, NULL);
#endif


  // free msg resources
  err = hot_msg_Release(&msg);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) Exit MulticastCommit\n");
#endif

  //gettimeofday(&tp1, NULL);
  //if (arrival_s[FIFO][tid]!=0)
  //    printf("%d,", (tp1.tv_sec-arrival_s[FIFO][tid])*1000L+(tp1.tv_usec-arrival_us[FIFO][tid])/1000L);
} // MulticasCommit

void
SendReply(hot_endpt_t endpoint, char* result) {
  hot_err_t err;
  hot_msg_t msg;
  hot_uint32 type=REPLY;

  // create msg
  msg = hot_msg_Create();

  // fill the msg in
  // result
  err=hot_msg_Write(msg, result, strlen(result));
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  //type
  err=hot_msg_WriteUint32(msg, &type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  // send the message
#ifdef DEBUG_GROUPCOMM
  printf("(GroupComm) Send Reply\n");
#endif
  err = hot_ens_Send(contexts[TOTAL].gctx, &endpoint, msg, NULL);

  // free msg resources
  err = hot_msg_Release(&msg);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
} // SendReply


/******** Group Communication Callbacks *******/
void exit_cb(
        hot_gctx_t gctx,
        void *env
) {}

void block(
        hot_gctx_t gctx,
	void *env)
{}


void receive_cast(
        hot_gctx_t gctx,
        void *env,
        hot_endpt_t *origin,
        hot_msg_t msg) {

  hot_err_t err;
  char contents [MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];         // message contents
  unsigned pos = 0;
  unsigned pos_response = 0;
  unsigned pos_writeset = 0;
  T_Mess message;
  To_M to_mess;
  int i = 0;
  hot_uint32 u = 0;
  char buf[MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];
  struct timeval tp1, tp2;
  // dcadena
  hot_uint32 thId = 0, idConnection = 0, idPetition = 0;
  hot_uint32 socket = 0, sockConnection = 0;
  char databaseName[MAXDBNAME /*+ EXTRASIZE - RMEXTRASIZE*/];
  struct itemhPetition *found = NULL;
  struct itemhOrderFifo *itemOrderFifo = NULL;
  struct itemhOrderTotal *itemOrderTotal = NULL;

#ifdef DEBUG_GROUPCOMM_STATS
   struct timeval time;  
#endif

  #ifdef DEBUG_GROUPCOMM
    printf("(GroupComm) message received (multicast)-----------------------------\n");
  #endif
  //decSemaphore (&mutex_deli);

  /* Process msg */
  /* Get message type */
  err= hot_msg_ReadUint32(msg, &message.type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  #ifdef DEBUG_GROUPCOMM
    printf("(GroupComm) type = %d\n", message.type);
  #endif

  if ((message.type == OPT) || (message.type == TO)) {

    /* idConnection */
    err = hot_msg_ReadUint32(msg, &message.opt.idConnection);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

	decSemaphore(& nconn_mutex);
    if (message.opt.idConnection > numConnection) {
      if (numConnection == 65535 /* (the number of aux. ports on a TCP/IP system) */) {
        numConnection = 0;
      } else { numConnection++; }
    }
	incSemaphore(& nconn_mutex);
	
    /* idPetition */
    err = hot_msg_ReadUint32(msg, &message.opt.idPetition);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* typeSQL */
    err=hot_msg_Read(msg, &message.opt.trans.typeSQL, 1);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* Read the thread id */
    err = hot_msg_ReadUint32(msg, &message.opt.mclientId);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* isQuery */
    err= hot_msg_ReadUint32(msg, &message.opt.trans.isQuery);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* noCC */
    err= hot_msg_ReadUint32(msg, &message.opt.trans.noCC);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* transCC */
    message.opt.trans.transCC = (hot_uint32 *) malloc (sizeof(hot_uint32) * message.opt.trans.noCC);
    for (i=0;i<message.opt.trans.noCC;i++) {
      err= hot_msg_ReadUint32(msg, &message.opt.trans.transCC[i]);
      if (err != HOT_OK)
        hot_sys_Panic(hot_err_ErrString(err));

      #ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) transCC[%d] = %d\n", i, message.opt.trans.transCC[i]);
      #endif
    }

    /* tid */
    err= hot_msg_ReadUint32(msg, &message.opt.trans.tid);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

	/* dbname */
	err= hot_msg_ReadUint32(msg, (hot_uint32 *)&pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
      
	err=hot_msg_Read(msg, message.opt.trans.dbname, pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    
    message.opt.trans.dbname[pos]=0;
      
    /* sqlcode */
    err=hot_msg_GetPos(msg, &pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    err=hot_msg_Read(msg, message.opt.trans.sqlcode, pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    message.opt.trans.sqlcode[pos]=0;

    /* endpoint */
    strcpy(message.opt.trans.endpoint.name, origin->name);

#ifdef DEBUG_GROUPCOMM_STATS
   //struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);   
   if ((message.opt.idPetition == 0) || (message.opt.idPetition == 1)){ //Conection and SET datastyle
      SETSTARTTIME(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);   
   }
   SETFINISHTIME(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);
   //printf("GETTIME CHECK GROUPCOMM<%ld> <%ld> <%d|%d|%d> <%s>\n", (steps[0][message.opt.idConnection][message.opt.idPetition]).startTime.tv_sec, (steps[0][message.opt.idConnection][message.opt.idPetition]).startTime.tv_usec, 0, message.opt.idConnection, message.opt.idPetition, message.opt.trans.sqlcode);  	        
   SETSTARTTIME(1, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);
   //(steps[1][idConnection][idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[1][idConnection][idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[1][idConnection][idPetition]).inUse = 1;
#endif

    if (message.type == OPT) {
    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) kind = OPT\n");
      printf("(GroupComm) idConnection = %d\n", message.opt.idConnection);
      printf("(GroupComm) idPetition = %d\n", message.opt.idPetition);
      printf("(GroupComm) typeSQL = %c\n", message.opt.trans.typeSQL);
      printf("(GroupComm) isQuery(1) = %d\n", message.opt.trans.isQuery);
      printf("(GroupComm) noCC = %d\n", message.opt.trans.noCC);
      printf("(GroupComm) tid = %d\n", message.opt.trans.tid);
      printf("(GroupComm) sqlcode = <%s>\n", message.opt.trans.sqlcode);
      printf("(GroupComm) endpoint1 = %s\n", message.opt.trans.endpoint.name);
    #endif

      //order[FIFO][message.opt.trans.tid]=1;
      itemOrderFifo = (struct itemhOrderFifo*) malloc (sizeof(struct itemhOrderFifo));
      itemOrderFifo->tid = message.opt.trans.tid;
      #ifdef DEBUG_GROUPCOMM_HASH
        printf("(HASHTABLE) Table <hOrderFifo> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", itemOrderFifo->tid, __FILE__, __LINE__);
      #endif
      if (!insert_hashtable(&hOrderFifo, &itemOrderFifo->tid, itemOrderFifo)) {
        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) ERROR : inserting in table hash hOrderFifo\n");
        #endif
      }
      /*
      gettimeofday(&tp1, NULL);
      arrival_s[FIFO][message.opt.trans.tid]=tp1.tv_sec;
      arrival_us[FIFO][message.opt.trans.tid]=tp1.tv_usec;
      */
      message.opt.qmId = -1;
      Opt_Delivery(message.opt);

      procFillHash (message);

      /*disorder[FIFO][idx[FIFO]++]=message.opt.trans.tid;*/
      //if (order[TOTAL][message.opt.trans.tid]) {
      i = message.opt.trans.tid;
      #ifdef DEBUG_GROUPCOMM_HASH
        printf("(HASHTABLE) Table <hOrderTotal> Operation <hash_lookup> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
      #endif
      if ((itemOrderTotal = (struct itemhOrderTotal*)get_hashtable(&hOrderTotal, &i)) != NULL) {
        // the to-delivery arrived before the opt-delivery
        // to-deliver the message too
        #ifdef DEBUG_GROUPCOMM_HASH
          printf("(HASHTABLE) Table <hOrderTotal> Operation <hash_remove> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
        #endif
        delete_hashtable(&hOrderTotal, &i);
        to_mess.type = TO;
        to_mess.tid = message.opt.trans.tid;
        to_mess.mclientId = message.opt.mclientId;
        strcpy(to_mess.endpoint.name, origin->name);
        To_Delivery(to_mess);
        /*disorder[TOTAL][idx[TOTAL]++]=message.opt.trans.tid;*/
      }
    } // if OPT

    /////////////////////////////////

    else if (message.type == TO) {
#ifdef DEBUG_GROUPCOMM_COMMIT
      cast_count_to++;
#endif

      #ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) kind = TO\n");
        printf("(GroupComm) idConnection = %d\n", message.opt.idConnection);
        printf("(GroupComm) idPetition = %d\n", message.opt.idPetition);
        printf("(GroupComm) typeSQL = %c\n", message.opt.trans.typeSQL);
        printf("(GroupComm) thId = %d\n", message.opt.thId);
        printf("(GroupComm) isQuery(2) = %d\n", message.opt.trans.isQuery);
        printf("(GroupComm) noCC = %d\n", message.opt.trans.noCC);
        printf("(GroupComm) tid = %d\n", message.opt.trans.tid);
        printf("(GroupComm) sqlcode = <%s>\n", message.opt.trans.sqlcode);
        printf("(GroupComm) endpoint2 = %s\n", message.opt.trans.endpoint.name);
      #endif

      //hot_sema_Dec(mutex_deli);
      decSemaphore (&mutex_deli);

      #ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) mutex TO tid = %d\n", message.opt.trans.tid);
      #endif

      // only to-deliver when the message has been opt-delivered before
      // 151003
      //order[TOTAL][message.opt.trans.tid]=1;
      itemOrderTotal = (struct itemhOrderTotal*) malloc (sizeof (struct itemhOrderTotal));
      itemOrderTotal->tid = message.opt.trans.tid;
      #ifdef DEBUG_GROUPCOMM_HASH
        printf("(HASHTABLE) Table <hOrderTotal> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", itemOrderTotal->tid, __FILE__, __LINE__);
      #endif
      if (!insert_hashtable(&hOrderTotal, &itemOrderTotal->tid, itemOrderTotal)) {
        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) ERROR : inserting in table hash hOrderTotal\n");
        #endif
      }
      /*
      gettimeofday(&tp1, NULL);
      arrival_s[TOTAL][message.opt.trans.tid]=tp1.tv_sec;
      arrival_us[TOTAL][message.opt.trans.tid]=tp1.tv_usec;
      disorder[TOTAL][idx[TOTAL]++]=message.opt.trans.tid;
      */
      // 151003
      //if (!order[FIFO][message.opt.trans.tid]) {
      i = message.opt.trans.tid;
      #ifdef DEBUG_GROUPCOMM_HASH
        printf("(HASHTABLE) Table <hOrderFifo> Operation <hash_lookup> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
      #endif
      if ((itemOrderFifo = (struct itemhOrderFifo *)get_hashtable(&hOrderFifo, &i)) == NULL) {
        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) to %d arrived before opt. Opt_deliver\n", message.opt.trans.tid);
        #endif

        // dcadena
        message.opt.qmId = -1;
        Opt_Delivery(message.opt);
        procFillHash (message);

      } //if
      else {
        #ifdef DEBUG_GROUPCOMM_HASH
          printf("(HASHTABLE) Table <hOrderFifo> Operation <hash_remove> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
        #endif
        delete_hashtable(&hOrderFifo, &i);
      }

      // to-deliver the message
      to_mess.type = TO;
      to_mess.tid = message.opt.trans.tid;
      // 250603
      to_mess.mclientId = message.opt.mclientId;
      strcpy(to_mess.endpoint.name, message.opt.trans.endpoint.name);
      To_Delivery(to_mess);
      #ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) end mutex TO tid = %d\n", message.opt.trans.tid);
      #endif

      //hot_sema_Inc(mutex_deli);
      incSemaphore(&mutex_deli);
      //tos_received++;
      // 151003
      /*if (tos_received == WARMUP+WARMUP+N_TXN) {
        PrintOrderStats();
        printf("(GroupComm)opts = %d, tos = %d \n %%opts = %d%%\n",
               opts_received, tos_received,
               opts_received*100/tos_received);
        PrintAborts();
      }
      */

    } //if TO
  } //if (OPT || TO)
  //////////////////
  else if (message.type == COMMIT) {
    //TODO quitar
#ifdef DEBUG_GROUPCOMM_COMMIT
    cast_count_commit++;
    /*
    if (cast_count_commit > (MAX_COMMIT-3)){
      printf("----------------------------------------------------------->Received %d COMMIT\n", cast_count_commit);
    }*/
#endif

    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) kind = COMMIT\n");
    #endif
    // tid
    // 270603
    err= hot_msg_ReadUint32(msg, &message.commit.mclientId);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    #ifdef DEBUG_GROUPCOMM
      printf ("(GroupComm) thId %d\n", message.commit.mclientId);
    #endif

    err= hot_msg_ReadUint32(msg, &message.commit.tid);
    // 151003
    /*if (message.commit.tid >= (WARMUP*2+N_TXN)*100+99) {
      printf("(GroupComm) tid received out of bounds %d\n", message.commit.tid);
      exit(1);
    }
    */
    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) tid = %d\n", message.commit.tid);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    err= hot_msg_ReadUint32(msg, &message.commit.recordsUpdates);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) recordsUpdates = %d\n", message.commit.recordsUpdates);
    #endif

    err= hot_msg_ReadUint32(msg, &message.commit.response_length);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) response_length = %d\n", message.commit.response_length);
    #endif

    err=hot_msg_Read(msg, message.commit.response, message.commit.response_length);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    // writeset, writeset_length
    err=hot_msg_GetPos(msg, &pos_writeset);
    message.commit.writeset_length=pos_writeset;
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    err=hot_msg_Read(msg, message.commit.writeset, message.commit.writeset_length);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    strcpy(message.commit.endpoint.name, origin->name);
    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) endpoint3 = %s\n", message.commit.endpoint.name);
    #endif
    Commit_Delivery(message.commit);
  } //if COMMIT

  /**************/
  /* CONNECTION */
  /**************/
  else if (message.type == CONNECTION) {
#ifdef DEBUG_GROUPCOMM_COMMIT
    cast_count_connection++;
#endif

    /* Read idConnection */
    err= hot_msg_ReadUint32(msg, &idConnection);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* Read socket of the message */
    err = hot_msg_ReadUint32(msg, &sockConnection);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    /* databaseName */
    err=hot_msg_GetPos(msg, &pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    err=hot_msg_Read(msg, databaseName, pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    databaseName[pos]=0;

    #ifdef DEBUG_GROUPCOMM
      printf ("(GroupComm) idConnection = %d\n", idConnection);
      printf ("(GroupComm) databaseName = %s\n", databaseName);
      printf ("(GroupComm) origin->name = %s\n", origin->name);
      printf ("(GroupComm) my_name = %s\n", my_name);
    #endif
	
	insertCONPetition(idConnection, /*idPetition*/ 0, -1, 0, 0, 0, CON_RESPONSE/*stp*/);	
	
    // 211003
    i = (idConnection * MAX_PETITION_PER_CLIENT) + 0;   // connection is (idConnection*MAX_PETITION_PER_CLIENT) + 0 in hPetition
    #ifdef DEBUG_GROUPCOMM
      printf ("(GroupComm) find petition %d\n", i);
    #endif
	
    #ifdef DEBUG_GROUPCOMM_HASH
      //printf("-->Reconnection? (HASHTABLE) Table <hPetition> Operation <hash_lookup> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
    #endif
    //if ((found = (struct itemhPetition *)get_hashtable(&hPetition, &i)) != NULL) {
    //  if ((strcmp (origin->name, my_name)) == 0) { //JSalas 14092004
    //    /* reconnection */
    //    thId = 0/* QMID found->thId*/;
    //    //#ifdef DEBUG_GROUPCOMM
    //      printf("(GroupComm) RECONNECTION : Arrancado thread %d\n", thId);
    //      printf("(GroupComm) RECONNECTION : Origen del mensaje : %s\n", origin->name);
    //      printf("(GroupComm) RECONNECTION : Nodo : %s\n", my_name);
    //    //#endif
    //    sockConnectionDriver [thId] = (int) sockConnection;
    //    strcpy (threadInformation[thId], databaseName);
    //    threadIdConnection[thId] = idConnection;
    //
    //    /*
    //    printf("(GroupComm) databaseName = %s\n", threadInformation[thId]);
    //    printf("(GroupComm) socketDriver = %d\n", sockConnectionDriver [thId]);
    //    printf("(GroupComm) threadIdConnection = %d\n", threadIdConnection[thId]);
    //    */
    //    //hot_sema_Inc (semaThreads [thId]);
    //    incSemaphore(&semaThreads[thId]);
    //  }

    //} else {
    /* GET Free Thread */
    if ((strcmp (origin->name, my_name)) == 0) {
#ifdef INFO_GROUPCOMM        
      printf ("(GroupComm) CONNECTION <%d> is LOCAL in Thread <%d>\n", i, thId);        
#endif   
      if ((found = (struct itemhPetition *)get_hashtable(&hPetition, &i)) != NULL) {
#ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) RECONNECTION : Arrancado thread %d\n", thId);
        printf("(GroupComm) RECONNECTION : Origen del mensaje : %s\n", origin->name);
        printf("(GroupComm) RECONNECTION : Nodo : %s\n", my_name);
#endif
      } else {
      	
      }      
      	
      if ((thId = getFreeThread())  == -1) {    
        printf ("(GroupComm) Pool of threads full. Petition rejected\n");
        /* Send error to Driver JDBC */
        bzero(buf, sizeof(buf));
        strcpy (buf, "E Pool of threads full. Request rejected");
        send (sockConnection, buf, sizeof(buf), 0);
        #ifdef DEBUG_GROUPCOMM_SEND
          printf("(GroupComm) (SEND 1) Bytes <%d> Message <%s> (ERROR)\n", sizeof(buf), buf);
        #endif
      
      } else {

#ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) Arrancado thread %d\n", thId);
        printf("(GroupComm) Origen del mensaje : %s\n", origin->name);
        printf("(GroupComm) Nodo : %s\n", my_name);
        printf("(GroupComm) socket Driver for QM%d = %d\n", thId, sockConnection);
#endif
        sockConnectionDriver [thId] = (int) sockConnection;
        bzero(threadInformation[thId], sizeof(threadInformation[thId]));
        strcpy (threadInformation[thId], databaseName);

        //printf("(GroupComm) before threadIdConnection = %d\n", threadIdConnection[thId]);
        threadIdConnection[thId] = 0;

        /*
        printf("(GroupComm) databaseName = %s\n", threadInformation[thId]);
        printf("(GroupComm) socketDriver = %d\n", sockConnectionDriver [thId]);
        printf("(GroupComm) after threadIdConnection = %d\n", threadIdConnection[thId]);
        */
        
        //hot_sema_Inc (semaThreads [thId]);
        incSemaphore(&semaThreads[thId]);
      }
      
    } else {
#ifdef INFO_GROUPCOMM
      printf ("(GroupComm) CONNECTION <%d> is NOT LOCAL\n", i);
#endif
    }        
  } /*else if (message.type == CONNECTION_OK) {
  	if ((strcmp (origin->name, my_name)) == 0) {
  		insertConnectionPetition(idConnection, thId, databaseName);  		
  	} else {
  		
  	}
  }*/
} // receive_cast


void sendInformationToThread (char *contents, hot_uint32 size, hot_uint32 thId, int idConnection) {
  int rval, petition;
  struct itemhPetition *foundPet = NULL;
  
//printf("sendInformationToThread[%d][%d] ... First Char <%c>", idConnection, thId, contents[0]);  
  /* Check change client */
  if (thId == -1){
 	petition = (idConnection * MAX_PETITION_PER_CLIENT) + 0;
#ifdef DEBUG_TRANSMNG
    //printf("(Transmng) save_and_check_Response <%d>\n", petition);
#endif
    if ((foundPet = (struct itemhPetition *) get_hashtable(&hPetition, & petition)) != NULL) {
      thId = foundPet->mclientId;
    } else {
#ifdef FATAL_TRANSMNG
      printf ("NOT Possible found Management Client <%d> in hPetition (FATAL ERROR)\n", petition);
#endif
      exit(0);
    }
  }
  
  #ifdef DEBUG_GROUPCOMM_SENDSIZE
    printf("(GroupComm) (SENDSIZE 1) TO Thread%d Bytes <%d> Message <%s>\n", thId, size, contents);
  #endif
  if((rval=sendWithSize(sockResGC[thId], contents, size))<0) {
    #ifdef ERROR_GROUPCOMM
      printf("(Groupcomm) ERROR sending datas to thread\n");
    #endif
  }
#ifdef DEBUG_GROUPCOMM
  printf ("(Groupcomm) sended response to Thread%d socket %d\n", thId, sockResGC[thId]);
#endif
}

// 061003
void responseToThread (int idConnection, char *contents, hot_uint32 size, hot_uint32 thId, bool local, hot_endpt_t endpoint) {
  if (local) {
    sendInformationToThread (contents, size, thId, idConnection);
  
  } else {
    SendUnicastToThread (contents, size, thId, endpoint, idConnection);
  }
}

void SendUnicastToThread (char *contents, hot_uint32 size, hot_uint32 thId, hot_endpt_t endpoint, hot_uint32 idConnection) {
  hot_err_t err;
  hot_msg_t msg;
  hot_uint32 type=RESPONSE;

  msg = hot_msg_Create();

  err=hot_msg_Write(msg, contents, size);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  // idConnection
  err=hot_msg_WriteUint32(msg, &idConnection);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("idConnection = %d\n", idConnection);
#endif

  // thId
  err=hot_msg_WriteUint32(msg, &thId);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("thId = %d\n", thId);
#endif

  // size
  err=hot_msg_WriteUint32(msg, &size);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("size = %d\n", size);
#endif

  //type
  err=hot_msg_WriteUint32(msg, &type);
#ifdef DEBUG_GROUPCOMM
  printf("type = %d\n", type);
#endif
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("sending response to %s\n", endpoint.name);
#endif

  // send point-to-point the message
  err = hot_ens_Send(contexts[TOTAL].gctx, &endpoint, msg, NULL);
  // free msg resources
  err = hot_msg_Release(&msg);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

} // SendResponseToThread

void receive_send(
        hot_gctx_t gctx,
        void *env,
        hot_endpt_t *origin,
        hot_msg_t msg)
{
  hot_err_t err;
  char contents [MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];         // message contents
  unsigned pos;
  T_Mess message;
  To_M to_mess;
  int i;
  hot_uint32 u, thId, size, socket, idConnection, idPetition;
  char buf[MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];
  struct itemhPetition *found = NULL;

#ifdef DEBUG_GROUPCOMM_STATS
   struct timeval time;
#endif

  #ifdef DEBUG_GROUPCOMM
    printf("(GroupComm) message received (unicast)-----------------------------\n");
  #endif

  // Get message type
  err= hot_msg_ReadUint32(msg, &message.type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  #ifdef DEBUG_GROUPCOMM
    printf("(GroupComm) type = %d\n", message.type);
  #endif

  if (message.type == RESPONSE) {
    err= hot_msg_ReadUint32(msg, &size);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    err= hot_msg_ReadUint32(msg, &thId);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

	err= hot_msg_ReadUint32(msg, &idConnection);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
      
    err=hot_msg_GetPos(msg, &pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    err=hot_msg_Read(msg, buf, pos);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    #ifdef DEBUG_GROUPCOMM
      printf("(GroupComm) kind = RESPONSE\n");
      printf("(GroupComm) size = %d\n", size);
      printf("(GroupComm) thId = %d\n", thId);
      printf("(GroupComm) idConnection = %d\n", idConnection);
      printf("(GroupComm) buffer = %s\n", buf);
    #endif

    /*socket = sockQM[thId];

#ifdef DEBUG_GROUPCOMM
    printf ("(GroupComm) socket = %d\n", socket);
    #endif*/

    // Send message to thread
    /*if((i=sendWithSize(socket, buf, size))<0) {
      printf("(GroupComm) Error sending information to Thread\n");
      exit(0);
      } */
    sendInformationToThread (buf, size, thId, idConnection);
  } // if RESPONSE
  else {
    if (message.type == INIT) {

      /*******************/
      /* FILL TABLE HASH */
      /*******************/
      message.opt.trans.isQuery = 1;
      message.opt.trans.noCC = 0;
      message.opt.qmId = MAXQM;
      // 190903
      message.opt.trans.tid = 0;

      sprintf (&message.opt.trans.sqlcode[0], "%d", INI);

      procInit (message.opt);

      #ifdef DEBUG_GROUPCOMM
        printf("(GroupComm) kind = INIT\n");
        printf("(GroupComm) qmId = %d\n", message.opt.qmId);
        printf("(GroupComm) sqlcode = %s\n", message.opt.trans.sqlcode);
      #endif

    } // INIT
    else {
      if (message.type == QUERY) {

        // 080903
        // idConnection
        err = hot_msg_ReadUint32(msg, &message.opt.idConnection);

		decSemaphore(& nconn_mutex);
        if (message.opt.idConnection > numConnection) {
          if (numConnection == 65535 /* (the number of aux. ports on a TCP/IP system) */) {
            numConnection = 0;
          } else { numConnection++; }
        }
        incSemaphore(& nconn_mutex);
        
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // 100903
        // idPetition
        err = hot_msg_ReadUint32(msg, &message.opt.idPetition);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // dcadena. Read the thread id
        err = hot_msg_ReadUint32(msg, &message.opt.mclientId);

        // isQuery
        err= hot_msg_ReadUint32(msg, &message.opt.trans.isQuery);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // noCC
        err= hot_msg_ReadUint32(msg, &message.opt.trans.noCC);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // transCC
        // 280803
        message.opt.trans.transCC = (hot_uint32 *) malloc (sizeof(hot_uint32) * message.opt.trans.noCC);
        for (i=0;i<message.opt.trans.noCC;i++) {
          err= hot_msg_ReadUint32(msg, &message.opt.trans.transCC[i]);
          if (err != HOT_OK)
            hot_sys_Panic(hot_err_ErrString(err));
        }

        // tid
        err= hot_msg_ReadUint32(msg, &message.opt.trans.tid);
        if (err != HOT_OK)
        hot_sys_Panic(hot_err_ErrString(err));

		/* dbname */
		err= hot_msg_ReadUint32(msg, (hot_uint32 *)&pos);
	    if (err != HOT_OK)
	      hot_sys_Panic(hot_err_ErrString(err));
	      
		err=hot_msg_Read(msg, message.opt.trans.dbname, pos);
	    if (err != HOT_OK)
	      hot_sys_Panic(hot_err_ErrString(err));
	    
	    message.opt.trans.dbname[pos]=0;

        // sqlcode
        err=hot_msg_GetPos(msg, &pos);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        err=hot_msg_Read(msg, message.opt.trans.sqlcode, pos);
        if (err != HOT_OK)
        	hot_sys_Panic(hot_err_ErrString(err));
        message.opt.trans.sqlcode[pos]=0;

        // endpoint
        strcpy(message.opt.trans.endpoint.name, origin->name);

#ifdef DEBUG_GROUPCOMM_STATS
   //struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);
   if ((message.opt.idPetition == 0) || (message.opt.idPetition == 1)){//Conection and SET datastyle
      SETSTARTTIME(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);   
   }
   SETFINISHTIME(0, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);
   SETSTARTTIME(1, message.opt.idConnection, message.opt.idPetition, time.tv_sec, time.tv_usec);   
   //printf("GETTIME CHECK GROUPCOMM QUERY<%ld> <%ld> <%d|%d|%d>\n", (steps[0][message.opt.idConnection][message.opt.idPetition]).startTime.tv_sec, (steps[0][message.opt.idConnection][message.opt.idPetition]).startTime.tv_usec, 0, message.opt.idConnection, message.opt.idPetition);  	        
   //(steps[1][idConnection][idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[1][idConnection][idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[1][idConnection][idPetition]).inUse = 1;
#endif

        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) idConnection = %d\n", message.opt.idConnection);
          printf("(GroupComm) idPetition = %d\n", message.opt.idPetition);
          printf("(GroupComm) thId = %d\n", message.opt.thId);
          printf("(GroupComm) isQuery(3) = %d\n", message.opt.trans.isQuery);
          printf("(GroupComm) noCC = %d\n", message.opt.trans.noCC);
          printf("(GroupComm) transCC[%d] = %d\n", i, message.opt.trans.transCC[i]);
          printf("(GroupComm) tid = %d\n", message.opt.trans.tid);
          printf("(GroupComm) sqlcode = <%s>\n", message.opt.trans.sqlcode);
          printf("(GroupComm) endpoint4 = %s\n", message.opt.trans.endpoint.name);
        #endif

        // to-deliver the message
        to_mess.type = QUERY;
        to_mess.tid = message.opt.trans.tid;
        strcpy(to_mess.endpoint.name, message.opt.trans.endpoint.name);

        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) calling query_delivery\n");
        #endif

        Query_Delivery(message.opt);
        //tos_received++;
      }// if QUERY
      else {
        message.opt.trans.typeSQL = 'S';
        // this can only be a message with a read only query
        // isQuery
        err= hot_msg_ReadUint32(msg, &message.opt.trans.isQuery);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // noCC
        err= hot_msg_ReadUint32(msg, &message.opt.trans.noCC);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        // transCC
        // 280803
        message.opt.trans.transCC = (hot_uint32 *) malloc (sizeof(hot_uint32) * message.opt.trans.noCC);
        for (i=0;i<message.opt.trans.noCC;i++) {
          err= hot_msg_ReadUint32(msg, &message.opt.trans.transCC[i]);
          if (err != HOT_OK)
            hot_sys_Panic(hot_err_ErrString(err));

          #ifdef DEBUG_GROUPCOMM
            printf("(GroupComm) transCC[%d] = %d\n", i, message.opt.trans.transCC[i]);
          #endif
        }

        // tid
        err= hot_msg_ReadUint32(msg, &message.opt.trans.tid);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

		/* dbname */
		err= hot_msg_ReadUint32(msg, (hot_uint32 *)&pos);
	    if (err != HOT_OK)
	      hot_sys_Panic(hot_err_ErrString(err));
	      
		err=hot_msg_Read(msg, message.opt.trans.dbname, pos);
	    if (err != HOT_OK)
	      hot_sys_Panic(hot_err_ErrString(err));
	    
	    message.opt.trans.dbname[pos]=0;
    
        // sqlcode
        err=hot_msg_GetPos(msg, &pos);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));

        err=hot_msg_Read(msg, message.opt.trans.sqlcode, pos);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));
        message.opt.trans.sqlcode[pos]=0;

        // endpoint
        strcpy(message.opt.trans.endpoint.name, origin->name);

        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) isQuery(3) = %d\n", message.opt.trans.isQuery);
          printf("(GroupComm) noCC = %d\n", message.opt.trans.noCC);
          printf("(GroupComm) tid = %d\n", message.opt.trans.tid);
          printf("(GroupComm) sqlcode = <%s>\n", message.opt.trans.sqlcode);
          printf("(GroupComm) endpoint5 = %s\n", message.opt.trans.endpoint.name);
        #endif

        // to-deliver the message
        to_mess.type = QUERY;
        to_mess.tid = message.opt.trans.tid;
        strcpy(to_mess.endpoint.name, message.opt.trans.endpoint.name);

        #ifdef DEBUG_GROUPCOMM
          printf("(GroupComm) calling query_delivery\n");
        #endif
        Query_Delivery(message.opt);
        //tos_received++;
      }
    }
  }
} // receive_send


void assign_masters (struct hashtable hCC, int nmembers) {
  int nCC;
  int i;
  struct itemhCC *item;
  struct iterator_hashtable iter;

#ifdef DEBUG_GROUPCOMM
  printf("ASSIGN MASTERS\n");
#endif

#ifdef DEBUG_GROUPCOMM
  nCC = num_elements_hashtable(&hCC);
  printf ("(GROUPCOMM) Elements in hCC = %d\n", nCC);
#endif

  if(!get_iterator_hashtable(&hCC, &iter, VALUE)) {
#ifdef DEBUG_GROUPCOMM
    printf("(GROUPCOMM) Could not create iterator.");
#endif
  } else {
    while(more_iterator(&iter)) {
      item = (struct itemhCC*) next_iterator(&iter);
      item->master = item->id_CC % nmembers;
#ifdef DEBUG_GROUPCOMM
      printf("(assign_masters) CC = %d  Master = %d\n", item->id_CC, item->master);
#endif
    }
  }
  free_iterator(&hCC, &iter);
}

void accepted_view(
        hot_gctx_t gctx,
	void *env,
	hot_view_state_t *view_state)
{
  context_state *s = (context_state*) env ;
  int size, i, oldmembers;

  // get the number of members of the previous view
  oldmembers = s->vs.nmembers;
  // Release old view
  if (s->vs.members != NULL)
    free(s->vs.members);
  s->vs = *view_state;
  size = sizeof(s->vs.members[0])*s->vs.nmembers ;
  s->vs.members = (hot_endpt_t*) malloc(size) ;
  memcpy(s->vs.members,view_state->members,size) ;

  REAL_MEMBERS = s->vs.nmembers;

  //  if (s->vs.rank == 0)

#ifdef DEBUG_GROUPCOMM
  printf("HOT_TEST:view (nmembers=%d, rank=%d)\n",s->vs.nmembers,s->vs.rank);
  printf("\tview_id = (%d,%s)\n", view_state->view_id.ltime, view_state->view_id.coord.name);
  //  printf("\tversion = \"%s\"\n", view_state->version);
  printf("\tgroup_name = \"%s\"\n", view_state->group_name);
  printf("\tprotocol = \"%s\"\n", view_state->protocol);
  printf("\tmy_rank = %d\n", 	view_state->rank);
  printf("\tmembers = %d\n", view_state->nmembers);
  //  printf("\tgroup daemon is %s\n", view_state->groupd ? "in use" : "not in use");
  //  printf("\tparameters = \"%s\"\n", view_state->params);
  //  printf("\txfer_view = %d\n", view_state->xfer_view);
  //  printf("\tprimary = %d\n", view_state->primary);
#endif

  for (i = 0; i < view_state->nmembers; i++)
//#ifdef DEBUG_GROUPCOMM
    printf("Member[%d] <%s>\n", i, view_state->members[i].name);
//#endif

  // if the view is shrinking, die
  /*if (oldmembers > s->vs.nmembers) {
    printf("View shrinking\n");
    StopQMs();
    //hot_sema_Inc(block_main_sem);
    //incSemaphore(&block_main_sem);
    //hot_thread_Yield();
    //yieldThread();
    exit(0);
  }
  */

  // dcadena 191203
  //view = s->vs;
  if (s->mcast_kind == TOTAL) {
    contexts[TOTAL].vs = s->vs;
  }

  if (begin) {
    if (s->vs.nmembers == INITIAL_MEMBERS) {
      // dcadena 191203
      /*
      // the membership of this group is complete
      complete[s-> mcast_kind]= true;
      // get the rank in the group
      my_rank[s->mcast_kind]= s-> vs.rank;
      if (s->mcast_kind == TOTAL) {
	MY_ID = my_rank[TOTAL];
	// 280803
	//Start(MY_ID,NUM_TOTAL_CC, NUM_LOCAL_CC);
	if (begin) {
	  begin = false;
	  Start(MY_ID);
	}
      }
      */

      // the membership of this group is complete
      contexts[s->mcast_kind].complete = true;
      // get the rank in the group
      if (s->mcast_kind == TOTAL) {
	MY_ID = contexts[TOTAL].vs.rank;
	if (begin) {
	  begin = false;
	  Start(MY_ID);
	}
      }

    }
  }
  else {
//#ifdef DEBUG_GROUPCOMM
    printf ("(GroupComm) a replica has failed\n");
//#endif
    // dcadena 191203
    /*
    // the membership of this group is complete
    complete[s-> mcast_kind]= true;
    // get the rank in the group
    my_rank[s->mcast_kind]= s-> vs.rank;
    if (s->mcast_kind == TOTAL) {
      MY_ID = my_rank[TOTAL];
    }
    */

    // the membership of this group is complete
    contexts[s->mcast_kind].complete = true;
    // get the rank in the group
    if (s->mcast_kind == TOTAL){
      MY_ID = contexts[s->mcast_kind].vs.rank;
      ChangeReplicaID(MY_ID); //JSalas 27072004 Review
    }
    assign_masters (hCC, REAL_MEMBERS);
  }

  /*if (complete[0] && complete[1] && (s->vs.nmembers < MEMBERS))
  {
     printf("View shrinking, exiting\n");
     hot_ens_Leave(gctx);
  }
  */

} // accepted_view


void sender_thread(context_state *s) {

} // sender_thread


void heartbeat(
        hot_gctx_t gctx,
	void *env,
	unsigned time)
{
  context_state *s = (context_state*) env ;


  int ntuples, ntuplesAux;
  char buf_JDBC[10 /*+ EXTRASIZE - RMEXTRASIZE*/];

  // When the memberships on both groups are complete
  //   start a sender thread in the first half of the members
  if (s->vs.nmembers == INITIAL_MEMBERS)
  {
    if  (contexts[TOTAL].complete && contexts[FIFO].complete && !sender) {
#ifdef DEBUG_GROUPCOMM
  printf("Sender\n");
#endif

       bzero(buf_JDBC, sizeof(buf_JDBC));

       ntuples = 199;

       convertToChar (buf_JDBC, 4, 0, ntuples);

       convertToInt (buf_JDBC, 4, &ntuplesAux, 0);

       //hot_thread_Create((void*)sender_thread, s, 0);
       //createThread((void*)sender_thread, s, NULL);
       sender= true;
    }
  }
} // hearbeat

/******** Join ********************************/
void join(enum kind_of_multicast prop) {
  hot_err_t err ;
  context_state *s;
  char *outboard;
  static struct utsname mname;

  s = (context_state *) malloc(sizeof(*s));
  memset(s,0,sizeof(*s));

  s->jops.heartbeat_rate = hb_rate;
  s->jops.argv = NULL; //argv;
  strcpy(s->jops.transports, "DEERING");
  if (prop==TOTAL)
    strcpy(s->jops.group_name, "HOT1Test");
  else
    strcpy(s->jops.group_name, "HOT2Test");
  if (prop == TOTAL)
     strcpy(s->jops.properties, "Gmp:Sync:Total:Heal:Frag:Flow:Slander:Suspect");
  else
     strcpy(s->jops.properties, "Gmp:Sync:Heal:Frag:Flow");
  s->jops.use_properties = 1;
  strcpy(s->jops.params, "suspect_max_idle=20:int;suspect_sweep=10.000:time");
  s->jops.groupd = 0;

  s->jops.conf.receive_cast = receive_cast;
  s->jops.conf.receive_send = receive_send;
  s->jops.conf.accepted_view = accepted_view;
  s->jops.conf.heartbeat = heartbeat;
  s->jops.conf.exit = exit_cb;
  s->jops.conf.block = block;
  s->jops.debug = 0;
  s->jops.client = 0;

  // clients are name with R followed by the node number
  // only one client per node is allowed
  uname(&mname);
  strcpy(my_name, "R");
  strcat(my_name, strtok(mname.nodename, "."));
  strcpy(s-> jops.endpt.name, my_name);

  outboard = (char*) getenv("ENS_OUTBOARD_TYPE") ;
  if (!outboard)
    outboard = "FORK" ;
  strcpy(s->jops.outboard, outboard);

  s->jops.env = s;

  s->mcast_kind = prop;

  // Join the group
  err = hot_ens_Join(&s->jops, &s->gctx);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  // Record the group context
  if (prop == TOTAL)
    contexts[TOTAL] = *s;
  else
    contexts[FIFO] = *s;
}

// 030903
char * discovery () {
  //char numCon[117 /*+ EXTRASIZE - RMEXTRASIZE*/], numMem[114 /*+ EXTRASIZE - RMEXTRASIZE*/], numPort[115 /*+ EXTRASIZE - RMEXTRASIZE*/];
  char numCon[256], numMem[256], numPort[256];
  int i;
  //char ip[1116 /*+ EXTRASIZE - RMEXTRASIZE*/];
  char ip[256];
  T_Mess mes;
  struct hostent *hptr;
  static struct utsname mname;

  uname(&mname);

  hptr = gethostbyname (mname.nodename);
  strcpy (ip, inet_ntoa(*((struct in_addr *)hptr->h_addr)));

  //mes.discovery_m = (char *) malloc (4+1+15+1+5+1+7+1);  // nuMem:ip:port:numConnection

  mes.discovery.type = DISC_RESP;

  itoa (contexts[TOTAL].vs.nmembers, numMem);
  strcpy (mes.discovery.msg, ":");
  strcat (mes.discovery.msg, numMem);
  strcat (mes.discovery.msg, ":");

  strcat (mes.discovery.msg, ip);
  strcat (mes.discovery.msg, ":");

  itoa (PORTPGSERVER, numPort);
  strcat (mes.discovery.msg, numPort);
  strcat (mes.discovery.msg, ":");

  decSemaphore(& nconn_mutex);
  itoa (numConnection, numCon);
  if (numConnection == 65535 /* (the number of aux. ports on a TCP/IP system) */) {
    numConnection = 0;
  } else { numConnection++; }
  incSemaphore(& nconn_mutex);
  
  strcat (mes.discovery.msg, numCon);
  strcat (mes.discovery.msg, ":");

#ifdef DEBUG_GROUPCOMM
  printf ("(GroupComm) Multicast message type = %d\n", mes.discovery.type);
  printf ("(GroupComm) buffer <%s>\n", mes.discovery.msg);
#endif

  SendMC (mes);
}

void copyOpt_M (Opt_M *dest, Opt_M orig) {
  int i;

  dest->mclientId = orig.mclientId;
  dest->type = orig.type;
  dest->trans.noCC = orig.trans.noCC;
  // 280803
  dest->trans.transCC = (hot_uint32 *) malloc (sizeof(hot_uint32)*orig.trans.noCC);
  for (i = 0; i < orig.trans.noCC; i++) {
    dest->trans.transCC[i] = orig.trans.transCC[i];
  }
  strcpy (dest->trans.sqlcode, orig.trans.sqlcode);
  dest->trans.tid = orig.trans.tid;
  dest->trans.endpoint = orig.endpoint;
  dest->trans.isQuery = orig.trans.isQuery;
  dest->endpoint = orig.endpoint;
  dest->trans.typeSQL = orig.trans.typeSQL;
}


/*********** Operations for pgconnection **********/
// 280803 [MAX_CC] por *
void MulticastOptTo(char* contents, hot_uint32 noCC, hot_uint32 *transCC, hot_uint32 type,
                    char typeQuery, hot_uint32 thId, hot_uint32 idConnection, hot_uint32 idPetition, char *dbname) {
  hot_err_t err;
  hot_msg_t msg;
  hot_uint32 tid;
  int i;
  // 030903
  //Opt_M mess;
  T_Mess mess;
  hot_uint32 isQuery;
  static struct utsname mname;
  hot_uint32 ldbname;
  
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) MulticastOptTo typeQuery : %c\n", thId, typeQuery);
  #endif

  if (typeQuery == 'S') {
    isQuery = 1;
  }
  else {
    isQuery = 0;
  }

  // mutex exclusion
  //hot_sema_Dec(mutexSequence);
  decSemaphore(&mutexSequence);
  //tid = sequence*100+view.rank;
  tid = sequence*100+contexts[TOTAL].vs.rank;
  sequence++;
  //hot_sema_Inc(mutexSequence);
  incSemaphore(&mutexSequence);

  if (type==TO) {
    // mutex exclusion JSALAS COMMENT THIS
    //hot_sema_Dec(mutexSequence);
    //decSemaphore(&mutexSequence);
    //sequence++;
    //hot_sema_Inc(mutexSequence);
    //incSemaphore(&mutexSequence);
    // create msg
    msg = hot_msg_Create();

    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) message to be multicast\n", thId);
    #endif
    // fill the msg in
    // only one string is allowed and it must be the first field!!!!!!!
    // sqlcode
    err=hot_msg_Write(msg, contents, strlen(contents));
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    #ifdef DEBUG_GROUPCOMM
      printf("Contest: <%s>\n", contents);
    #endif

	//dbname
	err=hot_msg_Write(msg, dbname, strlen(dbname));
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    #ifdef DEBUG_GROUPCOMM
      printf("dbname: <%s>\n", dbname);
    #endif

	//length dbname
	ldbname = strlen(dbname);
    err=hot_msg_WriteUint32(msg, &ldbname);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) length dbname = %d\n", thId, strlen(dbname));
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    // tid
    err = hot_msg_WriteUint32(msg, &tid);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) tid = %d\n", thId, tid);
    #endif
    // transCC
    // 290803
    if (noCC > 0) {
      for (i=noCC-1;i>=0;i--) {
        err=hot_msg_WriteUint32(msg, &transCC[i]);
        if (err != HOT_OK)
          hot_sys_Panic(hot_err_ErrString(err));
          #ifdef DEBUG_GROUPCOMM
            printf("(Thread%d) transCC[%d] = %d\n", thId, i, transCC[i]);
          #endif
      } // for i
    }
    // noCC
    err=hot_msg_WriteUint32(msg, &noCC);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) noCC = %d\n", thId, noCC);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    // isQuery
    err = hot_msg_WriteUint32(msg, &isQuery);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) pgconnection : isQuery = %d\n", thId, isQuery);
    #endif

    err=hot_msg_WriteUint32(msg, &thId);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) thId que lanza el mensaje = %d\n", thId, thId);
    #endif

    // typeSQL
    err=hot_msg_Write(msg, &typeQuery, 1);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) typeSQL = %c\n", thId, typeQuery);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    // 100903
    // idPetition
    err=hot_msg_WriteUint32(msg, &idPetition);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) idPetition = %d\n", thId, idPetition);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    // 080903
    // idConnection
    err=hot_msg_WriteUint32(msg, &idConnection);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) idConnection = %d\n", thId, idConnection);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    //type
    err=hot_msg_WriteUint32(msg, &type);
    #ifdef DEBUG_GROUPCOMM
      printf("(Thread%d) type = %d\n", thId, type);
    #endif
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));

    // multicast the message

    err = hot_ens_Cast(contexts[TOTAL].gctx, msg, NULL);
    // free msg resources
    err = hot_msg_Release(&msg);
    if (err != HOT_OK)
      hot_sys_Panic(hot_err_ErrString(err));
  } // To
  else
    {
      // ip multicast the message
      // 030903
      mess.type = OPT;
      mess.opt.mclientId=thId;
      mess.opt.type=typeQuery;
      // 080903
      mess.opt.idConnection = idConnection;
      mess.opt.idPetition = idPetition;
      mess.opt.trans.typeSQL = typeQuery;
      mess.opt.trans.isQuery=isQuery;
      mess.opt.trans.noCC=noCC;
      // 290803
      if (noCC > 0) {
        for (i=0;i<noCC;i++)
          mess.opt.trans.transCC[i]=transCC[i];
      }
      strcpy(mess.opt.trans.sqlcode, contents);
      mess.opt.trans.tid = tid;
      uname(&mname);
      sprintf (my_name, "%s", strtok(mname.nodename, "."));
      strcpy(mess.opt.trans.endpoint.name, my_name);
      strcpy(mess.opt.endpoint.name, my_name);
      //printf("(QM%d) sending the multicast \n");
      SendMC(mess);
    } // Opt
} // MulticastOptTo


// 280803 [MAX_CC] por *
char *SendQuery(char *query, hot_uint32 noCC, hot_uint32 *transCC,  hot_uint32 thId,
		char typeQuery, hot_uint32 idConnection, hot_uint32 idPetition, char *dbname) {
  struct timeval tp;
  long time_to_sleep;

#ifdef OPTIMISTIC
  MulticastOptTo(query, noCC, transCC, OPT, typeQuery, thId, idConnection, idPetition, dbname);
#endif
  MulticastOptTo(query, noCC, transCC, TO, typeQuery, thId, idConnection, idPetition, dbname);
#ifndef ASYNC
  //hot_sema_Dec(reply_sem); // client wait for reply
  decSemaphore(&reply_sem);
#endif

} //SendQuery


// 280803 [MAX_CC] por *
void SendQueryUnicast(char* contents, hot_uint32 noCC, hot_uint32 *transCC, hot_uint32 thId,
                      hot_uint32 idConnection, hot_uint32 idPetition, char *dbname) {
  hot_err_t err;
  hot_msg_t msg;
  hot_uint32 type=QUERY;
  hot_uint32 tid;
  int i;
  Opt_M mess;
  hot_uint32 isQuery = 1; // this is a query
  long dest;
  int my_rank;
  hot_uint32 ldbname;
  
  //hot_sema_Dec(mutexSequence);
  decSemaphore(&mutexSequence);
  //tid = sequence*100+view.rank;
  tid = sequence*100+contexts[TOTAL].vs.rank;
  sequence++;
  //hot_sema_Inc(mutexSequence);
  incSemaphore(&mutexSequence);
  // create msg
  msg = hot_msg_Create();

  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) message to be sent by unicast\n", thId);
  #endif
  // fill the msg in
  // Only one string is allowed in ensemble and it must be the first field
  // sqlcode
  err=hot_msg_Write(msg, contents, strlen(contents));
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) sqlcode = <%s>\n", thId, contents);
  #endif
  
 	//dbname
	err=hot_msg_Write(msg, dbname, strlen(dbname));
	if (err != HOT_OK)
	  hot_sys_Panic(hot_err_ErrString(err));
	
	#ifdef DEBUG_GROUPCOMM
	  printf("dbname: <%s>\n", dbname);
	#endif
	
	//length dbname
	ldbname = strlen(dbname);
    err=hot_msg_WriteUint32(msg, &ldbname);	
	#ifdef DEBUG_GROUPCOMM
	  printf("(Thread%d) length dbname = %d\n", thId, strlen(dbname));
	#endif
	if (err != HOT_OK)
	  hot_sys_Panic(hot_err_ErrString(err));
      
  // tid
  err = hot_msg_WriteUint32(msg, &tid);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) tid = %d\n", thId, tid);
  #endif
  // transCC
  // 290803
  if (noCC > 0) {
    for (i=noCC-1;i>=0;i--) {
      err=hot_msg_WriteUint32(msg, &transCC[i]);
      if (err != HOT_OK)
        hot_sys_Panic(hot_err_ErrString(err));
        #ifdef DEBUG_GROUPCOMM
          printf("(Thread%d) transCC[%d] = %d\n", thId, i, transCC[i]);
        #endif
    } // for i
  }
  // noCC
  err=hot_msg_WriteUint32(msg, &noCC);
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) noCC = %d\n", thId, noCC);
  #endif
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  // isQuery
  err = hot_msg_WriteUint32(msg, &isQuery);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) isQuery = %d\n", thId, isQuery);
  #endif

  // Add the thId
  err=hot_msg_WriteUint32(msg, &thId);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) thId = %d\n", thId, thId);
  #endif

  // 100903
  // idPetition
  err=hot_msg_WriteUint32(msg, &idPetition);
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) idPetition = %d\n", thId, idPetition);
  #endif
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  // 080903
  // idConnection
  err=hot_msg_WriteUint32(msg, &idConnection);
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) idConnection = %d\n", thId, idConnection);
  #endif
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  //type
  err=hot_msg_WriteUint32(msg, &type);
  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) type = %d\n", thId, type);
  #endif
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  my_rank = contexts[TOTAL].vs.rank;

  #ifdef DEBUG_GROUPCOMM
    printf("(Thread%d) sending query to %s nmembers %d\n", thId, contexts[TOTAL].vs.members[my_rank].name, contexts[TOTAL].vs.nmembers);
#endif
  // send point-to-point the message
  //err = hot_ens_Send(contexts[TOTAL], &view.members[my_rank[TOTAL]],  msg, NULL);
  err = hot_ens_Send(contexts[TOTAL].gctx, &contexts[TOTAL].vs.members[my_rank], msg, NULL);

  // free msg resources
  err = hot_msg_Release(&msg);

  #ifndef ASYNC
    //hot_sema_Dec(reply_sem); // client wait for reply
    decSemaphore(&reply_sem);
  #endif
} // SendReadOnlyQuery

/*********** Operations for pgserver **********/
void sendMsgInit () {
  hot_uint32 type;
  hot_err_t err;
  hot_msg_t msg;
  int my_rank;

  msg = hot_msg_Create();


  type = INIT;
  err=hot_msg_WriteUint32(msg, &type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) type = %d\n", type);
#endif

  my_rank = contexts[TOTAL].vs.rank;
  err = hot_ens_Send(contexts[TOTAL].gctx, &contexts[TOTAL].vs.members[my_rank],  msg, NULL);
  //err = hot_ens_Cast(contexts[TOTAL], msg, NULL);

  // free msg resources
  err = hot_msg_Release(&msg);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
}

void sendMsgConnection (char *databaseName, hot_uint32 socket, hot_uint32 idConnection) {
  hot_uint32 type;
  hot_err_t err;
  hot_msg_t msg;
  int i;


#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) sendMsgConnection dbName = %s\n", databaseName);
#endif

  // Send multicast connection
  // create msg
  msg = hot_msg_Create();

  // databaseName
  err=hot_msg_Write(msg, databaseName, i);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

  // Add the socketJDBC
  err=hot_msg_WriteUint32(msg, &socket);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) socket = %d\n",socket);
#endif

  // idConnection
  err=hot_msg_WriteUint32(msg, &idConnection);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) idConnection = %d\n", idConnection);
#endif

  //type
  type = CONNECTION;

  err=hot_msg_WriteUint32(msg, &type);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));
#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) type = %d\n", type);
#endif

  // multicast the message
  err = hot_ens_Cast(contexts[TOTAL].gctx, msg, NULL);

  // send unicast message
  //err = hot_ens_Send(contexts[TOTAL], &view.members[my_rank[TOTAL]],  msg, NULL);

  // free msg resources
  err = hot_msg_Release(&msg);
  if (err != HOT_OK)
    hot_sys_Panic(hot_err_ErrString(err));

#ifdef DEBUG_GROUPCOMM
  printf("(pgserver) Sent multicast message\n");
#endif
}
