/** 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; }
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(¤tTime); 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; }