#include "transmng.h"

// system imports
#include <sys/utsname.h>
// socket support
#include "socku.h"
// i/o
#include <stdio.h>
//#include "list.h"
//#include "commitlist.h"
// QM socket and process support
#include "qmsockets.h"
// Group communication support
#include "groupcomm.h"
#include "qmqueue.h"
// dcadena
// pgserver
#include "pgserver.h"
#include "hashtable.h"
#include "hashtypes.h"
#include "tools.h"
#include "log.h"
#include <signal.h>

#include "qmqueue.h"

#include "stat.h"

/* Log Management */
#define FATAL_TRANSMNG
#define ERROR_TRANSMNG
//#define INFO_TRANSMNG
//#define WARN_TRANSMNG
//#define DEBUG_TRANSMNG
//#define DEBUG_TRANSMNG_ARRAY
//#define DEBUG_TRANSMNG_HASH
//#define DEBUG_FILES_COMMIT
//#define DEBUG_TRANSMNG_COMMIT
//#define DEBUG_FILES_FLAG
//#define DEBUG_FILES_QUEUE
//#define DEBUG_TRANSMNG_STATS NOT DESCOMMENT

log_t log_commit[256];
log_t log_flag_finished[4];
log_t log_queue;

// number of aborts
int n_aborts = 0;
int n_tos = 0;
int n_commits = 0;

extern int cast_count_connection;
extern int cast_count_to;
extern int cast_count_commit;
extern int count_noticommit;

int remote_count_commit = 0; //TODO quitar
int count_commit_qmwsandapply = 0; //TODO quitar
int count_commit_qmcommit = 0; //TODO quitar

extern T_QMQueue_ptr waitingforQM[MAXQM+1];
extern QMState stateQMs[MAXQM+1];
extern T_Dllist_ptr freeConQMs;
extern T_Dllist_ptr freeQMs;

// data of the replica
struct T_Replica {
  int myid; // replica identifier
  //T_List_ptr transactionlist; // list of queued transactions
  struct hashtable transactionlist; // list of queued transactions
  //T_CommitList_ptr commitlist; // list of transactions whose commit has been received
  struct hashtable commitlist; // list of transactions whose commit arrived before to
  semaphore mutex;
}
replica;

// type of messages between replica managers and queue managers
enum messRQ_kind {
  execute_M, commit_M, abort_M
};

// messages between replica managers and queue managers
typedef struct {
  enum messRQ_kind type; // type of message
  T_Transaction * trans; // transaction
}
T_RQMess;

void executeTrans(T_Transaction * transaction);
void commitTrans(T_Transaction * transaction);
void commitTransCDB(T_Transaction * transaction);
void abortTrans(T_Transaction * transaction);
bool isLocal(T_Transaction * transaction);
void executeBlockedTrans(hot_uint32 *, int);
void removeTrans(T_Transaction *);
void freeTrans(T_Transaction **);
void Commit_Delivery(Commit_M);
//void Commit_Delivery_Lock(Commit_M, int lock);
void Commit_Delivery_UnLock(Commit_M);
void printAllQueue();
void printStat();
void postConnectionLock(T_Tid, int, char*);
void postDisconnectLock(T_Tid, int, int, int, char*);

/* ---------- Functions for T_Trans and T_Transaction ---------- */
void InitT_Trans(T_Trans *t_trans){
  //printf("sizeof(t_trans->sqlcode) <%d>\n", sizeof(t_trans->sqlcode));
  bzero(t_trans->sqlcode, sizeof(t_trans->sqlcode));
  bzero(t_trans->dbname, sizeof(t_trans->dbname));
  t_trans->tid = 0;
  bzero(t_trans->endpoint.name, sizeof(t_trans->endpoint.name)); //CHECK THIS
  t_trans->isQuery = 0;
  t_trans->typeSQL = 'N';
  t_trans->noCC = 0;
  t_trans->transCC = NULL;
}

void CloneT_Trans(T_Trans *dest, T_Trans *orig){
  int sizeCC = 0, i = 0;

  dest->noCC = orig->noCC;

  sizeCC = sizeof(hot_uint32) * dest->noCC;
  if (!(dest->transCC = (hot_uint32 *) malloc(sizeCC))) {
#ifdef FATAL_TRANSMNG
    printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
    exit(0);
  }
  for (i = 0; i < dest->noCC; i++) {
    dest->transCC[i] = orig->transCC[i];
  }

  memcpy(dest->sqlcode, orig->sqlcode, sizeof(char) * MAX_TXT);
  memcpy(dest->dbname, orig->dbname, sizeof(char) * MAX_TXT);
  dest->tid = orig->tid;

  strcpy(dest->endpoint.name, orig->endpoint.name);
  dest->isQuery = orig->isQuery;
  dest->typeSQL = orig->typeSQL;

#ifdef DEBUG_TRANSMNG
  printf("\nCopy T_Trans\n");
  printf("hot_uint32 noCC <%d>;\n", dest->transaction.noCC);
  printf("hot_uint32 *transCC;\n");
  for (i = 0; i < dest->transaction.noCC; i++) {
    printf("transCC[%d] = %d;\n", i, dest->transaction.transCC[i]);
  }
  printf("char sqlcode <%s>;\n", dest->transaction.sqlcode);
  printf("T_Tid tid <%d>;\n", dest->transaction.tid);
  printf("hot_endpt_t endpoint name <%s>;\n", dest->transaction.endpoint.name);
  printf("hot_uint32 isQuery <%d>;\n", dest->transaction.isQuery);
  printf("char typeSQL <%c>;\n", dest->transaction.typeSQL);
#endif

  return;
}

void AssignT_Trans(T_Trans *dest, T_Trans *orig){
  int sizeCC = 0, i = 0;

  dest->noCC = orig->noCC;
  dest->transCC = orig->transCC;

  memcpy(dest->sqlcode, orig->sqlcode, sizeof(char) * MAX_TXT);
  memcpy(dest->dbname, orig->dbname, sizeof(char) * MAX_TXT);
  dest->tid = orig->tid;

  strcpy(dest->endpoint.name, orig->endpoint.name);
  dest->isQuery = orig->isQuery;
  dest->typeSQL = orig->typeSQL;

#ifdef DEBUG_TRANSMNG
  printf("\nCopy T_Trans\n");
  printf("hot_uint32 noCC <%d>;\n", dest->transaction.noCC);
  printf("hot_uint32 *transCC;\n");
  for (i = 0; i < dest->transaction.noCC; i++) {
    printf("transCC[%d] = %d;\n", i, dest->transaction.transCC[i]);
  }
  printf("char sqlcode <%s>;\n", dest->transaction.sqlcode);
  printf("T_Tid tid <%d>;\n", dest->transaction.tid);
  printf("hot_endpt_t endpoint name <%s>;\n", dest->transaction.endpoint.name);
  printf("hot_uint32 isQuery <%d>;\n", dest->transaction.isQuery);
  printf("char typeSQL <%c>;\n", dest->transaction.typeSQL);
#endif

  return;
}

void resetT_Trans(T_Trans ** transaction) {
  Free((*transaction)->transCC);
  (*transaction)->noCC = 0;
}

void InitT_Transaction(T_Transaction *t_trans){
  t_trans->local = 0;
  t_trans->executedByAll = 0;
  t_trans->localNode = 0;
  t_trans->finished = 0;
  t_trans->committable = 0;
  t_trans->executing = 0;
  t_trans->aborting = 0;
  t_trans->committing = 0;
  t_trans->commitreceived = 0;
  t_trans->writeset_length = 0;

  t_trans->response_length = 0;
  bzero(t_trans->response, sizeof(t_trans->response));

  //T_writeset writeset;
  t_trans->qmId = -1;
  t_trans->mclientId = -1;
  t_trans->idConnection = 0;
  t_trans->idPetition = 0;
  t_trans->recordsUpdates = 0;
  t_trans->error = 0;

  t_trans->conns.early = 0;
  t_trans->conns.connection_petition_id = 0;
  strcpy(t_trans->conns.dbname, "");

  InitT_Trans(&t_trans->transaction);
}

void cloneT_Transaction(T_Transaction *dest, T_Transaction *orig){
  dest->local = orig->local;
  dest->executedByAll = orig->executedByAll;
  dest->localNode = orig->localNode;
  dest->finished = orig->finished;
  dest->committable = orig->committable;
  dest->executing = orig->executing;
  dest->aborting = orig->aborting;
  dest->committing = orig->committing;
  dest->commitreceived = orig->commitreceived;
  dest->writeset_length = orig->writeset_length;
  memcpy(dest->writeset, orig->writeset, orig->writeset_length);

  dest->response_length = orig->response_length;
  memcpy(dest->response, orig->response, orig->response_length);

  dest->qmId = orig->qmId;
  dest->mclientId = orig->mclientId;
  dest->idConnection = orig->idConnection;
  dest->idPetition = orig->idPetition;
  dest->recordsUpdates = orig->recordsUpdates;
  dest->error = orig->error;

  dest->conns.early = orig->conns.early;
  dest->conns.connection_petition_id = orig->conns.connection_petition_id;
  strcpy(dest->conns.dbname, orig->conns.dbname);

  CloneT_Trans(&dest->transaction, &orig->transaction);
}

void AssignT_Transaction(T_Transaction *dest, T_Transaction *orig){
  dest->local = orig->local;
  dest->executedByAll = orig->executedByAll;
  dest->localNode = orig->localNode;
  dest->finished = orig->finished;
  dest->committable = orig->committable;
  dest->executing = orig->executing;
  dest->aborting = orig->aborting;
  dest->committing = orig->committing;
  dest->commitreceived = orig->commitreceived;
  dest->writeset_length = orig->writeset_length;
  memcpy(dest->writeset, orig->writeset, orig->writeset_length);

  dest->response_length = orig->response_length;
  memcpy(dest->response, orig->response, orig->response_length);

  dest->qmId = orig->qmId;
  dest->mclientId = orig->mclientId;
  dest->idConnection = orig->idConnection;
  dest->idPetition = orig->idPetition;
  dest->recordsUpdates = orig->recordsUpdates;
  dest->error = orig->error;

  dest->conns.early = orig->conns.early;
  dest->conns.connection_petition_id = orig->conns.connection_petition_id;
  strcpy(dest->conns.dbname, orig->conns.dbname);

  AssignT_Trans(&dest->transaction, &orig->transaction);
}

void freeT_Transaction(T_Transaction ** transaction) {
  /*
  T_Trans *t_trans;
  T_Transaction *transact;
  transact = *transaction;
  t_trans = &transact->transaction;
  resetT_Trans(&t_trans);
  */
  Free((*transaction)->transaction.transCC);
  /*
  if ((*transaction)->transaction.noCC != 0){
    free((*transaction)->transaction.transCC);
    (*transaction)->transaction.transCC = NULL;
  }*/
  Free(*transaction);
}

/*void UpdateEarlyDisconnectQMMessage(int idConnection, earlyDisconnect *orig){
	struct itemhPetition *foundPet = NULL;
	int petition;
	
	decSemaphore(& replica.mutex);
	petition = (idConnection * MAX_PETITION_PER_CLIENT) + 0;
	if ((foundPet = (struct itemhPetition *) get_hashtable(&hPetition, & petition)) != NULL) {
		AssignEarlyDisconnect(foundPet->early, orig);
	} else {
		printf("UpdateQMMessageEarlyDisconnect ERROR hPetition NOT FOUND ");
	}
	incSemaphore(& replica.mutex);
}*/

/* ---------- Functions for T_Trans and T_Transaction ---------- */
void save_and_check_Response(T_Transaction * transaction){
  struct itemhPetition *foundPet = NULL;
  int petition = 0;
  int stp = -1;

//printf("voy <%d>\n", transaction->mclientId);
  //if (((int)transaction->mclientId) >= 0){
//printf("voy 1<%d>\n", transaction->mclientId);
    decSemaphore(& semaConnections[0/* TODO transaction->mclientId*/]);
//printf("voy 2<%d>\n", transaction->mclientId);    
//  }
//printf("voy 3<%d>\n", transaction->mclientId);
  petition = (transaction->idConnection * MAX_PETITION_PER_CLIENT) + 0/*transaction->idPetition*/;
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) save_and_check_Response <%d>\n", petition);
#endif

  if (((foundPet = (struct itemhPetition *) get_hashtable(&hPetition, & petition)) != NULL) && (foundPet->last.id_petition == transaction->idPetition)){
    //if (foundPet->recordsUpdates != -1) {
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) Petition %d is received\n", petition);
#endif
    /* Save response */
    foundPet->last.recordsUpdates = transaction->recordsUpdates;
    foundPet->last.response_length = transaction->response_length;
    if (!(foundPet->last.response = (char *) malloc(sizeof(char) * (transaction->response_length + EOF_SIZE)))) {
#ifdef FATAL_TRANSMNG
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
    }
    memcpy(foundPet->last.response, transaction->response, transaction->response_length);

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) Save response <%d> <%d>\n", transaction->qid, petition);
#endif

    sscanf(&transaction->transaction.sqlcode[0], "%d", &stp);
    if ((stp != CDB) && ((transaction->localNode) || (foundPet->last.is_change_nodelocal_new == 1)) && (foundPet->last.is_change_nodelocal_old == 0)) {
    	int i;
      char buf_JDBC[TAMBUFFER /*+ EXTRASIZE - RMEXTRASIZE*/];
      int tamBuffer, numFields;

      foundPet->last.is_sendtodriver=1;

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) sendInformationToThread\n", transaction->mclientId, petition);

	  printf("TRANSMNG RESPONSE: ");
	  for (i=0; i<TAMBUFFERJDBC;i++){
		printf("%c", transaction->response[i]);
		if (i == transaction->response_length){
			printf("|");
		}
	  }printf("\n");
