ClRcT clMsgMessageCancel(SaMsgQueueHandleT qHandle)
{
    ClRcT rc;
    ClRcT retCode;
    ClMsgQueueInfoT *pQInfo;

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

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

    rc = clMsgUnblockThreadsOfQueue(pQInfo);

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

    retCode = clHandleCheckin(gClMsgQDatabase, qHandle);
    if(retCode != CL_OK)
        clLogError("QUE", "CANL", "Failed to checkin queue handle. error code [0x%x].", retCode);

error_out:
    return rc;
}
static ClRcT clMsgDebugCliQueueInfo(ClUint32T argc,
                                    ClCharT **argv,
                                    ClCharT **ret)
{
    ClRcT rc = CL_OK;
    ClDebugPrintHandleT dbgHdl = 0;

    clDebugPrintInitialize(&dbgHdl);
    
    CL_OSAL_MUTEX_LOCK(&gClLocalQsLock);
    rc = clHandleWalk(gClMsgQDatabase, clMsgQueueInfoCb, (ClPtrT)dbgHdl);
    if (rc != CL_OK)
    {
        clLogError("MSG", "CLI", "Handle walk failed, error [%#x]", rc);
        CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);
        goto out;
    }
    CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);

    clDebugPrintFinalize(&dbgHdl, ret);
    
    return CL_OK;
out:    
    return rc;
}
ClRcT clMsgQueueStatusGet_4_0_0( SaNameT *pQName, SaMsgQueueStatusT *pQueueStatus)
{
    ClRcT rc = CL_OK;
    ClMsgQueueRecordT *pQEntry;
    SaMsgQueueHandleT qHandle;

    CL_MSG_INIT_CHECK(rc);
    if( rc != CL_OK)
    {
       goto error_out;
    }
    CL_OSAL_MUTEX_LOCK(&gClQueueDbLock);
    if(clMsgQNameEntryExists(pQName, &pQEntry) == CL_FALSE)
    {
        CL_OSAL_MUTEX_UNLOCK(&gClQueueDbLock);
        rc = CL_MSG_RC(CL_ERR_DOESNT_EXIST);
        clLogError("QUE", "STAT", "Queue [%.*s] does not exist. error code [0x%x].", pQName->length, pQName->value, rc);
        goto error_out;
    }
    qHandle = pQEntry->qHandle;
    CL_OSAL_MUTEX_UNLOCK(&gClQueueDbLock);

    rc = clMsgQueueStatusGet(qHandle, pQueueStatus);
    if(rc != CL_OK)
        clLogTrace("QUE", "STAT", "Failed to get the status of the queue [%.*s]. error code [0x%x].", pQName->length, pQName->value, rc);

error_out:
    return rc;
}
ClRcT clMsgQueueFreeByHandle(SaMsgQueueHandleT qHandle)
{
    ClRcT rc;
    ClMsgQueueInfoT *pQInfo;

    CL_OSAL_MUTEX_LOCK(&gClLocalQsLock);

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

    clMsgQueueFree(pQInfo);
    clLogDebug("QUE", "FREE", "Queue is freed through its handle."); 

    CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);

    rc = clHandleCheckin(gClMsgQDatabase, qHandle);
    if(rc != CL_OK)
        clLogError("QUE", "FREE", "Failed to checkin a queue handle. error code [0x%x].", rc);

    rc = clHandleDestroy(gClMsgQDatabase, qHandle);
    if(rc != CL_OK)
        clLogError("QUE", "FREE", "Failed to destroy a queue handle. error code [0x%x].", rc);

