/** Transaction의 상태를 변경한다.
  *
  * 변경 가능한 상태는 다음 중 하나이다.
  *        + TR_STATE_TERMINATE  0x08
  *        + TR_STATE_DELETE     0x10
  * 
  * 현재 상태에 따라서 다음과 같이 동작한다.
  *
  *  + TR_STATE_WAIT 
  *    - TR_STATE_TERMINATE : State 변경, nError = IF4ERR_USER_MODIFY
  *    - TR_STATE_DELETE : Transaction 삭제
  *  + TR_STATE_QUEUE 
  *    - TR_STATE_TERMINATE : Queue에서 제거, State 변경, nError = IF4ERR_USER_MODIFY
  *    - TR_STATE_DELETE : Queue에서 제거, Transaction 삭제
  *  + TR_STATE_RUN 
  *    - TR_STATE_TERMINATE : STATE가 변경되지 않고 IF4ERR_TRANSACTION_UPDATE_FAIL Return.
  *    - TR_STATE_DELETE : Transaction 삭제되지 않음 IF4ERR_TRANSACTION_UPDATE_FAIL Return
  *  + TR_STATE_TERMINATE 
  *    - TR_STATE_TERMINATE : 아무런 동작도 하지 않음
  *    - TR_STATE_DELETE : Transaction 삭제
  *
  */
int CTransactionManager::UpdateTransaction(WORD nTrID, BYTE nState)
{
    int                     nError = IF4ERR_NOERROR;
    EndDeviceTransaction    endTrInfo;
    EUI64                   id;
    cetime_t                nTime;

    time(&nTime);
    memset(&endTrInfo, 0, sizeof(EndDeviceTransaction));
    m_TransactionLocker.Lock();
    {
        if(LoadTransactionTarget(nTrID, &id) && LoadEndDeviceTransaction(&id, nTrID, &endTrInfo)) {
            switch(nState) {
                case TR_STATE_TERMINATE: 
                    switch(endTrInfo.trState) {
                        case TR_STATE_QUEUE:
                            m_pBatchJob->RemoveTransaction(nTrID);
                        case TR_STATE_WAIT:
                            UpdateEndDeviceTransaction(&id, nTrID, nTime, FALSE, FALSE, TR_STATE_TERMINATE, IF4ERR_USER_MODIFY);
                            UpdateTransactionHistory(nTrID, nTime, TR_STATE_TERMINATE, IF4ERR_USER_MODIFY);
                            break;
                        case TR_STATE_RUN:
                            nError = IF4ERR_TRANSACTION_UPDATE_FAIL;
                            break;
                        case TR_STATE_TERMINATE:
                            break;
                    }
                    break;
                case TR_STATE_DELETE: 
                    switch(endTrInfo.trState) {
                        case TR_STATE_QUEUE:
                            m_pBatchJob->RemoveTransaction(nTrID);
                        case TR_STATE_WAIT:
                        case TR_STATE_TERMINATE:
                            DeleteTransaction(nTrID);
                            break;
                        case TR_STATE_RUN:
                            nError = IF4ERR_TRANSACTION_UPDATE_FAIL;
                            break;
                    }
                    break;
                default: 
                    nError = IF4ERR_OUT_OF_RANGE;
                    break;
            }
        }else {
            if(nState == TR_STATE_DELETE) {
                DeleteTransaction(nTrID);
            }else {
                nError = IF4ERR_INVALID_TRANSACTION_ID;
            }
        }
    }
    m_TransactionLocker.Unlock();

    return nError;
}
BOOL CTransactionManager::Add(MIBValue *pValue, int nCount, WORD *nTransactionID)
{
    WORD        nTrID;
    cetime_t    nTime;
    BOOL        bOk = FALSE;

    m_TransactionLocker.Lock();
    {
        nTrID = GetNextTransactionID();
        time(&nTime);

        if(CreateTransactionRequest(nTrID, pValue) &&
           AppendEndDeviceTransaction(nTrID, nTime, pValue, nCount) &&
           UpdateTransactionHistory(nTrID, nTime, TR_STATE_WAIT, IF4ERR_NOERROR) &&
           UpdateTransactionID(nTrID)) {
            *nTransactionID = nTrID;
            bOk = TRUE;
        }else {
            DeleteTransaction(nTrID);
        }
    }
    m_TransactionLocker.Unlock();

	return bOk;
}
Exemple #3
0
int RetryDeleteTransaction(Ndb* pNdb, long iContextId, NdbError& err, int& nRetry)
{
    int iRes = -1;
    nRetry = 0;
    bool bRetry = true;
    bool bUnknown = false;
    while(bRetry && nRetry<g_nMaxRetry)
    {
        if(!DeleteTransaction(pNdb, iContextId, err))
        {
            iRes = 0;
            bRetry = false;
        }
        else
        {
            switch(err.status)
            {
            case NdbError::UnknownResult:
                bUnknown = true;
                ++nRetry;
                break;

            case NdbError::TemporaryError:
                bUnknown = false;
                SleepOneCall();
                ++nRetry;
                break;
            
            case NdbError::PermanentError:
                if(err.code==626 && bUnknown)
                    iRes = 0;
                bRetry = false;
                break;

            default:
                bRetry = false;
                break;
            }
        }
    }
    return iRes;
}
/** Logging Option이 Command에 걸려 있을 때 Logging을 해야 한다
  *  Option에 따라 Save/Event 등을 처리해야한다.
  */