#endif
//printf("sendInformationToThread mclientId <%d>\n", transaction->mclientId);	  	   
	  sendInformationToThread (transaction->response, transaction->response_length, transaction->mclientId, transaction->idConnection);	  
//printf("sendInformationToThread OK\n");	  
      if (transaction->response[0] != 'E'){
      	//printf("!!!!!!!!!!!!!!!!!!!!!!!!Response Trans: <%s>\n", transaction->response);
      	bzero (buf_JDBC, sizeof(buf_JDBC));
      	buf_JDBC [0] = 'T';
      	tamBuffer = 1;

      	// fields number
      	// QM
      	// Receive field information
      	numFields = 0;
      	convertToChar (buf_JDBC, sizeof(int), 1, numFields);
      	tamBuffer += sizeof(int);
      	sendInformationToThread (buf_JDBC, tamBuffer, transaction->mclientId, transaction->idConnection);
      } else {
      	//printf("!!!!!!!!!!!!!!!!!!!!!!!!Error Response Trans: <%s>\n", transaction->response);
      } 	
    }
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) save_and_check_Response\n", transaction->qid, petition);
#endif

  } else {
    //TODO puede que no sea error y que sea simplemente que ha llegado una nueva peticion por lo que ya no necesitaremos esta informacion
#ifdef WARN_TRANSMNG
    printf("(WARN_TRANSMNG) Not found petition <%d> in hPetition\n", petition);
#endif
  }
  //if (((int)transaction->mclientId) >= 0){
//printf("FALLO");  	
    incSemaphore(& semaConnections[0/*TODO transaction->mclientId*/]);
  //}
//printf("OK");  
}

/*int insertConnectionPetition(int idConnection, int mclientId, char *dbname){  
  struct itemhClient *client = NULL;

  // Introduce petition in hPetition
  client = (struct itemhClient *) malloc (sizeof(struct itemhClient));
  client->id = idConnection;
  client->mclientId = mclientId;
  //client->last_petition_executed = (idConnection * MAX_PETITION_PER_CLIENT) + 0;
  memcpy(&client->dbname, dbname, MAXDBNAME);
  
#ifdef DEBUG_TRANSMNG_HASH
  printf("(HASHTABLE) Table <hPetition> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", petition->id, __FILE__, __LINE__);
#endif

  if (!insert_hashtable(&hClient, &client->id, client)) {
#ifdef ERROR_TRANSMNG
    printf("(Transmng) ERROR in table hash hClient to add connection %d\n", client->id);
#endif
  }
#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Inserted connection %d in hClient. Elements of hPetition : %d\n", client->id, num_elements_hashtable(&hClient));
#endif
}*/

int insertNextPetition(int thId, int idConnection, int idPetition, int recUpd, int is_sendtodriver,
                       int is_change_nodelocal_new, int is_change_nodelocal_old, int stp){
  int previous = 0;
  struct itemhPetition *petition = NULL;
  int pet_connection = 0;
  
  pet_connection = (idConnection * MAX_PETITION_PER_CLIENT) + 0;
  if ((petition = (struct itemhPetition *)get_hashtable(&hPetition, &pet_connection)) != NULL) {
  	
    // Introduce petition in hPetition
    //petition = (struct itemhPetition *) malloc (sizeof(struct itemhPetition));
    //petition->id = (idConnection * MAX_PETITION_PER_CLIENT) + idPetition;
    //petition->num_connection = idConnection;
    petition->last.id_petition = idPetition;
    petition->mclientId = thId;

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) insertNextPetition <%d>\n", petition->id);
#endif

    //TODO puede ser que no se necesite
    /*
    if (transaction->noCC > 0) {
      petition->queueCC = petition->transCC[0];
    } else {
      petition->queueCC = 0;
    }
    */
    if (petition->last.response != NULL){
  	  free(petition->last.response);
  	  petition->last.response = NULL;
    }
    petition->last.response_length = 0;
    petition->last.recordsUpdates = recUpd;
    petition->last.is_sendtodriver = is_sendtodriver;
    petition->last.is_change_nodelocal_new = is_change_nodelocal_new;
    petition->last.is_change_nodelocal_old = is_change_nodelocal_old;
    //petition->state = state;

    if (stp == CON_RESPONSE){//TODO se puede inicializar a todos         	  	   		
	  petition->discon.idConnection = idConnection;
	  petition->discon.idPetition = idPetition;
	  petition->discon.last_petition = petition->id;
	  petition->discon.isfirst_petition = 2;
	  petition->discon.is_delay_disconnect = 0;
	  petition->discon.backup_stp = DISCON_RESPONSE;
	  petition->discon.tid = -1;  	
    }
    
    if ((stp != EARLY_DISCON) && (stp != DISCON_RESPONSE)){    	
    	petition->discon.last_received = (idConnection * MAX_PETITION_PER_CLIENT) + idPetition;
    	//printf("Last Received <%d>\n", petition->discon.last_received);
    }
  }else{
#ifdef ERROR_TRANSMNG
    printf("ERROR[insertNextPetition]: Connection Petition <%d> NOT FOUND \n", pet_connection);
#endif
  }
//#ifdef DEBUG_TRANSMNG_HASH
    //printf("(HASHTABLE) Table <hPetition> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", petition->id, __FILE__, __LINE__);
//#endif

//  if (!insert_hashtable(&hPetition, &petition->id, petition)) {
//#ifdef ERROR_TRANSMNG
//    printf("(Transmng) ERROR in table hash hPetition to add connection %d and petition %d\n", petition->num_connection,
//         petition->num_petition);
//#endif
//  }
//#ifdef DEBUG_TRANSMNG
//  printf("(Transmng) Inserted connection %d petition %d in hPetition. Elements of hPetition : %d\n", petition->num_connection,
//       petition->num_petition, num_elements_hashtable(&hPetition));
//#endif

  /* Remove previous petition, except connection petition */
//  previous = idPetition - 1;
//#ifdef DEBUG_TRANSMNG_HASH
//  printf("(Transmng) if (previous > 0) <%d> -> idConnection <%d> idPetition <%d>\n", previous, idConnection, idPetition);
//#endif
//  if (previous > 0) {
    //previous = ((idConnection * MAX_PETITION_PER_CLIENT) + idPetition) - 1;
    //previous = last_update_petition[thId];//PNF
//    if (delete_hashtable(& hPetition, & previous) == 0) {
//    	printf("1 (QMSOCKETS) Petition %d not found TYPE<> SQLCODE<%d>\n", previous, num_elements_hashtable(& hPetition));

//#ifdef DEBUG_TRANSMNG_HASH
//	}else{
//      printf("(Transmng) Previous Petition %d deleted %d inserted %d thId\n", previous, ((idConnection * MAX_PETITION_PER_CLIENT) + idPetition), thId);

    //} else {
    //  printf("(Transmng) HashTable Petition number of elements <%d>\n", num_elements_hashtable(& hPetition));
//#endif
//    }
//  }else{
//  	printf("(QMSOCKETS) Connection Petition %d has not been DELETE\n", ((idConnection * MAX_PETITION_PER_CLIENT) + idPetition));
//  }
  //last_update_petition[thId] = (idConnection * MAX_PETITION_PER_CLIENT) + idPetition;
}

int insertCONPetition(int idConnection, int idPetition, int recUpd, int is_sendtodriver,
                       int is_change_nodelocal_new, int is_change_nodelocal_old, int stp){
  int previous = 0;
  struct itemhPetition *petition = NULL;
 
  // Introduce petition in hPetition
  petition = (struct itemhPetition *) malloc (sizeof(struct itemhPetition));
  petition->id = (idConnection * MAX_PETITION_PER_CLIENT) + idPetition;
  petition->num_connection = idConnection;
  petition->num_petition = idPetition;
  petition->mclientId = -1;

  petition->last.response = NULL;
  petition->last.response_length = 0;
  petition->last.recordsUpdates = recUpd;
  petition->last.is_sendtodriver = is_sendtodriver;
  petition->last.is_change_nodelocal_new = is_change_nodelocal_new;
  petition->last.is_change_nodelocal_old = is_change_nodelocal_old;
  //petition->state = state;

  if (stp == CON_RESPONSE){//TODO se puede inicializar a todos         	  	   		
	petition->discon.idConnection = idConnection;
	petition->discon.idPetition = idPetition;
	petition->discon.last_petition = petition->id;
	petition->discon.isfirst_petition = 2;
	petition->discon.is_delay_disconnect = 0;
	petition->discon.backup_stp = DISCON_RESPONSE;
	petition->discon.tid = -1;  	
  }
  
#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hPetition> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", petition->id, __FILE__, __LINE__);
#endif

  if (!insert_hashtable(&hPetition, &petition->id, petition)) {
#ifdef ERROR_TRANSMNG
    printf("(Transmng) ERROR in table hash hPetition to add connection %d and petition %d\n", petition->num_connection,
         petition->num_petition);
#endif
  }
//#ifdef DEBUG_TRANSMNG
  //Oprintf("DEBUG[insertCONPetition] Connection petition <%d> is INSERTED [%d, %d]\n", petition->id, idConnection, idPetition);
//#endif  
//#ifdef DEBUG_TRANSMNG
  //printf("(Transmng) Inserted connection %d petition %d in hPetition. Elements of hPetition : %d\n", petition->num_connection,
  //     petition->num_petition, num_elements_hashtable(&hPetition));
//#endif

  /* Remove previous petition, except connection petition */
  //last_update_petition[thId] = (idConnection * MAX_PETITION_PER_CLIENT) + idPetition;
}

void CheckWaitingForQM(T_QMQueue_ptr waitingforQM, int qid){
  T_Transaction* trans;
  QM_message *mess = NULL;
#ifdef DEBUG_FILES_QUEUE
  char buffer_log[2048];
#endif

#ifdef DEBUG_FILES_QUEUE
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "INI CheckWaitingForQM <%d>\n", qid);
  write_in_log_qmqueue(&log_queue, buffer_log);
#endif

  /* Begin Critical section */
  //decSemaphore(& replica.mutex);
  //printf("4 Message to <%d> is empty tid <%d>\n", qid, trans->transaction.tid);
  if (!QMQ_isEmpty(waitingforQM)) {
        /* Assign QM to transaction */
    #ifdef WARN_QMSOCKETS
      printf("\n The queue is not empty\n\n");
    #endif

    trans = QMQ_getFirst(waitingforQM);
    mess = QMQ_getFirstQM_message(waitingforQM);
    //printf("3 Message to <%d> priority tid <%d>\n", qid, trans->transaction.tid);
    SendMessageToQMPriority(trans, mess, 1);
    //SendMessageToQM(trans, mess); //TODO send message not protection with semaphore replica.mutex
  }

#ifdef DEBUG_FILES_QUEUE
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "END CheckWaitingForQM <%d>\n", qid);
  write_in_log_qmqueue(&log_queue, buffer_log);
#endif

  //incSemaphore(& replica.mutex);
  /* End Critical section */
}

void setFreeConQM(int stateId){
  struct itemhDBConns *found = NULL;
//printf("setFreeConQM 1\n");  
  if (stateQMs[stateId].linkstatequeue == NULL){
//printf("setFreeConQM 2\n");  	
  	found = (struct itemhDBConns *)get_hashtable(&hDBConns, stateQMs[stateId].dbname);     	
//printf("setFreeConQM 3\n");  	
	if (found == NULL){
//printf("setFreeConQM 4\n");		
		stateQMs[stateId].state = FREE;
//printf("setFreeConQM 5\n");		
  		Dllist_enqueue(freeQMs, stateQMs[stateId].token);
//printf("setFreeConQM 6\n");  		
  		stateQMs[stateId].token = NULL;
//printf("setFreeConQM 7\n");  		
  		return;
	} else {
//printf("setFreeConQM 8\n");		
		stateQMs[stateId].linkstatequeue = found->reuseQM;
//printf("setFreeConQM 9\n");		
	}
  }
  
  if (stateQMs[stateId].linkstate != NULL){
//printf("setFreeConQM 10\n");  	
  	Dllist_enqueue(stateQMs[stateId].linkstatequeue, stateQMs[stateId].linkstate);   	
  
  }else{
//printf("setFreeConQM 11\n");  	
  	QMStateLink *link;
//printf("setFreeConQM 12\n");  	
  	if (found == NULL){
//printf("setFreeConQM 13\n");  		
  		found = (struct itemhDBConns *)get_hashtable(&hDBConns, stateQMs[stateId].dbname);
//printf("setFreeConQM 14\n");  		
  		if (found == NULL){
//printf("setFreeConQM 15\n");  			
			stateQMs[stateId].state = FREE;
//printf("setFreeConQM 16\n");			
  			Dllist_enqueue(freeQMs, stateQMs[stateId].token);
//printf("setFreeConQM 17\n");  			
  			stateQMs[stateId].token = NULL;
//printf("setFreeConQM 18\n");  			
  			return;
		}
  	}
//printf("setFreeConQM 19\n");  	
  	link = (QMStateLink *) malloc (sizeof(QMStateLink));
//printf("setFreeConQM 20\n");
  	link->stateId = stateId;
//printf("setFreeConQM 21\n");
    link->item = found;
//printf("setFreeConQM 22\n");
  	Dllist_insert(stateQMs[stateId].linkstatequeue, link);
//printf("setFreeConQM 23\n");  	
  }
//printf("setFreeConQM 24\n");  
  stateQMs[stateId].state = FREECON;
//printf("setFreeConQM 25\n");
//  if (stateQMs[stateId].token == NULL){printf("NNNNNNNNNNNNNNNUUUUUUUUUUUUULLLLLLLLLLLLLLLLLLLLLL\n");}
  Dllist_enqueue(freeConQMs, stateQMs[stateId].token);
//printf("setFreeConQM 26\n");  
  //stateQMs[stateId].token = NULL;
//printf("setFreeConQM 27\n");  
}

void FreeQMBlock(int qid) {
#ifdef DEBUG_FILES_QUEUE
  char buffer_log[2048];
#endif
  //Begin Critical section
  decSemaphore(&replica.mutex);
  decSemaphore(&QM_mutex); //Seguramente sobre, replica.mutex es más restrictivo

#ifdef DEBUG_FILES_QUEUE
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "INI Free QM <%d>\n", qid);
  write_in_log_qmqueue(&log_queue, buffer_log);
#endif

  if (stateQMs[qid].state == FREE) {
    printf("error releasing QM%d that is already free\n", qid);
    //exit(1);
  }
  // Warning :

  // The QM must be marked as free
  // even if a message is taken from
  // the queue, as sendmessagetoqm will
  // search for a free slot
  setFreeConQM(qid);    
  
  //Exist transaction waiting for QM?
  CheckWaitingForQM(waitingforQM[0 /*QMID qid*/], qid);

#ifdef DEBUG_FILES_QUEUE
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "END Free QM <%d>\n", qid);
  write_in_log_qmqueue(&log_queue, buffer_log);
#endif

  incSemaphore(&QM_mutex);
  incSemaphore(& replica.mutex);
  // End Critical section
}

void freeTrans(T_Transaction ** transaction) {
  //freeT_Transaction(transaction);
  Free((*transaction)->transaction.transCC);
  Free(*transaction);
}

void pgserver_thread() {
  StartServer();
}

void PrintAborts() {
  printf("(Transmng) Total aborts = %d\n", n_aborts);
}

void ChangeReplicaID(int sid){
  replica.myid = sid;
}

void Start(int sid) {
  int i, sock, newsock;
  char server[MAXSERVERPATH /*+ EXTRASIZE - RMEXTRASIZE*/];
  static struct utsname node_name;
  char *nodename = NULL;

  if (TYPECLIENT != 0) {
    /* Starting pgserver */
    createThread((void *) pgserver_thread, NULL, NULL);
  }

  uname(& node_name);
  nodename = strtok(node_name.nodename, ".");
  strcpy(server, getcwd(NULL, MAXSERVERPATH - (1 + strlen(nodename) + 1 + EOF_SIZE)));
  strcat(server, "/");
  strcat(server, nodename);
  strcat(server, "b");

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Starting socket response thread, server = %s\n", server);
#endif

  /* Create socket */
  sock = sockcreate(server);
  if (sock == -1) {
#ifdef FATAL_TRANSMNG
    printf("(Transmng) Impossible create socket (FATAL ERROR) -> Message ");
    perror("");
#endif
    exit(-1);
  }

  /* JSalas Sobra? 13 de Julio de 2004 En el siguiente bucle se inicializan */
  for (i = 0; i < MAXCLIENTS; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY
    printf("Iterator %d, SizeArray %d\n", i, (sizeof(sockResGC)/sizeof(int)));
    if (i >= (sizeof(sockResGC)/sizeof(int))) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s  Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif
    sockResGC[i] = 0;
  }

  for (i = 0; i < MAXCLIENTS/*MAXQM*/; i++) {
    /* accept connections */
    newsock = sockaccept(sock);
#ifdef DEBUG_TRANSMNG_ARRAY
    printf("Iterator %d, SizeArray %d\n", i, (sizeof(sockResGC)/sizeof(int)));
    if (i >= (sizeof(sockResGC)/sizeof(int))) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif
    sockResGC[i] = newsock;
  }

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Starting replica  manager %d\n", sid);
#endif

  replica.myid = sid;

  /* Create list of transactions */
  //replica.transactionlist = L_createlist();
  if(!init_hashtable(&replica.transactionlist, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  //replica.commitlist = CL_createlist();
  if(!init_hashtable(&replica.commitlist, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  /* Initiliaze mutex */
  createSemaphore(1, & replica.mutex);

  /* Create QM processes, sockets and notification processing thread */
  StartQMs();
}

void Query_Delivery(Opt_M msg) {
  int i;
  T_Transaction * trans;
  struct itemhCC * item;

/*#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   setFinishTimeArray(0, msg.idConnection, msg.idPetition, time);
   SETSTARTTIME(1, msg.idConnection, msg.idPetition, time);
#endif*/

  /* Begin Critical section */
  decSemaphore(& replica.mutex); //MOVE TO TOP

  trans = (T_Transaction *) malloc(sizeof(T_Transaction));
  InitT_Transaction(trans);

  AssignT_Trans(&trans->transaction, &msg.trans);

  trans->qmId = -1;
  trans->mclientId = msg.mclientId;
  trans->idConnection = msg.idConnection;
  trans->idPetition = msg.idPetition;

  trans->error = 0;

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) msg.trans.tid = %d\n", msg.trans.tid);
  printf("(Transmng) Executing QUERY %d \n", trans->transaction.tid);
#endif

  /* Mark the transaction as active and committable. */
  trans->committable = 1;
  trans->finished = 0;
  trans->executing = 0;

  /* queries are always local */
  trans->local = 1;
  trans->localNode = 1;

#ifdef DEBUG_TRANSMNG
  printf("--------- Query_Delivery----------\n");
#endif

  /* Begin Critical section */
  //decSemaphore(& replica.mutex); //MOVE TO TOP
  //replica.transactionlist = L_insertInOrder(replica.transactionlist, trans);
  if (!insert_hashtable(&replica.transactionlist, &trans->transaction.tid, trans)) {
#ifdef WARN_TRANSMNG
      printf("(Transmng) Not possible insert Transaction in HashTable\n");
#endif
  }

  // append the transaction to all its conflict class queues
  // and try to execute it, if it is local
  for (i = 0; i < trans->transaction.noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
    printf("Iterator %d, SizeArray %d\n", i, sizeof(trans->transaction.transCC));
    if (i >= sizeof(trans->transaction.transCC)) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", trans->transaction.transCC[i], __FILE__, __LINE__);
#endif

    if ((item = get_hashtable(&hCC, &trans->transaction.transCC[i])) == NULL){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", trans->transaction.transCC[i], __FILE__, __LINE__);
      exit(0);
#endif
    }

#ifdef DEBUG_TRANSMNG
    Q_print(item->queue);
#endif
    Q_insertQuery(item->queue, trans);
#ifdef DEBUG_TRANSMNG
    Q_print(item->queue);
#endif
  }

  if (isFirst(trans)) {
    /* Execute a transaction when it is the first in all queues and local or query */
    executeTrans(trans);
  }

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End Query_Delivery----------\n");
#endif
}

void Opt_Delivery(Opt_M msg) {
  int i, stp, idItem;
  T_Transaction * trans;
  struct itemhCC * item;

/*#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   setFinishTimeArray(0, msg.idConnection, msg.idPetition, time);
   SETSTARTTIME(1, msg.idConnection, msg.idPetition, time);
#endif*/

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Executing OPT %d %d\n", msg.trans.tid, msg.thId);
#endif

  /* Begin Critical section */
  decSemaphore(& replica.mutex); //MOVE TO TOP
  
  trans = (T_Transaction *) malloc(sizeof(T_Transaction));
  InitT_Transaction(trans);

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) mem. alloc trans \n");
#endif

  /* JSalas 27082004 */
  AssignT_Trans(&trans->transaction, &msg.trans);

#ifdef DEBUG_TRANSMNG
  printf("\nCopy T_Trans\n");
  printf("hot_uint32 noCC <%d>;\n", trans->transaction.noCC);
  printf("hot_uint32 *transCC;\n");
  for (i = 0; i < trans->transaction.noCC; i++) {
    printf("transCC[%d] = %d;\n", i, trans->transaction.transCC[i]);
  }
  printf("char sqlcode <%s>;\n", &trans->transaction.sqlcode[3]);
  printf("T_Tid tid <%d>;\n", trans->transaction.tid);
  printf("hot_endpt_t endpoint name <%s>;\n", trans->transaction.endpoint.name);
  printf("hot_uint32 isQuery <%d>;\n", trans->transaction.isQuery);
  printf("char typeSQL <%c>;\n", trans->transaction.typeSQL);
#endif

  trans->error = 0;

  /* mark the transaction as active and pending. */
  trans->committable = 0;
  trans->finished = 0;
  trans->executing = 0;
  trans->aborting = 0;
  trans->committing = 0;

  trans->qmId = msg.qmId;  
  
  trans->idConnection = msg.idConnection;
  trans->idPetition = msg.idPetition;
  sscanf(& trans->transaction.sqlcode[0], "%d", & stp);
  //printf("int stp <%d>;\n", stp);

  if ((stp == CDB) || 
      (stp == CON) || (stp == CON_RESPONSE) || (stp == RECON) || (stp == RECON_RESPONSE) ||
      (stp == DISCON) || (stp == DISCON_RESPONSE) || (stp == EARLY_DISCON)) {
    trans->executedByAll = 1;

  } else { trans->executedByAll = 0; }

  /* JSalas 27082004 */
  if (trans->transaction.noCC > 0){
    idItem = trans->transaction.transCC[0];
  } else {
    idItem = 0;
  }

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
#endif

  if ((item = (struct itemhCC *)get_hashtable(&hCC, &idItem)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
#endif
    exit(0);
  }

  trans->local = (item->master == replica.myid);
  
  if (strcmp(trans->transaction.endpoint.name, my_name) == 0) {
    trans->localNode = 1;  
  } else { trans->localNode = 0; }
  
  /* Failover */
  if (trans->localNode){
  	trans->mclientId = msg.mclientId;

  }else{
  	trans->mclientId = -1;    
  }
  
  /* Mark petition how received in hPetition */  
  if ((msg.qmId != MAXQM) && (stp != CON) && (stp != CON_RESPONSE)){
  	insertNextPetition(trans->mclientId, msg.idConnection, msg.idPetition, -1, 0, 0, 0, stp);
  /*}else{
  	if (msg.qmId == MAXQM){
  	  printf("MAXQM NOT Insert petition <%d> <%d>\n", msg.idConnection, msg.idPetition);
  	} else {  		
	  	if (stp == CON){
	  	  printf("CON NOT Insert petition <%d> <%d>\n", msg.idConnection, msg.idPetition);
	  	}else if (stp == CON_RESPONSE){
	  	  printf("CON_RESPONSE NOT Insert petition <%d> <%d>\n", msg.idConnection, msg.idPetition);
	  	}
  	}*/
  }
  
  //printf("MSG THID %d, TRANS THID %d\n", msg.mclientId, trans->mclientId);
  
#ifdef DEBUG_TRANSMNG
  printf("(Transmng) master = %d\n", item->master);
  printf("(Transmng) myid = %d\n", replica.myid);
  printf("(Transmng) local = %d\n", trans->local);
  printf("(Transmng) localNode = %d\n", trans->localNode);
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Opt_Delivery----------\n");
#endif

  /* Begin Critical section */
  //decSemaphore(& replica.mutex); //MOVE TO TOP

  if (msg.qmId != (MAXQM)) {
    //printf("msg.thId != (MAXQM)\n");
    //printf("insert_hashtable(&replica.transactionlist, %d, trans)", trans->transaction.tid);
    //replica.transactionlist = L_insertInOrder(replica.transactionlist, trans);
    if (!insert_hashtable(&replica.transactionlist, &trans->transaction.tid, trans)) {
#ifdef WARN_TRANSMNG
      printf("(Transmng) Not possible insert Transaction in HashTable\n");
#endif
    }

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) insert trans in list\n");
    printf("(Transmng) transaction.noCC = %d\n", trans->transaction.noCC);
#endif

    // Append the transaction to all its conflict class queues
    // and try to execute it, if it is local
    for (i = 0; i < trans->transaction.noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
      printf("Iterator %d, SizeArray %d\n", i, sizeof(trans->transaction.transCC));
      if (i >= sizeof(trans->transaction.transCC)) {
        printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
        exit(0);
      }
#endif

      idItem = trans->transaction.transCC[i];

#ifdef DEBUG_TRANSMNG_HASH
      printf("(HASHTABLE) Table <hCC> Operation <hash_lookup> Key <%d> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
#endif
      if ((item = (struct itemhCC *)get_hashtable(&hCC, &idItem)) == NULL) {
#ifdef FATAL_TRANSMNG
        printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
        exit(0);
#endif
      }

#ifdef DEBUG_TRANSMNG
      Q_print(item->queue); printf("(Transmng) inserting in queue %d \n", trans->transaction.transCC[i]);
#endif
      Q_insert(item->queue, trans);
#ifdef DEBUG_TRANSMNG
      Q_print(item->queue);
#endif
    }

#ifdef DEBUG_TRANSMNG
    if (trans->local)
      printf("(Transmng) local \n");
    else
      printf("(Transmng) remote\n");
#endif

    if (((trans->local) || (trans->executedByAll)) && isFirst(trans)) {
      /* execute a transaction when it is the first in all queues and local or query */
      executeTrans(trans);
    }

  } else { /* Executed by QMSpecial */
    //printf("msg.thId == (MAXQM)\n");
    executeTrans(trans);
//printf ("%s:%d freeTrans IN\n", __FILE__, __LINE__ );
    //freeTrans(&trans); TODO quitar cuando regrese de QMSpecial listatransaccionesQMSpecial
//printf ("%s:%d freeTrans OUT\n", __FILE__, __LINE__ );
  }
  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Opt_Delivery----------\n");
#endif
}

int to_to = 0; //TODO Quitar
//int to_commit_before = 0; //TODO Quitar
void To_Delivery(To_M msg) {
  T_Mess * commitMsg;
  T_Transaction * transaction;
  T_Transaction * trans;
  int i, idItem;
  struct itemhCC * item;
  Commit_M *commit_msg;
  int stp;

#ifdef DEBUG_TRANSMNG
  printf("--------- To_Delivery---------- <%d><%d>\n", msg.tid/*++to_to*/, msg.thId);
#endif

  /* Begin Critical section */
  decSemaphore(& replica.mutex);
  n_tos++;
  //if (msg.thId != (MAXQM)) {
  /* Mark the transaction as committable */
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &msg.tid)) == NULL){
  //transaction = L_getTransaction(replica.transactionlist, msg.tid);
  //if (transaction == NULL) {
#ifdef FATAL_TRANSMNG
    printf("(Transmng) Transaction %d do not exist in transactionList (FATAL ERROR)\n", msg.tid);
#endif
#ifdef DEBUG_TRANSMNG
    printf("--------- End_To_Delivery --------\n");
#endif

    incSemaphore(& replica.mutex);
    /* End Critical section */

    //exit(0);
    return;
  }

  transaction->committable = 1;
  transaction->error = 0;

  if (transaction->finished){
    sscanf(& transaction->transaction.sqlcode[0], "%d", & stp);
    if (/*(stp == CON) ||*/ (stp == CON_RESPONSE)){
      postConnectionLock(transaction->transaction.tid, 0, transaction->conns.dbname);
      incSemaphore(& replica.mutex);
      /* End Critical section */
      return;

    } else if (/*(stp == DISCON) ||*/ (stp == DISCON_RESPONSE) || (stp == EARLY_DISCON)){
      //printf("1 postDisconnectLock\n");
      postDisconnectLock(transaction->transaction.tid, transaction->conns.early, transaction->conns.connection_petition_id, 0, transaction->conns.dbname);
      incSemaphore(& replica.mutex);
      /* End Critical section */
      return;
    }
  }

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Executing TO %d \n", msg.tid);
#endif

  if (transaction->finished && isFirst(transaction)) {
    int stp;
    /* The transaction is executed (Local or remotely). */
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) the transaction is already executed \n");
#endif

    //TODO QMID transaction->qid = msg.thId;

    sscanf(& transaction->transaction.sqlcode[0], "%d", & stp);
    if (stp == CDB){
      commitTransCDB(transaction);//TODO commitTransCDB
    }else{
      commitTrans(transaction);
    }

  } else { // still active
    for (i = 0; i < transaction->transaction.noCC; i++) {
      // If a transaction is pending, local and executing, abort it
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
      printf("Iterator %d, SizeArray %d\n", i, sizeof(transaction->transaction.transCC));
      if (i >= sizeof(transaction->transaction.transCC)) {
        printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
        exit(0);
      }
#endif

      idItem = transaction->transaction.transCC[i];
#ifdef DEBUG_TRANSMNG_HASH
      printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
#endif

      if ((item = (struct itemhCC *)get_hashtable(&hCC, &idItem)) == NULL){
#ifdef FATAL_TRANSMNG
        printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
        exit(0);
#endif
      }

      if (!Q_isEmpty(item->queue)) {
        trans = Q_getFirst(item->queue);
        if (((trans->local) || (trans->executedByAll)) && !(trans->committable) && (trans->executing)) {
#ifdef DEBUG_TRANSMNG
          printf("(Transmng) abort transaction not to delivered\n");
#endif
          //TODO QMID trans->qid = msg.thId;
          abortTrans(trans);
        } //if
      } //if

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) reschedule the transaction %d\n", transaction->transaction.tid);
#endif
      Q_reschedule(item->queue, transaction->transaction.tid);
    } // for
  } // if

  if ((commit_msg = (Commit_M *)remove_hashtable(&replica.commitlist, &msg.tid)) != NULL){
  //if (CL_isIn(replica.commitlist, msg.tid)) {
    //T_CommitList_ptr commit_msg = NULL;

    //////// Now transactions whose commit arrives early are just discarded
    //////// The ws should be stored and applied here
  #ifdef WARN_TRANSMNG
    printf("(Transmng) Transaction <%d>: To arrived after Commit -> Apply Commit\n", msg.tid);
  #endif

    //commit_msg = CL_removeByID(replica.commitlist, msg.tid);
    Commit_Delivery_UnLock(*commit_msg);
    Free(commit_msg);
  #ifdef DEBUG_TRANSMNG
    printf("--------- End_To_Delivery --------\n");
  #endif

    //incSemaphore(& replica.mutex);
    /* End Critical section */
    //return;
  } // if

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_To_Delivery --------\n");
#endif
}

void Init_Delivery(Opt_M msg) {
  T_Transaction * trans = NULL;

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Executing INIT\n");
#endif
  /* Begin Critical section */
  decSemaphore(& replica.mutex);

  trans = (T_Transaction *) malloc(sizeof(T_Transaction));
  InitT_Transaction(trans);

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) mem. alloc trans \n");
#endif

  AssignT_Trans(&trans->transaction, &msg.trans);

  trans->error = 0;

  /* mark the transaction as active and pending. */
  trans->committable = 0;
  trans->finished = 0;
  trans->executing = 0;
  trans->aborting = 0;
  trans->committing = 0;

  trans->qmId = msg.qmId;
  trans->mclientId = -1;
  
  /* The procedure INIT is always local */
  trans->local = 1;
  trans->executedByAll = 1;
  trans->localNode = 1;

#ifdef DEBUG_TRANSMNG
  printf("--------- Init_Delivery----------\n");
#endif


  executeTrans(trans);
  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Init_Delivery----------\n");
#endif
}

int commit_commitTrans = 0;
int commit_commitTransinblocked = 0;
//TODO Quitar
/*
int commit_delivery = 0;
int commit_transaction_null = 0;
int commit_commitTrans = 0;
int commit_local = 0;
*/
int commit_nocommitTrans = 0;
int commit_isFirst = 0; //TODO Quitar
int commit_commitable = 0;

//TODO Quitar
/*int commit_commitTransinblocked = 0;
int commit_nofinished = 0;
int commit_nocommittable = 0;
int commit_nocommitting = 0;
int commit_noisFirstinBlocked = 0;


void printfCommitTransinblocked(){
  printf("(Transmng) Commit Trans In Blocked Trans <%d>:\n", commit_commitTransinblocked);
  printf("(Transmng) \t by Not Commitable <%d>\n", commit_nocommittable);
  printf("(Transmng) \t by Not isFirst <%d>\n", commit_noisFirstinBlocked);
  printf("(Transmng) \t by Committing <%d>\n", commit_nocommitting);
  printf("(Transmng) \t by Not Finished <%d>\n", commit_nofinished);
}

void printfCommit(){
  printf("(Transmng) Commit Delivery <%d>\n", commit_delivery);
  printf("(Transmng) Transaction Null <%d>\n", commit_transaction_null);
  printf("(Transmng) Commit Trans <%d>\n", commit_commitTrans);
  printf("(Transmng) Commit No Trans <%d>:\n", commit_nocommitTrans);
  printf("(Transmng) \t by Not Commitable <%d>\n", commit_isFirst);
  printf("(Transmng) \t by Not isFirst <%d>\n", commit_commitable);
  printf("(Transmng) Commit isLocal <%d>\n", commit_local);
  printfCommitTransinblocked();
}
*/

int commit_delivery_lock_local = 0;
void Commit_Delivery(Commit_M msg) {
  //Commit_Delivery_Lock(msg, 1);
  T_Transaction * transaction;
  int stp;

#ifdef DEBUG_FILES_FLAG
  char buffer_log[2048];
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Commit_Delivery -------- %d\n", msg.tid);
#endif

  /* Begin Critical section */
  decSemaphore(& replica.mutex);

#ifdef DEBUG_FILES_FLAG
  //char buffer_log[2048];
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "Commit_Delivery TID: <%d>\n", msg.tid);
  write_in_log_flag(&log_flag_finished[0], buffer_log);
#endif

  //commit_delivery++; //TODO Quitar

  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &msg.tid)) == NULL){
//printf("%s# %d # 1.\n", __FILE__, __LINE__ );

/*
#ifdef WRITESET_FIFO
  //transaction = L_getTransaction(replica.transactionlist, msg.tid);
  ////// if the commit arrived before the to-delivery
  // store the tid in the commit list
  //if (transaction == NULL) {
    Commit_M *commit_msg = NULL;
    //commit_transaction_null++; //TODO Quitar
    //if (commit_delivery > 59999){printfCommit();}

//#ifdef WARN_TRANSMNG
    printf("(Transmng) Transaction <%d>: Commit arrived before To -> Stored Commit\n", msg.tid);
//#endif

    if (!(commit_msg = (Commit_M*) malloc(sizeof(Commit_M)))) {
      #ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__ );
      #endif
      exit(0);
    }

    //Copy Commit_M
    commit_msg->type = msg.type;
    commit_msg->tid = msg.tid;
    commit_msg->thId = msg.thId;
    strcpy(commit_msg->endpoint.name, msg.endpoint.name);
    memcpy(commit_msg->writeset, msg.writeset, msg.writeset_length);
    commit_msg->writeset_length = msg.writeset_length;

    if (!insert_hashtable(&replica.commitlist, &msg.tid, commit_msg)) {
#ifdef WARN_TRANSMNG
      printf("(Transmng) Not possible insert Commit in HashTable\n");
#endif
    }

    //CL_insertInOrder(replica.commitlist, commit_msg);

    incSemaphore(& replica.mutex);
    //End Critical section

#ifdef DEBUG_TRANSMNG
    printf("--------- End_Commit_Delivery --------\n");
#endif
    return;
#else
*/
    commit_delivery_lock_local++;
    incSemaphore(& replica.mutex);
    /* End Critical section */
    return;
//#endif
  } //if

#ifndef WRITESET_FIFO
  sscanf(& transaction->transaction.sqlcode[0], "%d", & stp);
  if (((transaction->local) || (transaction->executedByAll)) && (stp != CDB)) {
  //if (transaction->local) || transaction->executedbyall{ //WS FIFO TO TOTAL
    commit_delivery_lock_local++;

    incSemaphore(& replica.mutex);
    /* End Critical section */
    return;
  }
#endif

  if (!(transaction->local)) {
    remote_count_commit++;

    if (transaction->finished == 1){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) The transaction %d is already finished (FATAL ERROR) | msg.tid %d\n", transaction->transaction.tid, msg.tid);
#endif
#ifdef DEBUG_FILES_FLAG
      close_log(&log_flag_finished[0]);
#endif
      printT_TransactionCompact(transaction);

      exit(0);
      //return;

    } else {
      transaction->finished = 1;
    }

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) memcopying %d bytes\n", msg.writeset_length);
#endif

    memcpy(transaction->writeset, msg.writeset, msg.writeset_length);
    transaction->writeset_length = msg.writeset_length;
    /* Additional Information */
    memcpy(transaction->response, msg.response, msg.response_length);
    transaction->response_length = msg.response_length;
    transaction->recordsUpdates = msg.recordsUpdates;

    save_and_check_Response(transaction);


#ifdef DEBUG_TRANSMNG
    printf("(Transmng) writeset= %s\n", transaction->writeset);
    printf("(Transmng) Executing COMMIT %d \n", transaction->transaction.tid);
#endif

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) trans remota \n");
#endif

    if (isFirst(transaction) && (transaction->committable)) {
      commit_commitTrans++; //TODO Quitar
      //if (commit_delivery > 59999){printfCommit();}

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) thId %d\n", msg.thId);
#endif

      //TODO QMID transaction->qid = msg.thId;
      commitTrans(transaction);

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) el to ya ha llegado \n");
#endif
    } else {
      if (transaction->committable){//TODO Quitar
        commit_commitable++;
      } else {
        commit_isFirst++;
      }
      commit_nocommitTrans++; //TODO Quitar
//if (commit_delivery > 59999){printfCommit();}

#ifdef DEBUG_TRANSMNG
       printf("(Transmng) el to NO ha llegado o no es la 1a \n");
#endif
    }

  } else { // it is local
    /*
    commit_local++; //TODO Quitar
    if (commit_delivery > 59999){printfCommit();}
    */
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) error, commit mes. do not arrive to the sender");
#endif
  }

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Commit_Delivery --------\n");
#endif
}

//void Commit_Delivery_UnLock(Commit_M msg, int lock) {
void Commit_Delivery_UnLock(Commit_M msg) {
  T_Transaction * transaction;
  int stp;

#ifdef DEBUG_FILES_FLAG
  char buffer_log[2048];
#endif
#ifdef DEBUG_TRANSMNG
  printf("--------- Commit_Delivery -------- %d\n", msg.tid);
#endif

#ifdef DEBUG_FILES_FLAG
  //char buffer_log[2048];
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "Commit_Delivery_UnLock TID: <%d>\n", msg.tid);
  write_in_log_flag(&log_flag_finished[1], buffer_log);
#endif

  /* Begin Critical section */
  /*if (lock){
    decSemaphore(& replica.mutex);
  }*/
  //commit_delivery++; //TODO Quitar

  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &msg.tid)) == NULL){
//printf("%s# %d # 1.\n", __FILE__, __LINE__ );

#ifdef WRITESET_FIFO
  //transaction = L_getTransaction(replica.transactionlist, msg.tid);
  ////// if the commit arrived before the to-delivery
  // store the tid in the commit list
  //if (transaction == NULL) {
    Commit_M *commit_msg = NULL;
    //commit_transaction_null++; //TODO Quitar
    //if (commit_delivery > 59999){printfCommit();}

#ifdef WARN_TRANSMNG
    printf("(Transmng) Transaction <%d>: Commit arrived before To -> Stored Commit\n", msg.tid);
#endif

    if (!(commit_msg = (Commit_M*) malloc(sizeof(Commit_M)))) {
      #ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__ );
      #endif
      exit(0);
    }

    /* Copy Commit_M */

    commit_msg->type = msg.type;
    commit_msg->tid = msg.tid;
    commit_msg->mclientId = msg.mclientId;
    strcpy(commit_msg->endpoint.name, msg.endpoint.name);
    memcpy(commit_msg->writeset, msg.writeset, msg.writeset_length);
    commit_msg->writeset_length = msg.writeset_length;

    if (!insert_hashtable(&replica.commitlist, &msg.tid, commit_msg)) {
#ifdef WARN_TRANSMNG
      printf("(Transmng) Not possible insert Commit in HashTable\n");
#endif
    }

    //CL_insertInOrder(replica.commitlist, commit_msg);
    /*if (lock){
      incSemaphore(& replica.mutex);
    }*/
    /* End Critical section */

#ifdef DEBUG_TRANSMNG
    printf("--------- End_Commit_Delivery --------\n");
#endif
    return;
#else
    /*if (lock){
      incSemaphore(& replica.mutex);
    }*/
    /* End Critical section */

    commit_delivery_lock_local++;
    return;
  #endif
  } //if