error_out:
    return rc;

}
static void clMsgEventCallbackFunc(ClEventSubscriptionIdT subscriptionId, ClEventHandleT eventHandle, ClSizeT eventDataSize)
{
    ClRcT rc;
    ClCpmEventNodePayLoadT nodePayload = {{0}};

    rc = clCpmEventPayLoadExtract(eventHandle, eventDataSize, CL_CPM_NODE_EVENT, (void *)&nodePayload);
    if(rc != CL_OK)
    {
        clLogError("EVT", "Cbk", "Failed to get event payload data. error code [0x%x].", rc);
        goto error_out;
    }

    if(nodePayload.operation != CL_CPM_NODE_DEPARTURE)
        goto out;

    clLogDebug("EVT", "Cbk", "Node [0x%x] is going down. Message queues are going to be failed over.", nodePayload.nodeIocAddress);

    if(nodePayload.nodeIocAddress == gLocalAddress)
    {
        CL_OSAL_MUTEX_LOCK(&gFinBlockMutex);
        rc = clMsgFinBlockStatusSet(MSG_MOVE_FIN_BLOCKED);
        CL_OSAL_MUTEX_UNLOCK(&gFinBlockMutex);
        if(rc != CL_OK)
            clLogError("EVT", "Cbk", "Failed at block the message finalize on this node. error code [0x%x].", rc);
    }

error_out:
out:
    clEventFree(eventHandle);
    return;
}
ClRcT clMsgQueueRetentionTimeSet(SaMsgQueueHandleT qHandle, SaTimeT *pRetenTime)
{
    ClRcT rc;
    ClRcT retCode;
    ClMsgQueueInfoT *pQInfo;

    CL_OSAL_MUTEX_LOCK(&gClLocalQsLock);
    rc = clHandleCheckout(gClMsgQDatabase, qHandle, (void **)&pQInfo);
    if(rc != CL_OK)
    {
        CL_OSAL_MUTEX_UNLOCK(&gClLocalQsLock);
        clLogError("QUE", "RET", "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);

    if(pQInfo->state == CL_MSG_QUEUE_CLOSED)
    {
        rc = CL_MSG_RC(CL_ERR_INVALID_HANDLE);
        clLogError("QUE", "RET", "Queue [%.*s] is in closed state. Cannot change retention time. error code [0x%x].", 
                pQInfo->pQueueEntry->qName.length, pQInfo->pQueueEntry->qName.value, rc);
        goto error_out_1;
    }

    if(pQInfo->creationFlags != 0)
    {
        rc = CL_MSG_RC(CL_ERR_BAD_OPERATION);
        clLogError("QUE", "RET", "Retention time can be set for only for non-persistent queues. error code [0x%x].", rc);
        goto error_out_1;
    }

    pQInfo->retentionTime = *pRetenTime;

error_out_1:
    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);
    retCode = clHandleCheckin(gClMsgQDatabase, qHandle);
    if(retCode != CL_OK)
        clLogError("QUE", "RET", "Failed to checkin queue handle. error code [0x%x].", retCode);

error_out:
    return rc;
}
void * clMsgClosedQueueMoveThread(void *pParam)
{
    ClRcT rc;
    CL_OSAL_MUTEX_LOCK(&gFinBlockMutex);
    rc = clMsgFinBlockStatusSet(MSG_MOVE_FIN_BLOCKED);
    CL_OSAL_MUTEX_UNLOCK(&gFinBlockMutex);
    if(rc != CL_OK)
        clLogError("MOV", "Thd", "Failed at block the message finalize on this node. error code [0x%x].", rc);

    return NULL;
}
void clMsgQueueFree(ClMsgQueueInfoT *pQInfo)
{
    ClRcT rc = CL_OK;
    SaNameT qName = {strlen("--Unknow--"), "--Unknow--"};
    ClUint32T i;

    CL_OSAL_MUTEX_LOCK(&pQInfo->qLock);

    (void)clMsgUnblockThreadsOfQueue(pQInfo);

    if(pQInfo->unlinkFlag == CL_FALSE && pQInfo->pQueueEntry != NULL)
    {
        saNameCopy(&qName, &pQInfo->pQueueEntry->qName);
    }
    
    if(pQInfo->timerHandle != 0)
    {
        rc = clTimerDelete(&pQInfo->timerHandle);
        if(rc != CL_OK)
            clLogError("QUE", "FREE", "Failed to delete [%.*s]'s timer handle. error code [0x%x].", 
                       qName.length, qName.value, rc);
    }
    
    clMsgQueueEmpty(pQInfo);

    for(i = 0; i < CL_MSG_QUEUE_PRIORITIES ; i++)
    {
        rc = clCntDelete(pQInfo->pPriorityContainer[i]);
        if(rc != CL_OK)
            clLogError("QUE", "FREE", "Failed to delete the [%.*s]'s [%d] priority container. error code [0x%x].", 
                       qName.length, qName.value, i, rc);
        else
            pQInfo->pPriorityContainer[i] = 0;
    }

    rc = clOsalCondDelete(pQInfo->qCondVar);
    if(rc != CL_OK)
        clLogError("QUE",  "FREE", "Failed to delete the [%.*s]'s condtional variable. error code [0x%x].",
                   qName.length, qName.value, rc);

    pQInfo->qCondVar = 0;

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

    rc = clOsalMutexDestroy(&pQInfo->qLock);
    if(rc != CL_OK)
        clLogError("QUE",  "FREE", "Failed to delete the [%.*s]'s lock. error code [0x%x].",
                   qName.length, qName.value, rc);

    clLogDebug("QUE", "FREE", "Freed the queue [%.*s].", qName.length, qName.value);

    return;
}
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     = 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 clMsgQueueOpen(SaMsgQueueHandleT qHandle,
        SaMsgQueueOpenFlagsT openFlags)
{
    ClRcT rc = CL_OK, retCode;
    ClMsgQueueInfoT *pQInfo;

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

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

    if(pQInfo->timerHandle)
        clTimerDelete(&pQInfo->timerHandle);

    if(openFlags & SA_MSG_QUEUE_EMPTY)
        clMsgQueueEmpty(pQInfo);

    pQInfo->openFlags = openFlags;
    pQInfo->state = CL_MSG_QUEUE_OPEN;
    pQInfo->closeTime = 0;

    CL_OSAL_MUTEX_UNLOCK(&pQInfo->qLock);

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

error_out:
    return rc;
}
ClRcT clMsgFinalizeBlocker(void)
{
    ClRcT rc = CL_OK;
    SaTimeT timeout = (SaTimeT)(CL_MSG_FIN_BLOCK_TIME * 1000000000LL);
    ClTimerTimeOutT tempTime = {0};

    CL_OSAL_MUTEX_LOCK(&gFinBlockMutex);

    if(gMsgMoveStatus == MSG_MOVE_DONE)
        goto out;

    clLogDebug("FIN", "BLOCK", "Message service finalize will be blocked for [%llu ns].", timeout);

    if(gMsgMoveStatus == MSG_MOVE_FIN_UNINIT)
    {
        rc = clOsalTaskCreateDetached("allClosedQueueMoverThread", CL_OSAL_SCHED_OTHER, CL_OSAL_THREAD_PRI_NOT_APPLICABLE, 0, clMsgClosedQueueMoveThread, NULL);
        if(rc != CL_OK)
        {
            clLogError("FIN", "BLOCK", "Failed to create a Queue mover thread. error code [0x%x].", rc);
            goto error_out;
        }
        clMsgTimeConvert(&tempTime, timeout);

        rc = clOsalCondWait(gFinBlockCond, &gFinBlockMutex, tempTime);
        if(CL_GET_ERROR_CODE(rc) == CL_ERR_TIMEOUT)
        {   
            clLogError("FIN", "BLOCK", "Finalize blocking timed out. Timeout is [%lld ns]. error code [0x%x].", timeout, rc);
        }   
        else if(rc != CL_OK)
        {
            clLogError("FIN", "BLOCK", "Failed at Conditional Wait. error code [0x%x].", rc);
        }
        else
        {
            clLogDebug("FIN", "BLOCK", "Message queues are failed over to [0x%x] node.", gQMoveDestNode);
        }
    }

    gMsgMoveStatus = MSG_MOVE_DONE;

    goto out;

    error_out:
    out:
    CL_OSAL_MUTEX_UNLOCK(&gFinBlockMutex);
     
    return rc;
}
static ClRcT clMsgQueueInfoCb(ClHandleDatabaseHandleT hdlDb,
                              ClHandleT hdl,
                              ClPtrT pCookie)
{
    ClRcT rc = CL_OK;
    ClMsgQueueInfoT *pQInfo = NULL;
    ClDebugPrintHandleT dbgHdl = (ClDebugPrintHandleT)pCookie;
    ClNameT *qName = NULL;
    ClUint32T i = 0;

    rc = clHandleCheckout(hdlDb, hdl, (void **)&pQInfo);
    if (rc != CL_OK)
    {
        clLogError("MSG", "CLI", "Handle checkout failed, error [%#x]", rc);
        goto out;
    }

    CL_OSAL_MUTEX_LOCK(&(pQInfo->qLock));
    
    qName = &(pQInfo->pQueueEntry->qName);    
    clDebugPrint(dbgHdl, "Name : [%.*s]\n", qName->length, qName->value);

    clDebugPrint(dbgHdl, "Open flags : ");
    if (pQInfo->openFlags & SA_MSG_QUEUE_CREATE)
    {
        clDebugPrint(dbgHdl, "CREATE");
    }
    if (pQInfo->openFlags & SA_MSG_QUEUE_RECEIVE_CALLBACK)
    {
        clDebugPrint(dbgHdl, " | RECEIVE_CALLBACK");
    }
    if (pQInfo->openFlags & SA_MSG_QUEUE_EMPTY)
    {
        clDebugPrint(dbgHdl, " | EMPTY");
    }
    clDebugPrint(dbgHdl, "\n");
    
    clDebugPrint(dbgHdl, "Persistent : %s\n",
                 (pQInfo->creationFlags & SA_MSG_QUEUE_PERSISTENT) ?
                 "Yes":
                 "No");

    if (pQInfo->creationFlags & SA_MSG_QUEUE_PERSISTENT)
    {
        clDebugPrint(dbgHdl, "Retention time : -\n");
    }
    else
    {
        clDebugPrint(dbgHdl,
                     "Retention time : %lld\n",
                     pQInfo->retentionTime);
    }
    
    clDebugPrint(dbgHdl,
                 "%5s %10s %10s %10s %10s\n",
                 "Priority",
                 " Size (bytes)",
                 " Used (bytes)",
                 " Avail (bytes)",
                 " Number of messages");
    for (i = 0; i < CL_MSG_QUEUE_PRIORITIES; ++i)
    {
        clDebugPrint(dbgHdl,
                     "%3d %15lld %15lld %10lld %15d\n",
                     i,
                     pQInfo->size[i],
                     pQInfo->usedSize[i],
                     (pQInfo->size[i]-pQInfo->usedSize[i]),
                     pQInfo->numberOfMessages[i]);
    }

    clDebugPrint(dbgHdl, "State : %s",
                 (pQInfo->state == CL_MSG_QUEUE_CREATED) ? "CREATED" :
                 (pQInfo->state == CL_MSG_QUEUE_OPEN) ? "OPEN" :
                 (pQInfo->state == CL_MSG_QUEUE_CLOSED) ? "CLOSED" :
                 "INVALID STATE");

    clDebugPrint(dbgHdl, "\n");
    
    CL_OSAL_MUTEX_UNLOCK(&(pQInfo->qLock));

    return CL_OK;
out:
    return rc;
}