BOOL CTransactionManager::ExecuteTransaction(WORD nTrID)
{
    char                trPath[64];
    BOOL                bOk = FALSE;
    MIBValue            *pMibValue = NULL, *pMib, *pParam;
    int                 nParamCount = 0;
    EUI64               id, id2;
    OID3                cmd;
    BYTE                nOption, nDay, nTry, nState=TR_STATE_WAIT;
    signed char         nNice;
    int                 nError = IF4ERR_NOERROR, i;
    cetime_t            nTime;
    BOOL                bGetResTime = FALSE;
    IF4_COMMAND_TABLE * cmdTbl = NULL;
    EndDeviceTransaction    endTrInfo;
	char			szID[20]={0, }, szID2[20]={0, }, szOID[20]={0, };
	//WORD			Param1=0, Param2=0;

    if(m_pTransactionManager->LoadTransactionInfo(nTrID, &pMibValue, &nParamCount)) {
        //IF4API_DumpMIBValue(pMibValue, nParamCount);

        pMib = pMibValue;
        memcpy(&id, pMib->stream.p, sizeof(EUI64));                 pMib = pMib->pNext; // Target ID
        memcpy(&cmd, &pMib->stream.id, sizeof(OID3));               pMib = pMib->pNext; // Command
        nOption = pMib->stream.u8;                                  pMib = pMib->pNext; // Option
        nDay = pMib->stream.u8;                                     pMib = pMib->pNext; // Day
        nNice = pMib->stream.s8;                                    pMib = pMib->pNext; // Nice
        nTry = pMib->stream.u8;                                     pMib = pMib->pNext; // Try

		EUI64ToStr(&id, szID);
		EUI64ToStr(&id2, szID2);
		VARAPI_OidToString(&cmd, szOID);

		XDEBUG("Execute Transaction: [%u] %d.%d.%d Opt=0x%02X Day=%d Nice=%d Try=%d\r\n",
            nTrID, cmd.id1, cmd.id2, cmd.id3, nOption, nDay, nNice, nTry);

		XDEBUG("Command OID: %s\r\n", szOID);

        time(&nTime);
        memset(&endTrInfo, 0, sizeof(EndDeviceTransaction));
        m_TransactionLocker.Lock();
        {
            LoadEndDeviceTransaction(&id, nTrID, &endTrInfo);
            UpdateEndDeviceTransaction(&id, nTrID, nTime, TRUE, TRUE, TR_STATE_RUN, nError);
            UpdateTransactionHistory(nTrID, nTime, TR_STATE_RUN, nError);
        }
        m_TransactionLocker.Unlock();

		XDEBUG("Pass LoadEndDeviceTransaction, UpdateEndDevice, UpdateTransaction Function!!\r\n");

        if((cmdTbl = FindCommand(&cmd))) {
            if(cmdTbl->pfnCommand) {
                IF4Wrapper wrapper;

                pParam = (MIBValue *)MALLOC(sizeof(MIBValue) *nParamCount - PARAM_CNT);
                for(i=0; i < nParamCount-PARAM_CNT && pMib ;i++, pMib=pMib->pNext) {
                    memcpy(&pParam[i], pMib, sizeof(MIBValue));
                    if(i) pParam[i-1].pNext = &pParam[i];
                }
                nError = cmdTbl->pfnCommand(&wrapper, pParam, nParamCount - PARAM_CNT);
                FREE(pParam);

                time(&nTime); bGetResTime = TRUE;
                XDEBUG("Transaction Result : [%u] %s(%d.%d.%d) ReqParamCnd=%d ResultCnt=%d Res=%d(%s)\r\n",
                    nTrID, cmdTbl->pszName, cmd.id1, cmd.id2, cmd.id3, 
                    nParamCount - PARAM_CNT, wrapper.nResult, 
                    nError, IF4API_GetErrorMessage(nError));

                if(wrapper.nResult > 0) {
                    if(nOption & ASYNC_OPT_RESULT_DATA_SAVE) {
                        sprintf(trPath,"%s/res/%u", TR_DIR, nTrID);
                        if(VARAPI_Serialize(trPath, wrapper.pResult)) bOk = TRUE;
                    } else bOk = TRUE;
                } else if(nError == IF4ERR_NOERROR) {
                    bOk = TRUE;
                }
                if(nError == IF4ERR_NOERROR || nTry <= (endTrInfo.trTry + 1)) {
                    if(nOption & (ASYNC_OPT_RETURN_CODE_EVT | ASYNC_OPT_RESULT_DATA_EVT))
                    {
                        // Event 전송 Code 추가 삽입
                        if(nError == IF4ERR_NOERROR) {
                            if(nOption & ASYNC_OPT_RESULT_DATA_EVT) {
                                // DATA Event가 우선권을 가진다
                                transactionEvent(nTrID, EVT_TYPE_DATA, nOption, 
                                    endTrInfo.trCreateTime, nTime, nError, wrapper.nResult, wrapper.pResult);
                            }else {
                                // Code Event
                                transactionEvent(nTrID, EVT_TYPE_CODE, nOption,
                                    endTrInfo.trCreateTime, nTime, nError, 0, NULL);
                            }
                        } else {
                            /*-- 결국 실패해서 Try 제한에 걸린 경우 
                             *-- Error Code만 리턴한다
                             --*/
                            transactionEvent(nTrID, EVT_TYPE_CODE, nOption,
                                endTrInfo.trCreateTime, nTime, nError, 0, NULL);
                        }
                    }
                    nState = TR_STATE_TERMINATE;
                }
                IF4API_FreeMIBValue(wrapper.pResult);
            }
        }else {
            nError = IF4ERR_INVALID_COMMAND;
        }

        if(!bGetResTime) time(&nTime);
        m_TransactionLocker.Lock();
        {
            UpdateEndDeviceTransaction(&id, nTrID, nTime, FALSE, FALSE, nState, nError);
            UpdateTransactionHistory(nTrID, nTime, nState, nError);

            if(nState == TR_STATE_TERMINATE && !(nOption & (ASYNC_OPT_RETURN_CODE_SAVE|ASYNC_OPT_RESULT_DATA_SAVE))) {
                /*-- Save Option이 설정되지 않은 상태에서 Terminate 된다면 Transaction을 삭제한다 --*/
                DeleteTransaction(nTrID);
            }
        }
        m_TransactionLocker.Unlock();
        
    }
    IF4API_FreeMIBValue(pMibValue);

    return bOk;
}
/** Agent가 초기화될 때 무결성 검사를 하는 코드 추가 필요
  *
  * 1) req에 있는 모든 Transaction ID 목록을 수집
  * 2) map에 있는 모든 Transaction Id 목록을 수집
  * 3) mbr에 있는 EndDevice Info 수집
  *    a) trID가 정확한지 검사
  *    b) 보관 기간이 넘어가지 않았는지 검사
  *    c) Queue에 들어간 후 1시간이 넘은 Transaction은 Wait로 변경
  *
  */
