When CCB apply (IMMND_EVT_A2ND_CCB_APPLY) gets TIMEOUT, IMMND will be informed the timeout via msg type IMMND_EVT_A2ND_CL_TIMEOUT, and then doing following things: 1) Attemp to abort CCB even the CCB state is in critical. 2) Remove client node from client dabase.
Once the CCB has been comitted, saImmOmCcbApply() returns SA_AIS_OK to user. As the client is removed at #2 above, any IMM operations on the IMM OM handle such as saImmOmCcbObjectDelete() or saImmOmFinalize() will result in BAD_HANDLE. With this fix, the client having critical CCB will not be purged when timeout happens at IMM sync requests. --- .../management/test_saImmOmCcbInitialize.c | 4 + .../management/test_saImmOmCcbObjectDelete.c | 120 ++++++++++++++++++ src/imm/immnd/ImmModel.cc | 18 +-- 3 files changed, 133 insertions(+), 9 deletions(-) diff --git a/src/imm/apitest/management/test_saImmOmCcbInitialize.c b/src/imm/apitest/management/test_saImmOmCcbInitialize.c index ab4fe158f..71d1c1703 100644 --- a/src/imm/apitest/management/test_saImmOmCcbInitialize.c +++ b/src/imm/apitest/management/test_saImmOmCcbInitialize.c @@ -160,6 +160,7 @@ extern void saImmOmCcbObjectDelete_11(void); extern void saImmOmCcbObjectDelete_12(void); extern void saImmOmCcbObjectDelete_13(void); extern void saImmOmCcbObjectDelete_14(void); +extern void saImmOmCcbObjectDelete_15(void); extern void saImmOmCcbObjectModify_2_01(void); extern void saImmOmCcbObjectModify_2_02(void); extern void saImmOmCcbObjectModify_2_03(void); @@ -299,6 +300,9 @@ __attribute__((constructor)) static void saImmOmInitialize_constructor(void) test_case_add( 6, saImmOmCcbObjectDelete_14, "saImmOmCcbObjectDelete - SA_AIS_ERR_FAILED_OPERATION, set NO_DANGLING reference to an object created in the same CCB and then delete reffered object"); + test_case_add( + 6, saImmOmCcbObjectDelete_15, + "saImmOmCcbObjectDelete - SA_AIS_OK, operate on CCB handle which had been previously applied but got TIMEOUT"); test_case_add(6, saImmOmCcbObjectModify_2_01, "saImmOmCcbObjectModify_2 - SA_AIS_OK"); diff --git a/src/imm/apitest/management/test_saImmOmCcbObjectDelete.c b/src/imm/apitest/management/test_saImmOmCcbObjectDelete.c index d8423b795..f02fb60a3 100644 --- a/src/imm/apitest/management/test_saImmOmCcbObjectDelete.c +++ b/src/imm/apitest/management/test_saImmOmCcbObjectDelete.c @@ -794,6 +794,126 @@ void saImmOmCcbObjectDelete_14(void) test_validate(rc, SA_AIS_ERR_FAILED_OPERATION); } +/* + * The saImmOmCcbObjectDelete_15 test case is created to verify that + * no SA_AIS_ERR_BAD_HANDLE is returned when working on the CCB handle + * which has been previously applied but got SA_AIS_ERR_TIMEOUT internally + * due to PBE hung. (refer to ticket #2889 for more info). + * + * This test case should be run on the same node with osafimmpbed process. + * The test case will report PASSED if the pre-condition does not meet. + */ +#include <pthread.h> +#include <unistd.h> + +static bool enable_pbe(void) +{ + const char *cmd = "immcfg -m -a saImmRepositoryInit=1" + " safRdn=immManagement,safApp=safImmService"; + + return (WEXITSTATUS(system(cmd)) == EXIT_SUCCESS); +} + +static bool pbe_running_on_this_node(void) +{ + const char *cmd = "pidof osafimmpbed >/dev/null 2>&1"; + + return (enable_pbe() && WEXITSTATUS(system(cmd)) == EXIT_SUCCESS); +} + +static int hang_pbe(void) +{ + const char *cmd = "pkill -STOP osafimmpbed"; + + return WEXITSTATUS(system(cmd)); +} + +static void *unhang_pbe(void *args) +{ + const char *cmd = "pkill -CONT osafimmpbed"; + + sleep(10); + if (WEXITSTATUS(system(cmd)) != EXIT_SUCCESS) + fprintf(stderr, "Failed to execute cmd: %s\n", cmd); + + return NULL; +} + +static void resume_pbe_in_bg(void) +{ + pthread_t thread; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread, &attr, &unhang_pbe, NULL); +} + +void saImmOmCcbObjectDelete_15(void) +{ + const SaImmAdminOwnerNameT adminOwnerName = + (SaImmAdminOwnerNameT) __func__; + SaImmAdminOwnerHandleT ownerHandle; + SaImmCcbHandleT ccbHandle; + SaNameT rdn = {strlen("saImmOmCcbObjectDelete_15"), + "saImmOmCcbObjectDelete_15"}; + SaNameT *nameValues[] = {&rdn}; + SaImmAttrValuesT_2 v2 = {"rdn", SA_IMM_ATTR_SANAMET, 1, + (void **)nameValues}; + SaUint32T int1Value1 = 7; + SaUint32T *int1Values[] = {&int1Value1}; + SaImmAttrValuesT_2 v1 = {"attr1", SA_IMM_ATTR_SAUINT32T, 1, + (void **)int1Values}; + const SaImmAttrValuesT_2 *attrValues[] = {&v1, &v2, NULL}; + const SaNameT *objectNames[] = {&rootObj, NULL}; + const SaNameT objectName = { + strlen("saImmOmCcbObjectDelete_15,rdn=root"), + "saImmOmCcbObjectDelete_15,rdn=root" + }; + + if (pbe_running_on_this_node() == false) { + printf("Not support! This test should run on the same node" + " with osafimmpbed.\n"); + test_validate(SA_AIS_OK, SA_AIS_OK); + return; + } + + safassert(immutil_saImmOmInitialize(&immOmHandle, &immOmCallbacks, + &immVersion), SA_AIS_OK); + safassert(immutil_saImmOmAdminOwnerInitialize( + immOmHandle, adminOwnerName, SA_TRUE, + &ownerHandle), SA_AIS_OK); + safassert(immutil_saImmOmAdminOwnerSet( + ownerHandle, objectNames, + SA_IMM_ONE), SA_AIS_OK); + + safassert(immutil_saImmOmCcbInitialize( + ownerHandle, 0, &ccbHandle), SA_AIS_OK); + safassert(immutil_saImmOmCcbObjectCreate_2( + ccbHandle, configClassName, &rootObj, + attrValues), SA_AIS_OK); + + // Make PBE hung while applying CCB + hang_pbe(); + resume_pbe_in_bg(); + safassert(immutil_saImmOmCcbApply(ccbHandle), SA_AIS_OK); + + SaAisErrorT ais = immutil_saImmOmCcbObjectDelete(ccbHandle, + &objectName); + if (ais != SA_AIS_OK) { + test_validate(ais, SA_AIS_OK); + return; + } + + safassert(immutil_saImmOmCcbApply(ccbHandle), SA_AIS_OK); + safassert(immutil_saImmOmCcbFinalize(ccbHandle), SA_AIS_OK); + safassert(immutil_saImmOmAdminOwnerRelease( + ownerHandle, objectNames, + SA_IMM_ONE), SA_AIS_OK); + safassert(immutil_saImmOmAdminOwnerFinalize(ownerHandle), SA_AIS_OK); + safassert(immutil_saImmOmFinalize(immOmHandle), SA_AIS_OK); +} + __attribute__((constructor)) static void saImmOmCcbObjectDelete_constructor(void) { diff --git a/src/imm/immnd/ImmModel.cc b/src/imm/immnd/ImmModel.cc index 80ba6efac..6f0593dc5 100644 --- a/src/imm/immnd/ImmModel.cc +++ b/src/imm/immnd/ImmModel.cc @@ -6065,7 +6065,7 @@ bool ImmModel::commitModify(const std::string& dn, ObjectInfo* afterImage) { /* Empty Admin Owner can imply (hard) release during apply/commit. This can happen if client invokes apply and then disconnects without waiting for reply. Typically because of timeout on - the syncronous ccbApply. This can happen for large CCBs + the synchronous ccbApply. This can happen for large CCBs and/or with a sluggish PBE. The releaseOn finalize will have auto-released the adminOwner on the before-image but not on the after image of modify. Corrected here. @@ -14392,7 +14392,7 @@ bool ImmModel::purgeSyncRequest(SaUint32T clientId) { SaInt32T subinv = m_IMMSV_UNPACK_HANDLE_LOW(inv); if (subinv < 0) { LOG_IN( - "Attempt to purge syncronous request for client connection," + "Attempt to purge synchronous request for client connection," "and found an asyncronous admin op request %d for that connection," "ignoring the asyncronous continuation", subinv); @@ -14415,7 +14415,7 @@ bool ImmModel::purgeSyncRequest(SaUint32T clientId) { if (ciFound != sAdmReqContinuationMap.end()) { sAdmReqContinuationMap.erase(ciFound); purged = true; - TRACE_5("Purged syncronous Admin-op continuation"); + TRACE_5("Purged synchronous Admin-op continuation"); } ciFound = sSearchReqContinuationMap.end(); @@ -14424,7 +14424,7 @@ bool ImmModel::purgeSyncRequest(SaUint32T clientId) { if (ci2->second.mConn == clientId) { if (purged || (ciFound != sSearchReqContinuationMap.end())) { LOG_WA( - "Attempt to purge syncronous search request for client connection," + "Attempt to purge synchronous search request for client connection," "but found multiple requests for that connection, " "incorrect use of imm handle"); return false; @@ -14445,7 +14445,7 @@ bool ImmModel::purgeSyncRequest(SaUint32T clientId) { if (ci2->second.mConn == clientId) { if (purged || (ciFound != sPbeRtReqContinuationMap.end())) { LOG_WA( - "Attempt to purge syncronous PRTA request for client connection," + "Attempt to purge synchronous PRTA request for client connection," "but found multiple requests for that connection, " "incorrect use of imm handle"); return false; @@ -14465,17 +14465,17 @@ bool ImmModel::purgeSyncRequest(SaUint32T clientId) { osaf_timespec_compare(&(*i3)->mWaitStartTime, &kZeroSeconds) == 1) { SaUint32T ccbId = (*i3)->mId; - if ((*i3)->mState > IMM_CCB_CRITICAL) { + if ((*i3)->mState >= IMM_CCB_CRITICAL) { LOG_IN( - "Attempt to purge syncronous request for client connection," - "ignoring CCB %u with state > IMM_CCB_CRITICAL", + "Attempt to purge synchronous request for client connection," + "ignoring CCB %u with state >= IMM_CCB_CRITICAL", ccbId); continue; } if (purged || (ccbFound != sCcbVector.end())) { LOG_WA( - "Attempt to purge syncronous CCB request for client connection," + "Attempt to purge synchronous CCB request for client connection," "but found multiple requests for that connection, " "incorrect use of imm handle"); return false; -- 2.18.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel