osaf/services/saf/immsv/README | 44 ++ osaf/services/saf/immsv/immnd/ImmModel.cc | 608 +++++++++++++++++++++++++++- osaf/services/saf/immsv/immnd/ImmModel.hh | 7 + osaf/services/saf/immsv/immnd/immnd_evt.c | 169 +++++++- osaf/services/saf/immsv/immnd/immnd_init.h | 3 + 5 files changed, 788 insertions(+), 43 deletions(-)
The patch contains code for IMM service part of transactional safe read diff --git a/osaf/services/saf/immsv/README b/osaf/services/saf/immsv/README --- a/osaf/services/saf/immsv/README +++ b/osaf/services/saf/immsv/README @@ -2704,6 +2704,50 @@ Bit 5 controls OpenSAF4.5 protocols allo Bit 6 controls OpenSAF4.6 protocols allowed or not (normally on/1). Bit 7 controls OpenSAF4.7 protocols allowed or not (normally on/1). + +Safe-read (transactional read) (5.0) +============================================= +http://sourceforge.net/p/opensaf/tickets/48/ + +Adds support for an OM CCB client to read-access a config object transactionally. +The API works exactly the same way as saImmOmAccessorGet, except that + + a) The API takes a SaImmCcbHandleT instead of a SaImmAccessorHandleT + + b) The values returned for the objects config attributes are from a version + of the object consistent with the CCB/transaction. This means either the + latest applied version or a newer version created in the same CCB but + not yet applied. + + c) Access to an object that has been deleted in the same CCB but not applied + is rejected with ERR_NOT_EXIST. + + d) Access to an object that has been created in the same CCB but not applied + is allowed, providing the latest version of the config attributes in that CCB. + + e) Safe read is not allowed using a runtime object as target. + +Runtime attributes residing in a config object are handled exactly the same as for +saImmOmAccessorGet. The reason a safe-read call is not allowed on a runtime *object* +is that a runtime object *only* contains runtime attributes. Performing a safe-read +on a runtime object makes no sense. + + +saImmOmCcbObjectRead(SaImmCcbHandleT ccbHandle, /* in */ + SaConstStringT objectName, /* in */ + const SaImmAttrNameT *attributeNames, /* in */ + SaImmAttrValuesT_2 ***attributes); /* out */ + + +Return Values : SA_AIS_ERR_BUSY - The object targeted by the request is already + the target of conflicting/exclusive operation in another CCB. + The conflicting operation would be a modify or delete. + + SA_AIS_ERR_INVALID_PARAM - The objectName parameter identifies a + runtime object. + + Returncodes otherwise identical to saImmOmAccessorGet. + ---------------------------------------- DEPENDENCIES ============ diff --git a/osaf/services/saf/immsv/immnd/ImmModel.cc b/osaf/services/saf/immsv/immnd/ImmModel.cc --- a/osaf/services/saf/immsv/immnd/ImmModel.cc +++ b/osaf/services/saf/immsv/immnd/ImmModel.cc @@ -36,8 +36,8 @@ #define SEARCH_TIMEOUT_SEC 600 /* Search timeout */ // Same strings exists in immnd_evt.c -#define IMM_VALIDATION_ABORT "IMM: Validation abort: " -#define IMM_RESOURCE_ABORT "IMM: Resource abort: " +#define IMM_VALIDATION_ABORT "IMM: Validation abort: " +#define IMM_RESOURCE_ABORT "IMM: Resource abort: " struct ContinuationInfo2 { @@ -203,6 +203,16 @@ typedef SaUint32T ImmObjectFlags; // c) modifies a NO_DANGLING attribute, // d) deletes an object that is referred to by some NO_DANGLING attribute. +#define IMM_SHARED_READ_LOCK 0x00000100 +//If shared read lock is on, it signifies that one or more ccbs have locked the +//object for safe-read. This prevents the object from being modified or deleted +//by any other ccb until safe-readers have released the read lock. +//If only one single ccb has a read lock on an object, i.e. the lock is currently +//not actually shared, then that ccb may upgrade the read-lock to an exclusive lock +//for delete or modify. +//See also the data structure sObjectReadLockCount. + + struct ObjectInfo { @@ -217,7 +227,8 @@ struct ObjectInfo void getAdminOwnerName(std::string *str) const; ImmAttrValue* mAdminOwnerAttrVal; //Pointer INTO mAttrValueMap - SaUint32T mCcbId; + SaUint32T mCcbId; //Zero => may be read-locked see:IMM_SHARED_READ_LOCK + //Nonzero => may be exclusive lock if id is active ccb ImmAttrValueMap mAttrValueMap; //<-Each ImmAttrValue needs explicit delete ClassInfo* mClassInfo; //<-Points INTO ClassMap. Not own copy! ImplementerInfo* mImplementer; //<-Points INTO ImplementerVector @@ -332,6 +343,8 @@ struct AugCcbParent SaUint32T mAugmentAdmo; /* Aug admo with ROF==true for aug ccbCreates #2428 */ }; +static ObjectShortCountMap sObjectReadLockCount; //Needs to be declared above CcbInfo + struct CcbInfo { CcbInfo(): mId(0), mAdminOwnerId(0), mCcbFlags(0), mOriginatingConn(0), @@ -340,6 +353,11 @@ struct CcbInfo mErrorStrings(NULL), mAugCcbParent(NULL) {} bool isOk() {return mVeto == SA_AIS_OK;} bool isActive() {return (mState < IMM_CCB_COMMITTED);} + void addObjReadLock(ObjectInfo* obj, std::string& objName); + void removeObjReadLock(ObjectInfo* obj, bool removeObject = true); + void removeAllObjReadLocks(); // Removes all locks held by *this* ccb. + bool isReadLockedByThisCcb(ObjectInfo* obj); + SaUint32T mId; SaUint32T mAdminOwnerId; SaUint32T mCcbFlags; @@ -357,9 +375,97 @@ struct CcbInfo ImplementerSet mLocalAppliers; ImmsvAttrNameList* mErrorStrings;/*Error strings generated by current op */ AugCcbParent* mAugCcbParent; + ObjectSet mSafeReadSet; }; typedef std::vector<CcbInfo*> CcbVector; +void CcbInfo::addObjReadLock(ObjectInfo* obj, std::string& objName) +{ + ObjectShortCountMap::iterator oscm; + if(obj->mObjFlags & IMM_SHARED_READ_LOCK) { + TRACE_7("Object '%s' already locked for safe-read by some ccb(s)", objName.c_str()); + //Read-lock is a shared lock, join the group of lockers. + } else { + osafassert(!(obj->mObjFlags & IMM_CREATE_LOCK )); + osafassert(!(obj->mObjFlags & IMM_DELETE_LOCK )); + /* IMM_RT_UPDATE_LOCK does not conflict with safe read because it deals with + PRTO/PRTA updates, i.e. runtime data and not config data. + */ + + osafassert(obj->mCcbId == 0); + /* A non-zero mCcbId for an object indicates exclusive lock (create/delete/modify) + if and only if the identified ccb is still *active*. A zero mCcbId for an object + *guarantees* that it is not exclusive locked. + This function *requires* that the invoker has done the pre-check of no interference + of a proposed shared reader with any pre-existing exclusive op and zeroed the ccbId + if and only if an existing ccbId was no longer identifying an active ccb. + + There is no explicit ccb-modify lock since it can be inferred by (a) the ccb-id + of an object identifying an active CCB and (b) neither the create or modify + flag being set on the object. + */ + + obj->mObjFlags |= IMM_SHARED_READ_LOCK; + } + + this->mSafeReadSet.insert(obj); /* Ccb keeps track of its safe-readers. */ + + oscm = sObjectReadLockCount.find(obj); + if(oscm == sObjectReadLockCount.end()) { + sObjectReadLockCount[obj] = 1; + } else { + // TODO: Should check that we dont increment beyond maxshort. + (oscm->second)++; + LOG_IN("Incremented read-lock count for %s to %u", objName.c_str(), oscm->second); + } + +} + +void CcbInfo::removeAllObjReadLocks() +{ + /* Removes all the read-locks set by this ccb. + Must be executed with ccb-commit or ccb-abort. + */ + ObjectSet::iterator osi; + + for(osi = this->mSafeReadSet.begin(); osi != this->mSafeReadSet.end(); ++osi) + { + removeObjReadLock(*osi, false); + } + this->mSafeReadSet.clear(); +} + +void CcbInfo::removeObjReadLock(ObjectInfo* obj, bool removeObject /* = true*/) +{ + ObjectShortCountMap::iterator oscm = sObjectReadLockCount.find(obj); + osafassert(oscm != sObjectReadLockCount.end()); + osafassert(oscm->second > 0); + (oscm->second)--; + TRACE("CcbInfo::removeObjReadLock decremented safe read count for %p to %u", + obj, oscm->second); + if(oscm->second == 0) { + sObjectReadLockCount.erase(obj); + TRACE("Object %p no longer has any read locks", obj); + obj->mObjFlags &= ~IMM_SHARED_READ_LOCK; + } else { + TRACE("Object %p still has read lock count of %u", obj, oscm->second); + } + + if(removeObject) { + this->mSafeReadSet.erase(obj); + } +} + +bool CcbInfo::isReadLockedByThisCcb(ObjectInfo* obj) +{ + TRACE_ENTER(); + ObjectSet::iterator osi = this->mSafeReadSet.find(obj); + bool result = (osi != this->mSafeReadSet.end()); + TRACE_LEAVE(); + return result; +} + + struct AdminOwnerInfo { AdminOwnerInfo(): mId(0), mConn(0), mNodeId(0), mReleaseOnFinalize(false), @@ -454,7 +560,7 @@ static const std::string saImmOiTimeout( static SaImmRepositoryInitModeT immInitMode = SA_IMM_INIT_FROM_FILE; -static SaUint32T ccbIdLongDnGuard = 0; /* Disallow long DN additions if longDnsAllowed is being changed in ccb*/ +static SaUint32T sCcbIdLongDnGuard = 0; /* Disallow long DN additions if longDnsAllowed is being changed in ccb*/ static bool sIsLongDnLoaded = false; /* track long DNs before opensafImm=opensafImm,safApp=safImmService is created */ static bool sAbortNonCriticalCcbs = false; /* Set to true at coord by the special imm admin-op to abort ccbs #1107 */ @@ -1355,7 +1461,7 @@ immModel_adminOperationInvoke(IMMND_CB * implNodeId, pbeExpected, displayRes, cb->mIsCoord); if(sAbortNonCriticalCcbs && !wasAbortNonCritical) { - LOG_IN("ABT cb->mForceClean set to true"); + TRACE("cb->mForceClean set to true"); cb->mForceClean = true; } return err; @@ -1476,6 +1582,18 @@ immModel_ccbAugmentAdmo(IMMND_CB *cb, Sa } SaAisErrorT +immModel_objectIsLockedByCcb(IMMND_CB *cb, struct ImmsvOmSearchInit* req) +{ + return ImmModel::instance(&cb->immModel)->objectIsLockedByCcb(req); +} + +SaAisErrorT +immModel_ccbReadLockObject(IMMND_CB *cb, struct ImmsvOmSearchInit* req) +{ + return ImmModel::instance(&cb->immModel)->ccbReadLockObject(req); +} + +SaAisErrorT immModel_searchInitialize(IMMND_CB *cb, struct ImmsvOmSearchInit* req, void** searchOp, SaBoolT isSync, SaBoolT isAccessor) { @@ -2892,7 +3010,7 @@ ImmModel::getLongDnsAllowed(ObjectInfo* { TRACE_ENTER(); bool longDnsAllowed = false; - if(ccbIdLongDnGuard) { + if(sCcbIdLongDnGuard) { /* A ccb is currently mutating longDnsAllowed */ return false; } @@ -5856,8 +5974,9 @@ ImmModel::ccbCommit(SaUint32T ccbId, Con }//for ccb->mMutations.clear(); - - if(ccbIdLongDnGuard == ccbId) {ccbIdLongDnGuard= 0;} + ccb->removeAllObjReadLocks(); + + if(sCcbIdLongDnGuard == ccbId) {sCcbIdLongDnGuard = 0;} //If there are implementers involved then send the final apply callback //to them and remove the implementers from the Ccb. @@ -6069,7 +6188,7 @@ ImmModel::ccbAbort(SaUint32T ccbId, Conn } } - if(ccbIdLongDnGuard == ccbId) {ccbIdLongDnGuard= 0;} + if(sCcbIdLongDnGuard == ccbId) {sCcbIdLongDnGuard = 0;} return true; } @@ -6259,6 +6378,7 @@ ImmModel::ccbTerminate(SaUint32T ccbId) createsAbortedInCcb.clear(); ccb->mMutations.clear(); + ccb->removeAllObjReadLocks(); if(ccb->mImplementers.size()) { LOG_WA("Ccb destroyed without notifying some implementers from IMMND."); CcbImplementerMap::iterator ix; @@ -6357,14 +6477,20 @@ ImmModel::ccbAugmentInit(immsv_oi_ccb_up case IMM_CCB_READY: case IMM_CCB_COMMITTED: case IMM_CCB_ABORTED: - case IMM_CCB_PREPARE: - case IMM_CCB_VALIDATING: case IMM_CCB_VALIDATED: case IMM_CCB_PBE_ABORT: case IMM_CCB_CRITICAL: - LOG_WA("Ccb Augment attempted in wrong CCB state"); + LOG_WA("Ccb Augment attempted in wrong CCB state %u", ccb->mState); err = SA_AIS_ERR_BAD_OPERATION; - goto done; + goto done; + + case IMM_CCB_VALIDATING: + LOG_IN("Augment CCB in state VALIDATING"); + goto augment_for_safe_read; + + case IMM_CCB_PREPARE: + LOG_IN("Augment CCB in state PREPARE %u", IMM_CCB_PREPARE); + goto augment_for_safe_read; case IMM_CCB_CREATE_OP: TRACE("Augment CCB in state CREATE_OP"); @@ -6378,7 +6504,6 @@ ImmModel::ccbAugmentInit(immsv_oi_ccb_up case IMM_CCB_MODIFY_OP: TRACE("Augment CCB in state MODIFY_OP"); - omuti = ccb->mMutations.find(objectName); if(omuti != ccb->mMutations.end()){ obj = omuti->second->mAfterImage; @@ -6421,9 +6546,11 @@ ImmModel::ccbAugmentInit(immsv_oi_ccb_up osafassert(omuti->second->mContinuationId == rsp->inv); osafassert(omuti->second->mWaitForImplAck); + augment_for_safe_read: + TRACE("obj:%p", obj); - TRACE("obj->mImplementer:%p", obj->mImplementer); - osafassert(obj && obj->mImplementer); + //TRACE("obj->mImplementer:%p", obj->mImplementer); + //osafassert(obj && obj->mImplementer); if(ccb->mVeto != SA_AIS_OK) { @@ -6466,12 +6593,15 @@ ImmModel::ccbAugmentInit(immsv_oi_ccb_up ccb->mAugCcbParent->mState = ccb->mState; ccb->mAugCcbParent->mErrorStrings = ccb->mErrorStrings; ccb->mAugCcbParent->mContinuationId = rsp->inv; - ccb->mAugCcbParent->mImplId = obj->mImplementer->mId; + ccb->mAugCcbParent->mImplId = (obj)?obj->mImplementer->mId:0; ccb->mAugCcbParent->mAugmentAdmo = 0; ccb->mOriginatingConn = originatingConn; ccb->mOriginatingNode = originatingNode; - ccb->mState = IMM_CCB_READY; + if(ccb->mState < IMM_CCB_VALIDATING) { + ccb->mState = IMM_CCB_READY; + } + ccb->mWaitStartTime = 0; ccb->mErrorStrings = NULL; @@ -8491,6 +8621,7 @@ ImmModel::ccbObjectModify(const ImmsvOmC ObjectNameSet afimPreOpNDRefs; // Set of NO_DANGLING references from after image before CCB operation bool hasNoDanglingRefs = false; bool modifiedImmMngt = false; /* true => modification of the SAF immManagement object. */ + bool upgradeReadLock = false; if(sz >= SA_MAX_UNEXTENDED_NAME_LENGTH) { if(longDnsPermitted) { @@ -8577,7 +8708,7 @@ ImmModel::ccbObjectModify(const ImmsvOmC err = SA_AIS_ERR_BAD_OPERATION; goto ccbObjectModifyExit; } - + ccbIdOfObj = object->mCcbId; if(ccbIdOfObj != ccbId) { i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), @@ -8588,6 +8719,25 @@ ImmModel::ccbObjectModify(const ImmsvOmC err = SA_AIS_ERR_BUSY; goto ccbObjectModifyExit; } + + if(ccbIdOfObj == 0) { + ObjectShortCountMap::iterator oscm = sObjectReadLockCount.find(object); + if(oscm != sObjectReadLockCount.end()) + { + if((oscm->second > 1) || !(ccb->isReadLockedByThisCcb(object))) + { + TRACE("ERR_BUSY: object '%s' is safe-read-locked by %u ccb(s)", + objectName.c_str(), oscm->second); + err = SA_AIS_ERR_BUSY; + goto ccbObjectModifyExit; + } else { + osafassert((oscm->second == 1) && (ccb->isReadLockedByThisCcb(object))); + TRACE("CcbModify: Object '%s' safe-read-locked only by this ccb (%u) => " + "upgrade to exclusive lock is possible", objectName.c_str(), ccbId); + upgradeReadLock = true; + } + } + } } if(object->mObjFlags & IMM_RT_UPDATE_LOCK) { @@ -9208,12 +9358,12 @@ ImmModel::ccbObjectModify(const ImmsvOmC /* Check if *this* ccb is attempting to alter longDnsAllowed.*/ if(longDnsPermitted != longDnsAllowedAfter) { - if(ccbIdLongDnGuard) { + if(sCcbIdLongDnGuard) { /* This case should never happen since it is guarded by regular ccb handling. */ setCcbErrorString(ccb, "IMM: ERR_BUSY: Other Ccb (%u) already using %s", - ccbIdLongDnGuard, immLongDnsAllowed.c_str()); + sCcbIdLongDnGuard, immLongDnsAllowed.c_str()); LOG_IN("IMM: ERR_BUSY: Other Ccb (%u) already using %s", - ccbIdLongDnGuard, immLongDnsAllowed.c_str()); + sCcbIdLongDnGuard, immLongDnsAllowed.c_str()); err = SA_AIS_ERR_BUSY; } else { if(!longDnsAllowedAfter) { @@ -9281,7 +9431,7 @@ ImmModel::ccbObjectModify(const ImmsvOmC } } /* End of LONG DN check */ - ccbIdLongDnGuard = ccbId; + sCcbIdLongDnGuard = ccbId; } } } @@ -9368,7 +9518,7 @@ ImmModel::ccbObjectModify(const ImmsvOmC if(err == SA_AIS_OK) { object->mCcbId = ccbId; //Overwrite any old obsolete ccb id. osafassert(oMut); - if(!chainedOp) { + if(!chainedOp) { ccb->mMutations[objectName] = oMut; if(adminOwner->mReleaseOnFinalize) { //NOTE: this may not be good enough. For a modify the @@ -9377,6 +9527,9 @@ ImmModel::ccbObjectModify(const ImmsvOmC } } ccb->mOpCount++; + if(upgradeReadLock) { + ccb->removeObjReadLock(object); + } } else { //err != SA_AIS_OK if(ccb->mState == IMM_CCB_MODIFY_OP) {ccb->mState = IMM_CCB_READY;} @@ -9500,7 +9653,7 @@ ImmModel::ccbObjectDelete(const ImmsvOmC setCcbErrorString(ccb, IMM_RESOURCE_ABORT "CCB is not in an expected state"); goto ccbObjectDeleteExit; } - + if(reqConn && (ccb->mOriginatingConn != reqConn)) { LOG_NO("ERR_BAD_HANDLE: Missmatch on connection for ccb id %u", ccbId); err = SA_AIS_ERR_BAD_HANDLE; @@ -9650,6 +9803,23 @@ ImmModel::deleteObject(ObjectMap::iterat ccb->mId, ccbIdOfObj); return SA_AIS_ERR_BUSY; } + + if(ccbIdOfObj == 0) { + ObjectShortCountMap::iterator oscm = sObjectReadLockCount.find(oi->second); + if(oscm != sObjectReadLockCount.end()) { + if((oscm->second > 1) || !(ccb->isReadLockedByThisCcb(oi->second))) { + TRACE("ERR_BUSY: object '%s' is read-locked by %u other ccb(s)", + oi->first.c_str(), oscm->second); + osafassert(!doIt); + return SA_AIS_ERR_BUSY; + } else if (doIt) { + osafassert((oscm->second == 1) && (ccb->isReadLockedByThisCcb(oi->second))); + TRACE("CcbDelete: Object '%s' safe-read-locked only by this ccb (%u) => " + "upgrade to exclusive lock is possible", oi->first.c_str(), ccb->mId); + ccb->removeObjReadLock(oi->second); + } + } + } } if(oi->second->mClassInfo->mCategory != SA_IMM_CLASS_CONFIG) { @@ -10400,6 +10570,20 @@ ImmModel::ccbCompletedContinuation(immsv } ccb = *i1; + if(ccb->mAugCcbParent && + (ccb->mAugCcbParent->mContinuationId == rsp->inv)) { + ccb->mOriginatingConn = ccb->mAugCcbParent->mOriginatingConn; + ccb->mOriginatingNode = ccb->mAugCcbParent->mOriginatingNode; + ccb->mState = ccb->mAugCcbParent->mState; + ccb->mErrorStrings = ccb->mAugCcbParent->mErrorStrings; + + ccb->mAugCcbParent->mErrorStrings = NULL; + ccb->mAugCcbParent->mContinuationId = 0; + free(ccb->mAugCcbParent); + ccb->mAugCcbParent = NULL; + } + + if(ccb->mState == IMM_CCB_VALIDATED) { LOG_IN("GOING FROM IMM_CCB_VALIDATED to IMM_CCB_PREPARE Ccb:%u", ccbId); ccb->mState = IMM_CCB_PREPARE; @@ -10700,6 +10884,252 @@ ImmModel::ccbObjModifyContinuation(SaUin TRACE_LEAVE(); } +SaAisErrorT +ImmModel::ccbReadLockObject(const ImmsvOmSearchInit* req) +{ + TRACE_ENTER(); + SaAisErrorT err = SA_AIS_OK; + SaUint32T ccbId = req->ccbId; + size_t sz = strnlen((char *) req->rootName.buf, (size_t)req->rootName.size); + std::string objectName((const char*)req->rootName.buf, sz); + ObjectMap::iterator i; + ObjectInfo* obj = NULL; + SaUint32T ccbIdOfObj=0; + CcbVector::iterator i1; + CcbInfo* ccb = 0; + + if (objectName.empty()) { + LOG_NO("ERR_INVALID_PARAM: Empty DN is not allowed"); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + // Validate object name + if(! (nameCheck(objectName)||nameToInternal(objectName)) ) { + LOG_NO("ERR_INVALID_PARAM: Not a proper object name"); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + i = sObjectMap.find(objectName); + if (i == sObjectMap.end()) { + //TRACE_7("ERR_NOT_EXIST: Object '%s' does not exist", objectName.c_str()); + err = SA_AIS_ERR_NOT_EXIST; + goto done; + } + + obj = i->second; + + osafassert(obj->mClassInfo); + + if(obj->mClassInfo->mCategory != SA_IMM_CLASS_CONFIG) { + LOG_NO("ERR_INVALID_PARAM: object '%s' is not a configuration object", + objectName.c_str()); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), CcbIdIs(ccbId)); + if (i1 == sCcbVector.end()) { + LOG_NO("ERR_BAD_HANDLE: ccb id %u does not exist", ccbId); + err = SA_AIS_ERR_BAD_HANDLE; + goto done; + } + ccb = *i1; + + if(!ccb->isOk()) { + LOG_IN("ERR_FAILED_OPERATION: ccb %u is in an error state " + "rejecting ccbObjectRead operation ", ccbId); + /* !ccb->isOk(), error string with abort reason must already be set */ + err = SA_AIS_ERR_FAILED_OPERATION; + goto done; + } + + if(ccb->mState > IMM_CCB_READY) { + if(ccb->mAugCcbParent == NULL) { + LOG_WA("ERR_BAD_OPERATION: ccb %u is not in an expected state: %u " + "rejecting ccbObjectRead operation ", ccbId, ccb->mState); + err = SA_AIS_ERR_BAD_OPERATION; + goto done; + } else { + if(ccb->mState < IMM_CCB_CRITICAL) { + LOG_IN("SafeRead inside augmentation allowed"); + } else { + LOG_WA("ERR_BAD_OPERATION: ccb %u is not in an expected state: %u " + "rejecting ccbObjectRead operation ", ccbId, ccb->mState); + err = SA_AIS_ERR_BAD_OPERATION; + goto done; + } + } + } + + ccbIdOfObj = obj->mCcbId; + if(ccbIdOfObj != ccbId) { + i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), + CcbIdIs(ccbIdOfObj)); + if ((i1 != sCcbVector.end()) && ((*i1)->isActive())) { + TRACE_7("ERR_BUSY: ccb id %u differs from active ccb id on object %u", + ccbId, ccbIdOfObj); + err = SA_AIS_ERR_BUSY; + goto done; + } + /* Set ccb-id to zero to signify no exclusive lock set. + CcbId of 0 does not mean that a shared read lock must be set for the object. + It only means that zero or more shared read locks *could* be set for this object. + */ + obj->mCcbId = 0; + } else { + TRACE_7("Safe-read: Object '%s' is currently *exclusive* locked by *same* ccb %u", + objectName.c_str(), ccbId); + /* Read-lock succeeds as a no-op. + Actual access will fail if it is delete locked in same ccb. + We could fail here for the delete locked case, but it is actually not the + requested locking for the ccb that fails, it is the safe-read-access done later. + The safe read of the object will fail with ERR_NOT_EXIST because the object is + scheduled for delete in the *same* ccb as the reader. If the object was locked + for delete in a different ccb then the safe-reader in this ccb would get ERR_BUSY. + */ + osafassert(err == SA_AIS_OK); + goto done; + } + + if(ccb->isReadLockedByThisCcb(obj)) { + TRACE("Object %s is already safe-read-locked by this ccb %u", + objectName.c_str(), ccbId); + } else { + ccb->addObjReadLock(obj, objectName); + } + + done: + TRACE_LEAVE(); + return err; +} + +SaAisErrorT +ImmModel::objectIsLockedByCcb(const ImmsvOmSearchInit* req) +{ + // ##Redo this whole method to simply check ccb and ccb mutation.? + TRACE_ENTER(); + SaAisErrorT err = SA_AIS_OK; + SaUint32T ccbId = req->ccbId; + size_t sz = strnlen((char *) req->rootName.buf, (size_t)req->rootName.size); + std::string objectName((const char*)req->rootName.buf, sz); + ObjectMap::iterator i; + ObjectInfo* obj = NULL; + SaUint32T ccbIdOfObj=0; + CcbVector::iterator i1; + CcbInfo* ccb = 0; + + if (objectName.empty()) { + LOG_NO("ERR_INVALID_PARAM: Empty DN is not allowed"); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + // Validate object name + if(! (nameCheck(objectName)||nameToInternal(objectName)) ) { + LOG_NO("ERR_INVALID_PARAM: Not a proper object name"); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + i = sObjectMap.find(objectName); + if (i == sObjectMap.end()) { + //TRACE_7("ERR_NOT_EXIST: Object '%s' does not exist", objectName.c_str()); + err = SA_AIS_ERR_NOT_EXIST; + goto done; + } + + obj = i->second; + osafassert(obj->mClassInfo); + + if(obj->mClassInfo->mCategory != SA_IMM_CLASS_CONFIG) { + LOG_NO("ERR_INVALID_PARAM: object '%s' is not a configuration object", + objectName.c_str()); + err = SA_AIS_ERR_INVALID_PARAM; + goto done; + } + + i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), CcbIdIs(ccbId)); + if (i1 == sCcbVector.end()) { + LOG_NO("ERR_BAD_HANDLE: ccb id %u does not exist", ccbId); + err = SA_AIS_ERR_BAD_HANDLE; + goto done; + } + ccb = *i1; + + if(!ccb->isOk()) { + LOG_IN("ERR_FAILED_OPERATION: ccb %u is in an error state " + "rejecting ccbObjectRead operation ", ccbId); + /* !ccb->isOk(), error string with abort reason must already be set */ + err = SA_AIS_ERR_FAILED_OPERATION; + goto done; + } + + if(ccb->mState > IMM_CCB_READY) { + if(ccb->mAugCcbParent == NULL) { + LOG_WA("ERR_BAD_OPERATION: ccb %u is not in an expected state: %u " + "rejecting ccbObjectRead operation ", ccbId, ccb->mState); + err = SA_AIS_ERR_BAD_OPERATION; + goto done; + } else { + if(ccb->mState < IMM_CCB_CRITICAL) { + LOG_IN("SafeRead inside augmentation allowed"); + } else { + LOG_WA("ERR_BAD_OPERATION: ccb %u is not in an expected state: %u " + "rejecting ccbObjectRead operation ", ccbId, ccb->mState); + err = SA_AIS_ERR_BAD_OPERATION; + goto done; + } + } + } + + ccbIdOfObj = obj->mCcbId; + if(ccbIdOfObj == ccbId) { + TRACE_7("Object '%s' is currently *exclusive* locked by same ccb %u", + objectName.c_str(), ccbId); + osafassert(err == SA_AIS_OK); + goto done; + } else if(ccb->isReadLockedByThisCcb(obj)) { + TRACE_7("Object '%s' is currently *shared* read locked by same ccb %u", + objectName.c_str(), ccbId); + osafassert(err == SA_AIS_OK); + goto done; + } else if(ccbIdOfObj) { + //CcbId is not zero. + TRACE_7("Object '%s' is currently NOT locked by same ccb %u", + objectName.c_str(), ccbId); + i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), + CcbIdIs(ccbIdOfObj)); + if ((i1 != sCcbVector.end()) && ((*i1)->isActive())) { + TRACE_7("ERR_BUSY: Safe-read: ccb id %u differs from active ccb id on object %u", + ccbId, ccbIdOfObj); + err = SA_AIS_ERR_BUSY; + goto done; + } + /* clear the obsolete ccb-id */ + ccbIdOfObj = 0; + } + + if(ccb->mAugCcbParent) { + LOG_IN("This is a lock check in an augmented CCB"); + } + + /* Intentionally NO check for admin-owner. SafeRead allows read sharing with + other CCBs, => no admin-owner exclusivity. + */ + + if(ccbIdOfObj == 0) { + TRACE_7("Object '%s' is currently not locked by any ccb", objectName.c_str()); + err = SA_AIS_ERR_INTERRUPT; + goto done; + } + + done: + TRACE_LEAVE(); + return err; +} + SaAisErrorT ImmModel::accessorGet(const ImmsvOmSearchInit* req, ImmSearchOp& op) @@ -10724,6 +11154,14 @@ ImmModel::accessorGet(const ImmsvOmSearc SaImmSearchOptionsT notAllowedOptions = 0LL; bool nonExtendedNameCheck = req->searchParam.present > ImmOmSearchParameter_PR_oneAttrParam; bool checkAttribute = false; + bool isSafeRead = (req->ccbId != 0); + CcbInfo* ccb = NULL; + CcbVector::iterator i1; + + + if(isSafeRead) { + TRACE_7("SafeRead (accessorGet) on Object: '%s'", objectName.c_str()); + } if(nonExtendedNameCheck) { op.setNonExtendedName(); @@ -10753,13 +11191,100 @@ ImmModel::accessorGet(const ImmsvOmSearc TRACE_7("ERR_NOT_EXIST: Object '%s' does not exist", objectName.c_str()); err = SA_AIS_ERR_NOT_EXIST; goto accessorExit; - } else if(i->second->mObjFlags & IMM_CREATE_LOCK) { - TRACE_7("ERR_NOT_EXIST: Object '%s' is being created, but ccb " - "or PRTO PBE, not yet applied", objectName.c_str()); - err = SA_AIS_ERR_NOT_EXIST; - goto accessorExit; - } - + } + if(i->second->mObjFlags & IMM_CREATE_LOCK) { + /* Both regular accessor-get and safe-read affected by create lock.*/ + if(isSafeRead) { + if(req->ccbId != i->second->mCcbId) { + TRACE_7("ERR_NOT_EXIST: Object '%s' is being created but not in this ccb.", + objectName.c_str()); + err = SA_AIS_ERR_NOT_EXIST; + goto accessorExit; + } + TRACE("req->ccbId == i->second->mCcbId i.e. same ccb ok for safe-read"); + obj = i->second; + } else { /* Regular accessor-get */ + TRACE_7("ERR_NOT_EXIST: Object '%s' is being created, but ccb " + "or PRTO PBE, not yet applied", objectName.c_str()); + err = SA_AIS_ERR_NOT_EXIST; + goto accessorExit; + } + } else if(isSafeRead) { + /* Interference with unapplied create taken care of above in if-branch for + both safeRead and regular accessorGet. + + Regular accessor-get is not affected by open delete, modify, or safe-reads. + It simply accesses the current committed version. + + Safe-read *is* affected by unapplied modify or delete, hence this else branch. + + Mdify in same ccb => safe-read must read the after-image-version in the same ccb. + Delete in same ccb => the object becomes inaccesible (ERR_NOT_EXIST) for safe-read. + Mofify or delete by *other* ccb => safe-read should have been rejected (ERR_BUSY) + in objectIsLockedByCcb(). + + Safe-read is of course not affected by other safe-read operations on this object + in same or other ccbs. Latest commited version is read. + */ + + i1 = std::find_if(sCcbVector.begin(), sCcbVector.end(), CcbIdIs(req->ccbId)); + osafassert(i1 != sCcbVector.end()); /*Already checked in objectIsLockedByCcb. */ + ccb = *i1; + if((i->second->mCcbId == 0) && !(ccb->isReadLockedByThisCcb(i->second))) { + LOG_WA("Safe read on object %s NOT locked by ccb (%u). Should not be caught here", + objectName.c_str(), req->ccbId); + /* If we get here this may be seen as a bug to be be corrected. Should perhaps + assert here, but be lenient for now and just report "INTERRUPT" which should + result in an new attempt to lock the object for safe-read. + The safe-read lock should have been obtained before reacing accessor-get. + */ + err = SA_AIS_ERR_INTERRUPT; /* Try to lock the object for safe read.*/ + goto accessorExit; + } + + if(i->second->mCcbId != req->ccbId) { + if(i->second->mCcbId == 0) { + TRACE_7("Object %s locked for shared read in ccb (%u) and possibly other ccbs", + objectName.c_str(), req->ccbId); + osafassert(i->second->mObjFlags & IMM_SHARED_READ_LOCK); + obj = i->second; /* Use latest committed version. */ + } else { + LOG_WA("Safe read on object %s exclusive locked by other ccb (%u). " + "Should not be caught here", objectName.c_str(), i->second->mCcbId); + /* If we get here this may be seen as a bug to be be corrected. Should perhaps + assert here, but be lenient for now and just report "BUSY". + */ + err = SA_AIS_ERR_BUSY; + goto accessorExit; + } + } else {/* i->second->mCcbId == req->ccbId */ + osafassert(i->second->mCcbId != 0); + TRACE_7("Safe read on object *exclusive* locked by *this* ccb %u", req->ccbId); + + /* This can not be a safe-read. */ + osafassert(!(i->second->mObjFlags & IMM_SHARED_READ_LOCK)); + + /* Prior op can not be a create. Determine if it is delete or modify */ + + if(i->second->mObjFlags & IMM_DELETE_LOCK) { + LOG_IN("ERR_NOT_EXIST: Object '%s' is being deleted in same ccb %u", + objectName.c_str(), req->ccbId); + err = SA_AIS_ERR_NOT_EXIST; + goto accessorExit; + } + + /* Prior op must be a modify.in same ccb. Use latest afim for safe-read. */ + TRACE_7("Safe read of Object '%s' that was modified in same ccb %u", + objectName.c_str(), req->ccbId); + /* Find mutation */ + ObjectMutationMap::iterator omuti = ccb->mMutations.find(objectName); + osafassert(omuti != ccb->mMutations.end()); + ObjectMutation* oMut = omuti->second; + osafassert(oMut->mOpType == IMM_MODIFY); + obj = oMut->mAfterImage; + } + } //if(safeRead) + // Validate scope if (scope != SA_IMM_ONE) { LOG_NO("ERR_INVALID_PARAM: invalid search scope"); @@ -10784,9 +11309,15 @@ ImmModel::accessorGet(const ImmsvOmSearc //TODO: Reverse the order of matching attribute names. //The class should be searched first since we must return error - //if the attribute is not defined in the class of the object. - - obj = i->second; + //if the attribute is not defined in the class of the object + + //SafeRead works exactly like accessor get with respect to runtime attributes. + + if(!obj) { + osafassert(!isSafeRead); //SafeRead checks bypassed somehow above. + obj = i->second; + } + if(obj->mObjFlags & IMM_DN_INTERNAL_REP) { nameToExternal(objectName); } @@ -11093,7 +11624,12 @@ ImmModel::searchInitialize(ImmsvOmSearch goto searchInitializeExit; } - + if(req->ccbId) { + LOG_WA("SafeRead ended up in ImmModel::searchInitialize ccb:%u", req->ccbId); + err = SA_AIS_ERR_LIBRARY; + goto searchInitializeExit; + } + // Validate root name if(! (nameCheck(rootName)||nameToInternal(rootName)) ) { LOG_NO("ERR_INVALID_PARAM: Not a proper root name"); diff --git a/osaf/services/saf/immsv/immnd/ImmModel.hh b/osaf/services/saf/immsv/immnd/ImmModel.hh --- a/osaf/services/saf/immsv/immnd/ImmModel.hh +++ b/osaf/services/saf/immsv/immnd/ImmModel.hh @@ -79,6 +79,9 @@ typedef std::vector<SaInvocationT> Invoc /* Maps an object pointer, to a set of object pointers.*/ typedef std::multimap<ObjectInfo*, ObjectInfo*> ObjectMMap; +/**/ +typedef std::map<ObjectInfo*, uint16_t> ObjectShortCountMap; + /* Object mutation */ struct ObjectMutation; typedef std::map<std::string, ObjectMutation*> ObjectMutationMap; @@ -382,6 +385,10 @@ public: SaAisErrorT nextSyncResult(ImmsvOmRspSearchNext** rsp, ImmSearchOp& op); + SaAisErrorT objectIsLockedByCcb(const ImmsvOmSearchInit* req); + + SaAisErrorT ccbReadLockObject(const ImmsvOmSearchInit* req); + SaAisErrorT accessorGet( const ImmsvOmSearchInit* req, ImmSearchOp& op); diff --git a/osaf/services/saf/immsv/immnd/immnd_evt.c b/osaf/services/saf/immsv/immnd/immnd_evt.c --- a/osaf/services/saf/immsv/immnd/immnd_evt.c +++ b/osaf/services/saf/immsv/immnd/immnd_evt.c @@ -217,10 +217,10 @@ static uint32_t immnd_evt_proc_search_fi static uint32_t immnd_evt_proc_accessor_get(IMMND_CB *cb, IMMND_EVT *evt, IMMSV_SEND_INFO *sinfo); +static uint32_t immnd_evt_proc_safe_read(IMMND_CB *cb, IMMND_EVT *evt, IMMSV_SEND_INFO *sinfo); + static uint32_t immnd_evt_proc_mds_evt(IMMND_CB *cb, IMMND_EVT *evt); -/*static uint32_t immnd_evt_immd_new_active(IMMND_CB *cb);*/ - static void immnd_evt_ccb_abort(IMMND_CB *cb, SaUint32T ccbId, SaUint32T **clientArr, SaUint32T * clArrSize, SaUint32T *nodeId); @@ -358,7 +358,8 @@ uint32_t immnd_evt_destroy(IMMSV_EVT *ev } else if (evt->info.immnd.type == IMMND_EVT_ND2ND_SEARCH_REMOTE_RSP) { freeSearchNext(&evt->info.immnd.info.rspSrchRmte.runtimeAttrs, false); } else if ((evt->info.immnd.type == IMMND_EVT_A2ND_SEARCHINIT) || - (evt->info.immnd.type == IMMND_EVT_A2ND_ACCESSOR_GET)) { + (evt->info.immnd.type == IMMND_EVT_A2ND_ACCESSOR_GET) || + (evt->info.immnd.type == IMMND_EVT_A2ND_OBJ_SAFE_READ)) { free(evt->info.immnd.info.searchInit.rootName.buf); evt->info.immnd.info.searchInit.rootName.buf = NULL; evt->info.immnd.info.searchInit.rootName.size = 0; @@ -606,6 +607,10 @@ void immnd_process_evt(void) rc = immnd_evt_proc_search_next(cb, &evt->info.immnd, &evt->sinfo); break; + case IMMND_EVT_A2ND_OBJ_SAFE_READ: + rc = immnd_evt_proc_safe_read(cb, &evt->info.immnd, &evt->sinfo); + break; + case IMMND_EVT_A2ND_ACCESSOR_GET: rc = immnd_evt_proc_accessor_get(cb, &evt->info.immnd, &evt->sinfo); break; @@ -1795,6 +1800,80 @@ static uint32_t immnd_evt_proc_search_fi } /**************************************************************************** + * Name : immnd_evt_proc_safe_read + * + * Description : Function to process the saImmOmCcbObjectRead call. + * This call can in some cases be resolved with success locally. + * This will be the case if the object to be accessed is already + * locked previously by this CCB. + * + * + * Arguments : IMMND_CB *cb - IMMND CB pointer + * IMMND_EVT *evt - Received Event structure + * IMMSV_SEND_INFO *sinfo - sender info + *****************************************************************************/ +static uint32_t immnd_evt_proc_safe_read(IMMND_CB *cb, IMMND_EVT *evt, IMMSV_SEND_INFO *sinfo) +{ + IMMSV_EVT send_evt; + uint32_t rc = NCSCC_RC_SUCCESS; + SaAisErrorT err = SA_AIS_OK; + TRACE_ENTER(); + memset(&send_evt, 0, sizeof(IMMSV_EVT)); + + if(evt->info.searchInit.ccbId == 0) { + err = SA_AIS_ERR_LIBRARY; + LOG_WA("ERR_LIBRARY: Received zero ccb-id for safe-read"); + goto error; + } + + /* Dive into ImmModel to do locking checks. + If already locked in this ccb continue with accessor. + If locked by other ccb then reject with ERR_BUSY + If not locked, then generate fevs message for locking AND read. + */ + + err = immModel_objectIsLockedByCcb(cb, &(evt->info.searchInit)); + + switch (err) { + case SA_AIS_OK: + TRACE("Safe read: Object is locked by this CCB(%u). Go ahead and safe-read", + evt->info.searchInit.ccbId); + /* Invoke accessor_get which will send the reply. */ + break; + + case SA_AIS_ERR_BUSY: + TRACE("Object is locked by some other CCB than this CCB(%u). Reply with BUSY", + evt->info.searchInit.ccbId); + goto error; + + case SA_AIS_ERR_INTERRUPT: + TRACE("Object not locked. Ccb (%u) needs to lock it over fevs. Reply with INTERRUPT", + evt->info.searchInit.ccbId); + /* Should result in fevs message to read-lock object. */ + goto error; + + default: + TRACE("Unusual error from immModel_isLockedByMe: %u", err); + goto error; + } + + rc = immnd_evt_proc_accessor_get(cb, evt, sinfo); + goto done; + + error: + send_evt.type = IMMSV_EVT_TYPE_IMMA; + send_evt.info.imma.type = IMMA_EVT_ND2A_IMM_ERROR; + send_evt.info.imma.info.errRsp.error = err; + send_evt.info.imma.info.errRsp.errStrings = NULL; + + rc = immnd_mds_send_rsp(cb, sinfo, &send_evt); + + done: + TRACE_LEAVE(); + return rc; +} + +/**************************************************************************** * Name : immnd_evt_proc_accessor_get * * Description : Function to process the saImmOmAccessorGet call. @@ -1822,7 +1901,13 @@ static uint32_t immnd_evt_proc_accessor_ /* Search Init */ memset(&send_evt, 0, sizeof(IMMSV_EVT)); - TRACE_2("ACCESSOR GET:%s", evt->info.searchInit.rootName.buf); + + if(evt->info.searchInit.ccbId != 0) { + TRACE_2("SAFE READ :%s CcbId: %u", evt->info.searchInit.rootName.buf, evt->info.searchInit.ccbId); + } else { + TRACE_2("ACCESSOR GET:%s", evt->info.searchInit.rootName.buf); + } + /*Look up client-node */ immnd_client_node_get(cb, evt->info.searchInit.client_hdl, &cl_node); @@ -3205,6 +3290,20 @@ static SaAisErrorT immnd_fevs_local_chec } break; + case IMMND_EVT_A2ND_OBJ_SAFE_READ: + TRACE("IMMND_EVT_A2ND_OBJ_SAFE_READ noted in fevs_local_checks"); + if(!immModel_protocol50Allowed(cb) || immModel_pbeNotWritable(cb)) { + error = SA_AIS_ERR_TRY_AGAIN; + } + /* + Change signature of method to take name and ccbID + + error = immModel_objectIsLockedByCcb(cb, &(evt->info.searchInit)); + if(error == SA_AIS_OK) { error = SA_AIS_ERR_NO_BINDINGS;} + */ + + break; + case IMMND_EVT_A2ND_OBJ_CREATE_2: if(!immModel_protocol46Allowed(cb) || immModel_pbeNotWritable(cb)) { error = SA_AIS_ERR_TRY_AGAIN; @@ -3548,7 +3647,6 @@ static SaAisErrorT immnd_fevs_local_chec } break; - case IMMND_EVT_A2ND_PBE_ADMOP_RSP: if(fevsReq->sender_count != 0x0) { LOG_WA("ERR_LIBRARY: IMMND_EVT_A2ND_PBE_ADMOP_RSP fevsReq->sender_count != 0x0"); @@ -3562,7 +3660,7 @@ static SaAisErrorT immnd_fevs_local_chec break; default: - LOG_ER("UNPACK FAILURE, unrecognized message type: %u over FEVS", + LOG_ER("UNPACK FAILURE, unrecognized message type: %u caught in fevs_local_checks", frwrd_evt.info.immnd.type); error = SA_AIS_ERR_LIBRARY; break; @@ -4378,6 +4476,58 @@ static void immnd_evt_sync_fevs_base(IMM } +static void immnd_evt_safe_read_lock(IMMND_CB *cb, IMMND_EVT *evt, + SaBoolT originatedAtThisNd, SaImmHandleT clnt_hdl, MDS_DEST reply_dest) +{ + IMMSV_EVT send_evt; + IMMND_IMM_CLIENT_NODE *cl_node = NULL; + SaAisErrorT err = SA_AIS_OK; + TRACE_ENTER(); + + err = immModel_objectIsLockedByCcb(cb, &(evt->info.searchInit)); + + switch (err) { + case SA_AIS_OK: + TRACE("safe_read_lock: Object is already locked by this CCB(%u)!!", + evt->info.searchInit.ccbId); + break; + + case SA_AIS_ERR_BUSY: + TRACE("Object is locked by some other CCB than this CCB(%u). Reply with BUSY", + evt->info.searchInit.ccbId); + break; + + case SA_AIS_ERR_INTERRUPT: + TRACE("Object not locked. Ccb (%u) will now lock it", + evt->info.searchInit.ccbId); + err = immModel_ccbReadLockObject(cb, &(evt->info.searchInit)); + break; + + default: + TRACE("Unusual error from immModel_isLockedByMe: %u", err); + } + + if(originatedAtThisNd) { + immnd_client_node_get(cb, clnt_hdl, &cl_node); + if (cl_node == NULL || cl_node->mIsStale) { + LOG_WA("IMMND - Client went down so no response"); + return; + } + TRACE_2("Send immediate reply to client"); + + memset(&send_evt, '\0', sizeof(IMMSV_EVT)); + send_evt.type = IMMSV_EVT_TYPE_IMMA; + send_evt.info.imma.info.errRsp.error = err; + send_evt.info.imma.type = IMMA_EVT_ND2A_IMM_ERROR; + + if (immnd_mds_send_rsp(cb, &(cl_node->tmpSinfo), &send_evt) != NCSCC_RC_SUCCESS) { + LOG_WA("immnd_evt_class_delete: SENDRSP FAILED TO SEND"); + } + } + + TRACE_LEAVE(); +} + /**************************************************************************** * Name : immnd_evt_pbe_admop_rsp @@ -5141,7 +5291,7 @@ static void immnd_evt_proc_admop(IMMND_C if (originatedAtThisNd) { immnd_client_node_get(cb, clnt_hdl, &cl_node); if (cl_node == NULL || cl_node->mIsStale) { - LOG_ER("IMMND - Client went down so no response"); + LOG_WA("IMMND - Client went down so no response"); return; } @@ -8293,6 +8443,11 @@ immnd_evt_proc_fevs_dispatch(IMMND_CB *c immnd_evt_sync_fevs_base(cb, &frwrd_evt.info.immnd, originatedAtThisNd, clnt_hdl, reply_dest); break; + case IMMND_EVT_A2ND_OBJ_SAFE_READ: + TRACE("IMMND_EVT_A2ND_OBJ_SAFE_READ Received over fevs"); + immnd_evt_safe_read_lock(cb, &frwrd_evt.info.immnd, originatedAtThisNd, clnt_hdl, reply_dest); + break; + default: LOG_ER("UNPACK FAILURE, unrecognized message type: %u over FEVS", frwrd_evt.info.immnd.type); break; diff --git a/osaf/services/saf/immsv/immnd/immnd_init.h b/osaf/services/saf/immsv/immnd/immnd_init.h --- a/osaf/services/saf/immsv/immnd/immnd_init.h +++ b/osaf/services/saf/immsv/immnd/immnd_init.h @@ -202,6 +202,9 @@ extern "C" { SaAisErrorT immModel_searchInitialize(IMMND_CB *cb, struct ImmsvOmSearchInit *req, void **searchOp, SaBoolT isSync, SaBoolT isAccessor); + SaAisErrorT immModel_objectIsLockedByCcb(IMMND_CB *cb, struct ImmsvOmSearchInit *req); + SaAisErrorT immModel_ccbReadLockObject(IMMND_CB *cb, struct ImmsvOmSearchInit *req); + SaAisErrorT immModel_testTopResult(void *searchOp, SaUint32T *implNodeId, SaBoolT *bRtAttrsToFetch); SaAisErrorT ------------------------------------------------------------------------------ Transform Data into Opportunity. Accelerate data analysis in your applications with Intel Data Analytics Acceleration Library. Click to learn more. http://pubads.g.doubleclick.net/gampad/clk?id=278785351&iu=/4140 _______________________________________________ Opensaf-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/opensaf-devel