#ifndef WRITESET_FIFO
  sscanf(& transaction->transaction.sqlcode[0], "%d", & stp);
  if (((transaction->local) || (transaction->executedByAll)) && (stp != CDB)) {
  //if (transaction->local) || transaction->executedbyall{ //WS FIFO TO TOTAL
    /*if (lock){
      incSemaphore(& replica.mutex);
    }*/
    /* End Critical section */

    commit_delivery_lock_local++;
    return;
  }
#endif

  remote_count_commit++;
  if (transaction->finished == 1){
#ifdef FATAL_TRANSMNG
    printf("(Transmng) The transaction %d is already finished (FATAL ERROR) | msg.tid %d\n", transaction->transaction.tid, msg.tid);
#endif
    printT_TransactionCompact(transaction);
    return;
    //exit(0);

  } else {
    transaction->finished = 1;
  }

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) memcopying %d bytes\n", msg.writeset_length);
#endif

  memcpy(transaction->writeset, msg.writeset, msg.writeset_length);
  transaction->writeset_length = msg.writeset_length;

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) writeset= %s\n", transaction->writeset);
  printf("(Transmng) Executing COMMIT %d \n", transaction->transaction.tid);
#endif

  if (!(transaction->local)) {
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) trans remota \n");
#endif

    if (isFirst(transaction) && (transaction->committable)) {
      commit_commitTrans++; //TODO Quitar
      //if (commit_delivery > 59999){printfCommit();}

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) thId %d\n", msg.thId);
#endif

      //TODO QMID transaction->qid = msg.thId;
      commitTrans(transaction);

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) el to ya ha llegado \n");
#endif
    } else {
      /*
      if (isFirst(transaction)){//TODO Quitar
        commit_isFirst++;
      }
      if (transaction->committable){//TODO Quitar
        commit_commitable++;
      }
      commit_nocommitTrans++; //TODO Quitar
      if (commit_delivery > 59999){printfCommit();}
      */
#ifdef DEBUG_TRANSMNG
       printf("(Transmng) el to NO ha llegado o no es la 1a \n");
#endif
    }

  } else { // it is local
    /*
    commit_local++; //TODO Quitar
    if (commit_delivery > 59999){printfCommit();}
    */
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) error, commit mes. do not arrive to the sender");
#endif
  }
  /*if (lock){
    incSemaphore(& replica.mutex);
  }*/
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Commit_Delivery --------\n");
#endif
}

void postCommit(T_Tid tid, hot_uint32 recordsUpdates) {
  T_Transaction * transaction;
  struct itemhPetition * petition;
  unsigned int key_petition;

  int t = 0;//DEBUG_FILES_COMMIT

#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(2, msg.idConnection, msg.idPetition, time);
   //SETSTARTTIME(3, msg.idConnection, msg.idPetition, time);
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_Commit %d--------\n", tid);
#endif
  
  /* Begin Critical section */
  decSemaphore(& replica.mutex);

  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("Post_Commit.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }

#ifdef DEBUG_TRANSMNG_STATS
  if (transaction->local){
  	   SETFINISHTIME(3, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
	   //setFinishTimeArray(3, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   	   
  }else{
  	   SETFINISHTIME(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
	   //setFinishTimeArray(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);   	   
  }
  SETSTARTTIME(4, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
  //(steps[4][transaction->idConnection][transaction->idPetition]).startTime.tv_sec = time.tv_sec;
  //(steps[4][transaction->idConnection][transaction->idPetition]).startTime.tv_usec = time.tv_usec;
  //(steps[4][transaction->idConnection][transaction->idPetition]).inUse = 1;
#endif

#ifdef DEBUG_FILES_COMMIT
  for (t=0; t<transaction->transaction.noCC; t++){
    write_in_log_cc (&log_commit[transaction->transaction.transCC[t]], transaction->writeset, transaction->writeset_length);
  }
#endif

  //transaction = L_getTransaction(replica.transactionlist, tid);
  /* REMOVE QMID if (transaction->qid == -1) {
    if (transaction->local) {
      // Send reply to client
#ifdef DEBUG_TRANSMNG
      printf("(Transmng) sending reply to %s \n", transaction->transaction.endpoint.name);
#endif
      if (transaction->transaction.isQuery)
        SendReply(transaction->transaction.endpoint, "my reply");
    } // if
  }*/

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) removing trans %d\n", transaction->transaction.tid);
#endif
  removeTrans(transaction);
  executeBlockedTrans(transaction->transaction.transCC, transaction->transaction.noCC);
  //freeTrans(transaction);

  // Introduce petition in hPetition
  /*
  petition = (struct itemhPetition *) malloc(sizeof(struct itemhPetition));
  petition->id = (transaction->idConnection * MAX_PETITION_PER_CLIENT) + transaction->idPetition;
  petition->num_connection = transaction->idConnection;
  petition->num_petition = transaction->idPetition;
  petition->thId = transaction->qid;
  petition->recordsUpdates = recordsUpdates;
  //petition->state = 1;
  petition->response = 0;
#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hPetition> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", petition->id, __FILE__, __LINE__);
#endif

  if (!insert_hashtable(&hPetition, &petition->id, petition)) {
#ifdef ERROR_TRANSMNG
    printf("(Transmng) ERROR in table hash hPetition to add connection %d and petition %d\n", petition->num_connection,
         petition->num_petition);
#endif
  }*/

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Inserted connection %d petition %d in hPetition. Elements of hPetition : %d\n", petition->num_connection,
       petition->num_petition, num_elements_hashtable(&hPetition));
#endif
//printf ("%s:%d freeTrans IN\n", __FILE__, __LINE__ );
  freeTrans(&transaction); //JSalas removed from after executeBlockedTrans
//printf ("%s:%d freeTrans OUT\n", __FILE__, __LINE__ );
  if (transaction != NULL){
    printf("(Transmng) TRANSACTION IS NOT NULL 0\n");
    exit(0);
  }

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_Commit %d --------\n", tid);
#endif

  n_commits++;
}

void postConnection(T_Tid tid, char *dbname) {
  postConnectionLock(tid, 1, dbname);
}
void postConnectionLock(T_Tid tid, int lock, char *dbname) {
  T_Transaction * transaction;
  struct itemhPetition *petition;  
  int id;
  //struct itemhDBConns *found;

#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_Connection %d--------\n", tid);
#endif

  if (lock){
    /* Begin Critical section */
    decSemaphore(& replica.mutex);
  }

  //transaction = L_getTransaction(replica.transactionlist, tid);
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("Post_Connection.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }

#ifdef DEBUG_TRANSMNG_STATS
   SETSTARTTIME(4, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);   
#endif

  transaction->finished = 1;

  if (!transaction->committable){
    if (lock){
      incSemaphore(& replica.mutex);
    }
    return;
  }

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) removing trans %d\n", transaction->transaction.tid);
#endif

  removeTrans(transaction);
  executeBlockedTrans(transaction->transaction.transCC, transaction->transaction.noCC);
  //freeTrans(transaction);

  // Introduce connection in hPetition
  /*
  petition = (struct itemhPetition *) malloc(sizeof(struct itemhPetition));
  petition->id = (transaction->idConnection * MAX_PETITION_PER_CLIENT) + 0;
  petition->num_connection = transaction->idConnection;
  petition->num_petition = 0;
  petition->thId = transaction->qid;
  petition->recordsUpdates = 0;
  petition->state = 1;
  petition->response = 0;

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hPetition> Operation <hash_add> Key <%u> File <%s> Line <%d>\n", petition->id, __FILE__, __LINE__);
#endif

  if (!insert_hashtable(&hPetition, &petition->id, petition)) {
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) ERROR in table hash hPetition\n");
#endif
  }
  */
  id = (transaction->idConnection * MAX_PETITION_PER_CLIENT) + 0;
  if ((petition = (struct itemhPetition *) get_hashtable(& hPetition, & id)) != NULL) {
    petition->last.recordsUpdates = 0;
  }
  
#ifdef DEBUG_TRANSMNG
  printf("(Transmng) Inserted connection %d petition %d in hPetition. Elements of hPetition : %d\n", petition->num_connection,
       petition->num_petition, num_elements_hashtable(&hPetition));
#endif

//printf ("%s:%d freeTrans IN\n", __FILE__, __LINE__ );
  freeTrans(&transaction); //JSalas removed from after executeBlockedTrans
//printf ("%s:%d freeTrans OUT\n", __FILE__, __LINE__ );
  if (transaction != NULL){
    printf("(Transmng) TRANSACTION IS NOT NULL 0\n");
    exit(0);
  }

//printf ("%s:%d OUT\n", __FILE__, __LINE__ );
  if (lock){
    incSemaphore(& replica.mutex);
    /* End Critical section */
  }

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_Connection %d --------\n", tid);
#endif
}

void View_Change(T_Mess * msg) {
  /* Begin Critical section */
  decSemaphore(& replica.mutex);

  // to do

  incSemaphore(& replica.mutex);
  /* End Critical section */
}

void executeTrans(T_Transaction * transaction) {
  /* PRE: the transaction is local and in front of all queues */
  QM_message *mess = NULL;

#ifdef DEBUG_FILES_FLAG
  char buffer_log[2048];
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "executeTrans TID: <%d> Executing <%d>\n", transaction->transaction.tid, transaction->executing);
  write_in_log_flag(&log_flag_finished[3], buffer_log);
#endif

  if (!(mess = (QM_message *) malloc (sizeof(QM_message)))) {
    #ifdef FATAL_TRANSMNG
      printf("%s:%d # Out of memory.\n", __FILE__, __LINE__ );
    #endif
    exit(0);
  }

  initQMMessage(mess); //08092004

  transaction->executing = 1;
  mess->type = QM_execute;
  //mess->mclientId = transaction
  //mess->trans = * transaction;
  AssignT_Transaction(&mess->trans, transaction);
  SendMessageToQM(transaction, mess);

#ifdef DEBUG_TRANSMNG
  if (transaction->qid != MAXQM) {
    printf("(Transmng) RM submitted transaction %d for execution, executing=%d\n", transaction->transaction.tid,
         transaction->executing);
  }
#endif
}

int postExecute(T_Tid tid, char writeset[], long writeset_length, char response[], long response_length, int recordsUpdates){
  // PRE: the QM has just notified the end of the transaction
  T_Transaction * transaction;

#ifdef DEBUG_FILES_FLAG
  char buffer_log[2048];
#endif

#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_Execute -------- <%d>\n", tid);
#endif
  
  /* Begin Critical section */
  decSemaphore(& replica.mutex);

#ifdef DEBUG_FILES_FLAG
  //char buffer_log[2048];
  bzero(buffer_log, sizeof(buffer_log));
  sprintf(buffer_log, "postExecute TID: <%d>\n", tid);
  write_in_log_flag(&log_flag_finished[2], buffer_log);
#endif

  // the transaction could have been aborted while under execution
  // in this case, executing will be 0

  //transaction = L_getTransaction(replica.transactionlist, tid);
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("postExecute.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }

#ifdef DEBUG_TRANSMNG_STATS
   //struct timeval time;   
   //gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   SETFINISHTIME(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   SETSTARTTIME(3, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   //(steps[3][transaction->idConnection][transaction->idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[3][transaction->idConnection][transaction->idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[3][transaction->idConnection][transaction->idPetition]).inUse = 1;
#endif

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) trans %d executing = %d\n", tid, transaction->executing);
#endif

  if (transaction->executing) {
    if (transaction->finished == 1){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) The transaction %d is already finished (FATAL ERROR) | tid %d\n", transaction->transaction.tid, tid);
#endif
      printT_TransactionCompact(transaction);
#ifdef DEBUG_FILES_FLAG
      close_log(&log_flag_finished[2]);
#endif
      //exit(0);
      return -1;
    } else {
      transaction->finished = 1;
    }

/*
#ifdef DEBUG_TRANSMNG
    printf("(Transmng) memcopying %d bytes\n", writeset_length);
#endif
*/
    if (!(transaction->transaction.isQuery)) {
      //int t = 0;//DEBUG_FILES_COMMIT

      memcpy(transaction->writeset, writeset, writeset_length);
      transaction->writeset_length = writeset_length;

      /* Additional Information */
      memcpy(transaction->response, response, response_length);
      transaction->response_length = response_length;
      transaction->recordsUpdates = recordsUpdates;

      //save_and_check_Response(transaction);

//#ifdef DEBUG_FILES_COMMIT
//      for (t=0; t<transaction->transaction.noCC; t++){
//        write_in_log_cc (&log_commit[transaction->transaction.transCC[t]], transaction->writeset, transaction->writeset_length);
//      }
//#endif
    }

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) postExecute: %s\n", writeset);
#endif

    if ((transaction->committable) && !(transaction->transaction.isQuery)) {
      // if the to has arrived while executing, commit the transaction
      commitTrans(transaction);
    }
    //else {
//#ifdef DEBUG_TRANSMNG
      //printf("(Transmng) Error transaction %d has not been commit %d\n", tid, transaction->committable);
//#endif
    //}
  }

#ifdef DEBUG_TRANSMNG
  else {
    printf("(Transmng) trans %d executing = %d\n", tid, transaction->executing);
  }
#endif

  // Aqui lo comento porque este registro se introducira luego en el post_commit
  /*if (transaction->transaction.isQuery){ petition = (struct itemhPetition *) malloc (sizeof(struct itemhPetition));
  petition->id = (transaction->idConnection*MAX_PETITION_PER_CLIENT) + transaction->idPetition;
  petition->num_connection = transaction->idConnection; petition->num_petition = transaction->idPetition;
  petition->thId = transaction->qid; petition->recordsUpdates = 0; petition->state = 1;
  if (hash_add(hPetition, (HASHKEYTYPE)petition->id, petition) == FALSE) { printf ("ERROR in table hash hPetition\n"); }
  #ifdef DEBUG_TRANSMNG printf ("(Inserted connection %d petition %d in hPetition. Elements in hPetition: %d\n",
  petition->num_connection, petition->num_petition, hash_count(hPetition)); #endif }*/

  incSemaphore(& replica.mutex);
  /* End Critical section */

  if (transaction->transaction.isQuery) {
    postCommit(tid, 0);
  }

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_Execute --------\n");
#endif
  return 0;
}

void postCDB(T_Tid tid, char response[], long response_length, int recordsUpdates) {
  T_Transaction * transaction;

#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS   
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_CDB --------\n"); //JSalas
#endif

  /* Begin Critical section */
  decSemaphore(& replica.mutex);
//printf("--------- Post_CDB -------- 1\n");
  //transaction = L_getTransaction(replica.transactionlist, tid);
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("Post_CDB.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }
//printf("--------- Post_CDB -------- 2\n");
#ifdef DEBUG_TRANSMNG_STATS
   //struct timeval time;   
   //gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   SETFINISHTIME(2, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
   SETSTARTTIME(3, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);
#endif

#ifdef DEBUG_TRANSMNG
  //printf("removing trans %d\n", transaction->transaction.tid);
#endif
  /* Save response */
//printf("--------- Post_CDB -------- 3\n");  
  memcpy(transaction->response, response, response_length);
//printf("--------- Post_CDB -------- 4\n");  
  transaction->response_length = response_length;
//printf("--------- Post_CDB -------- 5\n");  
  transaction->recordsUpdates = recordsUpdates;  
//printf("save_and_check_Response 1\n");
  save_and_check_Response(transaction);
//printf("save_and_check_Response 2\n");
  transaction->finished = 1;
  //transaction->committable = 1;
  if ((transaction->committable) && !(transaction->transaction.isQuery)) {
    // if the to has arrived while executing, commit the transaction
    //printf("***************** Executing commitTransCDB *************** %d\n ", transaction->transaction.tid);
    commitTransCDB(transaction);
  }

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_CDB %d --------\n", tid);
#endif
}

void postDisconnect(T_Tid tid, int early, int connection_petition, char *dbname) {
  postDisconnectLock(tid, early, connection_petition, 1, dbname);
}

void postDisconnectLock(T_Tid tid, int early, int connection_petition, int lock, char *dbname) {
  T_Transaction * transaction;
  hot_uint32 thId;
  struct itemhDBConns *found;
/*
struct itemhCC * item; //TODO Quitar
int i, idItem;
*/
#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
#endif

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_Disconnect -------- <%d>\n", tid);
#endif

  if (lock){
    /* Begin Critical section */
    //printf("postDisconnect 1\n");
    decSemaphore(& replica.mutex);
  }
  //printf("postDisconnect 2\n");
  //transaction = L_getTransaction(replica.transactionlist, tid);
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("Post_Disconnect.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }

#ifdef DEBUG_TRANSMNG_STATS
   SETSTARTTIME(4, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);   
#endif

  transaction->finished = 1;

  if (!transaction->committable){
    transaction->conns.early = early;
    transaction->conns.connection_petition_id = connection_petition;
    strcpy(transaction->conns.dbname, dbname);
    if (lock){
      incSemaphore(& replica.mutex);
    }
    return;
  }

#ifdef DEBUG_TRANSMNG_COMMIT
    //printStat();
#endif

  //printf("postDisconnect 3\n");
/* JSALAS */
//printAllQueue();
/* JSALAS */

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) removing trans %d\n", transaction->transaction.tid);
#endif

  //printf("postDisconnect 4\n");
  thId = transaction->mclientId;
  //printf("postDisconnect 5\n");

  //printf("postDisconnect 6\n");
  removeTrans(transaction);
  executeBlockedTrans(transaction->transaction.transCC, transaction->transaction.noCC);
  //printf("postDisconnect 7\n");

  // Free thread
  //if (transaction->local)
  if (transaction->localNode == 1){
     freeThread(thId, 1);

  }else{
     freeThread(thId, 0);
  }

  //printf("postDisconnect 8\n");
//printf ("%s:%d freeTrans IN\n", __FILE__, __LINE__ );
  freeTrans(&transaction); //JSalas removed from after executeBlockedTrans
//printf ("%s:%d freeTrans OUT\n", __FILE__, __LINE__ );
  if (transaction != NULL){
    printf("(Transmng) TRANSACTION IS NOT NULL 0\n");
    exit(0);
  }

  /* Remove connection petition  */
  if (!early) {
    if (delete_hashtable(& hPetition, & connection_petition) == 0) {
      printf("1 (QMSOCKETS) Petition %d not found TYPE<%d> SQLCODE<%d>\n", connection_petition, early, num_elements_hashtable(& hPetition));

//#ifdef DEBUG_TRANSMNG_HASH
	}else{
		//printf("1 (QMSOCKETS) Petition %d found TYPE<%d> SQLCODE<%d>\n", connection_petition, early, num_elements_hashtable(& hPetition));
      //Oprintf("DEBUG[postDisconnect]: Connection Petition has been %d DELETED\n", connection_petition);
//    }
//    else {
//      printf("(Transmng) HashTable Petition number of elements <%d>\n", num_elements_hashtable(& hPetition));
//#endif
    }
  }else{
  	printf("(QMSOCKETS) DISCONNECTION is EARLY\n");
  }

  /*if (delete_hashtable(& hClient, & connection_petition) == 0) {
#ifdef DEBUG_TRANSMNG_HASH
      printf("(Transmng) Client %d not found\n", connection_petition);
  }else {
      printf("(Transmng) HashTable Client number of elements <%d>\n", num_elements_hashtable(& hClient));
#endif
  }*/
    
  if ((found = (struct itemhDBConns *)get_hashtable(&hDBConns, dbname)) == NULL) {
      #ifdef ERROR_TRANSMNG
        printf("(Transmng) Not possible found connection in hashtable\n");
      #endif

  }else{
    found->open_conns--;
    //printf("[PostDisconnect] Close Connections <%d> <%s> THID <%d> TID <%d>\n", found->open_conns, dbname, thId, tid);
    if (found->open_conns==0){
#ifdef DEBUG_TRANSMNG_STATS
	  //Only for long benchmark and same database connection
	  //toFile();    	
#endif
      /* TODO Antes de Borrar liberar QMs conectados
        if (delete_hashtable(& hDBConns, dbname) == 0) {
        #ifdef ERROR_TRANSMNG
        printf("(Transmng) Not possible delete connection in hashtable <%s>\n", dbname);
        #endif
      }*/
    }
  }

  //printf("postDisconnect 9\n");
  //JSalas freeThread(thId);
  if (lock){
    incSemaphore(& replica.mutex);
  }
  //printf("postDisconnect 10\n");
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_Disconnect %d --------\n", tid);
#endif
}

void commitTrans(T_Transaction * transaction) {
  int stp;
  QM_message *mess = NULL;

#ifdef DEBUG_TRANSMNG
  printf("--------- commitTrans -------- <%d>\n", transaction->transaction.tid);
#endif

  sscanf(& transaction->transaction.sqlcode[0], "%d", & stp);
  transaction->committing = 1;
  if (((transaction->local) || (transaction->executedByAll)) && (stp != CDB)) {
    // Send reply to client
    // cliente antiguo
    //SendReply(transaction->transaction.endpoint, "my reply");
    // Broadcast a commit message to all replica managers
    //if ((stp != CDB) && (stp!= CON) && (stp!= DISCON))
    MulticastCommit(transaction->writeset, transaction->writeset_length, transaction->response, transaction->response_length, transaction->recordsUpdates, transaction->transaction.tid, transaction->mclientId);

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) commit of local trans. Broadcast commit %d writeset length = %d\n", transaction->transaction.tid,
         transaction->writeset_length);
#endif

    if (!(mess = (QM_message *) malloc (sizeof(QM_message)))) {
#ifdef FATAL_TRANSMNG
      printf("%s:%d # Out of memory.\n", __FILE__, __LINE__ );
#endif
      exit(0);
    }

    initQMMessage(mess); //08092004

    count_commit_qmcommit++;

    // commit locally the transaction
    mess->type = QM_commit;
    //mess->trans = * transaction;
    AssignT_Transaction(&mess->trans, transaction);
    SendMessageToQM(transaction, mess);

    save_and_check_Response(transaction);

  } else { // remote transaction
    // el if creo que sobra, comprobar
    if (isFirst(transaction)) {

      if (!(mess = (QM_message *) malloc (sizeof(QM_message)))) {
#ifdef FATAL_TRANSMNG
        printf("%s:%d # Out of memory.\n", __FILE__, __LINE__ );
#endif
        exit(0);
      }

      initQMMessage(mess); //08092004

      count_commit_qmwsandapply++;

      // CALL postgres to apply the writeset
      mess->type = QM_apply_ws_and_commit;
      //msg.trans = * transaction;
      //mess->mclientId = transaction->mclientId;
      AssignT_Transaction(&mess->trans, transaction);
      SendMessageToQM(transaction, mess);
      // commit locally the remote transaction

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) commit of a remote transaction %d, apply writesetlength= %d\n", transaction->transaction.tid,
           transaction->writeset_length);
#endif

    } // if
  } // if
}

void commitTransCDB(T_Transaction * transaction) {
  QM_message *mess = NULL;

  if (!(mess = (QM_message *) malloc (sizeof(QM_message)))) {
#ifdef FATAL_TRANSMNG
    printf("%s:%d # Out of memory.\n", __FILE__, __LINE__ );
#endif
    exit(0);
  }

  initQMMessage(mess); //08092004

  transaction->committing = 1;
  // commit locally the transaction
  mess->type = QM_commit;
  //msg.trans = * transaction;
  AssignT_Transaction(&mess->trans, transaction);
  SendMessageToQM(transaction, mess);

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) commit a CDB transaction %d\n", transaction->transaction.tid);
#endif
}

