/*******************************************************************************
Feature  API: clTcCkptDelete

Description : This API will first call Checkpoint Close and then 
              Checkpoint delete. The latter function requires the
			  name given to the checkpoint, during Checkpoint open.

Arguments In: 
	1. ClTcCkptDataT : contains the ckpt handle
	2. Checkpoint Name

Arguments Out:
	1. ClTcCkptDataT : returns time taken to write the section

Return Value:
	integer 0 if success, non zero if failure
*******************************************************************************/
int clTcCkptDelete ( 
	const char*	   ckpt_name,
	ClTcCkptDataT* ckpt_data )
{
	ClRcT 		ret_code = CL_OK;
	ClNameT 	ckpt_name_t={0};
    ClTimeT startTime = 0;
    ClTimeT endTime = 0;
	ClTimeT time_taken_us =0;

	/* Initialize name struct for ckpt
	 */
	strncpy(ckpt_name_t.value, ckpt_name,CL_MAX_NAME_LENGTH-1);
	ckpt_name_t.length = strlen(ckpt_name_t.value);

	/* time check 1 start 
	 */
    startTime = clOsalStopWatchTimeGet();

	/* Delete checkpoint (test: check memory profile to ensure all resources
	 * are actually released)
	 */
	ret_code = clCkptCheckpointDelete( ckpt_svc_hdl, &ckpt_name_t);
	if ( ret_code != CL_OK )
	{
		printf("clTcCkptDelete: Failed to delete checkpoint %s: 0x%d \n",
			   ckpt_name, ret_code); 
	}
	ret_code = clCkptCheckpointClose((ClCkptHdlT)ckpt_data->ckpt_hdl);
	if ( ret_code != CL_OK )
	{
		printf("clTcCkptDelete: Failed to close checkpoint %s: 0x%d \n",
			   ckpt_name, ret_code); 
	}


	/* time check 1 end 
	 */
    endTime = clOsalStopWatchTimeGet();
	time_taken_us = endTime - startTime;

	ckpt_data->time_taken_ms = 0;
	ckpt_data->time_taken_us  = time_taken_us;

	return ret_code;
}
ClRcT clMsgQueueStatusGet(SaMsgQueueHandleT qHandle,
        SaMsgQueueStatusT *pQueueStatus)
{
    ClRcT rc, retCode;
    ClMsgQueueInfoT *pQInfo;
    ClUint32T i = 0;

    CL_OSAL_MUTEX_LOCK(&gClLocalQsLock);

    rc = clHandleCheckout(gClMsgQDatabase, qHandle, (void **)&pQInfo);
    if(rc != CL_OK)
    {
        CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);
        clLogError("QUE", "STAT", "Failed to checkout the queue handle. error code [0x%x].", rc);
        goto error_out;
    }

    CL_OSAL_MUTEX_LOCK(&pQInfo->qLock);
    CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);

    pQueueStatus->creationFlags = pQInfo->creationFlags;
    pQueueStatus->retentionTime = pQInfo->retentionTime;
    pQueueStatus->closeTime     = (clOsalStopWatchTimeGet() - pQInfo->closeTime) * 1000 ;

    for(i = 0; i < CL_MSG_QUEUE_PRIORITIES; ++i)
    {
        pQueueStatus->saMsgQueueUsage[i].queueSize = pQInfo->size[i];
        pQueueStatus->saMsgQueueUsage[i].queueUsed = pQInfo->usedSize[i];
        pQueueStatus->saMsgQueueUsage[i].numberOfMessages = pQInfo->numberOfMessages[i];
    }

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

    retCode = clHandleCheckin(gClMsgQDatabase, qHandle);
    if(retCode != CL_OK)
        clLogError("QUE", "STAT", "Failed to check-in the queue handle. error code [0x%x].", retCode);

error_out:
    return rc;
}
ClRcT
clTestCkptRead(ClCkptHdlT  ckptHdl,
               ClUint32T   numSections,
               ClTimeT *pTime)
      