BOOL CTransactionManager::IntegrityCheck(void)
{
    BOOL                    bOk = TRUE, bIntegrity, bSkipTest;
    DIR			            *dir_fdesc;
    dirent		            *dp;
	int			            i, nCnt, nTrCnt, nParamCnt;
	char		            trPath[64];
    WORD                    *pTrIdArr=NULL, *pChkTrIdArr=NULL, *pIdx;
    MIBValue                *pParam, *pMib;
    UINT                    sval;
    cetime_t                currentTime;
    UINT                    nDay;
    EndDeviceTransaction    *pEndTrInfo;
    EUI64                   id;

    time(&currentTime);
    sprintf(trPath, "%s/req", TR_DIR);
    XDEBUG(" Integrity Check Start\r\n");
    m_TransactionLocker.Lock();
    {
        XDEBUG(" Read Transaction ID List\r\n");
        dir_fdesc = opendir(trPath);
        if (!dir_fdesc) {
            m_TransactionLocker.Unlock();
            return FALSE;
        }
        for(nTrCnt=0;(dp=readdir(dir_fdesc));) {
            if(dp->d_name[0] != '.') nTrCnt++;
        }
	    closedir(dir_fdesc);

        pTrIdArr = (WORD *)MALLOC(sizeof(WORD) * nTrCnt);
        pChkTrIdArr = (WORD *)MALLOC(sizeof(WORD) * nTrCnt);

        dir_fdesc = opendir(trPath);
        if (!dir_fdesc) {
            FREE(pTrIdArr);
            m_TransactionLocker.Unlock();
            return FALSE;
        }
        for(i=0;(dp=readdir(dir_fdesc)) && i < nTrCnt; ) {
            if(dp->d_name[0] == '.') continue;
            sscanf(dp->d_name,"%u", &sval); pTrIdArr[i] = (WORD) sval;
            i++;
        }
	    closedir(dir_fdesc);

        XDEBUG(" Sort Transaction ID List\r\n");
        qsort(pTrIdArr, nTrCnt, sizeof(WORD), CompTrID);
        memcpy(pChkTrIdArr, pTrIdArr, sizeof(WORD) * nTrCnt);

        /*-- End Device 정보 검사 --*/
        XDEBUG(" EndDevice Information Check\r\n");
        sprintf(trPath, "%s/mbr", TR_DIR);
        dir_fdesc = opendir(trPath);
        if (!dir_fdesc) {bSkipTest = TRUE; bOk = FALSE;}
        else            bSkipTest = FALSE;

        while(!bSkipTest && (dp=readdir(dir_fdesc)) != NULL) {
            if(dp->d_name[0] == '.') continue;
            
            nCnt = 0; bIntegrity = TRUE; pEndTrInfo = NULL;
            StrToEUI64(dp->d_name, &id);
            if(LoadEndDeviceTransaction(&id, &pEndTrInfo, &nCnt)) {
                /* EndDevice에 있는 TR ID가 유효한지 검사
                 * 잘못된 ID라면 해당 Transaction 삭제 
                 */
                for(i=0;i<nCnt;i++) {
                    bIntegrity = TRUE; pParam = NULL; nParamCnt = 0;

                    if((pIdx = (WORD *)bsearch(&pEndTrInfo[i].trID, pTrIdArr, nTrCnt, sizeof(WORD), CompTrID))) {
                        pChkTrIdArr[(pIdx - pTrIdArr)] = 0;
                        if(LoadTransaction(pEndTrInfo[i].trID, TR_GET_OPT_REQUEST, NULL, 
                                    &pParam, &nParamCnt, NULL, NULL, NULL, NULL)) {
                            pMib = pParam;
                            /*-- Target ID  --*/    pMib = pMib->pNext; 
                            /*-- Command    --*/    pMib = pMib->pNext; 
                            /*-- Option     --*/    pMib = pMib->pNext; 
                            nDay = (UINT)(pMib->stream.u8 ? pMib->stream.u8 : m_nTransactionSaveDay);
                            /*-- 저장 유효기간이 지났는지 검사 --*/
                            if((currentTime - pEndTrInfo[i].trCreateTime) > (int)(DAY_SEC *  nDay)) { // 유효기간 초과
                                bIntegrity = FALSE;
                                XDEBUG("  Transaction Delete [Out of date] : %u\r\n", pEndTrInfo[i].trID);
                            }
                        } else { // Transaction 정보를 읽지 못했을 때
                            bIntegrity = FALSE;
                            XDEBUG("  Transaction Delete [Read Transaction Info Fail] : %u\r\n", pEndTrInfo[i].trID);
                        }
                        FREE(pParam);
                    } else { // 잘못된 ID (ID 목록에 없음)
                        bIntegrity = FALSE;
                        XDEBUG("  Transaction Delete [Read End Device Info Fail] : %u\r\n", pEndTrInfo[i].trID);
                    }
                    if(!bIntegrity) DeleteTransaction(pEndTrInfo[i].trID, &id);
                }
            } else {    // EndDevice 정보 읽기 실패 : EndDevice Info File 삭제
                remove(dp->d_name);
            }
            FREE(pEndTrInfo);
        }
	    if(!bSkipTest) closedir(dir_fdesc);

        /*-- EndDevice Info는 없고 Transaction 정보만 있는 경우 삭제 --*/
        for(i=0; i<nTrCnt; i++) {
            if(pChkTrIdArr[i]) {
                XDEBUG("  Transaction Delete [Invalid Transaction Info] : %u\r\n", pChkTrIdArr[i]);
                DeleteTransaction(pChkTrIdArr[i]);
            }
        }

        /*-- Mapping  검사 : Transaction Info는 없고 Mapping만 있어도 삭제 --*/
        XDEBUG(" Transaction Mapping Check\r\n");
        sprintf(trPath, "%s/map", TR_DIR);
        dir_fdesc = opendir(trPath);
        if (!dir_fdesc) {bSkipTest = TRUE; bOk = FALSE;}
        else            bSkipTest = FALSE;

        while(!bSkipTest && (dp=readdir(dir_fdesc)) != NULL) {
            if(dp->d_name[0] == '.') continue;
            sscanf(dp->d_name,"%u", &sval); 
            if(!bsearch(&sval, pTrIdArr, nTrCnt, sizeof(WORD), CompTrID)) {
                DeleteTransaction(sval);
            }
        }
	    if(!bSkipTest) closedir(dir_fdesc);

        /*-- Result 검사 : Trasaction Info는 없고 Result만 있어도 삭제 --*/
        XDEBUG(" Transaction Result Check\r\n");
        sprintf(trPath, "%s/res", TR_DIR);
        dir_fdesc = opendir(trPath);
        if (!dir_fdesc) {bSkipTest = TRUE; bOk = FALSE;}
        else            bSkipTest = FALSE;

        while(!bSkipTest && (dp=readdir(dir_fdesc)) != NULL) {
            if(dp->d_name[0] == '.') continue;
            sscanf(dp->d_name,"%u", &sval); 
            if(!bsearch(&sval, pTrIdArr, nTrCnt, sizeof(WORD), CompTrID)) {
                DeleteTransaction(sval);
            }
        }
	    if(!bSkipTest) closedir(dir_fdesc);
            
        FREE(pTrIdArr);
        FREE(pChkTrIdArr);
    }
    m_TransactionLocker.Unlock();
    XDEBUG(" Integrity Check Terminate\r\n");

    return bOk;
}