//int count_removetrans = 0; //TODO Quitar
void removeTrans(T_Transaction * transaction) {
  int i;
  struct itemhCC * item;

#ifdef DEBUG_TRANSMNG_STATS
   struct timeval time;   
   gettimeofday(&time, NULL);//STATS
   //setFinishTimeArray(4, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec);   
   SETFINISHTIMELOCAL(4, transaction->idConnection, transaction->idPetition, time.tv_sec, time.tv_usec, transaction->local);
   //SETSTARTTIME(5, transaction->idConnection, transaction->idPetition, time);
   //SETSTARTTIME(5, transaction->idConnection, transaction->idPetition, time);
#endif

  //count_removetrans++; //TODO Quitar
  //printf("(Transmng) count_removetrans <%d>\n", count_removetrans);

  if (transaction == NULL){
#ifdef ERROR_TRANSMNG
    printf("(Transmng) removeTrans: Transaction is NULL -> File <%s> Line <%d>\n", __FILE__, __LINE__);
#endif
    return;
  }

//printf("(removeTrans) noCC <%d> File <%s> Line <%d>\n", transaction->transaction.noCC, __FILE__, __LINE__);
  for (i = 0; i < transaction->transaction.noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
    printf("Iterator %d, SizeArray %d\n", i, sizeof(transaction->transaction.transCC));
    if (i > sizeof(transaction->transaction.transCC)) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%d> File <%s> Line <%d>\n", transaction->transaction.transCC[i], __FILE__, __LINE__);
#endif

    if ((item = (struct itemhCC *)get_hashtable(&hCC, &transaction->transaction.transCC[i])) == NULL){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", transaction->transaction.transCC[i], __FILE__, __LINE__);
#endif
      exit(0);
    }
//printf("1 (Q_remove(item->queue);) -> File <%s> Line <%d>\n", __FILE__, __LINE__);
    Q_remove(item->queue);
//printf("2 (Q_remove(item->queue);) -> File <%s> Line <%d>\n", __FILE__, __LINE__);
  }
  //printf("1 (L_removeByID tid = <%d> <%d>) -> File <%s> Line <%d>\n", transaction->transaction.tid, transaction->qmId, __FILE__, __LINE__);
  //replica.transactionlist = L_removeByID(replica.transactionlist, transaction->transaction.tid);
  if (((T_Transaction *)remove_hashtable(&replica.transactionlist, &transaction->transaction.tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("removeTrans.Impossible get transaction <%d> (FATAL ERROR)\n", transaction->transaction.tid);
#endif
    exit(0);
  }

//printf("2 (L_removeByID tid = <%d>) -> File <%s> Line <%d>\n", transaction->transaction.tid, __FILE__, __LINE__);
  //printf("removedTrans tid = <%d> -> File <%s> Line <%d>\n", transaction->transaction.tid, __FILE__, __LINE__);
}

void executeBlockedTrans(hot_uint32 * transCC, int noCC) {
  // POST: removes the transaction and starts new ones
  int i;
  T_Transaction * trans;
  struct itemhCC * item;

  for (i = 0; i < noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
    printf("Iterator %d, SizeArray %d\n", i, sizeof(transCC));
    if (i > sizeof(transCC)) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif

#ifdef DEBUG_TRANSMNG_HASH
      printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", transCC[i], __FILE__, __LINE__);
#endif

    if ((item = (struct itemhCC *)get_hashtable(&hCC, &transCC[i])) == NULL){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", transCC[i], __FILE__, __LINE__);
      exit(0);
#endif
    }

    if (!Q_isEmpty(item->queue)) {
      trans = Q_getFirst(item->queue);

#ifdef DEBUG_TRANSMNG
      printf("(Transmng) First trans %d \n", trans->transaction.tid);
      printf("(Transmng) noCC = %d\n", noCC);
#endif

      if ((trans->finished) && (trans->committable) && !(trans->committing) && isFirst(trans)) {
        int stp;
        sscanf(& trans->transaction.sqlcode[0], "%d", & stp);

#ifdef DEBUG_TRANSMNG
        printf("(Transmng) found a trans ready to commit %d \n", trans->transaction.tid);
#endif
        commit_commitTransinblocked++; //TODO quitar
        //printfCommitTransinblocked(); //TODO quitar
        if (stp == CDB){
          commitTransCDB(trans);//TODO commitTransCDB
        }else{
          commitTrans(trans);
        }
      } /*else {//if
        if (!(trans->finished)){ commit_nofinished++ ;}//TODO quitar
        if (trans->finished){
          if (!(trans->committable)){ commit_nocommittable++ ;}//TODO quitar
          if (trans->committing){ commit_nocommitting++ ;}//TODO quitar
          if (!(isFirst(trans))){ commit_noisFirstinBlocked++ ;}//TODO quitar
        }
      }*/
    } //if
  } //for

  for (i = 0; i < noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
    printf("Iterator %d, SizeArray %d\n", i, sizeof(transCC));
    if (i > sizeof(transCC)) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", transCC[i], __FILE__, __LINE__);
#endif

    if ((item = (struct itemhCC *)get_hashtable(&hCC, &transCC[i])) == NULL){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", transCC[i], __FILE__, __LINE__);
      exit(0);
#endif
    }

    if (!Q_isEmpty(item->queue)) {
      trans = Q_getFirst(item->queue);
#ifdef DEBUG_TRANSMNG
      printf("(Transmng) primera trans %d \n", trans->transaction.tid);
#endif

      if (((trans->local) || (trans->executedByAll)) && !(trans->executing) && isFirst(trans)) {
#ifdef DEBUG_TRANSMNG
        printf("(Transmng) found a trans to execute  %d \n", trans->transaction.tid);
#endif
        executeTrans(trans);
      } //if
    } //if
  } //for
}

void abortTrans(T_Transaction * transaction) {
  QM_message *mess = NULL;

  if (!(mess = (QM_message *) malloc (sizeof(QM_message)))) {
#ifdef FATAL_TRANSMNG
    printf("%s:%d # Out of memory.\n", __FILE__, __LINE__ );
#endif
    exit(0);
  }

  initQMMessage(mess); //08092004

  mess->type = QM_abort;
  //msg.trans = * transaction;

#ifdef DEBUG_TRANSMNG
  printf("(Transmng) RM submitting transaction  %d for abortion \n", transaction->transaction.tid);
#endif

  //CHECK estaba despues de sendMessageToQM
  transaction->executing = 0;
  transaction->aborting = 1;
  transaction->finished = 0;

  AssignT_Transaction(&mess->trans, transaction);
  // submit the trans to the QM to abort it.
  SendMessageToQM(transaction, mess);

  // increment the total number of aborts
  if (n_tos > WARMUP)
    n_aborts++;
}

void postAbort(T_Tid tid) {
  // PRE: the QM has just notified the abort of the transaction
  T_Transaction * transaction;

#ifdef DEBUG_TRANSMNG
  printf("--------- Post_Abort --------\n");
#endif
  /* Begin Critical section */
  decSemaphore(& replica.mutex);
  //transaction = L_getTransaction(replica.transactionlist, tid);
  if ((transaction = (T_Transaction *)get_hashtable(&replica.transactionlist, &tid)) == NULL){
#ifdef FATAL_TRANSMNG
    printf("Post_Disconnect.Impossible get transaction <%d> (FATAL ERROR)\n", tid);
#endif
    exit(0);
  }

  transaction->aborting = 0;
  // reschedule the transaction
#ifdef DEBUG_TRANSMNG
  printf("(Transmng) reschedule " /* msg->tid */);
#endif
  executeBlockedTrans(transaction->transaction.transCC, transaction->transaction.noCC);

  incSemaphore(& replica.mutex);
  /* End Critical section */

#ifdef DEBUG_TRANSMNG
  printf("--------- End_Post_Abort --------\n");
#endif
}

bool isFirst(T_Transaction * trans) {
  struct itemhCC * item;
  int i, idItem;
  for (i = 0; i < trans->transaction.noCC; i++) {
#ifdef DEBUG_TRANSMNG_ARRAY_REVIEW
    printf("Iterator %d, SizeArray %d\n", i, sizeof(trans->transaction.transCC));
    if (i > sizeof(trans->transaction.transCC)) {
      printf("Array Index Outbounds (FATAL ERROR) -> File: %s Line: %d\n", __FILE__, __LINE__);
      exit(0);
    }
#endif

#ifdef DEBUG_TRANSMNG_HASH
    printf("(HASHTABLE) Table <hCC> Operation <hash_lookup, NOT CHECK> Key <%u> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
#endif

    idItem = trans->transaction.transCC[i];
    if ((item = (struct itemhCC *)get_hashtable(&hCC, &idItem)) == NULL){
#ifdef FATAL_TRANSMNG
      printf("(Transmng) Conflict Classes <%d> Not Found in Hashtable (FATAL ERROR) -> File <%s> Line <%d>\n", idItem, __FILE__, __LINE__);
      exit(0);
#endif
    }

#ifdef DEBUG_TRANSMNG
    printf("(Transmng) id trans en cola %d \n", (Q_getFirst(item->queue)->transaction.tid));
#endif

    if (!isEqualId(Q_getFirst(item->queue)->transaction.tid, trans->transaction.tid))
      return 0;
  }
  return 1;
}

// 280803
/*int firstCC(){ int i; for (i=0;i<replica.numCC;i++) if (replica.localCC[i]) return i; printf("local CC
not found\n"); exit(1); };*/

int test(int argc, char * argv[]) {
  Opt_M opt, opt2, opt3, opt4, opt5, opt6, opt7, opt8;
  To_M to, to2, to3, to4, to5, to6, to7, to8;
  Commit_M commit1, commit2, commit3, commit4, commit5, commit6, commit7, commit8;
  // 280803
  //Start(0,4,2);
  Start(0);
  /* Trans remotas =s. cc opt1, opt2,to1,to2,c1,c2 opt.type = OPT; opt.trans.noCC =1;
  opt.trans.transCC[0]=3; opt.trans.tid = 101; Opt_Delivery(opt);
  opt2.type = OPT; opt2.trans.noCC =1; opt2.trans.transCC[0]=3; //  opt2.trans.transCC[1]= ; opt2.trans.tid = 202;
  Opt_Delivery(opt2); to.type = TO; to.tid = 101; To_Delivery(to); to2.type = TO; to2.tid = 202; To_Delivery(to2);
  commit1.tid = 101; Commit_Delivery(commit1); commit2.tid= 202; Commit_Delivery(commit2); */
  /* Trans remotas =s. cc opt1, to1 opt2,to2,c1,c2 opt.type = OPT; opt.trans.noCC =1; opt.trans.transCC[0]=3; opt.trans.tid =
  101; Opt_Delivery(opt); to.type = TO; to.tid = 101; To_Delivery(to);
  opt2.type = OPT; opt2.trans.noCC =1; opt2.trans.transCC[0]=3; //  opt2.trans.transCC[1]= ; opt2.trans.tid = 202;
  Opt_Delivery(opt2); to2.type = TO; to2.tid = 202; To_Delivery(to2);
  commit1.tid = 101; Commit_Delivery(commit1); commit2.tid= 202; Commit_Delivery(commit2); */
  /* Trans remotas =s. cc opt1, opt2 to2,to1,c1,c2 opt.type = OPT; opt.trans.noCC =1;
  opt.trans.transCC[0]=3; opt.trans.tid = 101; Opt_Delivery(opt);
  opt2.type = OPT; opt2.trans.noCC =1; opt2.trans.transCC[0]=3; //  opt2.trans.transCC[1]= ; opt2.trans.tid = 202;
  Opt_Delivery(opt2); to2.type = TO; to2.tid = 202; To_Delivery(to2); to.type = TO; to.tid = 101; To_Delivery(to);
  commit1.tid = 101; Commit_Delivery(commit1); commit2.tid= 202; Commit_Delivery(commit2); */
  /* Trans locales todas  cc comunes, 1 remota disjunta: opt1, opt2,opt3,opt4 to3,to1,to2,to4,c2,c3
  opt.type = OPT; opt.trans.noCC =2; opt.trans.transCC[0]=0; opt.trans.transCC[1]=1; opt.trans.tid = 101; Opt_Delivery(opt);
  opt2.type = OPT; opt2.trans.noCC =2; opt2.trans.transCC[0]=0; opt2.trans.transCC[1]= 1; opt2.trans.tid = 202;
  Opt_Delivery(opt2); opt3.type = OPT; opt3.trans.noCC =2; opt3.trans.transCC[0]=0; opt3.trans.transCC[1]=1; opt3.trans.tid =
  303; Opt_Delivery(opt3); opt4.type = OPT; opt4.trans.noCC =1; opt4.trans.transCC[0]=3; //opt4.trans.transCC[1]=3 ;
  opt4.trans.tid = 404; Opt_Delivery(opt4); to3.type = TO; to3.tid = 303; To_Delivery(to3);
  to.type = TO; to.tid = 101; To_Delivery(to); to2.type = TO; to2.tid = 202; To_Delivery(to2);
  to4.type = TO; to4.tid = 404; To_Delivery(to4); */
  /* commit2.tid= 202; Commit_Delivery(commit2); commit1.tid = 101; Commit_Delivery(commit1);
  commit3.tid= 303; Commit_Delivery(commit3); */
  /* commit4.tid = 404; commit4.writeset_length= sizeof("<Remote write set>"); strcpy(commit4.writeset, "<Remote write set>");
  Commit_Delivery(commit4); */
  /* Trans remotas,  1 local con 1cc comun: opt1, opt2,opt3,opt4 to3,to1,to2,to4,c2,c3
  opt.type = OPT; opt.trans.noCC =2; opt.trans.transCC[0]=3; opt.trans.transCC[1]=1; opt.trans.tid = 101; Opt_Delivery(opt);
  opt2.type = OPT; opt2.trans.noCC =2; opt2.trans.transCC[0]=3; opt2.trans.transCC[1]= 1; opt2.trans.tid = 202;
  Opt_Delivery(opt2); opt3.type = OPT; opt3.trans.noCC =2; opt3.trans.transCC[0]=3; opt3.trans.transCC[1]=1; opt3.trans.tid =
  303; Opt_Delivery(opt3); opt4.type = OPT; opt4.trans.noCC =1; opt4.trans.transCC[0]=1; //opt4.trans.transCC[1]=3 ;
  opt4.trans.tid = 404; Opt_Delivery(opt4); to3.type = TO; to3.tid = 303; To_Delivery(to3);
  to.type = TO; to.tid = 101; To_Delivery(to); to2.type = TO; to2.tid = 202; To_Delivery(to2);
  to4.type = TO; to4.tid = 404; To_Delivery(to4); commit2.tid= 202; commit2.writeset_length= sizeof("<Remote write set>");
  strcpy(commit2.writeset, "<Remote write set>"); Commit_Delivery(commit2);
  commit1.tid = 101; commit1.writeset_length= sizeof("<Remote write set>"); strcpy(commit1.writeset, "<Remote write set>");
  Commit_Delivery(commit1); commit3.tid= 303; commit3.writeset_length= sizeof("<Remote write set>"); strcpy(commit3.writeset,
  "<Remote write set>"); Commit_Delivery(commit3); */
  /* commit4.tid = 404; commit4.writeset_length= sizeof("<Remote write set>"); strcpy(commit4.writeset, "<Remote write set>");
  Commit_Delivery(commit4); */
  /* Trans remotas,  1 local con 1cc comun: opt1, opt2,opt3,opt4 to3,to1,to2,to4,c2,c3 */
  opt.type = OPT;
  opt.mclientId = -1;
  opt.trans.noCC = 1;
  opt.trans.transCC[0] = 0;
  //opt.trans.transCC[1]=1;
  opt.trans.tid = 101;
  Opt_Delivery(opt);
  opt2.type = OPT;
  opt2.mclientId = -1;
  opt2.trans.noCC = 1;
  opt2.trans.transCC[0] = 1;
  //opt2.trans.transCC[1]=1;
  opt2.trans.tid = 202;
  Opt_Delivery(opt2);
  opt3.type = OPT;
  opt3.mclientId = -1;
  opt3.trans.noCC = 2;
  opt3.trans.transCC[0] = 0;
  opt3.trans.transCC[1] = 1;
  opt3.trans.tid = 303;
  Opt_Delivery(opt3);
  opt4.type = OPT;
  opt4.mclientId = -1;
  opt4.trans.noCC = 2;
  opt4.trans.transCC[0] = 1;
  opt4.trans.transCC[1] = 3;
  opt4.trans.tid = 404;
  Opt_Delivery(opt4);
  opt5.type = OPT;
  opt5.mclientId = -1;
  opt5.trans.noCC = 2;
  opt5.trans.transCC[0] = 2;
  opt5.trans.transCC[1] = 1;
  opt5.trans.tid = 505;
  Opt_Delivery(opt5);
  opt6.type = OPT;
  opt6.mclientId = -1;
  opt6.trans.noCC = 1;
  opt6.trans.transCC[0] = 2;
  //opt6.trans.transCC[1]=3 ;
  opt6.trans.tid = 606;
  Opt_Delivery(opt6);
  opt7.type = OPT;
  opt7.mclientId = -1;
  opt7.trans.noCC = 1;
  opt7.trans.transCC[0] = 3;
  //  opt7.trans.transCC[1]=3 ;
  opt7.trans.tid = 707;
  Opt_Delivery(opt7);
  opt8.type = OPT;
  opt8.mclientId = -1;
  opt8.trans.noCC = 1;
  opt8.trans.transCC[0] = 3;
  //  opt8.trans.transCC[1]=3 ;
  opt8.trans.tid = 808;
  Opt_Delivery(opt8);
  to.type = TO;
  to.tid = 101;
  To_Delivery(to);
  to2.type = TO;
  to2.tid = 202;
  To_Delivery(to2);
  to5.type = TO;
  to5.tid = 505;
  To_Delivery(to5);
  to3.type = TO;
  to3.tid = 303;
  To_Delivery(to3);
  to7.type = TO;
  to7.tid = 707;
  To_Delivery(to7);
  to4.type = TO;
  to4.tid = 404;
  To_Delivery(to4);
  to6.type = TO;
  to6.tid = 606;
  To_Delivery(to6);
  to8.type = TO;
  to8.tid = 808;
  To_Delivery(to8);
  commit6.tid = 606;
  commit6.writeset_length = sizeof("<Remote write set>");
  strcpy(commit6.writeset, "<Remote write set>");
  Commit_Delivery(commit6);
  commit5.tid = 505;
  commit5.writeset_length = sizeof("<Remote write set>");
  strcpy(commit5.writeset, "<Remote write set>");
  Commit_Delivery(commit5);
  commit7.tid = 707;
  commit7.writeset_length = sizeof("<Remote write set>");
  strcpy(commit7.writeset, "<Remote write set>");
  Commit_Delivery(commit7);
  commit8.tid = 808;
  commit8.writeset_length = sizeof("<Remote write set>");
  strcpy(commit8.writeset, "<Remote write set>");
  Commit_Delivery(commit8);
  // process transactions
  /*    switch (msg ->type) { case OPT: Opt_Delivery(msg->opt); break; case TO: To_Delivery(msg->to); break; case COMMIT:
  Commit_Delivery(msg->commit); break; case QUERY: Query_Delivery(msg->query); break; case VIEW: View_Change(msg); break;
  case REPLY: Send_Reply(msg); break; } */
  StopQMs();
}

void printStat(){
  /*printf("POSTCOMMIT:\n");
  printf("---->Received %d CONNECTION\n", cast_count_connection);
  printf("---->Received %d TO\n", cast_count_to);
  printf("---->Received %d ALL COMMIT\n", cast_count_commit);
  printf("---->Received %d LOCAL COMMIT\n", commit_delivery_lock_local);
  printf("---->Received %d REMOTE COMMIT\n", remote_count_commit);
  printf("---->Received %d REMOTE COMMIT TRANSACTION IN COMMIT_DELIVERY\n", commit_commitTrans);
  printf("---->Received %d REMOTE NO COMMIT TRANSACTION IN COMMIT_DELIVERY\n", commit_nocommitTrans);
  printf("\t by NOT COMMITABLE <%d>\n", commit_isFirst);
  printf("\t by NOT ISFIRST <%d>\n", commit_commitable);
  printf("---->Received %d REMOTE COMMIT TRANSACTION IN EXECUTEBLOCKEDTRANS\n", commit_commitTransinblocked);
  printf("---->Received %d QM COMMIT\n", count_commit_qmcommit);
  printf("---->Received %d QM WSANDAPLLY\n", count_commit_qmwsandapply);
  printf("---->Received %d NOTIFICATION COMMIT\n", count_noticommit);
  */
  toFile();
  //calculateStat(0);
}

void printQMQueue(){
  int i;
  for (i=0;i<=MAXQM;i++){
    printf("(QMQUEUE) %d\n", i);
    QMQ_printFirstAndNumElements(waitingforQM[i]);
  }
}

void printAllQueue(){
  struct itemhCC *item;
  struct iterator_hashtable iter;

  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);
      printf("(QUEUE) CC = %d  Master = %d\n", item->id_CC, item->master);
      Q_printFirstAndNumElements(item->queue);
    }
  }
  free_iterator(&hCC, &iter);

  printQMQueue();
}