{
    ClRcT           rc = CL_OK;
    ClUint32T       i = 0;
    ClCkptIOVectorElementT  iov[numSections];
    ClUint32T               readIdx = 0;
    ClTimeT oldTime = 0;
    ClTimeT newTime = 0;
    ClCkptSectionIdT  defaultSecId = CL_CKPT_DEFAULT_SECTION_ID;

    memset(iov, 0, numSections * sizeof(ClCkptIOVectorElementT));
    for( i = 0; i < numSections; i++ )
    {
        if( numSections != 1 )
        {
            iov[i].sectionId.id = clHeapCalloc(1, 15);
            if( NULL == iov[i].sectionId.id )
            {   
                return CL_OK;
            }
            snprintf( (ClCharT *) iov[i].sectionId.id, 15,"section%d", i);
            iov[i].sectionId.idLen = strlen((ClCharT *) iov[i].sectionId.id) + 1;
        }
        else
        {
            iov[i].sectionId = defaultSecId;
        }
        iov[i].dataSize = 0;
        iov[i].dataBuffer = NULL;
        iov[i].readSize = 0;
        iov[i].dataOffset = 0;
    }
    if( numSections == 1 )
    {
        oldTime = clOsalStopWatchTimeGet();
        for( i = 0; i < 100; i++ )
        {
            rc = clCkptCheckpointRead(ckptHdl, &iov[0], numSections, &readIdx); 
        }
        newTime = clOsalStopWatchTimeGet();
    }
    else
    {
        oldTime = clOsalStopWatchTimeGet();
        rc = clCkptCheckpointRead(ckptHdl, iov, numSections, &readIdx); 
        newTime = clOsalStopWatchTimeGet();
    }

    *pTime = newTime - oldTime;

    for( i = 0; i < numSections; i++ )
    {
        clHeapFree(iov[i].dataBuffer);
        if( NULL != iov[i].sectionId.id ) 
        {
            clHeapFree(iov[i].sectionId.id);
        }
    }
    return CL_OK;
}
ClRcT
clTestSectionOverwrite(ClCkptHdlT  ckptHdl,
                      ClUint32T   numSections,
                      ClUint32T   sectionSize,
                      ClTimeT     *pTime)
{
    ClRcT             rc = CL_OK;
    ClUint32T         i  = 0;
    ClUint8T          data[sectionSize];
    ClCkptSectionIdT  secId[numSections];
    ClTimeT oldTime = 0;
    ClTimeT newTime = 0;
    ClCkptSectionIdT  defaultSecId = CL_CKPT_DEFAULT_SECTION_ID;
    ClUint32T         numWrites    = 0;

    memset(data, 'a', sectionSize);

    if( numSections != 1 )
    {
        for( i = 0; i < numSections; i++ )
        {
            secId[i].id = clHeapCalloc(1, 15); 
            if( NULL == secId[i].id )
            {
                return CL_OK;
            }
            snprintf((ClCharT *) secId[i].id,15, "section%d", i);
            secId[i].idLen = strlen((ClCharT *) secId[i].id) + 1;
        }
        numWrites = numSections;
    }
    if( numSections == 1 )
    {
        numWrites = 100;
        oldTime = clOsalStopWatchTimeGet();
        for( i = 0; i < numWrites; i++ )
        {
            rc = clCkptSectionOverwrite(ckptHdl, &defaultSecId, data, sectionSize);
        }
        newTime = clOsalStopWatchTimeGet();
    }
    else
    {
        oldTime = clOsalStopWatchTimeGet();
        for( i = 0; i < numWrites; i++ )
        {
            rc = clCkptSectionOverwrite(ckptHdl, &secId[i], data, sectionSize);
        }
        newTime = clOsalStopWatchTimeGet();
    }

    *pTime = newTime - oldTime;

    if( numSections != 1 )
    {
        for( i = 0; i < numSections; i++ )
        {
            clHeapFree(secId[i].id);
        }
    }
    return CL_OK;
}
/*******************************************************************************
Feature  API: clTcCkptRead

Description : 

This API will not attempt to validate arguments, the thinking being that 
this is a volitional act by the invoker of this API to ensure that invalid 
parameters can be handled gracefully by the subsystem

Arguments In: 
	1. ClTcCkptDataT : contains the ckpt handle
	2. Section Name Prefix; if NULL no section names; if not NULL then the 
	                        section names will range from 
							<section_name_Prefix>1 to <section_name_prefix>9999
	3. section number
	4. data to read
	5. size of data to read 

Arguments Out:
	1. ClTcCkptDataT : returns time taken to read the section

Return Value:
	integer 0 if success, non zero if failure
*******************************************************************************/
int clTcCkptRead (
	ClTcCkptDataT* ckpt_data,
	const char*	   section_name_prefix,
	int			   section_num,
	void*		   data,
	int			   data_size )
{
	ClRcT 					ret_code = CL_OK;
	ClUint32T				error_index;
#if GO_TO_SECTION_DIRECTLY
	ClCharT					section_id_name[ CL_MAX_NAME_LENGTH ];
#endif
    ClCkptIOVectorElementT  io_vector;
    ClTimeT startTime = 0;
    ClTimeT endTime = 0;
    ClTimeT time_taken_us = 0;

	/* we either iterate through the sections until
	 * we get to the section of interest; or go directly
	 * to the section, assuming a known section Id; 
	 * the former is more general purpose and will be used here
	 */
#if GO_TO_SECTION_DIRECTLY
	if ( section_name_prefix != NULL )
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "%s%05d", section_name_prefix, section_num);
	}
	else
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "s%05d", section_num);
	}

	io_vector.sectionId.id = (ClUint8T*)section_id_name;
	io_vector.sectionId.idLen = strlen(section_id_name);
#else
	ret_code = clTcIterToSectionId(ckpt_data, section_num, &io_vector.sectionId);
	if (ret_code != CL_OK)
	{
		printf("clTcCkptRead: Failed to get section id: 0x%x\n", ret_code); 
		return ret_code;
	}
#endif

	/* assign other fields of the IoVector
	 */
	io_vector.dataBuffer  = NULL;
	io_vector.dataSize	  = data_size;
	io_vector.dataOffset  = 0;
	io_vector.readSize	  = 0;

	/* time check 1 start 
 	 */
	startTime = clOsalStopWatchTimeGet();
	ret_code = clCkptCheckpointRead((ClCkptHdlT)ckpt_data->ckpt_hdl,
									&io_vector, 1, &error_index );
	/* time check 1 end 
	 */
    endTime = clOsalStopWatchTimeGet();
	time_taken_us = endTime - startTime;

	ckpt_data->time_taken_ms = 0;
	ckpt_data->time_taken_us  = time_taken_us;

	if (ret_code != CL_OK)
	{
		printf("clTcCkptRead: Failed to read: 0x%x\n", ret_code); 
		return ret_code;
	}
	else
	{
		if ( io_vector.readSize != data_size )
		{
			printf("clTcCkptRead: Read %d bytes; expected %d bytes\n", 
				   (int)io_vector.readSize, data_size);
		}

		if (data_size <= io_vector.readSize)
		{
			memcpy(data, io_vector.dataBuffer, data_size);
		}
		else
		{
			memcpy(data, io_vector.dataBuffer, io_vector.readSize);
		}

		/* Free up buffer allocated by Ckpt Service
		 */
		clHeapFree(io_vector.dataBuffer);
	}

	return ret_code;
}
/*******************************************************************************
Feature  API: clTcCkptWrite

Description : 

This API will not attempt to validate arguments, the thinking being that 
this is a volitional act by the invoker of this API to ensure that invalid 
parameters can be handled gracefully by the subsystem

Arguments In: 
	1. ClTcCkptDataT : contains the ckpt handle
	2. Section Name Prefix; if NULL no section names; if not NULL then the 
	                        section names will range from 
							<section_name_Prefix>1 to <section_name_prefix>9999
	3. section number
	4. data to write
	5. size of data to write 

Arguments Out:
	1. ClTcCkptDataT : returns time taken to write the section

Return Value:
	integer 0 if success, non zero if failure
*******************************************************************************/
int clTcCkptWrite (
	ClTcCkptDataT* ckpt_data,
	const char*	   section_name_prefix,
	int			   section_num,
	void*		   data,
	int			   data_size )
{
	ClRcT 						ret_code = CL_OK;
#if GO_TO_SECTION_DIRECTLY
	ClCharT						section_id_name[ CL_MAX_NAME_LENGTH ];
#endif
    ClCkptSectionIdT    		section_id;

    ClTimeT startTime = 0;
    ClTimeT endTime = 0;
	ClTimeT					time_taken_us = 0;


	/* Does the ckpt_data have a valid chek point handle
	 */

	
	/* we either iterate through the sections until
	 * we get to the section of interest; or go directly
	 * to the section, assuming a known section Id; 
	 * the former is more general purpose and will be used here
	 */
#if GO_TO_SECTION_DIRECTLY
	if ( section_name_prefix != NULL )
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "%s%05d", section_name_prefix, section_num);
	}
	else
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "s%05d", section_num);
	}
	section_id.id = (ClUint8T*)section_id_name;
	section_id.idLen = strlen(section_id_name);
#else
	ret_code = clTcIterToSectionId(ckpt_data, section_num, &section_id);

	if (ret_code != CL_OK)
	{
		printf("clTcCkptWrite: Failed to get section id: 0x%x\n", ret_code); 
		return ret_code;
	}
#endif

	/* Set the local replica to be active 
	 * the api sets it only if required (i.e the type is async collocated)
	 */
	ret_code = clTcActivateReplica(ckpt_data);
	if (ret_code != CL_OK)
	{
		printf("clTcCkptWrite: Failed to activate ckpt: 0x%x\n", ret_code); 
		return ret_code;
	}

	/* time check 1 start 
 	 */
    startTime = clOsalStopWatchTimeGet();
	ret_code = clCkptSectionOverwrite((ClCkptHdlT)ckpt_data->ckpt_hdl,
									  &section_id,
									  data, data_size);
	/* time check 1 end 
	 */
    endTime = clOsalStopWatchTimeGet();
	time_taken_us = endTime - startTime;

	ckpt_data->time_taken_ms = 0;
	ckpt_data->time_taken_us  = time_taken_us;

	if (ret_code != CL_OK)
	{
		printf("clTcCkptWrite: Failed to write: 0x%x\n",
			   ret_code); 
	}

	return ret_code;
}
/*******************************************************************************
Feature  API: clTcCkptCreate

Description : Create a checkpoint given a name and the number of sections. In 
addition the nature of the checkpoint needs to be specified, synchronous versus 
asynchronous. If asynchronous collocated versus non collocated.

This API will not attempt to validate arguments, the thinking being that 
this is a volitional act by the invoker of this API to ensure that invalid 
parameters can be handled gracefully by the subsystem

Arguments In: 
	1. Checkpoint Name
	2. Section Name Prefix; if NULL no section names; if not NULL then the 
	                        section names will range from 
							<section_name_Prefix>1 to <section_name_prefix>9999
	3. Number of Sections
	4. Size of section
	5. Synchronous/Asynchronous Collocated/Asynhrnous Noncollocated
	6. Output data:

Arguments Out:
	1. ClTcCkptDataT : returns time taken to create ckpt, and ckpt_handle

Return Value:
	integer 0 if success, non zero if failure
*******************************************************************************/
int
clTcCkptCreate (
	const char 		*ckpt_name,
	const char 		*section_name_prefix,
	int				num_sections,
	int				section_size,
	ClTcCkptTypeE	ckpt_type,
	ClTcCkptDataT	*ckpt_data )
{

	ClRcT 								ret_code = CL_OK;
	ClNameT 							ckpt_name_t = {0};
	ClCkptCheckpointCreationAttributesT	ckpt_cr_attr;
	ClCkptOpenFlagsT					ckpt_open_flags;
	ClTimeT								timeout;

	int									section_num;
	ClCharT								section_id_name[ CL_MAX_NAME_LENGTH ];
	ClUint8T							*section_name_ptr;
    ClCkptSectionIdT          			section_id;
    ClCkptSectionCreationAttributesT    section_cr_attr;
#ifdef PRE_ALLOCATE_SECTION
	ClPtrT							    section_data;
#endif

    ClTimeT startTime = 0;
    ClTimeT endTime = 0;
    ClTimeT time_taken_us = 0;

	/* First ensure that the Initialize function is called
	 */
	ret_code = clTcCkptSvcInit();
	if (ret_code != CL_OK)
	{
		printf("clTcCkptCreate: failed to initialze service \n");
		return ret_code;
	}

	/* Initiailze name struct for ckpt
	 */
	strncpy(ckpt_name_t.value, ckpt_name, CL_MAX_NAME_LENGTH-1);
	ckpt_name_t.length = strlen(ckpt_name_t.value);

	/* Get the max size for a  name of sectionId
	 */
	if (section_name_prefix != NULL)
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "%s%05d", section_name_prefix, num_sections );
	}
	else
	{
		snprintf(section_id_name,CL_MAX_NAME_LENGTH, "s%05d", num_sections);	 
	}


	/* Initialize check point creation flags
	 */
	switch (ckpt_type)
	{
		case TC_CKPT_SYNC:
			ckpt_cr_attr.creationFlags = CL_CKPT_WR_ALL_REPLICAS;
			break;

		case TC_CKPT_ASYNC_COLLOC:
			ckpt_cr_attr.creationFlags = CL_CKPT_CHECKPOINT_COLLOCATED;
			break;

		case TC_CKPT_ASYNC_NON_COLLOC:
			ckpt_cr_attr.creationFlags = CL_CKPT_WR_ACTIVE_REPLICA;
			break;

		default:
			printf("clTcCkptCreate: (warning) invalid checkpoint type\n");
			ckpt_cr_attr.creationFlags = ckpt_type;
	}

	/* Maximum checkpoint size = size of all checkpoints combined
	 */
	ckpt_cr_attr.checkpointSize = num_sections * section_size;

	/* Can make this a configurable parameter when reading from 
	 * a file as opposed to API arguments; for now hardcoded to
	 * forever
	 */
	ckpt_cr_attr.retentionDuration = (ClTimeT)-1;

	ckpt_cr_attr.maxSections = num_sections;

	ckpt_cr_attr.maxSectionSize = section_size;

	ckpt_cr_attr.maxSectionIdSize = (ClSizeT)(strlen(section_id_name)+1);

	/* Initialize the checkpoint open flags
	 */
	ckpt_open_flags = (CL_CKPT_CHECKPOINT_READ  |
					   CL_CKPT_CHECKPOINT_WRITE |
					   CL_CKPT_CHECKPOINT_CREATE);

	/* Can make this a configurable parameter when reading from 
	 * a file as opposed to API arguments; for now hardcoded to
	 * forever
	 */
	timeout = (ClTimeT)-1;

	/* time check 1 start 
	 */
    startTime = clOsalStopWatchTimeGet();

	ret_code = clCkptCheckpointOpen(ckpt_svc_hdl, 
									&ckpt_name_t, 
									&ckpt_cr_attr,
									ckpt_open_flags,
									timeout,
									( ClCkptHdlT *)(&ckpt_data->ckpt_hdl));
	/* time check 1 end
	 */
    endTime = clOsalStopWatchTimeGet();

	time_taken_us = endTime - startTime;

	ckpt_data->time_taken_ms = 0;
	ckpt_data->time_taken_us  = time_taken_us;

	if (ret_code != CL_OK)
	{
		printf("clTcCkptCreate: Failed to create ckpt:0x%x \n", ret_code);
		return ret_code;
	}

	/* Intialize section create arguments 
	 */
	
	section_id.idLen = (ClUint16T)strlen(section_id_name); 
	section_id.id    = (ClUint8T*)section_id_name;

	/* If there is a section name prefix, then set the
	 * prefix and advance a pointer to affix the unique
	 * id of a section within the section create loop
	 */
	if ( section_name_prefix != NULL )
	{
		snprintf((ClCharT*)section_id.id,CL_MAX_NAME_LENGTH, "%s", section_name_prefix);
		/* pointer to the part of the string that the 
	 	 * unique identifier of a section will be placed
	 	 */
		section_name_ptr = section_id.id + strlen(section_name_prefix);
	}
	else
	{
		snprintf((ClCharT*)section_id.id, CL_MAX_NAME_LENGTH,"s");

		section_name_ptr = section_id.id + 1; 
	}


	/* Expiration time for section can also be varied
	 * once parameters are read from a configuration file
	 */
	section_cr_attr.expirationTime = (ClTimeT)CL_TIME_END;

	/* ensure that the section ids need to be named
	 */
	section_cr_attr.sectionId = &section_id;

#ifdef PRE_ALLOCATE_SECTION
	/* create a data buffer, because the size given to
	 * the section at creation remains with it forever
	 * not sure if this is a bug
	 */
	section_data = clHeapAllocate(section_size);
	if (section_data == NULL)
	{
		printf("clTcCkptCreate: Failed to allocate section data\n");
		goto clean_up_code;
	}
#endif
	
	/* Set the local replica to be active 
	 * You cannot do any activity on this checkpoint
	 * including a status get (see Bug 6118) unless you 
	 * call this API
	 * 
	 */
	if (ckpt_type == TC_CKPT_ASYNC_COLLOC)
	{
   		ret_code = clCkptActiveReplicaSet((ClCkptHdlT)ckpt_data->ckpt_hdl);
		if (ret_code != CL_OK)
		{
			printf("clTcCkptCreate: Failed to activate replica :0x%x\n", 
			   	   ret_code);
			goto clean_up_code;
		}
	}

	/* Create the sections within the checkpoint
	 */
	for ( section_num = 1; section_num <= num_sections; section_num++ )
	{
		sprintf((ClCharT*)section_name_ptr, "%05d", section_num);
		section_id.idLen = strlen((ClCharT*)section_id.id);

		/* time check 2 start (cumulative)
	 	 */
        startTime = clOsalStopWatchTimeGet();
		ret_code = clCkptSectionCreate((ClCkptHdlT)ckpt_data->ckpt_hdl,
									   &section_cr_attr,
									   NULL, 0);
		/* time check 2 end (cumulative)
		 */
        endTime = clOsalStopWatchTimeGet();

		/* does not account for overflow
		 */
		time_taken_us = endTime - startTime;
		ckpt_data->time_taken_us  += time_taken_us;

		if (ret_code != CL_OK)
		{
			printf("clTcCkptCreate: Failed to create section #%d :0x%x \n", 
					section_num, ret_code);
			goto clean_up_code;
		}
	}

	/* total time taken excluding any intialization code
	 * time check 1 + time check 2
	 */

	/* free up memory allocated to initialize section
	 */
#ifdef PRE_ALLOCATE_SECTION
	clHeapFree(section_data);
#endif
	return ret_code;

	clean_up_code:
	/* Delete checkpoint (test: check memory profile to ensure all resources
	 * are actually released)
	 */
	if ( clCkptCheckpointDelete( ckpt_svc_hdl, &ckpt_name_t) != CL_OK )
	{
		printf("clTcCkptCreate: Failed to delete checkpoint %s\n", ckpt_name); 
	}

	return ret_code;	
}
ClRcT _clTxnAgentProcessMgrCmd(
        CL_IN   ClBufferHandleT     inMsgHandle,
        CL_IN   ClBufferHandleT     outMsgHandle,
        CL_IN   ClTxnMessageHeaderT *pMsgHdr)
{
    ClRcT   rc  = CL_OK;
    ClTxnCmdT   tCmd = {.resp = CL_OK };
    ClTxnCommHandleT commHandle = NULL;
    ClUint32T   mCount = pMsgHdr->msgCount;
    ClTimeT t1, t2;

    
    CL_FUNC_ENTER();

    clLogDebug("AGT", NULL,
            "Received processing cmd from TM. Message count [%d]", 
            pMsgHdr->msgCount);
    t1 = clOsalStopWatchTimeGet();

    while ( (CL_OK == tCmd.resp) && (pMsgHdr->msgCount > 0) )
    {

        pMsgHdr->msgCount--;

        rc = VDECL_VER(clXdrUnmarshallClTxnCmdT, 4, 0, 0)(inMsgHandle, &tCmd);
        switch (tCmd.cmd)
        {
            case CL_TXN_CMD_INIT:
                rc = clTxnAgentTxnDefnReceive(tCmd, inMsgHandle); 
                if(CL_OK != rc)
                {
                    clLogError("AGT", "MTA",
                            "Failed to process init command from manager, rc=[0x%x]",
                            rc);
                    /* Construct payload to send response back to server */
                    clTxnMutexLock(clTxnAgntCfg->actMtx);
                    
                   /* tCmd.resp = rc; */

                    rc = clTxnCommIfcNewSessionCreate(CL_TXN_MSG_AGNT_RESP, 
                                                      pMsgHdr->srcAddr, 
                                                      CL_TXN_SERVICE_AGENT_RESP_RECV, 
                                                      NULL, CL_TXN_RMD_DFLT_TIMEOUT,  
                                                      CL_TXN_COMMON_ID, /* Value is 0x1 */
                                                      &commHandle);
                    if (CL_OK == rc)
                    {
                        rc = clTxnCommIfcSessionAppendTxnCmd(commHandle, &tCmd);

                        if (CL_OK != rc)
                        {
                            clLogError("AGT", NULL,
                                    "Failed to append cmd in the response with error [0x%x]",
                                    rc); 
                            clTxnMutexUnlock(clTxnAgntCfg->actMtx);
                            break;
                        }
                        rc = clTxnCommIfcSessionRelease(commHandle);
                        if (CL_OK != rc)
                        {
                            clLogError("AGT", NULL,
                                    "Failed to release session with error[0x%x]",
                                    rc); 
                            clTxnMutexUnlock(clTxnAgntCfg->actMtx);
                            break;
                        }
                        clTxnMutexUnlock(clTxnAgntCfg->actMtx);
                    }
                    else
                        clLogError("AGT", "ATM", 
                                "Failed to create new session for key [Node:0x%x,Port:0x%x]", 
                                pMsgHdr->srcAddr.nodeAddress, pMsgHdr->srcAddr.portId);
                    break;

                }
                /* Request for the first time */
                if(mCount == (pMsgHdr->msgCount + 1) )
                {
                    rc = _clTxnAgentTxnStart(tCmd);
                    if(CL_OK != rc)
                    {
                        /*tCmd.resp = rc; */
                        clLogError("AGT", "MTA",
                                "Failed to start transaction[0x%x:0x%x], rc=[0x%x]",
                                tCmd.txnId.txnMgrNodeAddress,
                                tCmd.txnId.txnId,
                                rc);
                        break;
                    }
                    clLogDebug("AGT", "MTA",
                            "Transaction[0x%x:0x%x] started",
                            tCmd.txnId.txnMgrNodeAddress,
                            tCmd.txnId.txnId);
                }
                break;

            case CL_TXN_CMD_PREPARE:
            case CL_TXN_CMD_1PC_COMMIT:
            case CL_TXN_CMD_2PC_COMMIT:
            case CL_TXN_CMD_ROLLBACK:
                rc = clTxnAgentProcessJob(pMsgHdr, tCmd, outMsgHandle, &commHandle);
                if(CL_OK != rc)
                {
                  /*  tCmd.resp = rc; */
                    clLog(CL_LOG_ERROR, "AGT", NULL,
                            "Error in processing cmd [%s] from server. rc [0x%x]", 
                            _clTxnCmdNameGet(tCmd.cmd), rc);
                }
                if(!pMsgHdr->msgCount && 
                    ( (tCmd.cmd == CL_TXN_CMD_ROLLBACK) || 
                      (tCmd.cmd == CL_TXN_CMD_2PC_COMMIT) ) 
                  )
                {
                    rc = _clTxnAgentTxnStop(tCmd);
                    if(CL_OK != rc)
                    {
                       /* tCmd.resp = rc; */
                        clLogError("AGT", "MTA",
                                "Failed to stop transaction[0x%x:0x%x], rc=[0x%x]",
                                tCmd.txnId.txnMgrNodeAddress,
                                tCmd.txnId.txnId, rc);
                    }
                    else
                        clLogDebug("AGT", "MTA",
                                "Transaction[0x%x:0x%x] stopped",
                                tCmd.txnId.txnMgrNodeAddress,
                                tCmd.txnId.txnId);
                }
                
                /* Remove the joblist when ROLLBACK or COMMIT is complete */
                if( (tCmd.cmd == CL_TXN_CMD_ROLLBACK) || 
                    (tCmd.cmd == CL_TXN_CMD_2PC_COMMIT) ) 
                {
                    ClTxnDefnPtrT pTxnDefn = NULL;
                    clLogDebug("AGT", NULL,
                            "Received remove cmd from server");
                    rc = clTxnDbTxnDefnGet(clTxnAgntCfg->activeTxnMap, 
                                    tCmd.txnId, &pTxnDefn);
                    if(CL_OK == rc)
                    {
                        if(1 < pTxnDefn->jobCount)
                        {
                            rc = clTxnAppJobRemove(pTxnDefn, tCmd.jobId);
                            if(CL_OK != rc)
                            {
                                ClNameT name = {0};
                                clCpmComponentNameGet(0, &name);
                                clLog(CL_LOG_ERROR, "AGT", NULL,
                                     "REMOVE cmd received. Error in removing the job information for component [%s] rc [0x%x]", 
                                     name.value, rc);
                                return rc;
                            }

                        }
                        else if(1 == pTxnDefn->jobCount) /* This is the last job, delete the entire txn list */
                        {
                            ClCntNodeHandleT nodeHandle;
                            rc  = clCntNodeFind(
                                    clTxnAgntCfg->activeTxnMap, 
                                    (ClCntKeyHandleT )&(tCmd.txnId), 
                                    &nodeHandle);
                            if(rc == CL_OK)
                            {
                                rc = clCntNodeDelete(clTxnAgntCfg->activeTxnMap, nodeHandle);
                                if(CL_OK != rc)
                                {
                                    clLog(CL_LOG_ERROR, "AGT", NULL, 
                                         "REMOVE cmd received. Error in deleting txn defn for txnId [0x%x] rc [0x%x]", 
                                         tCmd.txnId.txnId, rc);
                                    return rc;
                                }
                            }

                        }
                        else
                        {
                            clLog(CL_LOG_ERROR, "AGT", NULL,
                            "Remove cmd received. There is no txndefn corresponding to txnId [0x%x]. Jobcount [%d]\n",
                             tCmd.txnId.txnId, pTxnDefn->jobCount);
                        }
                    }
                }
                
                break;
                default:
                    clLog(CL_LOG_ERROR, "AGT", NULL, 
                        "Invalid command received from TM [0x%x]", tCmd.cmd);
                    rc = CL_ERR_INVALID_PARAMETER;
                    break;
        }
    }
    if((tCmd.cmd != CL_TXN_CMD_REMOVE_JOB) && commHandle)
    {
        rc = clTxnCommIfcReadMessage(commHandle, outMsgHandle);
        if(CL_OK != rc)
        {
            clLogError("AGT", NULL,
                    "Failed to write the response with error [0x%x]",
                    rc);
        }
        else
            clLogDebug("AGT", "ATM",
                    "Successfully sent response back");
        t2 = clOsalStopWatchTimeGet();
        clLogDebug("AGT", NULL,
                "Time taken to complete command[%d], [%lld]usecs",
                tCmd.cmd, (t2-t1) );
    }

    if (CL_OK != rc)
    {
            rc = CL_GET_ERROR_CODE(rc);
    }

    CL_FUNC_EXIT();
    return (rc);
}
Exemplo n.º 9
0
ClRcT clRmdObjInit(ClRmdObjHandleT *p)
{
    ClRcT retCode = CL_OK;
    ClRmdObjT *pRmdObject = NULL;
    //unsigned long timeStamp = 0;
    struct timeval tm1;

#ifdef DEBUG
    static ClUint8T rmdAddedTodbgComp = CL_FALSE;

    if (CL_FALSE == rmdAddedTodbgComp)
    {
        retCode = dbgAddComponent(COMP_PREFIX, COMP_NAME, COMP_DEBUG_VAR_PTR);
        rmdAddedTodbgComp = CL_TRUE;
        if (CL_OK != retCode)
        {
            clLogError("OBG","INI","dbgAddComponent FAILED ");
            CL_FUNC_EXIT();
            return retCode;
        }
    }
#endif
    CL_FUNC_ENTER();

    if (NULL == p)
    {
        RMD_DBG1((" RMD Invalid Object handle passed\n"));
        CL_FUNC_EXIT();
        return ((CL_RMD_RC(CL_ERR_INVALID_PARAMETER)));
    }

    retCode = clOsalInitialize(NULL);

    retCode = clTimerInitialize(NULL);
    pRmdObject = (ClRmdObjT *) clHeapAllocate(sizeof(ClRmdObjT));

    if (NULL == pRmdObject)
    {
        RMD_DBG1((" RMD No Memory\n"));
        CL_FUNC_EXIT();
        return ((CL_RMD_RC(CL_ERR_NO_MEMORY)));
    }

    gettimeofday(&tm1, NULL);
    //timeStamp = tm1.tv_sec * 1000000 + tm1.tv_usec;
    pRmdObject->msgId = 1;
    retCode = clOsalMutexCreate(&pRmdObject->semaForSendHashTable);

    if (CL_OK != CL_GET_ERROR_CODE(retCode))
    {
        RMD_DBG1((" RMD send Mutex creation failed\n"));
        CL_FUNC_EXIT();
        return (retCode);
    }
    retCode = clOsalMutexCreate(&pRmdObject->semaForRecvHashTable);

    if (CL_OK != CL_GET_ERROR_CODE(retCode))
    {
        RMD_DBG1((" RMD  recv Mutex creation failed\n"));

        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForSendHashTable));
        CL_FUNC_EXIT();
        return (retCode);
    }

    retCode =
        clCntHashtblCreate(NUMBER_OF_RECV_BUCKETS, recvKeyCompare,
                           recvHashFunction, recvHashDeleteCallBack,
                           recvHashDeleteCallBack, CL_CNT_UNIQUE_KEY,
                           &pRmdObject->rcvRecContainerHandle);
    if (CL_OK != CL_GET_ERROR_CODE(retCode))
    {
        RMD_DBG1((" RMD  send Hash table creation failed\n"));

        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForRecvHashTable));
        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForSendHashTable));
        CL_FUNC_EXIT();
        return (retCode);
    }
    retCode =
        clCntHashtblCreate(NUMBER_OF_SEND_BUCKETS, sendKeyCompare,
                           sendHashFunction, sendHashDeleteCallBack,
                           sendHashDestroyCallBack, CL_CNT_UNIQUE_KEY,
                           &pRmdObject->sndRecContainerHandle);
    if (CL_OK != CL_GET_ERROR_CODE(retCode))
    {
        RMD_DBG1((" RMD  recv Hash table creation failed\n"));

        IGNORE_RETURN(clCntDelete(pRmdObject->rcvRecContainerHandle));
        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForRecvHashTable));
        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForSendHashTable));
        CL_FUNC_EXIT();
        return (retCode);
    }

    pRmdObject->responseCntxtDbHdl = 0;
    retCode = clHandleDatabaseCreate(NULL, &pRmdObject->responseCntxtDbHdl);
    if (retCode != CL_OK)
    {
        RMD_DBG1((" RMD  Sync Handle Database create failed\n"));
        IGNORE_RETURN(clCntDelete(pRmdObject->sndRecContainerHandle));
        IGNORE_RETURN(clCntDelete(pRmdObject->rcvRecContainerHandle));
        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForRecvHashTable));
        IGNORE_RETURN(clOsalMutexDelete(pRmdObject->semaForSendHashTable));

        CL_FUNC_EXIT();
        return retCode;
    }

    pRmdObject->numAtmostOnceEntry = 0;
    pRmdObject->lastAtmostOnceCleanupTime = clOsalStopWatchTimeGet();
    pRmdObject->rmdStats.nRmdCalls = 0;
    pRmdObject->rmdStats.nFailedCalls = 0;
    pRmdObject->rmdStats.nResendRequests = 0;
    pRmdObject->rmdStats.nRmdReplies = 0;
    pRmdObject->rmdStats.nBadReplies = 0;
    pRmdObject->rmdStats.nRmdRequests = 0;
    pRmdObject->rmdStats.nBadRequests = 0;
    pRmdObject->rmdStats.nCallTimeouts = 0;
    pRmdObject->rmdStats.nDupRequests = 0;
    pRmdObject->rmdStats.nAtmostOnceCalls = 0;
    pRmdObject->rmdStats.nResendReplies = 0;
    pRmdObject->rmdStats.nReplySend = 0;
    pRmdObject->rmdStats.nRmdCallOptimized = 0;
    *p = (ClRmdObjHandleT) pRmdObject;
    CL_FUNC_EXIT();
    return (CL_OK);
}