int main(int argc, char * argv[]) {
  int i;
  T_Mess message;
  //To_M to_mess;
  //struct timeval tp1, tp2;

  // Check argument number
  //if (argc != 6  && argc != 4 && argc != 2/* JSalas 3 */) {  	
  //		printf("Usage:\n %s replicas\n", argv[0]); // JSalas Number_of_CC_per_replica
#ifdef DEBUG_TRANSMNG_STATS  		
  //		printf("OR\n");
  //  	printf("Usage:\n %s replicas clients pattern\n", argv[0]);
  //  	printf("OR\n");
  //  	printf("Usage:\n %s replicas clients transactions warmup freeze\n", argv[0]);
#endif
  //  	exit(1);    
  //}

  if (argc < 2) {  	
    printf("Usage: transmng number_of_replicas -m [multicast_address] -p [port] -c [maximun_number_of_clients] -q [maximun_number_of_query_manager]\n");
  	exit(1);    
  }

  //Default Values
  TEST_PORT = 3456;
  //MAXCLIENTS = 100;
  //MAXQM = 30;
  
  i=2;  
  while (i<argc){
  	//printf ("i: %s\n", argv[i]);
  	//printf ("i+1: %s\n", argv[i+1]);
  	if (strcmp(argv[i], "-m") == 0){
        TEST_ADDR = strdup(argv[i+1]);
        i++;            	  	
    }else if (strcmp(argv[i], "-p") == 0){
    	TEST_PORT = atoi(argv[i+1]);
    	i++;
    }else if (strcmp(argv[i], "-c") == 0){
    	//MAXCLIENTS = atoi(argv[i+1]);
    	i++;
    }else if (strcmp(argv[i], "-q") == 0){
    	//MAXQM = atoi(argv[i+1]);
    	i++;
    }		
    i++;		
  }
  
  //printf ("TEST_ADDR: %s\n", TEST_ADDR);
  //printf ("TEST_PORT: %d\n", TEST_PORT);
  if (TEST_ADDR == NULL){
  	TEST_ADDR = strdup("234.5.6.7");     
  }

  signal(SIGUSR1, printAllQueue);
  signal(SIGUSR2, printStat);

#ifdef DEBUG_FILES_COMMIT
  // Initialization of files_commit
  for (i=0; i<256; i++){
    init_log_cc(&log_commit[i], i);
  }
#endif

#ifdef DEBUG_FILES_FLAG
  init_log_flag(&log_flag_finished[0], "finished_commit_delivery");
  init_log_flag(&log_flag_finished[1], "finished_commit_delivery_unlock");
  init_log_flag(&log_flag_finished[2], "finished_post_execute");
  init_log_flag(&log_flag_finished[3], "finished_executeTrans");
#endif

#ifdef DEBUG_FILES_QUEUE
  init_log_qmqueue(&log_queue, "js");
#endif

  // Initialization of variables
  INITIAL_MEMBERS = -1;
  REAL_MEMBERS = -1;
  MY_ID = -1;
  hb_rate = 1000;
  //opts_received = 0;
  //tos_received = 0;
  ncasts = 0;
  
  numConnection = 0;
  createSemaphore(1, & nconn_mutex);
  
  /*
  idx[TOTAL] = 0;
  idx[FIFO] = 0;
  */
  seqno = 0;
  begin = true;

  // Init QM semaphore
  createSemaphore(1, & QM_mutex);

  /* Initialize Hash Tables */
  //hMiddler = (HASHTABLE)hash_create(100000, TRUE);
  if(!init_hashtable(&hMiddler, 100000, tcl_hash, key_string_copy, value_copy, key_string_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  //hCC = (HASHTABLE)hash_create(100000, FALSE);
  if(!init_hashtable(&hCC, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  //hPetition = (HASHTABLE)hash_create(100000, FALSE);
  if(!init_hashtable(&hPetition, 100000, petition_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }
  set_value_free_function_hashtable(&hPetition, value_destroy_hPetition);

  //hClient = (HASHTABLE)hash_create(100000, FALSE);
  /*if(!init_hashtable(&hClient, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }*/
  
  //hOrderTotal = (HASHTABLE)hash_create(100000, FALSE);
  if(!init_hashtable(&hOrderTotal, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  //hOrderFifo = (HASHTABLE)hash_create(100000, FALSE);
  if(!init_hashtable(&hOrderFifo, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }

  if(!init_hashtable(&hDBConns, 100000, tcl_hash, key_string_copy, value_copy, key_string_compare)){
      fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }
  
  //hQMClient = (HASHTABLE)hash_create(100000, FALSE);
  /*if(!init_hashtable(&hQMClient, 100000, numeric_hash, key_numeric_copy, value_copy, keys_numeric_compare)){
  	  fprintf(stderr, "Could not initialize hashtable.\n");
      exit(EXIT_FAILURE);
  }*/

  // get the value of parameters and check correctness
  INITIAL_MEMBERS = atoi(argv[1]);
  REAL_MEMBERS = INITIAL_MEMBERS;

#ifdef DEBUG_TRANSMNG_STATS
  //Oif (argc == 6){
	  //setNumClients(atoi(argv[2]));  
	  //setNumTransactions(atoi(argv[3]));
	  //setWarmup(atoi(argv[4]), atoi(argv[5]));
  //O}
  //Oif (argc == 4){
  	  //setNumClients(atoi(argv[2]));
  	  //printf("argv[3]=<%s>\n", argv[3]);
  	  //setFileProperties(argv[3]);
  	  //OinitStatData(argv[3], atoi(argv[2]), atoi(argv[1]));
  //O}
#endif
  
  /*
  for (i = 0; i < (WARMUP * 2 + N_TXN) * 100; i++) {
    //order[0][i]=order[1][i]=0;
    arrival_s[0] [i] = arrival_s[1] [i] = 0;
    arrival_us[0] [i] = arrival_us[1] [i] = 0;
    disorder[FIFO] [i] = disorder[TOTAL] [i] = 0;
  }
  */

  // At the beginning none of the groups has completed its membership
  contexts[TOTAL].complete = false;
  contexts[FIFO].complete = false;

  createSemaphore(1, & mutex_deli);

  // Join both groups for fifo and total order
  join(FIFO);
  join(TOTAL);

  // The main program blocks waiting for the rest
  //   of the group members to finish
  // 030903
  // Message is not a Opt_m. it is a T_Mess
  InitMCSocket();
  while (1) {
    RecvMC(& message);

#ifdef DEBUG_TRANSMNG
    printf("(TRANSMNG) Multicast message %d received\n", message.type);
#endif

    if (message.type == OPT) {
      //opts_received++;

#ifdef OPTIMISTIC
      /* Begin Critical section */
      decSemaphore(& mutex_deli);

  #ifdef DEBUG_TRANSMNG
      printf("(TRANSMNG) ******** MC tid = %d\n", message.opt.trans.tid);
  #endif

      itemOrderFifo = (struct itemhOrderFifo *) malloc(sizeof(struct itemhOrderFifo));
      itemOrderFifo->tid = message.opt.trans.tid;
      #ifdef DEBUG_TRANSMNG_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)) {
        return -1;
      }
      /*
      gettimeofday(& tp1, NULL);
      arrival_s[FIFO] [message.opt.trans.tid] = tp1.tv_sec;
      arrival_us[FIFO] [message.opt.trans.tid] = tp1.tv_usec;
      disorder[FIFO] [idx[FIFO] ++] = message.opt.trans.tid;
      */
  #ifdef DEBUG_TRANSMNG
      //printf("(TRANSMNG) idx %d, tid %d\n", idx[FIFO], message.opt.trans.tid);
  #endif

      i = message.opt.trans.tid;
      #ifdef DEBUG_TRANSMNG_HASH
        printf("(HASHTABLE) Table <hOrderTotal> Operation <hash_lookup> Key <%u> File <%s> Line <%d>\n", i, __FILE__, __LINE__);
      #endif
      if ((itemOrderTotal = (struct hOrderTotal *)get_hashtable(&hOrderTotal, &i)) != NULL) {
        // the to-delivery arrived before the opt-delivery
        #ifdef DEBUG_TRANSMNG_HASH
          printf("(HASHTABLE) Table <hOrderTotal> Operation <hash_remove> Key <%u> File <%s> Line <%d>\n", itemOrderTotal->tid, __FILE__, __LINE__);
        #endif
        delete_hashtable(&hOrderTotal, &itemOrderTotal->tid);

  #ifdef DEBUG_TRANSMNG
        printf("(TRANSMNG) TO arrived before OPT %d !!!!!\n", message.opt.trans.tid);
  #endif
      } else
  #ifdef DEBUG_TRANSMNG
        printf("(TRANSMNG) endpoint8 = %s\n", message.opt.endpoint.name);
  #endif
      Opt_Delivery(message.opt);
  #ifdef DEBUG_TRANSMNG
      printf("(TRANSMNG) ******** END MC tid = %d\n", message.opt.trans.tid);
  #endif

      incSemaphore(& mutex_deli);
      /* End Critical section */
#endif
    } else if (message.type == DISCOVERY) {
#ifdef DEBUG_TRANSMNG
      printf("Driver Send DISCOVERY ...\n");
#endif
      /* Begin Critical section */
      decSemaphore(& mutex_deli);
      discovery();
      incSemaphore(& mutex_deli);
      /* End Critical section */
    }
  } //while

  createSemaphore(0, & block_main_sem);
  decSemaphore(& block_main_sem);
  //printf("(TRANSMNG) transmng finishing\n");
  
  Free(TEST_ADDR);
  exit(0);
}
