"Fossies" - the Fresh Open Source Software Archive

Member "opensaf-5.21.09/src/imm/immnd/ImmModel.cc" (14 Sep 2021, 730458 Bytes) of package /linux/misc/opensaf-5.21.09.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ImmModel.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.21.06_vs_5.21.09.

    1 /*      -*- OpenSAF  -*-
    2  *
    3  * (C) Copyright 2008 The OpenSAF Foundation
    4  * Copyright Ericsson AB 2009, 2017 - All Rights Reserved.
    5  * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved.
    6  *
    7  * This program is distributed in the hope that it will be useful, but
    8  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    9  * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
   10  * under the GNU Lesser General Public License Version 2.1, February 1999.
   11  * The complete license can be accessed from the following location:
   12  * http://opensource.org/licenses/lgpl-license.php
   13  * See the Copying file included with the OpenSAF distribution for full
   14  * licensing terms.
   15  *
   16  * Author(s): Ericsson AB
   17  *
   18  */
   19 
   20 #include <set>
   21 #include <algorithm>
   22 #include <time.h>
   23 
   24 #include "imm/immnd/ImmModel.h"
   25 #include "imm/immnd/ImmAttrValue.h"
   26 #include "imm/immnd/ImmSearchOp.h"
   27 
   28 #include "immnd.h"
   29 #include "base/osaf_unicode.h"
   30 #include "base/osaf_extended_name.h"
   31 #include "base/saf_def.h"
   32 
   33 // Local types
   34 #define DEFAULT_TIMEOUT_SEC 6  /* Should be saImmOiTimeout in SaImmMngt */
   35 #define PRT_LOW_THRESHOLD 1    /* See ImmModel::immNotPbeWritable */
   36 #define PRT_HIGH_THRESHOLD 4   /* See ImmModel::immNotPbeWritable */
   37 #define CCB_CRIT_THRESHOLD 8   /* See ImmModel::immNotPbeWritable */
   38 #define SEARCH_TIMEOUT_SEC 600 /* Search timeout */
   39 
   40 struct ContinuationInfo2 {
   41   ContinuationInfo2()
   42       : mCreateTime(kZeroSeconds), mConn(0), mTimeout(0), mImplId(0) {}
   43   ContinuationInfo2(SaUint32T conn, SaUint32T timeout)
   44       : mConn(conn), mTimeout(timeout), mImplId(0) {
   45     osaf_clock_gettime(CLOCK_MONOTONIC, &mCreateTime);
   46   }
   47   timespec mCreateTime;
   48   SaUint32T mConn;
   49   SaUint32T mTimeout;  // 0=> no timeout. Otherwise timeout in SECONDS.
   50   // Default copy constructor and assignement operator used in ContinuationMap2
   51   SaUint32T mImplId;
   52 };
   53 typedef std::map<SaInvocationT, ContinuationInfo2> ContinuationMap2;
   54 
   55 struct ContinuationInfo3 {
   56   ContinuationInfo3() : mConn(0), mReply_dest(0LL), mImplementer(NULL) {}
   57   ContinuationInfo3(SaUint32T conn, SaUint64T reply_dest, ImplementerInfo* i)
   58       : mConn(conn), mReply_dest(reply_dest), mImplementer(i) {}
   59 
   60   // time_t  mCreateTime;
   61   SaUint32T mConn;
   62   SaUint64T mReply_dest;
   63   ImplementerInfo* mImplementer;
   64   // Default copy constructor and assignement operator used in ContinuationMap3
   65 };
   66 
   67 typedef std::map<SaInvocationT, ContinuationInfo3> ContinuationMap3;
   68 
   69 struct AttrInfo {
   70   AttrInfo() : mValueType(0), mFlags(0), mNtfId(0) {}
   71   SaUint32T mValueType;
   72   SaImmAttrFlagsT mFlags;
   73   SaUint32T mNtfId;
   74   ImmAttrValue mDefaultValue;
   75 };
   76 
   77 struct ImplementerInfo {
   78   ImplementerInfo()
   79       : mId(0),
   80         mConn(0),
   81         mNodeId(0),
   82         mMds_dest(0LL),
   83         mAdminOpBusy(0),
   84         mDying(false),
   85         mApplier(false),
   86         mTimeout(DEFAULT_TIMEOUT_SEC),
   87         mApplierDisconnected(0) {}
   88   SaUint32T mId;
   89   SaUint32T mConn;  // Current implementer, only valid on one node.
   90   // NULL otherwise.
   91   unsigned int mNodeId;
   92   std::string mImplementerName;
   93   SaUint64T mMds_dest;
   94   unsigned int mAdminOpBusy;
   95   bool mDying;
   96   bool mApplier;       // This is an applier OI
   97   SaUint32T mTimeout;  // OI callback timeout
   98   SaUint64T mApplierDisconnected;  // Time when applier is disconnected
   99 };
  100 
  101 typedef std::vector<ImplementerInfo*> ImplementerVector;
  102 typedef std::set<ImplementerInfo*> ImplementerSet;
  103 typedef std::map<std::string, ImplementerSet*> ImplementerSetMap;
  104 
  105 typedef std::map<ImplementerInfo*, ContinuationInfo2> ImplementerEvtMap;
  106 
  107 struct ImplementerCcbAssociation {
  108   explicit ImplementerCcbAssociation(ImplementerInfo* impl)
  109       : mImplementer(impl), mContinuationId(0), mWaitForImplAck(false) {}
  110   ImplementerInfo* mImplementer;
  111   SaUint32T mContinuationId;  // used to identify related pending msg replies.
  112   bool mWaitForImplAck;
  113 };
  114 
  115 typedef std::map<SaUint32T, ImplementerCcbAssociation*> CcbImplementerMap;
  116 
  117 typedef std::set<ObjectInfo*> ObjectSet;
  118 
  119 struct ClassInfo {
  120   explicit ClassInfo(SaUint32T category)
  121       : mCategory(category), mImplementer(NULL) {}
  122   ~ClassInfo() {
  123     mCategory = 0;
  124     mImplementer = NULL;
  125   }
  126 
  127   SaUint32T mCategory;
  128   AttrMap mAttrMap;               //<-Each AttrInfo requires explicit delete
  129   ImplementerInfo* mImplementer;  //<- Main OI points INTO sImplementerVector
  130   ObjectSet mExtent;
  131   ImplementerSet mAppliers;  // OIs did classImplementerSet on this class
  132 };
  133 typedef std::map<std::string, ClassInfo*> ClassMap;
  134 
  135 typedef std::map<std::string, ImmAttrValue*> ImmAttrValueMap;
  136 
  137 typedef SaUint32T ImmObjectFlags;
  138 #define IMM_CREATE_LOCK 0x00000001
  139 // If create lock is on, it signifies that a ccb has reserved space in
  140 // the name-tree for the object, pending the ccb-apply. The object must
  141 // be invisible in contents (invisinble to search and get), visible in name
  142 // to creates from any ccb, and finally, invisible as 'parent' to creates
  143 // from other Ccb's. Creates of subobjects in the same ccb must be allowed.
  144 // Deletes from other ccbs need not test on ths lock because they will conflict
  145 // on the ccbId of the object anyway.
  146 // The lock is also used during creates of persistent runtime objects (PRTOs).
  147 // If the Persistent Back End (PBE) is enabled, then the create of the PRTO
  148 // has to wait on ack from the PBE before being released to the client.
  149 // During the wait, the create lock is set on the object.
  150 
  151 #define IMM_DELETE_LOCK 0x00000002
  152 // If the delete-lock is on, it signifies that a ccb has registered a delete
  153 // of this object, pending the apply of the ccb. The only signifficance of this
  154 // is to prevent the creates of subobjects to this object in any ccb.
  155 // Even in the SAME ccb it is not allowed to create subobject to a registered
  156 // delete.
  157 // The lock is also used during deletes of persistent runtime objects (PRTOs).
  158 // If the Persistent Back End (PBE) is enabled, then the deletes of a subtree,
  159 // which may include both PRTOs and RTOs, has to wait on ack from the PBE,
  160 // before being released to the client.
  161 // During the wait, the delete lock is set on the object.
  162 
  163 #define IMM_DN_INTERNAL_REP 0x00000004
  164 // If this flag is set it indicates that the DN has been changed in rep
  165 // from external rep to an internal rep, where any escaped commas "\,"
  166 // in external rep have been replaced by an escape hash "\#" in internal rep;
  167 // Escape hash in external rep are not allowed, will be rejected in create.
  168 
  169 #define IMM_PRTO_FLAG 0x00000008
  170 // Flag indicates that the object is a persistent runtime object (PRTO).
  171 // This flag is not reliably set in general. I.e. it can not (yet) be
  172 // used in general to test if the object is a PRTO.
  173 // If the flag is set then the object must be a PRTO.
  174 // If the flag is not set, the object could still be a PRTO.
  175 // It is currently only used in rtObjectDelete() and deleteRtObject()
  176 
  177 #define IMM_RT_UPDATE_LOCK 0x00000010
  178 // This is only set by rtObjectUpdate() when the update includes persistent
  179 // runtime attributes PRTAs. The PRTAs may belong to either a runtime object
  180 // or a configureation object. If the PBE is enabled, then the updates of
  181 // cached RTAs (peristent or just cached) included in the call, has to wait
  182 // for ack from the PBE on the perisistification of the PRTAs.
  183 // The lock must be inspected/read by both ccb calls and RT calls.
  184 
  185 #define IMM_DELETE_ROOT 0x00000020
  186 // This flag is set in conjunction with a delete-operation only on the root
  187 // object for the possibly cascading delete. This is used to identify the root
  188 // delete object during the commit of the ccb/prto-delete, so that we can
  189 // decrement  the child-counter in any parent(s) of the deleted subtree.
  190 
  191 #define IMM_RTNFY_FLAG 0x00000040
  192 // Flag indicates that the object is a runtime object that has some
  193 // attributes flagged for special notification. See: SA_IMM_ATTR_NOTIFY.
  194 // This flag is not reliably set in general. I.e. it can not be
  195 // used in general to test if the object has a notifiable attribute.
  196 // If the flag is set then the object must have such an attribute.
  197 // But if the flag is not set, the object may still have such an attr.
  198 // It is currently only used in rtObjectDelete() and deleteRtObject()
  199 
  200 #define IMM_NO_DANGLING_FLAG 0x00000080
  201 // The flag indicates that a CCB operation is done on an object with
  202 // NO_DANGLING attributes.
  203 // The flag is set to the object in next cases:
  204 // a) creates an object with no dangling attribute(s) (that is/are not empty).
  205 // b) deletes an object that has no dangling attribute(s) (that are not empty).
  206 // c) modifies a NO_DANGLING attribute,
  207 // d) deletes an object that is referred to by some NO_DANGLING attribute.
  208 
  209 #define IMM_SHARED_READ_LOCK 0x00000100
  210 // If shared read lock is on, it signifies that one or more ccbs have locked the
  211 // object for safe-read. This prevents the object from being modified or deleted
  212 // by any other ccb until safe-readers have released the read lock.
  213 // If only one single ccb has a read lock on an object, i.e. the lock is
  214 // currently  not actually shared, then that ccb may upgrade the read-lock to an
  215 // exclusive lock  for delete or modify.  See also the data structure
  216 // sObjectReadLockCount.
  217 
  218 struct ObjectInfo {
  219   ObjectInfo()
  220       : mAdminOwnerAttrVal(NULL),
  221         mCcbId(0),
  222         mClassInfo(NULL),
  223         mImplementer(NULL),
  224         mObjFlags(0),
  225         mParent(NULL),
  226         mChildCount(0) {}
  227 
  228   ~ObjectInfo() {
  229     mAdminOwnerAttrVal = NULL;
  230     mCcbId = 0;
  231     mClassInfo = NULL;
  232     mImplementer = NULL;
  233     mObjFlags = 0;
  234     mParent = NULL;
  235     mChildCount = 0;
  236   }
  237 
  238   void getAdminOwnerName(std::string* str) const;
  239 
  240   ImmAttrValue* mAdminOwnerAttrVal;  // Pointer INTO mAttrValueMap
  241   SaUint32T mCcbId;  // Zero => may be read-locked see:IMM_SHARED_READ_LOCK
  242                      // Nonzero => may be exclusive lock if id is active ccb
  243   ImmAttrValueMap mAttrValueMap;  //<-Each ImmAttrValue needs explicit delete
  244   ClassInfo* mClassInfo;          //<-Points INTO ClassMap. Not own copy!
  245   ImplementerInfo* mImplementer;  //<-Points INTO ImplementerVector
  246   ImmObjectFlags mObjFlags;
  247   ObjectInfo* mParent;    //<-Points to parent object
  248   SaUint32T mChildCount;  //<-Nrof children, transitive
  249 };
  250 
  251 struct DeferredRtAUpdate {
  252   SaUint64T fevsMsgNo;
  253   immsv_attr_mods_list* attrModsList;
  254 };
  255 
  256 typedef std::list<DeferredRtAUpdate> DeferredRtAUpdateList;
  257 
  258 typedef std::map<std::string, DeferredRtAUpdateList*> DeferredObjUpdatesMap;
  259 
  260 void ObjectInfo::getAdminOwnerName(std::string* str) const {
  261   osafassert(this->mAdminOwnerAttrVal);
  262   str->clear();
  263   if (!(this->mAdminOwnerAttrVal->empty())) {
  264     str->assign(this->mAdminOwnerAttrVal->getValueC_str());
  265   }
  266 }
  267 
  268 typedef enum {
  269   IMM_CREATE = 1,
  270   IMM_MODIFY = 2,
  271   IMM_DELETE = 3,
  272   IMM_CREATE_CLASS = 4,
  273   IMM_DELETE_CLASS = 5,
  274   IMM_UPDATE_EPOCH = 6
  275 } ImmMutationType;
  276 
  277 struct ObjectMutation {
  278   explicit ObjectMutation(ImmMutationType opType)
  279       : mOpType(opType),
  280         mAfterImage(NULL),
  281         mContinuationId(0),
  282         mAugmentAdmo(0),
  283         mSavedData(NULL),
  284         mWaitForImplAck(false),
  285         mIsAugDelete(false),
  286         m2PbeCount(0) {}
  287   ~ObjectMutation() {
  288     osafassert(mAfterImage == NULL);
  289     mContinuationId = 0;
  290     mAugmentAdmo = 0;
  291     mWaitForImplAck = false;
  292     mIsAugDelete = false;
  293     if (mSavedData) {
  294       switch (mOpType) {
  295         case IMM_CREATE:
  296           immsv_free_attrvalues_list((IMMSV_ATTR_VALUES_LIST*)mSavedData);
  297           break;
  298 
  299         case IMM_MODIFY:
  300           immsv_free_attrmods((IMMSV_ATTR_MODS_LIST*)mSavedData);
  301           break;
  302 
  303         case IMM_DELETE:
  304           TRACE("Nothing to do");
  305           break;
  306 
  307         default:
  308           osafassert(false);
  309       }
  310       mSavedData = NULL;
  311     }
  312   }
  313 
  314   ImmMutationType mOpType;
  315   ObjectInfo* mAfterImage;
  316   SaUint32T mContinuationId;  // used to identify related pending msg replies.
  317   SaUint32T mAugmentAdmo; /* Aug admo with ROF==true for aug ccbCreates #2428 */
  318   void* mSavedData;       // For special applier PRTO. Type of data depends on
  319                      // mOpType
  320   bool mWaitForImplAck;  // ack required from implementer for THIS object
  321   bool mIsAugDelete;     // The mutation is an augmented delete.
  322   SaUint8T m2PbeCount;   // How many PBE replies to wait for (2PBE only).
  323 };
  324 
  325 typedef enum {
  326   IMM_CCB_EMPTY = 1,      // State after creation
  327   IMM_CCB_READY = 2,      // Ready for new ops, or commit or abort.
  328   IMM_CCB_CREATE_OP = 3,  // Ongoing create (pending implementer calls/replies)
  329   IMM_CCB_MODIFY_OP = 4,  // Ongoing modify (pending implementer calls/replies)
  330   IMM_CCB_DELETE_OP = 5,  // Ongoing delete (pending implementer calls/replies)
  331   IMM_CCB_VALIDATING =
  332       6,  // Explicit validate started (saImmOmCcbValidate only)
  333   IMM_CCB_VALIDATED =
  334       7,  // Explicit validate has completed (saImmOmCcbValidate only)
  335   IMM_CCB_PREPARE = 8,   // Waiting for nodes prepare & completed calls/replies
  336   IMM_CCB_CRITICAL = 9,  // Unilateral abort no longer allowed (except by PBE).
  337   IMM_CCB_PBE_ABORT = 10,  // The Persistent back end replied with abort
  338   IMM_CCB_COMMITTED = 11,  // Committed at nodes pending implementer apply calls
  339   IMM_CCB_ABORTED = 12,    // READY->ABORTED PREPARE->ABORTED
  340   IMM_CCB_ILLEGAL = 13     // CCB has been removed.
  341 } ImmCcbState;
  342 
  343 struct AugCcbParent {
  344   AugCcbParent()
  345       : mOriginatingConn(0),
  346         mOriginatingNode(0),
  347         mState(IMM_CCB_ILLEGAL),
  348         mErrorStrings(NULL),
  349         mContinuationId(0),
  350         mImplId(0),
  351         mAugmentAdmo(0) {}
  352   SaUint32T mOriginatingConn;        // Deferred Originating conn
  353   unsigned int mOriginatingNode;     // Deferred originating node
  354   ImmCcbState mState;                // Deferred state
  355   ImmsvAttrNameList* mErrorStrings;  // Deferred errorStrings
  356   SaUint32T mContinuationId;         // Deferred continuationId
  357   SaUint32T mImplId;                 /* ImplId for augmenting implementer*/
  358   SaUint32T mAugmentAdmo; /* Aug admo with ROF==true for aug ccbCreates #2428 */
  359 };
  360 
  361 static ObjectShortCountMap
  362     sObjectReadLockCount;  // Needs to be declared above CcbInfo
  363 
  364 struct CcbInfo {
  365   CcbInfo()
  366       : mId(0),
  367         mAdminOwnerId(0),
  368         mCcbFlags(0),
  369         mOriginatingConn(0),
  370         mOriginatingNode(0),
  371         mState(IMM_CCB_ILLEGAL),
  372         mVeto(SA_AIS_OK),
  373         mWaitStartTime(kZeroSeconds),
  374         mOpCount(0),
  375         mPbeRestartId(0),
  376         mErrorStrings(NULL),
  377         mAugCcbParent(NULL),
  378         mPurged(false) {}
  379   bool isOk() { return mVeto == SA_AIS_OK; }
  380   bool isActive() { return (mState < IMM_CCB_COMMITTED); }
  381   void addObjReadLock(ObjectInfo* obj, std::string& objName);
  382   void removeObjReadLock(ObjectInfo* obj, bool removeObject = true);
  383   void removeAllObjReadLocks();  // Removes all locks held by *this* ccb.
  384   bool isReadLockedByThisCcb(ObjectInfo* obj);
  385 
  386   SaUint32T mId;
  387   SaUint32T mAdminOwnerId;
  388   SaUint32T mCcbFlags;
  389 
  390   SaUint32T mOriginatingConn;  // If !NULL then originating at this node
  391   // with this conn.
  392   unsigned int mOriginatingNode;  // Needed for node crash Ccb GC
  393   ImmCcbState mState;
  394   CcbImplementerMap mImplementers;
  395   ObjectMutationMap mMutations;
  396   SaAisErrorT mVeto;  // SA_AIS_OK as long as no "participan" voted error.
  397   timespec mWaitStartTime;
  398   SaUint32T mOpCount;
  399   SaUint32T mPbeRestartId; /* ImplId for new PBE to resolve CCBs in critical */
  400   ImplementerSet mLocalAppliers;
  401   ImmsvAttrNameList* mErrorStrings; /*Error strings generated by current op */
  402   AugCcbParent* mAugCcbParent;
  403   ObjectSet mSafeReadSet;
  404   bool mPurged; /* True if the ccb continuation is purged.
  405                    Note that on remote nodes, mPurged is always 'false' */
  406 };
  407 typedef std::vector<CcbInfo*> CcbVector;
  408 
  409 void CcbInfo::addObjReadLock(ObjectInfo* obj, std::string& objName) {
  410   ObjectShortCountMap::iterator oscm;
  411   if (obj->mObjFlags & IMM_SHARED_READ_LOCK) {
  412     TRACE_7("Object '%s' already locked for safe-read by some ccb(s)",
  413             objName.c_str());
  414     // Read-lock is a shared lock, join the group of lockers.
  415   } else {
  416     osafassert(!(obj->mObjFlags & IMM_CREATE_LOCK));
  417     osafassert(!(obj->mObjFlags & IMM_DELETE_LOCK));
  418     /* IMM_RT_UPDATE_LOCK does not conflict with safe read because it deals with
  419        PRTO/PRTA updates, i.e. runtime data and not config data.
  420     */
  421 
  422     osafassert(obj->mCcbId == 0);
  423     /* A non-zero mCcbId for an object indicates exclusive lock
  424        (create/delete/modify) if and only if the identified ccb is still
  425        *active*. A zero mCcbId for an object *guarantees* that it is not
  426        exclusive locked. This function *requires* that the invoker has done the
  427        pre-check of no interference of a proposed shared reader with any
  428        pre-existing exclusive op and zeroed the ccbId if and only if an existing
  429        ccbId was no longer identifying an active ccb.
  430 
  431        There is no explicit ccb-modify lock since it can be inferred by (a) the
  432        ccb-id of an object identifying an active CCB and (b) neither the create
  433        or modify flag being set on the object.
  434     */
  435 
  436     obj->mObjFlags |= IMM_SHARED_READ_LOCK;
  437   }
  438 
  439   this->mSafeReadSet.insert(obj); /* Ccb keeps track of its safe-readers. */
  440 
  441   oscm = sObjectReadLockCount.find(obj);
  442   if (oscm == sObjectReadLockCount.end()) {
  443     sObjectReadLockCount[obj] = 1;
  444   } else {
  445     // TODO: Should check that we dont increment beyond maxshort.
  446     (oscm->second)++;
  447     LOG_IN("Incremented read-lock count for %s to %u", objName.c_str(),
  448            oscm->second);
  449   }
  450 }
  451 
  452 void CcbInfo::removeAllObjReadLocks() {
  453   /* Removes all the read-locks set by this ccb.
  454      Must be executed with ccb-commit or ccb-abort.
  455   */
  456   ObjectSet::iterator osi;
  457 
  458   for (osi = this->mSafeReadSet.begin(); osi != this->mSafeReadSet.end();
  459        ++osi) {
  460     removeObjReadLock(*osi, false);
  461   }
  462   this->mSafeReadSet.clear();
  463 }
  464 
  465 void CcbInfo::removeObjReadLock(ObjectInfo* obj,
  466                                 bool removeObject /* = true*/) {
  467   ObjectShortCountMap::iterator oscm = sObjectReadLockCount.find(obj);
  468   osafassert(oscm != sObjectReadLockCount.end());
  469   osafassert(oscm->second > 0);
  470   (oscm->second)--;
  471   TRACE("CcbInfo::removeObjReadLock decremented safe read count for %p to %u",
  472         obj, oscm->second);
  473   if (oscm->second == 0) {
  474     sObjectReadLockCount.erase(obj);
  475     TRACE("Object %p no longer has any read locks", obj);
  476     obj->mObjFlags &= ~IMM_SHARED_READ_LOCK;
  477   } else {
  478     TRACE("Object %p still has read lock count of %u", obj, oscm->second);
  479   }
  480 
  481   if (removeObject) {
  482     this->mSafeReadSet.erase(obj);
  483   }
  484 }
  485 
  486 bool CcbInfo::isReadLockedByThisCcb(ObjectInfo* obj) {
  487   TRACE_ENTER();
  488   ObjectSet::iterator osi = this->mSafeReadSet.find(obj);
  489   bool result = (osi != this->mSafeReadSet.end());
  490   TRACE_LEAVE();
  491   return result;
  492 }
  493 
  494 struct AdminOwnerInfo {
  495   AdminOwnerInfo()
  496       : mId(0),
  497         mConn(0),
  498         mNodeId(0),
  499         mReleaseOnFinalize(false),
  500         mDying(false) {}
  501   SaUint32T mId;
  502   std::string mAdminOwnerName;
  503   SaUint32T mConn;
  504   unsigned int mNodeId;
  505   ObjectSet mTouchedObjects;  // No good, sync needs the object names.
  506   bool mReleaseOnFinalize;
  507   bool mDying;
  508 };
  509 typedef std::vector<AdminOwnerInfo*> AdminOwnerVector;
  510 
  511 typedef enum {
  512   IMM_NODE_UNKNOWN = 0,          // Initial state
  513   IMM_NODE_LOADING = 1,          // We are participating in a cluster restart.
  514   IMM_NODE_FULLY_AVAILABLE = 2,  // Normal fully available state.
  515   IMM_NODE_ISOLATED = 3,     // We are trying to join an established cluster.
  516   IMM_NODE_W_AVAILABLE = 4,  // We are being synced, no reads allowed here
  517   IMM_NODE_R_AVAILABLE = 5   // We are write locked while other nodes are
  518                             // being synced.
  519 } ImmNodeState;
  520 
  521 // Missing parents map used in loading and sync when objects not always
  522 // inserted in tree order. The Object set contains pointers to known children
  523 // of the missing parent.
  524 typedef std::map<std::string, ObjectSet> MissingParentsMap;
  525 
  526 // Local variables
  527 
  528 static std::set<SaUint32T> sDiscardNodeSet;
  529 static ClassMap sClassMap;
  530 static AdminOwnerVector sOwnerVector;
  531 static CcbVector sCcbVector;
  532 static ObjectMap sObjectMap;
  533 static ObjectMMap sReverseRefsNoDanglingMMap;
  534 /* Maps an object pointer, to the set of pointers to *other* objects
  535    (not including self and not including children AS CHILDREN)
  536    where all those other objects contain at least one NO_DANGLING
  537    flagged reference (SaNameT) containing the DN of this object.
  538    Child objects could appear in the set of referencing objects if
  539    the child *explicitly* points to the parent in such a NO_DANGLING
  540    flagged attribute. That could be optimized out (?) but the main issue
  541    is if that is more convenient for the rest of the code related to this.
  542 */
  543 static ImplementerVector sImplementerVector;
  544 static MissingParentsMap sMissingParents;
  545 static ContinuationMap2 sAdmReqContinuationMap;
  546 static ContinuationMap3 sAdmImplContinuationMap;
  547 static ContinuationMap2 sSearchReqContinuationMap;
  548 static ContinuationMap3 sSearchImplContinuationMap;
  549 static ContinuationMap2 sPbeRtReqContinuationMap;
  550 static ObjectMutationMap sPbeRtMutations; /* Persistent Runtime Mutations
  551                                               At most one mutating op per Prto
  552                                               is allowed. Entry removed on on
  553                                               ack from PBE. */
  554 static ImplementerEvtMap
  555     sImplDetachTime; /* Give admop TRY_AGAIN when impl death is recent */
  556 static SaUint32T sPbeRtMinContId = 0; /* Monitors that no PbePrto gets stuck. */
  557 static SaUint32T sPbeRtBacklog = 0;   /* Monitors PbePrto capacity problems. */
  558 static SaUint32T sPbeRegressPeriods = 0;
  559 
  560 static IdVector sNodesDeadDuringSync;  // Keep track of implementers/nodes that
  561 static IdVector
  562     sImplsDeadDuringSync;  // die after finalizeSync is sent by coord,
  563                            // but before it arrives over fevs.
  564                            // This to avoid apparent implementor
  565                            // re-create by finalizeSync (at non coord).
  566 static IdVector
  567     sAdmosDeadDuringSync; /* Keep track of admo that die during sync */
  568 
  569 static DeferredObjUpdatesMap sDeferredObjUpdatesMap;
  570 
  571 static ImplementerSetMap sObjAppliersMap;
  572 
  573 static SaUint32T sLastContinuationId = 0;
  574 
  575 static ImmNodeState sImmNodeState = IMM_NODE_UNKNOWN;
  576 
  577 static const std::string immObjectDn(OPENSAF_IMM_OBJECT_DN);
  578 static const std::string immAttrClasses(OPENSAF_IMM_ATTR_CLASSES);
  579 static const std::string immAttrEpoch(OPENSAF_IMM_ATTR_EPOCH);
  580 static const std::string immClassName(OPENSAF_IMM_CLASS_NAME);
  581 static const std::string immAttrNostFlags(OPENSAF_IMM_ATTR_NOSTD_FLAGS);
  582 static const std::string immSyncBatchSize(OPENSAF_IMM_SYNC_BATCH_SIZE);
  583 static const std::string immPbeBSlaveName(OPENSAF_IMM_2PBE_APPL_NAME);
  584 static const std::string immLongDnsAllowed(OPENSAF_IMM_LONG_DNS_ALLOWED);
  585 static const std::string immAccessControlMode(OPENSAF_IMM_ACCESS_CONTROL_MODE);
  586 static const std::string immAuthorizedGroup(OPENSAF_IMM_AUTHORIZED_GROUP);
  587 static const std::string immScAbsenceAllowed(OPENSAF_IMM_SC_ABSENCE_ALLOWED);
  588 static const std::string immMaxClasses(OPENSAF_IMM_MAX_CLASSES);
  589 static const std::string immMaxAdmOwn(OPENSAF_IMM_MAX_ADMINOWNERS);
  590 static const std::string immMaxCcbs(OPENSAF_IMM_MAX_CCBS);
  591 static const std::string immMaxImp(OPENSAF_IMM_MAX_IMPLEMENTERS);
  592 static const std::string immMinApplierTimeout(OPENSAF_IMM_MIN_APPLIER_TIMEOUT);
  593 
  594 static const std::string immMngtClass("SaImmMngt");
  595 static const std::string immManagementDn(
  596     "safRdn=immManagement,safApp=safImmService");
  597 static const std::string saImmRepositoryInit("saImmRepositoryInit");
  598 static const std::string saImmOiTimeout("saImmOiTimeout");
  599 static const std::string saImmFileSystemStatus("saImmFileSystemStatus");
  600 static const std::string saImmSyncrTimeout("saImmSyncrTimeout");
  601 static SaImmRepositoryInitModeT immInitMode = SA_IMM_INIT_FROM_FILE;
  602 static bool sRegenerateDb = false;
  603 
  604 static SaUint32T sCcbIdLongDnGuard =
  605     0; /* Disallow long DN additions if longDnsAllowed is being changed in ccb*/
  606 static bool sIsLongDnLoaded =
  607     false; /* track long DNs before opensafImm=opensafImm,safApp=safImmService
  608               is created */
  609 static bool sAbortNonCriticalCcbs =
  610     false;                                /* Set to true at coord by the special imm admin-op to abort ccbs
  611                                              #1107 */
  612 static SaUint32T sTerminatedCcbcount = 0; /* Terminated ccbs count. calculated
  613                                              at cleanTheBasement  for every
  614                                              second*/
  615 // Show the status of underlying file system.
  616 static bool sFileSystemAvailable = true;
  617 
  618 struct AttrFlagIncludes {
  619   explicit AttrFlagIncludes(SaImmAttrFlagsT attrFlag) : mFlag(attrFlag) {}
  620 
  621   bool operator()(AttrMap::value_type& item) const {
  622     return (item.second->mFlags & mFlag) != 0;
  623   }
  624 
  625   SaImmAttrFlagsT mFlag;
  626 };
  627 
  628 struct IdIs {
  629   explicit IdIs(SaUint32T id) : mId(id) {}
  630 
  631   bool operator()(AdminOwnerInfo*& item) const { return item->mId == mId; }
  632 
  633   SaUint32T mId;
  634 };
  635 
  636 struct CcbIdIs {
  637   explicit CcbIdIs(SaUint32T id) : mId(id) {}
  638 
  639   bool operator()(CcbInfo*& item) const { return item->mId == mId; }
  640 
  641   SaUint32T mId;
  642 };
  643 
  644 void immModel_setScAbsenceAllowed(IMMND_CB* cb) {
  645   if (cb->mCanBeCoord == 4) {
  646     osafassert(cb->mScAbsenceAllowed > 0);
  647   } else {
  648     osafassert(cb->mScAbsenceAllowed == 0);
  649   }
  650   ImmModel::instance(&cb->immModel)->setScAbsenceAllowed(cb->mScAbsenceAllowed);
  651 }
  652 
  653 SaAisErrorT immModel_ccbResult(IMMND_CB* cb, SaUint32T ccbId) {
  654   return ImmModel::instance(&cb->immModel)->ccbResult(ccbId);
  655 }
  656 
  657 IMMSV_ATTR_NAME_LIST* immModel_ccbGrabErrStrings(IMMND_CB* cb,
  658                                                  SaUint32T ccbId) {
  659   return ImmModel::instance(&cb->immModel)->ccbGrabErrStrings(ccbId);
  660 }
  661 
  662 void immModel_abortSync(IMMND_CB* cb) {
  663   ImmModel::instance(&cb->immModel)->abortSync();
  664 }
  665 
  666 void immModel_isolateThisNode(IMMND_CB* cb) {
  667   ImmModel::instance(&cb->immModel)->isolateThisNode(cb->node_id, cb->mIsCoord);
  668 }
  669 
  670 void immModel_abortNonCriticalCcbs(IMMND_CB* cb) {
  671   SaUint32T arrSize;
  672   SaUint32T* implConnArr = NULL;
  673   SaUint32T* clientArr = NULL;
  674   SaUint32T clientArrSize = 0;
  675   SaClmNodeIdT pbeNodeId;
  676   SaUint32T nodeId;
  677   CcbVector::iterator i3 = sCcbVector.begin();
  678   for (; i3 != sCcbVector.end(); ++i3) {
  679     if ((*i3)->mState < IMM_CCB_CRITICAL) {
  680       osafassert(immModel_ccbAbort(cb, (*i3)->mId, &arrSize, &implConnArr,
  681                                    &clientArr, &clientArrSize, &nodeId,
  682                                    &pbeNodeId));
  683       osafassert(immModel_ccbFinalize(cb, (*i3)->mId) == SA_AIS_OK);
  684       if (arrSize) {
  685         free(implConnArr);
  686       }
  687       if (clientArrSize) {
  688         free(clientArr);
  689       }
  690     }
  691   }
  692 }
  693 
  694 void immModel_pbePrtoPurgeMutations(IMMND_CB* cb, SaUint32T nodeId,
  695                                     SaUint32T* reqArrSize,
  696                                     SaUint32T** reqConnArr) {
  697   ConnVector cv;
  698   ConnVector::iterator cvi;
  699   ImmModel::instance(&cb->immModel)->pbePrtoPurgeMutations(nodeId, cv);
  700   *reqArrSize = (SaUint32T)cv.size();
  701   if (*reqArrSize) {
  702     unsigned int ix = 0;
  703     *reqConnArr = (SaUint32T*)malloc((*reqArrSize) * sizeof(SaUint32T));
  704     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
  705       (*reqConnArr)[ix] = (*cvi);
  706     }
  707   }
  708 }
  709 
  710 SaAisErrorT immModel_adminOwnerCreate(IMMND_CB* cb,
  711                                       const ImmsvOmAdminOwnerInitialize* req,
  712                                       SaUint32T ownerId, SaUint32T conn,
  713                                       SaClmNodeIdT nodeId) {
  714   bool preLoad = (cb->preLoadPid > 0);
  715   ImmNodeState prevState = IMM_NODE_UNKNOWN;
  716   SaAisErrorT err = SA_AIS_OK;
  717   if (preLoad) {
  718     prevState = sImmNodeState;
  719     sImmNodeState = IMM_NODE_LOADING;
  720     TRACE("Preload admo create");
  721   }
  722 
  723   err = ImmModel::instance(&cb->immModel)
  724             ->adminOwnerCreate(req, ownerId, conn, nodeId);
  725 
  726   if (preLoad) {
  727     sImmNodeState = prevState;
  728     TRACE("Preload, returning model state to %u", prevState);
  729   }
  730 
  731   return err;
  732 }
  733 
  734 SaAisErrorT immModel_adminOwnerDelete(IMMND_CB* cb, SaUint32T ownerId,
  735                                       SaUint32T hard) {
  736   return ImmModel::instance(&cb->immModel)
  737       ->adminOwnerDelete(ownerId, hard, cb->m2Pbe);
  738 }
  739 
  740 void immModel_addDeadAdminOwnerDuringSync(SaUint32T ownerId) {
  741   osafassert(sImmNodeState == IMM_NODE_W_AVAILABLE); /* Sync client */
  742   osafassert(sOwnerVector.empty());
  743   /* Remember the dead admo during sync.
  744    * They will be cleaned up when finalizing sync. */
  745   TRACE("Adding admo id=%u to sAdmosDeadDuringSync", ownerId);
  746   sAdmosDeadDuringSync.push_back(ownerId);
  747 }
  748 
  749 SaAisErrorT immModel_ccbCreate(IMMND_CB* cb, SaUint32T adminOwnerwnerId,
  750                                SaUint32T ccbFlags, SaUint32T ccbId,
  751                                SaClmNodeIdT nodeId, SaUint32T conn) {
  752   return ImmModel::instance(&cb->immModel)
  753       ->ccbCreate(adminOwnerwnerId, ccbFlags, ccbId, nodeId, conn);
  754 }
  755 
  756 SaAisErrorT immModel_classCreate(IMMND_CB* cb,
  757                                  const struct ImmsvOmClassDescr* req,
  758                                  SaUint32T reqConn, unsigned int nodeId,
  759                                  SaUint32T* continuationId, SaUint32T* pbeConn,
  760                                  unsigned int* pbeNodeId) {
  761   return ImmModel::instance(&cb->immModel)
  762       ->classCreate(req, reqConn, nodeId, continuationId, pbeConn, pbeNodeId);
  763 }
  764 
  765 SaAisErrorT immModel_classDelete(IMMND_CB* cb,
  766                                  const struct ImmsvOmClassDescr* req,
  767                                  SaUint32T reqConn, unsigned int nodeId,
  768                                  SaUint32T* continuationId, SaUint32T* pbeConn,
  769                                  unsigned int* pbeNodeId) {
  770   return ImmModel::instance(&cb->immModel)
  771       ->classDelete(req, reqConn, nodeId, continuationId, pbeConn, pbeNodeId);
  772 }
  773 
  774 SaAisErrorT immModel_ccbObjectCreate(
  775     IMMND_CB* cb, struct ImmsvOmCcbObjectCreate* req, SaUint32T* implConn,
  776     SaClmNodeIdT* implNodeId, SaUint32T* continuationId, SaUint32T* pbeConn,
  777     SaClmNodeIdT* pbeNodeId, SaNameT* objName, bool* dnOrRdnIsLong,
  778     bool isObjectDnUsed) {
  779   std::string objectName;
  780 
  781   if (req->attrValues && (req->attrValues->n.attrName.size == 0 ||
  782                           req->attrValues->n.attrValueType == 0)) {
  783     LOG_NO(
  784         "ERR_INVALID_PARAM: Attribute name or attribute type is not properly set");
  785     return SA_AIS_ERR_INVALID_PARAM;
  786   }
  787 
  788   /* Find RDN and parent DN */
  789   if (isObjectDnUsed) {
  790     std::string parentName;
  791 
  792     if (req->parentOrObjectDn.size == 0) {
  793       LOG_NO("ERR_INVALID_PARAM: Object DN cannot be empty string");
  794       return SA_AIS_ERR_INVALID_PARAM;
  795     }
  796 
  797     uint32_t n;
  798     /* start from second character. The first character cannot be comma */
  799     for (n = 1; n < req->parentOrObjectDn.size; n++) {
  800       if (req->parentOrObjectDn.buf[n] == ',' &&
  801           req->parentOrObjectDn.buf[n - 1] != '\\') {
  802         break;
  803       }
  804     }
  805 
  806     if (n + 1 < req->parentOrObjectDn.size) {
  807       parentName.append(req->parentOrObjectDn.buf + n + 1,
  808                         strnlen(req->parentOrObjectDn.buf + n + 1,
  809                                 req->parentOrObjectDn.size - (n + 1)));
  810     }
  811 
  812     // Add RDN attribute to req->attrValues
  813     IMMSV_ATTR_VALUES_LIST* attr =
  814         (IMMSV_ATTR_VALUES_LIST*)calloc(1, sizeof(IMMSV_ATTR_VALUES_LIST));
  815     osafassert(attr);
  816     attr->n.attrName.buf = NULL;
  817     attr->n.attrName.size = 0;
  818     /* Temporary setting type to SA_IMM_ATTR_SASTRINGT, which will be later set
  819      * to the right type */
  820     attr->n.attrValueType = SA_IMM_ATTR_SASTRINGT;
  821     attr->n.attrValuesNumber = 1;
  822     attr->n.attrValue.val.x.buf = strndup(req->parentOrObjectDn.buf, n);
  823     attr->n.attrValue.val.x.size = strlen(attr->n.attrValue.val.x.buf) + 1;
  824     attr->next = req->attrValues;
  825     req->attrValues = attr;
  826 
  827     // Add parent to req
  828     req->parentOrObjectDn.size = parentName.size() + 1;
  829     memcpy(req->parentOrObjectDn.buf, parentName.c_str(),
  830            req->parentOrObjectDn.size);
  831   }
  832 
  833   SaAisErrorT err =
  834       ImmModel::instance(&cb->immModel)
  835           ->ccbObjectCreate(req, implConn, implNodeId, continuationId, pbeConn,
  836                             pbeNodeId, objectName, dnOrRdnIsLong,
  837                             isObjectDnUsed);
  838 
  839   if (err == SA_AIS_OK) {
  840     osaf_extended_name_alloc(objectName.c_str(), objName);
  841   }
  842 
  843   return err;
  844 }
  845 
  846 struct immsv_attr_values_list* immModel_specialApplierTrimCreate(
  847     IMMND_CB* cb, SaUint32T clientId, struct ImmsvOmCcbObjectCreate* req) {
  848   return ImmModel::instance(&cb->immModel)
  849       ->specialApplierTrimCreate(clientId, req);
  850 }
  851 
  852 void immModel_specialApplierSavePrtoCreateAttrs(
  853     IMMND_CB* cb, struct ImmsvOmCcbObjectCreate* req,
  854     SaUint32T continuationId) {
  855   return ImmModel::instance(&cb->immModel)
  856       ->specialApplierSavePrtoCreateAttrs(req, continuationId);
  857 }
  858 
  859 void immModel_specialApplierSaveRtUpdateAttrs(
  860     IMMND_CB* cb, struct ImmsvOmCcbObjectModify* req,
  861     SaUint32T continuationId) {
  862   return ImmModel::instance(&cb->immModel)
  863       ->specialApplierSaveRtUpdateAttrs(req, continuationId);
  864 }
  865 
  866 struct immsv_attr_mods_list* immModel_specialApplierTrimModify(
  867     IMMND_CB* cb, SaUint32T clientId, struct ImmsvOmCcbObjectModify* req) {
  868   return ImmModel::instance(&cb->immModel)
  869       ->specialApplierTrimModify(clientId, req);
  870 }
  871 
  872 bool immModel_isSpecialAndAddModify(IMMND_CB* cb, SaUint32T clientId,
  873                                     SaUint32T ccbId) {
  874   return ImmModel::instance(&cb->immModel)
  875       ->isSpecialAndAddModify(clientId, ccbId);
  876 }
  877 
  878 void immModel_genSpecialModify(IMMND_CB* cb,
  879                                struct ImmsvOmCcbObjectModify* req) {
  880   ImmModel::instance(&cb->immModel)->genSpecialModify(req);
  881 }
  882 
  883 struct immsv_attr_mods_list* immModel_canonicalizeAttrModification(
  884     IMMND_CB* cb, const struct ImmsvOmCcbObjectModify* req) {
  885   return ImmModel::instance(&cb->immModel)->canonicalizeAttrModification(req);
  886 }
  887 
  888 struct immsv_attr_mods_list* immModel_getAllWritableAttributes(
  889     IMMND_CB* cb, const ImmsvOmCcbObjectModify* req, bool* hasLongDn) {
  890   return ImmModel::instance(&cb->immModel)
  891       ->getAllWritableAttributes(req, hasLongDn);
  892 }
  893 
  894 SaUint32T immModel_getLocalAppliersForObj(IMMND_CB* cb, const SaNameT* objName,
  895                                           SaUint32T ccbId,
  896                                           SaUint32T** aplConnArr,
  897                                           bool externalRep) {
  898   ConnVector cv;
  899   ConnVector::iterator cvi;
  900 
  901   ImmModel::instance(&cb->immModel)
  902       ->getLocalAppliersForObj(objName, ccbId, cv, externalRep);
  903 
  904   SaUint32T arrSize = (SaUint32T)cv.size();
  905 
  906   if (arrSize) {
  907     unsigned int ix = 0;
  908     *aplConnArr = (SaUint32T*)malloc((arrSize) * sizeof(SaUint32T));
  909 
  910     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
  911       (*aplConnArr)[ix] = (*cvi);
  912     }
  913   }
  914 
  915   return arrSize;
  916 }
  917 
  918 SaUint32T immModel_getLocalAppliersForCcb(IMMND_CB* cb, SaUint32T ccbId,
  919                                           SaUint32T** aplConnArr,
  920                                           SaUint32T* applCtnPtr) {
  921   ConnVector cv;
  922   ConnVector::iterator cvi;
  923 
  924   ImmModel::instance(&cb->immModel)
  925       ->getLocalAppliersForCcb(ccbId, cv, applCtnPtr);
  926 
  927   SaUint32T arrSize = (SaUint32T)cv.size();
  928 
  929   if (arrSize) {
  930     unsigned int ix = 0;
  931     *aplConnArr = (SaUint32T*)malloc((arrSize) * sizeof(SaUint32T));
  932 
  933     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
  934       (*aplConnArr)[ix] = (*cvi);
  935     }
  936   }
  937 
  938   return arrSize;
  939 }
  940 
  941 SaUint32T immModel_getPbeApplierConn(IMMND_CB* cb) {
  942   return ImmModel::instance(&cb->immModel)->getPbeApplierConn();
  943 }
  944 
  945 SaAisErrorT immModel_ccbObjectModify(
  946     IMMND_CB* cb, const struct ImmsvOmCcbObjectModify* req, SaUint32T* implConn,
  947     SaClmNodeIdT* implNodeId, SaUint32T* continuationId, SaUint32T* pbeConn,
  948     SaClmNodeIdT* pbeNodeId, SaNameT* objName, bool* hasLongDns) {
  949   std::string objectName;
  950   bool pbeFile = (cb->mPbeFile != NULL);
  951   bool changeRim = false;
  952   bool changeSyncr = false;
  953   SaAisErrorT err =
  954       ImmModel::instance(&cb->immModel)
  955           ->ccbObjectModify(req, implConn, implNodeId, continuationId, pbeConn,
  956                             pbeNodeId, objectName, hasLongDns, pbeFile,
  957                             &changeRim, &changeSyncr);
  958 
  959   if (err == SA_AIS_OK) {
  960     osaf_extended_name_alloc(objectName.c_str(), objName);
  961   }
  962 
  963   if (err == SA_AIS_OK && changeRim) {
  964     cb->mPbeDisableCcbId = req->ccbId;
  965     TRACE("The mPbeDisableCcbId is set to ccbid:%u", cb->mPbeDisableCcbId);
  966   }
  967 
  968   if (err == SA_AIS_OK && changeSyncr) {
  969     cb->mSyncrTimeout = true;
  970     TRACE("Syncr Timeout is changed");
  971   }
  972 
  973   return err;
  974 }
  975 
  976 SaAisErrorT immModel_ccbObjectDelete(
  977     IMMND_CB* cb, const struct ImmsvOmCcbObjectDelete* req, SaUint32T reqConn,
  978     SaUint32T* arrSize, SaUint32T** implConnArr, SaUint32T** implIdArr,
  979     SaStringT** objNameArr, SaUint32T* pbeConn, SaClmNodeIdT* pbeNodeId,
  980     bool* augDelete, bool* hasLongDn)
  981 
  982 {
  983   ConnVector cv;
  984   IdVector iv;
  985   ObjectNameVector ov;
  986   ConnVector::iterator cvi;
  987   IdVector::iterator ivi;
  988   ObjectNameVector::iterator oni;
  989   unsigned int ix = 0;
  990 
  991   SaAisErrorT err = ImmModel::instance(&cb->immModel)
  992                         ->ccbObjectDelete(req, reqConn, ov, cv, iv, pbeConn,
  993                                           pbeNodeId, augDelete, hasLongDn);
  994   *arrSize = (SaUint32T)cv.size();
  995   osafassert(*arrSize == iv.size());
  996   osafassert(*arrSize == ov.size());
  997   if ((err == SA_AIS_OK) && (*arrSize)) {
  998     *implConnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
  999 
 1000     *implIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1001 
 1002     *objNameArr = (SaStringT*)malloc((*arrSize) * sizeof(SaStringT));
 1003 
 1004     for (cvi = cv.begin(), ivi = iv.begin(), oni = ov.begin(); cvi != cv.end();
 1005          ++cvi, ++ivi, ++oni, ++ix) {
 1006       std::string delObjName = (*oni);
 1007       (*implConnArr)[ix] = (*cvi);
 1008       (*implIdArr)[ix] = (*ivi);
 1009       (*objNameArr)[ix] = (SaStringT)malloc(delObjName.size() + 1);
 1010       strncpy((*objNameArr)[ix], delObjName.c_str(), delObjName.size() + 1);
 1011     }
 1012   }
 1013   osafassert(ix == (*arrSize));
 1014   return err;
 1015 }
 1016 
 1017 void immModel_getNonCriticalCcbs(IMMND_CB* cb, SaUint32T** ccbIdArr,
 1018                                  SaUint32T* ccbIdArrSize) {
 1019   IdVector ccbs;
 1020   IdVector::iterator ix2;
 1021 
 1022   ImmModel::instance(&cb->immModel)->getNonCriticalCcbs(ccbs);
 1023   *ccbIdArrSize = (SaUint32T)ccbs.size();
 1024   if (*ccbIdArrSize) {
 1025     unsigned int ix;
 1026     *ccbIdArr = (SaUint32T*)malloc((*ccbIdArrSize) * sizeof(SaUint32T));
 1027 
 1028     for (ix2 = ccbs.begin(), ix = 0; ix2 != ccbs.end(); ++ix2, ++ix) {
 1029       (*ccbIdArr)[ix] = (*ix2);
 1030     }
 1031     osafassert(ix == (*ccbIdArrSize));
 1032   }
 1033 }
 1034 
 1035 SaUint32T immModel_getIdForLargeAdmo(IMMND_CB* cb) {
 1036   return ImmModel::instance(&cb->immModel)->getIdForLargeAdmo();
 1037 }
 1038 
 1039 void immModel_getOldCriticalCcbs(IMMND_CB* cb, SaUint32T** ccbIdArr,
 1040                                  SaUint32T* ccbIdArrSize, SaUint32T* pbeConn,
 1041                                  unsigned int* pbeNodeId, SaUint32T* pbeId) {
 1042   IdVector ccbs;
 1043   IdVector::iterator ix2;
 1044 
 1045   if (ImmModel::instance(&cb->immModel)->getPbeOi(pbeConn, pbeNodeId, false)) {
 1046     ImmModel::instance(&cb->immModel)
 1047         ->getOldCriticalCcbs(ccbs, pbeConn, pbeNodeId, pbeId);
 1048     *ccbIdArrSize = (SaUint32T)ccbs.size();
 1049     if (*ccbIdArrSize) {
 1050       unsigned int ix;
 1051       *ccbIdArr = (SaUint32T*)malloc((*ccbIdArrSize) * sizeof(SaUint32T));
 1052 
 1053       for (ix2 = ccbs.begin(), ix = 0; ix2 != ccbs.end(); ++ix2, ++ix) {
 1054         (*ccbIdArr)[ix] = (*ix2);
 1055       }
 1056       osafassert(ix == (*ccbIdArrSize));
 1057     }
 1058   }
 1059 }
 1060 
 1061 void immmModel_getLocalImplementers(IMMND_CB* cb, SaUint32T* arrSize,
 1062                                     SaUint32T** implIdArr,
 1063                                     SaUint32T** implConnArr) {
 1064   ConnVector cv;
 1065   ConnVector::iterator cvi;
 1066   IdVector idv;
 1067   IdVector::iterator idv_it;
 1068   unsigned int ix = 0;
 1069 
 1070   ImmModel::instance(&cb->immModel)->getLocalImplementers(cv, idv);
 1071   if (cv.size()) {
 1072     *arrSize = cv.size();
 1073     *implIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1074     *implConnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1075     for (cvi = cv.begin(), idv_it = idv.begin(); cvi != cv.end();
 1076          ix++, cvi++, idv_it++) {
 1077       (*implIdArr)[ix] = (*idv_it);
 1078       (*implConnArr)[ix] = (*cvi);
 1079     }
 1080   }
 1081 }
 1082 unsigned int immModel_pbeOiExists(IMMND_CB* cb) {
 1083   SaUint32T pbeConn = 0;
 1084   unsigned int pbeNode = 0;
 1085   if (ImmModel::instance(&cb->immModel)->getPbeOi(&pbeConn, &pbeNode, false)) {
 1086     return pbeNode;
 1087   }
 1088 
 1089   return 0;
 1090 }
 1091 
 1092 unsigned int immModel_pbeBSlaveExists(IMMND_CB* cb) {
 1093   SaUint32T pbeBConn = 0;
 1094   unsigned int pbeBNode = 0;
 1095   if (ImmModel::instance(&cb->immModel)
 1096           ->getPbeBSlave(&pbeBConn, &pbeBNode, false)) {
 1097     return pbeBNode;
 1098   }
 1099 
 1100   return 0;
 1101 }
 1102 
 1103 bool immModel_protocol41Allowed(IMMND_CB* cb) {
 1104   return ImmModel::instance(&cb->immModel)->protocol41Allowed();
 1105 }
 1106 
 1107 bool immModel_protocol43Allowed(IMMND_CB* cb) {
 1108   return ImmModel::instance(&cb->immModel)->protocol43Allowed();
 1109 }
 1110 
 1111 bool immModel_oneSafe2PBEAllowed(IMMND_CB* cb) {
 1112   return ImmModel::instance(&cb->immModel)->oneSafe2PBEAllowed();
 1113 }
 1114 
 1115 bool immModel_protocol45Allowed(IMMND_CB* cb) {
 1116   return ImmModel::instance(&cb->immModel)->protocol45Allowed();
 1117 }
 1118 
 1119 bool immModel_protocol46Allowed(IMMND_CB* cb) {
 1120   return ImmModel::instance(&cb->immModel)->protocol46Allowed();
 1121 }
 1122 
 1123 bool immModel_protocol47Allowed(IMMND_CB* cb) {
 1124   return ImmModel::instance(&cb->immModel)->protocol47Allowed();
 1125 }
 1126 
 1127 bool immModel_protocol50Allowed(IMMND_CB* cb) {
 1128   return ImmModel::instance(&cb->immModel)->protocol50Allowed();
 1129 }
 1130 
 1131 bool immModel_protocol51Allowed(IMMND_CB* cb) {
 1132   return ImmModel::instance(&cb->immModel)->protocol51Allowed();
 1133 }
 1134 
 1135 bool immModel_protocol51710Allowed(IMMND_CB* cb) {
 1136   return ImmModel::instance(&cb->immModel)->protocol51710Allowed();
 1137 }
 1138 
 1139 bool immModel_protocol51906Allowed(IMMND_CB* cb) {
 1140   return ImmModel::instance(&cb->immModel)->protocol51906Allowed();
 1141 }
 1142 
 1143 OsafImmAccessControlModeT immModel_accessControlMode(IMMND_CB* cb) {
 1144   return ImmModel::instance(&cb->immModel)->accessControlMode();
 1145 }
 1146 
 1147 const char* immModel_authorizedGroup(IMMND_CB* cb) {
 1148   return ImmModel::instance(&cb->immModel)->authorizedGroup();
 1149 }
 1150 
 1151 bool immModel_purgeSyncRequest(IMMND_CB* cb, SaUint32T clientId) {
 1152   return ImmModel::instance(&cb->immModel)->purgeSyncRequest(clientId);
 1153 }
 1154 
 1155 SaUint32T immModel_cleanTheBasement(
 1156     IMMND_CB* cb, SaInvocationT** admReqArr, SaUint32T* admReqArrSize,
 1157     SaInvocationT** searchReqArr, SaUint32T* searchReqArrSize,
 1158     SaUint32T** ccbIdArr, SaUint32T* ccbIdArrSize, SaUint32T** pbePrtoReqArr,
 1159     SaUint32T* pbePrtoReqArrSize, IMMSV_OCTET_STRING **applierArr,
 1160     SaUint32T *applierArrSize, bool iAmCoordNow) {
 1161   InvocVector admReqs;
 1162   InvocVector searchReqs;
 1163   InvocVector::iterator ix1;
 1164   IdVector ccbs;
 1165   IdVector pbePrtoReqs;
 1166   ImplNameVector appliers;
 1167   IdVector::iterator ix2;
 1168   unsigned int ix;
 1169 
 1170   SaUint32T stuck = ImmModel::instance(&cb->immModel)
 1171                         ->cleanTheBasement(admReqs, searchReqs, ccbs,
 1172                                            pbePrtoReqs, appliers,
 1173                                            iAmCoordNow);
 1174 
 1175   *admReqArrSize = (SaUint32T)admReqs.size();
 1176   if (*admReqArrSize) {
 1177     *admReqArr =
 1178         (SaInvocationT*)malloc((*admReqArrSize) * sizeof(SaInvocationT));
 1179     for (ix1 = admReqs.begin(), ix = 0; ix1 != admReqs.end(); ++ix1, ++ix) {
 1180       (*admReqArr)[ix] = (*ix1);
 1181     }
 1182     osafassert(ix == (*admReqArrSize));
 1183   }
 1184 
 1185   *searchReqArrSize = (SaUint32T)searchReqs.size();
 1186   if (*searchReqArrSize) {
 1187     *searchReqArr =
 1188         (SaInvocationT*)malloc((*searchReqArrSize) * sizeof(SaInvocationT));
 1189     for (ix1 = searchReqs.begin(), ix = 0; ix1 != searchReqs.end();
 1190          ++ix1, ++ix) {
 1191       (*searchReqArr)[ix] = (*ix1);
 1192     }
 1193     osafassert(ix == (*searchReqArrSize));
 1194   }
 1195 
 1196   *ccbIdArrSize = (SaUint32T)ccbs.size();
 1197   if (*ccbIdArrSize) {
 1198     *ccbIdArr = (SaUint32T*)malloc((*ccbIdArrSize) * sizeof(SaUint32T));
 1199 
 1200     for (ix2 = ccbs.begin(), ix = 0; ix2 != ccbs.end(); ++ix2, ++ix) {
 1201       (*ccbIdArr)[ix] = (*ix2);
 1202     }
 1203     osafassert(ix == (*ccbIdArrSize));
 1204   }
 1205 
 1206   *pbePrtoReqArrSize = (SaUint32T)pbePrtoReqs.size();
 1207   if (*pbePrtoReqArrSize) {
 1208     *pbePrtoReqArr =
 1209         (SaUint32T*)malloc((*pbePrtoReqArrSize) * sizeof(SaUint32T));
 1210 
 1211     for (ix2 = pbePrtoReqs.begin(), ix = 0; ix2 != pbePrtoReqs.end();
 1212          ++ix2, ++ix) {
 1213       (*pbePrtoReqArr)[ix] = (*ix2);
 1214     }
 1215     osafassert(ix == (*pbePrtoReqArrSize));
 1216   }
 1217 
 1218   timespec now;
 1219   osaf_clock_gettime(CLOCK_MONOTONIC, &now);
 1220   timespec nextSearch;
 1221   timespec opSearchTime;
 1222   ImmSearchOp* op;
 1223   IMMND_OM_SEARCH_NODE* searchOp;
 1224   IMMND_OM_SEARCH_NODE** prevSearchOp;
 1225   IMMND_IMM_CLIENT_NODE* cl_node =
 1226       (IMMND_IMM_CLIENT_NODE*)ncs_patricia_tree_getnext(&cb->client_info_db,
 1227                                                         NULL);
 1228   int clearCounter = 0;
 1229   while (cl_node) {
 1230     if (!cl_node->mIsSync && cl_node->searchOpList &&
 1231         osaf_timer_is_expired_sec(&now, &cl_node->mLastSearch,
 1232                                   SEARCH_TIMEOUT_SEC)) {
 1233       nextSearch = now;
 1234       clearCounter = 0;
 1235       searchOp = cl_node->searchOpList;
 1236       prevSearchOp = &cl_node->searchOpList;
 1237       while (searchOp) {
 1238         osafassert(searchOp->searchOp);
 1239         op = (ImmSearchOp*)searchOp->searchOp;
 1240         opSearchTime = op->getLastSearchTime();
 1241         if (!op->isSync() && osaf_timer_is_expired_sec(&now, &opSearchTime,
 1242                                                        SEARCH_TIMEOUT_SEC)) {
 1243           TRACE_2(
 1244               "Clear search result. Timeout %dsec. Search id: %d, OM handle: %llx",
 1245               SEARCH_TIMEOUT_SEC, searchOp->searchId, cl_node->imm_app_hdl);
 1246           *prevSearchOp = searchOp->next;
 1247           immModel_deleteSearchOp(op);
 1248           free(searchOp);
 1249           searchOp = *prevSearchOp;
 1250           clearCounter++;
 1251         } else {
 1252           if (osaf_timespec_compare(&opSearchTime, &nextSearch) == -1) {
 1253             nextSearch = opSearchTime;
 1254           }
 1255           prevSearchOp = &searchOp->next;
 1256           searchOp = searchOp->next;
 1257         }
 1258       }
 1259 
 1260       cl_node->mLastSearch = nextSearch;
 1261 
 1262       if (clearCounter) {
 1263         LOG_NO(
 1264             "Clear %d search result(s) for OM handle %llx. Search timeout %dsec",
 1265             clearCounter, cl_node->imm_app_hdl, SEARCH_TIMEOUT_SEC);
 1266       }
 1267     }
 1268 
 1269     cl_node = (IMMND_IMM_CLIENT_NODE*)ncs_patricia_tree_getnext(
 1270         &cb->client_info_db, cl_node->patnode.key_info);
 1271   }
 1272 
 1273   if(appliers.size() > 0) {
 1274     *applierArrSize = appliers.size();
 1275     *applierArr = (IMMSV_OCTET_STRING *)malloc(
 1276             appliers.size() * sizeof(IMMSV_OCTET_STRING));
 1277     for(size_t i=0; i<appliers.size(); ++i) {
 1278       (*applierArr)[i].buf = strdup(appliers[i].c_str());
 1279       (*applierArr)[i].size = strlen((*applierArr)[i].buf);
 1280     }
 1281   }
 1282 
 1283   return stuck;
 1284 }
 1285 
 1286 SaAisErrorT immModel_ccbApply(IMMND_CB* cb, SaUint32T ccbId, SaUint32T reqConn,
 1287                               SaUint32T* arrSize, SaUint32T** implConnArr,
 1288                               SaUint32T** implIdArr, SaUint32T** ctnArr,
 1289                               bool validateOnly) {
 1290   ConnVector cv;
 1291   IdVector implsv;
 1292   IdVector ctnv;
 1293   ConnVector::iterator cvi;
 1294   IdVector::iterator ivi1;
 1295   IdVector::iterator ivi2;
 1296   unsigned int ix = 0;
 1297 
 1298   SaAisErrorT err =
 1299       ImmModel::instance(&cb->immModel)
 1300           ->ccbApply(ccbId, reqConn, cv, implsv, ctnv, validateOnly);
 1301 
 1302   *arrSize = (SaUint32T)cv.size();
 1303   if (*arrSize) {
 1304     *implConnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1305 
 1306     *implIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1307 
 1308     *ctnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1309 
 1310     for (cvi = cv.begin(), ivi1 = implsv.begin(), ivi2 = ctnv.begin();
 1311          cvi != cv.end(); ++cvi, ++ivi1, ++ivi2, ++ix) {
 1312       (*implConnArr)[ix] = (*cvi);
 1313       (*implIdArr)[ix] = (*ivi1);
 1314       (*ctnArr)[ix] = (*ivi2);
 1315     }
 1316   }
 1317   osafassert(ix == (*arrSize));
 1318   return err;
 1319 }
 1320 
 1321 bool immModel_ccbAbort(IMMND_CB* cb, SaUint32T ccbId, SaUint32T* arrSize,
 1322                        SaUint32T** implConnArr, SaUint32T** clientArr,
 1323                        SaUint32T* clArrSize, SaUint32T* nodeId,
 1324                        SaClmNodeIdT* pbeNodeId) {
 1325   ConnVector cv, cl;
 1326   ConnVector::iterator cvi, cli;
 1327   unsigned int ix = 0;
 1328 
 1329   bool aborted = ImmModel::instance(&cb->immModel)
 1330                      ->ccbAbort(ccbId, cv, cl, nodeId, pbeNodeId);
 1331 
 1332   if (aborted && (cb->mPbeDisableCcbId == ccbId)) {
 1333     TRACE("PbeDisableCcbId %u has been aborted", ccbId);
 1334     cb->mPbeDisableCcbId = 0;
 1335     cb->mPbeDisableCritical = false;
 1336   }
 1337 
 1338   *arrSize = (SaUint32T)cv.size();
 1339   if (*arrSize) {
 1340     *implConnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1341 
 1342     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
 1343       (*implConnArr)[ix] = (*cvi);
 1344     }
 1345   }
 1346   osafassert(ix == (*arrSize));
 1347 
 1348   ix = 0;
 1349   *clArrSize = (SaUint32T)cl.size();
 1350   if (*clArrSize) {
 1351     *clientArr = (SaUint32T*)malloc((*clArrSize) * sizeof(SaUint32T));
 1352     for (cli = cl.begin(); cli != cl.end(); ++cli, ++ix) {
 1353       (*clientArr)[ix] = (*cli);
 1354     }
 1355   }
 1356   osafassert(ix == (*clArrSize));
 1357   return aborted;
 1358 }
 1359 
 1360 void immModel_getCcbIdsForOrigCon(IMMND_CB* cb, SaUint32T deadCon,
 1361                                   SaUint32T* arrSize, SaUint32T** ccbIdArr) {
 1362   ConnVector cv;
 1363   ConnVector::iterator cvi;
 1364   unsigned int ix = 0;
 1365   ImmModel::instance(&cb->immModel)->getCcbIdsForOrigCon(deadCon, cv);
 1366   *arrSize = (SaUint32T)cv.size();
 1367   if (*arrSize) {
 1368     *ccbIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1369     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
 1370       (*ccbIdArr)[ix] = (*cvi);
 1371     }
 1372   }
 1373   osafassert(ix == (*arrSize));
 1374 }
 1375 
 1376 void immModel_resetDiscardNodes(IMMND_CB* cb) {
 1377   cb->mLostNodes = 0;
 1378   sDiscardNodeSet.clear();
 1379 }
 1380 
 1381 void immModel_eraseDiscardNode(IMMND_CB* cb, SaUint32T nodeId) {
 1382   cb->mLostNodes--;
 1383   if (nodeId) sDiscardNodeSet.erase(nodeId);
 1384 }
 1385 
 1386 void immModel_discardNode(IMMND_CB* cb, SaUint32T nodeId, SaUint32T* arrSize,
 1387                           SaUint32T** ccbIdArr, SaUint32T* globArrSize,
 1388                           SaUint32T** globccbIdArr) {
 1389   ConnVector cv, gv;
 1390   ConnVector::iterator cvi, gvi;
 1391   unsigned int ix = 0;
 1392   if (sDiscardNodeSet.find(nodeId) == sDiscardNodeSet.end()) {
 1393     sDiscardNodeSet.insert(nodeId);
 1394     cb->mLostNodes++;
 1395   }
 1396   ImmModel::instance(&cb->immModel)
 1397       ->discardNode(nodeId, cv, gv, cb->mIsCoord, false);
 1398   *arrSize = (SaUint32T)cv.size();
 1399   if (*arrSize) {
 1400     *ccbIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1401     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
 1402       (*ccbIdArr)[ix] = (*cvi);
 1403     }
 1404   }
 1405   osafassert(ix == (*arrSize));
 1406 
 1407   *globArrSize = (SaUint32T)gv.size();
 1408   ix = 0;
 1409   if (*globArrSize) {
 1410     *globccbIdArr = (SaUint32T*)malloc((*globArrSize) * sizeof(SaUint32T));
 1411     for (gvi = gv.begin(); gvi != gv.end(); ++gvi, ++ix) {
 1412       (*globccbIdArr)[ix] = (*gvi);
 1413     }
 1414   }
 1415   osafassert(ix == (*globArrSize));
 1416 }
 1417 
 1418 void immModel_getAdminOwnerIdsForCon(IMMND_CB* cb, SaUint32T deadCon,
 1419                                      SaUint32T* arrSize,
 1420                                      SaUint32T** admoIdArr) {
 1421   ConnVector cv;
 1422   ConnVector::iterator cvi;
 1423   unsigned int ix = 0;
 1424   ImmModel::instance(&cb->immModel)->getAdminOwnerIdsForCon(deadCon, cv);
 1425   *arrSize = (SaUint32T)cv.size();
 1426   if (*arrSize) {
 1427     *admoIdArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1428     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
 1429       (*admoIdArr)[ix] = (*cvi);
 1430     }
 1431   }
 1432   osafassert(ix == (*arrSize));
 1433 }
 1434 
 1435 SaAisErrorT immModel_adminOperationInvoke(
 1436     IMMND_CB* cb, const struct ImmsvOmAdminOperationInvoke* req,
 1437     SaUint32T reqConn, SaUint64T reply_dest, SaInvocationT inv,
 1438     SaUint32T* implConn, SaClmNodeIdT* implNodeId, bool pbeExpected,
 1439     bool* displayRes) {
 1440   bool wasAbortNonCritical = sAbortNonCriticalCcbs;
 1441   SaAisErrorT err = ImmModel::instance(&cb->immModel)
 1442                         ->adminOperationInvoke(
 1443                             req, reqConn, reply_dest, inv, implConn, implNodeId,
 1444                             pbeExpected, displayRes, cb->mIsCoord);
 1445 
 1446   if (sAbortNonCriticalCcbs && !wasAbortNonCritical) {
 1447     TRACE("cb->mForceClean set to true");
 1448     cb->mForceClean = true;
 1449   }
 1450   return err;
 1451 }
 1452 
 1453 SaUint32T /* Returns admo-id for object if object exists and active admo exists,
 1454              otherwise zero. */
 1455     immModel_getAdmoIdForObj(IMMND_CB* cb, const char* opensafImmObj) {
 1456   TRACE_ENTER();
 1457   SaUint32T admoId = 0;
 1458   std::string objectName(opensafImmObj);
 1459   std::string admOwner;
 1460 
 1461   AdminOwnerVector::iterator i = sOwnerVector.begin();
 1462   ObjectMap::iterator oi = sObjectMap.find(objectName);
 1463   if (oi == sObjectMap.end()) {
 1464     TRACE("immModel_getAdmoIdForObj: Could not find %s", opensafImmObj);
 1465     goto done;
 1466   }
 1467 
 1468   oi->second->getAdminOwnerName(&admOwner);
 1469   for (; i != sOwnerVector.end(); ++i) {
 1470     if (!(*i)->mDying && (*i)->mAdminOwnerName == admOwner) {
 1471       admoId = (*i)->mId;
 1472       break;
 1473     }
 1474   }
 1475 
 1476 done:
 1477   TRACE_LEAVE();
 1478   return admoId;
 1479 }
 1480 
 1481 SaUint32T immModel_findConnForImplementerOfObject(
 1482     IMMND_CB* cb, IMMSV_OCTET_STRING* objectName) {
 1483   size_t sz = strnlen((char*)objectName->buf, (size_t)objectName->size);
 1484 
 1485   std::string objectDn((const char*)objectName->buf, sz);
 1486 
 1487   return ImmModel::instance(&cb->immModel)
 1488       ->findConnForImplementerOfObject(objectDn);
 1489 }
 1490 
 1491 bool immModel_ccbWaitForCompletedAck(IMMND_CB* cb, SaUint32T ccbId,
 1492                                      SaAisErrorT* err, SaUint32T* pbeConn,
 1493                                      SaClmNodeIdT* pbeNodeId, SaUint32T* pbeId,
 1494                                      SaUint32T* pbeCtn) {
 1495   return ImmModel::instance(&cb->immModel)
 1496       ->ccbWaitForCompletedAck(ccbId, err, pbeConn, pbeNodeId, pbeId, pbeCtn,
 1497                                cb->mPbeDisableCritical);
 1498 }
 1499 
 1500 bool immModel_ccbWaitForDeleteImplAck(IMMND_CB* cb, SaUint32T ccbId,
 1501                                       SaAisErrorT* err, bool augDelete) {
 1502   return ImmModel::instance(&cb->immModel)
 1503       ->ccbWaitForDeleteImplAck(ccbId, err, augDelete);
 1504 }
 1505 
 1506 bool immModel_ccbCommit(IMMND_CB* cb, SaUint32T ccbId, SaUint32T* arrSize,
 1507                         SaUint32T** implConnArr) {
 1508   ConnVector cv;
 1509   ConnVector::iterator cvi;
 1510   unsigned int ix = 0;
 1511 
 1512   bool pbeModeChange = ImmModel::instance(&cb->immModel)->ccbCommit(ccbId, cv);
 1513 
 1514   *arrSize = (SaUint32T)cv.size();
 1515   if (*arrSize) {
 1516     *implConnArr = (SaUint32T*)malloc((*arrSize) * sizeof(SaUint32T));
 1517 
 1518     for (cvi = cv.begin(); cvi != cv.end(); ++cvi, ++ix) {
 1519       (*implConnArr)[ix] = (*cvi);
 1520     }
 1521   }
 1522 
 1523   osafassert(ix == (*arrSize));
 1524   return pbeModeChange;
 1525 }
 1526 
 1527 SaAisErrorT immModel_ccbFinalize(IMMND_CB* cb, SaUint32T ccbId) {
 1528   return ImmModel::instance(&cb->immModel)->ccbTerminate(ccbId);
 1529 }
 1530 
 1531 SaAisErrorT immModel_ccbAugmentInit(IMMND_CB* cb,
 1532                                     IMMSV_OI_CCB_UPCALL_RSP* ccbUpcallRsp,
 1533                                     SaUint32T originatingNode,
 1534                                     SaUint32T originatingConn,
 1535                                     SaUint32T* adminOwnerId) {
 1536   return ImmModel::instance(&cb->immModel)
 1537       ->ccbAugmentInit(ccbUpcallRsp, originatingNode, originatingConn,
 1538                        adminOwnerId);
 1539 }
 1540 
 1541 void immModel_ccbAugmentAdmo(IMMND_CB* cb, SaUint32T adminOwnerId,
 1542                              SaUint32T ccbId) {
 1543   ImmModel::instance(&cb->immModel)->ccbAugmentAdmo(adminOwnerId, ccbId);
 1544 }
 1545 
 1546 SaAisErrorT immModel_objectIsLockedByCcb(IMMND_CB* cb,
 1547                                          struct ImmsvOmSearchInit* req) {
 1548   return ImmModel::instance(&cb->immModel)->objectIsLockedByCcb(req);
 1549 }
 1550 
 1551 SaAisErrorT immModel_ccbReadLockObject(IMMND_CB* cb,
 1552                                        struct ImmsvOmSearchInit* req) {
 1553   return ImmModel::instance(&cb->immModel)->ccbReadLockObject(req);
 1554 }
 1555 
 1556 SaAisErrorT immModel_searchInitialize(IMMND_CB* cb,
 1557                                       struct ImmsvOmSearchInit* req,
 1558                                       void** searchOp, bool isSync,
 1559                                       bool isAccessor) {
 1560   SaAisErrorT err = SA_AIS_OK;
 1561   ImmSearchOp* op = new ImmSearchOp();
 1562   *searchOp = op;
 1563 
 1564   if (isSync) {
 1565     op->setIsSync();
 1566   }
 1567   if (isAccessor) {
 1568     op->setIsAccessor();
 1569   }
 1570 
 1571   if (isAccessor) {
 1572     TRACE("Allocating accessor searchOp:%p", op);
 1573   } else {
 1574     TRACE("Allocating iterator searchOp:%p", op);
 1575   }
 1576 
 1577   /* Reset search time */
 1578   op->updateSearchTime();
 1579 
 1580   if (isAccessor) {
 1581     err = ImmModel::instance(&cb->immModel)->accessorGet(req, *op);
 1582   } else {
 1583     err = ImmModel::instance(&cb->immModel)->searchInitialize(req, *op);
 1584   }
 1585 
 1586   return err;
 1587 }
 1588 
 1589 SaAisErrorT immModel_testTopResult(void* searchOp, SaUint32T* implNodeId,
 1590                                    bool* bRtAttrsToFetch) {
 1591   SaAisErrorT err;
 1592   ImplementerInfo* implInfo = NULL;
 1593   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1594 
 1595   err = op->testTopResult((void**)&implInfo, bRtAttrsToFetch);
 1596   *implNodeId = (implInfo) ? implInfo->mNodeId : 0;
 1597 
 1598   return err;
 1599 }
 1600 
 1601 SaAisErrorT immModel_nextResult(IMMND_CB* cb, void* searchOp,
 1602                                 IMMSV_OM_RSP_SEARCH_NEXT** rsp,
 1603                                 SaUint32T* implConn, SaUint32T* implNodeId,
 1604                                 struct ImmsvAttrNameList** rtAttrsToFetch,
 1605                                 MDS_DEST* implDest, bool retardSync,
 1606                                 SaUint32T* implTimeout) {
 1607   AttributeList* rtAttrs = NULL;
 1608   SaAisErrorT err = SA_AIS_OK;
 1609   osafassert(searchOp && rsp);
 1610   if (rtAttrsToFetch) {
 1611     osafassert(implConn && implNodeId && implDest);
 1612   }
 1613   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1614 
 1615   if (op->isSync()) {
 1616     /* Special handling for sync. Because immsv_sync (sync object send)
 1617        is asyncronous, it can not be throttled directly. Insead we throttle the
 1618        sync object send by retarding the iterator used in syncing.
 1619        In addition, the nextResult operation is handled differently for sync.
 1620     */
 1621     if (retardSync) {
 1622       TRACE_2(
 1623           "ERR_TRY_AGAIN: Too many pending incoming fevs "
 1624           "messages (> %u) rejecting sync iteration next request",
 1625           cb->mFevsMaxPending);
 1626       return SA_AIS_ERR_TRY_AGAIN;
 1627     }
 1628     err = ImmModel::instance(&cb->immModel)->nextSyncResult(rsp, *op);
 1629   } else {
 1630     ImplementerInfo* implInfo = NULL;
 1631     /* Reset search time */
 1632     op->updateSearchTime();
 1633 
 1634     err = op->nextResult(rsp, (void**)&implInfo,
 1635                          (rtAttrsToFetch) ? (&rtAttrs) : NULL);
 1636 
 1637     if (err == SA_AIS_OK) {
 1638       if (implInfo) {
 1639         if (implConn) {
 1640           *implConn = implInfo->mConn;
 1641         }
 1642         if (implNodeId) {
 1643           *implNodeId = implInfo->mNodeId;
 1644         }
 1645         if (implDest) {
 1646           *implDest = implInfo->mMds_dest;
 1647         }
 1648         if (implTimeout) {
 1649           *implTimeout = implInfo->mTimeout;
 1650         }
 1651       } else {
 1652         if (implConn) {
 1653           *implConn = 0;
 1654         }
 1655         if (implNodeId) {
 1656           *implNodeId = 0;
 1657         }
 1658         if (implDest) {
 1659           *implDest = 0;
 1660         }
 1661         if (implTimeout) {
 1662           *implTimeout = 0;
 1663         }
 1664       }
 1665       /* If it doesn't involve any OI, we can pop out the object.
 1666          There are 3 cases:
 1667          1. There are no pure rt attributes
 1668          2. There are pure rt attributes to fetch but OI detached
 1669          (*implNodeId==0) 3. nextResult() is called by
 1670          immnd_evt_proc_oi_att_pull_rpl() to get the updated values for pure rt
 1671          attributes. In this case, rtAttrsToFetch==NULL
 1672        */
 1673       if (!rtAttrsToFetch || /* Case 3 */
 1674           !(*implNodeId)) {  /* Case 1 & 2 */
 1675         op->popLastResult();
 1676       }
 1677     }
 1678   }
 1679 
 1680   if (err != SA_AIS_OK) {
 1681     return err;
 1682   }
 1683 
 1684   if (rtAttrs && (*implNodeId)) {
 1685     AttributeList::iterator ai;
 1686     for (ai = rtAttrs->begin(); ai != rtAttrs->end(); ++ai) {
 1687       ImmsvAttrNameList* p =
 1688           (ImmsvAttrNameList*)malloc(sizeof(ImmsvAttrNameList)); /*alloc-1*/
 1689       p->name.size = (SaUint32T)(*ai).name.length() + 1;
 1690       p->name.buf = (char*)malloc(p->name.size); /*alloc-2*/
 1691       strncpy(p->name.buf, (*ai).name.c_str(), p->name.size);
 1692 
 1693       p->next = *rtAttrsToFetch;
 1694       *rtAttrsToFetch = p;
 1695     }
 1696   }
 1697   return err;
 1698 }
 1699 
 1700 void immModel_deleteSearchOp(void* searchOp) {
 1701   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1702   if (op) {
 1703     if (op->isSync()) {
 1704       ObjectSet::iterator* osip = (ObjectSet::iterator*)op->syncOsi;
 1705       ImmsvAttrNameList* theAttList = (ImmsvAttrNameList*)op->attrNameList;
 1706       if (osip) {
 1707         delete osip;
 1708         op->syncOsi = NULL;
 1709         immsv_evt_free_attrNames(theAttList);
 1710         op->attrNameList = NULL;
 1711         op->classInfo = NULL;
 1712       }
 1713     }
 1714     if (op->isAccessor()) {
 1715       TRACE("Deleting accessor searchOp %p", op);
 1716     } else {
 1717       TRACE("Deleting iterator searchOp %p", op);
 1718     }
 1719     delete op;
 1720   }
 1721 }
 1722 
 1723 void immModel_fetchLastResult(void* searchOp, IMMSV_OM_RSP_SEARCH_NEXT** rsp) {
 1724   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1725   *rsp = op->fetchLastResult();
 1726 }
 1727 
 1728 void immModel_popLastResult(void* searchOp) {
 1729   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1730   op->popLastResult();
 1731 }
 1732 
 1733 void immModel_clearLastResult(void* searchOp) {
 1734   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1735   op->clearLastResult();
 1736 }
 1737 
 1738 bool immModel_isSearchOpAccessor(void* searchOp) {
 1739   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1740   return op->isAccessor();
 1741 }
 1742 
 1743 bool immModel_isSearchOpNonExtendedNameSet(void* searchOp) {
 1744   ImmSearchOp* op = (ImmSearchOp*)searchOp;
 1745   return op->isNonExtendedNameSet();
 1746 }
 1747 
 1748 void immModel_setAdmReqContinuation(IMMND_CB* cb, SaInvocationT invoc,
 1749                                     SaUint32T reqConn) {
 1750   ImmModel::instance(&cb->immModel)->setAdmReqContinuation(invoc, reqConn);
 1751 }
 1752 
 1753 void immModel_setSearchReqContinuation(IMMND_CB* cb, SaInvocationT invoc,
 1754                                        SaUint32T reqConn,
 1755                                        SaUint32T implTimeout) {
 1756   ImmModel::instance(&cb->immModel)
 1757       ->setSearchReqContinuation(invoc, reqConn, implTimeout);
 1758 }
 1759 
 1760 void immModel_setSearchImplContinuation(IMMND_CB* cb, SaUint32T searchId,
 1761                                         SaUint32T reqNodeId,
 1762                                         MDS_DEST reply_dest) {
 1763   SaInvocationT tmp_hdl = m_IMMSV_PACK_HANDLE(searchId, reqNodeId);
 1764   ImmModel::instance(&cb->immModel)
 1765       ->setSearchImplContinuation(tmp_hdl, (SaUint64T)reply_dest);
 1766 }
 1767 
 1768 SaAisErrorT immModel_implementerSet(IMMND_CB* cb,
 1769                                     const IMMSV_OCTET_STRING* implName,
 1770                                     SaUint32T implConn, SaUint32T implNodeId,
 1771                                     SaUint32T implId, MDS_DEST mds_dest,
 1772                                     SaUint32T implTimeout,
 1773                                     bool* discardImplementer) {
 1774   return ImmModel::instance(&cb->immModel)
 1775       ->implementerSet(implName, implConn, implNodeId, implId,
 1776                        (SaUint64T)mds_dest, implTimeout, discardImplementer);
 1777 }
 1778 
 1779 SaAisErrorT immModel_implIsFree(IMMND_CB* cb, const IMMSV_OI_IMPLSET_REQ* req,
 1780                                 SaUint32T* impl_id) {
 1781   *impl_id = 0;
 1782   SaImmOiImplementerNameT impName = req->impl_name.buf;
 1783   std::string implName(impName);
 1784   if (implName.empty()) {
 1785     LOG_NO("ERR_INVALID_PARAM: Empty implementer name");
 1786     return SA_AIS_ERR_INVALID_PARAM;
 1787   }
 1788 
 1789   ImplementerInfo* impl =
 1790       ImmModel::instance(&cb->immModel)->findImplementer(implName);
 1791 
 1792   if (!impl) {
 1793     return SA_AIS_OK;
 1794   }
 1795 
 1796   if (impl->mId == 0) {
 1797     return SA_AIS_OK;
 1798   }
 1799   if (impl->mDying) {
 1800     return SA_AIS_ERR_TRY_AGAIN;
 1801   }
 1802 
 1803   /* Check for redundant request that comes from previously timed out client */
 1804   if (impl->mConn == m_IMMSV_UNPACK_HANDLE_HIGH(req->client_hdl) &&
 1805       impl->mNodeId == m_IMMSV_UNPACK_HANDLE_LOW(req->client_hdl)) {
 1806     *impl_id = impl->mId;
 1807   }
 1808 
 1809   return SA_AIS_ERR_EXIST;
 1810 }
 1811 
 1812 SaUint32T immModel_getImplementerId(IMMND_CB* cb, SaUint32T deadConn) {
 1813   return ImmModel::instance(&cb->immModel)->getImplementerId(deadConn);
 1814 }
 1815 
 1816 void immModel_discardImplementer(IMMND_CB* cb, SaUint32T implId,
 1817                                  bool reallyDiscard, SaUint32T* globArrSize,
 1818                                  SaUint32T** globccbIdArr) {
 1819   ConnVector gv;
 1820   ConnVector::iterator gvi;
 1821   ImmModel::instance(&cb->immModel)
 1822       ->discardImplementer(implId, reallyDiscard, gv, cb->mIsCoord);
 1823 
 1824   if (globArrSize && globccbIdArr) {
 1825     *globArrSize = (SaUint32T)gv.size();
 1826     unsigned int ix = 0;
 1827     if (*globArrSize) {
 1828       *globccbIdArr = (SaUint32T*)malloc((*globArrSize) * sizeof(SaUint32T));
 1829       for (gvi = gv.begin(); gvi != gv.end(); ++gvi, ++ix) {
 1830         (*globccbIdArr)[ix] = (*gvi);
 1831       }
 1832     }
 1833     osafassert(ix == (*globArrSize));
 1834   }
 1835 }
 1836 
 1837 SaAisErrorT immModel_implementerClear(IMMND_CB* cb,
 1838                                       const struct ImmsvOiImplSetReq* req,
 1839                                       SaUint32T implConn, SaUint32T implNodeId,
 1840                                       SaUint32T* globArrSize,
 1841                                       SaUint32T** globccbIdArr) {
 1842   SaAisErrorT err;
 1843   ConnVector gv;
 1844   ConnVector::iterator gvi;
 1845   err = ImmModel::instance(&cb->immModel)
 1846             ->implementerClear(req, implConn, implNodeId, gv, cb->mIsCoord);
 1847 
 1848   if (globArrSize && globccbIdArr) {
 1849     *globArrSize = (SaUint32T)gv.size();
 1850     SaUint32T ix = 0;
 1851     if (*globArrSize) {
 1852       *globccbIdArr = (SaUint32T*)malloc((*globArrSize) * sizeof(SaUint32T));
 1853       for (gvi = gv.begin(); gvi != gv.end(); ++gvi, ++ix) {
 1854         (*globccbIdArr)[ix] = (*gvi);
 1855       }
 1856     }
 1857     osafassert(ix == (*globArrSize));
 1858   }
 1859 
 1860   return err;
 1861 }
 1862 
 1863 SaAisErrorT immModel_classImplementerSet(IMMND_CB* cb,
 1864                                          const struct ImmsvOiImplSetReq* req,
 1865                                          SaUint32T implConn,
 1866                                          SaUint32T implNodeId,
 1867                                          SaUint32T* ccbId) {
 1868   return ImmModel::instance(&cb->immModel)
 1869       ->classImplementerSet(req, implConn, implNodeId, ccbId);
 1870 }
 1871 
 1872 SaAisErrorT immModel_classImplementerRelease(
 1873     IMMND_CB* cb, const struct ImmsvOiImplSetReq* req, SaUint32T implConn,
 1874     SaUint32T implNodeId) {
 1875   return ImmModel::instance(&cb->immModel)
 1876       ->classImplementerRelease(req, implConn, implNodeId);
 1877 }
 1878 
 1879 SaAisErrorT immModel_objectImplementerSet(IMMND_CB* cb,
 1880                                           const struct ImmsvOiImplSetReq* req,
 1881                                           SaUint32T implConn,
 1882                                           SaUint32T implNodeId,
 1883                                           SaUint32T* ccbId) {
 1884   return ImmModel::instance(&cb->immModel)
 1885       ->objectImplementerSet(req, implConn, implNodeId, ccbId);
 1886 }
 1887 
 1888 SaAisErrorT immModel_objectImplementerRelease(
 1889     IMMND_CB* cb, const struct ImmsvOiImplSetReq* req, SaUint32T implConn,
 1890     SaUint32T implNodeId) {
 1891   return ImmModel::instance(&cb->immModel)
 1892       ->objectImplementerRelease(req, implConn, implNodeId);
 1893 }
 1894 
 1895 void immModel_ccbCompletedContinuation(IMMND_CB* cb,
 1896                                        struct immsv_oi_ccb_upcall_rsp* rsp,
 1897                                        SaUint32T* reqConn) {
 1898   ImmModel::instance(&cb->immModel)->ccbCompletedContinuation(rsp, reqConn);
 1899 }
 1900 
 1901 void immModel_ccbObjDelContinuation(IMMND_CB* cb,
 1902                                     struct immsv_oi_ccb_upcall_rsp* rsp,
 1903                                     SaUint32T* reqConn, bool* augDelete) {
 1904   ImmModel::instance(&cb->immModel)
 1905       ->ccbObjDelContinuation(rsp, reqConn, augDelete);
 1906 }
 1907 
 1908 void immModel_ccbObjCreateContinuation(IMMND_CB* cb, SaUint32T ccbId,
 1909                                        SaUint32T invocation, SaAisErrorT error,
 1910                                        SaUint32T* reqConn) {
 1911   ImmModel::instance(&cb->immModel)
 1912       ->ccbObjCreateContinuation(ccbId, invocation, error, reqConn);
 1913 }
 1914 
 1915 void immModel_pbePrtObjCreateContinuation(IMMND_CB* cb, SaUint32T invocation,
 1916                                           SaAisErrorT err, SaClmNodeIdT nodeId,
 1917                                           SaUint32T* reqConn,
 1918                                           SaUint32T* spApplConn,
 1919                                           struct ImmsvOmCcbObjectCreate* req) {
 1920   ImmModel::instance(&cb->immModel)
 1921       ->pbePrtObjCreateContinuation(invocation, err, nodeId, reqConn,
 1922                                     spApplConn, req);
 1923 }
 1924 
 1925 void immModel_pbeClassCreateContinuation(IMMND_CB* cb, SaUint32T invocation,
 1926                                          SaClmNodeIdT nodeId,
 1927                                          SaUint32T* reqConn) {
 1928   ImmModel::instance(&cb->immModel)
 1929       ->pbeClassCreateContinuation(invocation, nodeId, reqConn);
 1930 }
 1931 
 1932 void immModel_pbeClassDeleteContinuation(IMMND_CB* cb, SaUint32T invocation,
 1933                                          SaClmNodeIdT nodeId,
 1934                                          SaUint32T* reqConn) {
 1935   ImmModel::instance(&cb->immModel)
 1936       ->pbeClassDeleteContinuation(invocation, nodeId, reqConn);
 1937 }
 1938 
 1939 void immModel_pbeUpdateEpochContinuation(IMMND_CB* cb, SaUint32T invocation,
 1940                                          SaClmNodeIdT nodeId) {
 1941   ImmModel::instance(&cb->immModel)
 1942       ->pbeUpdateEpochContinuation(invocation, nodeId);
 1943 }
 1944 
 1945 int immModel_pbePrtObjDeletesContinuation(
 1946     IMMND_CB* cb, SaUint32T invocation, SaAisErrorT err, SaClmNodeIdT nodeId,
 1947     SaUint32T* reqConn, SaStringT** objNameArr, SaUint32T* arrSizePtr,
 1948     SaUint32T* spApplConn, SaUint32T* pbe2BConn) {
 1949   ObjectNameVector ov;
 1950   ObjectNameVector::iterator oni;
 1951   int numOps = 0;
 1952   osafassert(arrSizePtr);
 1953 
 1954   numOps = ImmModel::instance(&cb->immModel)
 1955                ->pbePrtObjDeletesContinuation(invocation, err, nodeId, reqConn,
 1956                                               ov, spApplConn, pbe2BConn);
 1957 
 1958   (*arrSizePtr) = (SaUint32T)ov.size();
 1959   if (*arrSizePtr) {
 1960     unsigned int ix = 0;
 1961     *objNameArr = (SaStringT*)malloc((*arrSizePtr) * sizeof(SaStringT));
 1962 
 1963     for (oni = ov.begin(); oni != ov.end(); ++oni, ++ix) {
 1964       std::string delObjName = (*oni);
 1965       (*objNameArr)[ix] = (SaStringT)strdup(delObjName.c_str());
 1966     }
 1967     osafassert(ix == (*arrSizePtr));
 1968   }
 1969   return numOps;
 1970 }
 1971 
 1972 void immModel_pbePrtAttrUpdateContinuation(IMMND_CB* cb, SaUint32T invocation,
 1973                                            SaAisErrorT err, SaClmNodeIdT nodeId,
 1974                                            SaUint32T* reqConn,
 1975                                            SaUint32T* spApplConn,
 1976                                            struct ImmsvOmCcbObjectModify* req) {
 1977   ImmModel::instance(&cb->immModel)
 1978       ->pbePrtAttrUpdateContinuation(invocation, err, nodeId, reqConn,
 1979                                      spApplConn, req);
 1980 }
 1981 
 1982 void immModel_ccbObjModifyContinuation(IMMND_CB* cb, SaUint32T ccbId,
 1983                                        SaUint32T invocation, SaAisErrorT error,
 1984                                        SaUint32T* reqConn) {
 1985   ImmModel::instance(&cb->immModel)
 1986       ->ccbObjModifyContinuation(ccbId, invocation, error, reqConn);
 1987 }
 1988 
 1989 SaAisErrorT immModel_classDescriptionGet(IMMND_CB* cb,
 1990                                          const IMMSV_OCTET_STRING* clName,
 1991                                          struct ImmsvOmClassDescr* res) {
 1992   return ImmModel::instance(&cb->immModel)->classDescriptionGet(clName, res);
 1993 }
 1994 
 1995 void immModel_fetchAdmOpContinuations(IMMND_CB* cb, SaInvocationT inv,
 1996                                       bool local, SaUint32T* implConn,
 1997                                       SaUint32T* reqConn,
 1998                                       SaUint64T* reply_dest) {
 1999   if (local) {
 2000     ImmModel::instance(&cb->immModel)
 2001         ->fetchAdmImplContinuation(inv, implConn, reply_dest);
 2002   }
 2003 
 2004   ImmModel::instance(&cb->immModel)->fetchAdmReqContinuation(inv, reqConn);
 2005 }
 2006 
 2007 void immModel_fetchSearchReqContinuation(IMMND_CB* cb, SaInvocationT inv,
 2008                                          SaUint32T* reqConn) {
 2009   ImmModel::instance(&cb->immModel)->fetchSearchReqContinuation(inv, reqConn);
 2010 }
 2011 
 2012 void immModel_fetchSearchImplContinuation(IMMND_CB* cb, SaUint32T searchId,
 2013                                           SaUint32T reqNodeId,
 2014                                           MDS_DEST* reply_dest) {
 2015   SaInvocationT tmp_hdl = m_IMMSV_PACK_HANDLE(searchId, reqNodeId);
 2016   ImmModel::instance(&cb->immModel)
 2017       ->fetchSearchImplContinuation(tmp_hdl, (SaUint64T*)reply_dest);
 2018 }
 2019 
 2020 void immModel_prepareForLoading(IMMND_CB* cb) {
 2021   ImmModel::instance(&cb->immModel)->prepareForLoading();
 2022 }
 2023 
 2024 bool immModel_readyForLoading(IMMND_CB* cb) {
 2025   return ImmModel::instance(&cb->immModel)->readyForLoading();
 2026 }
 2027 
 2028 SaInt32T immModel_getLoader(IMMND_CB* cb) {
 2029   return ImmModel::instance(&cb->immModel)->getLoader();
 2030 }
 2031 
 2032 void immModel_setLoader(IMMND_CB* cb, SaInt32T loaderPid) {
 2033   ImmModel::instance(&cb->immModel)->setLoader(loaderPid);
 2034 }
 2035 
 2036 void immModel_setRegenerateDbFlag(IMMND_CB* cb, bool value) {
 2037   ImmModel::instance(&cb->immModel)->setRegenerateDbFlag(value);
 2038 }
 2039 
 2040 bool immModel_getRegenerateDbFlag(IMMND_CB* cb) {
 2041   return ImmModel::instance(&cb->immModel)->getRegenerateDbFlag();
 2042 }
 2043 
 2044 void immModel_recognizedIsolated(IMMND_CB* cb) {
 2045   ImmModel::instance(&cb->immModel)->recognizedIsolated();
 2046 }
 2047 
 2048 bool immModel_syncComplete(IMMND_CB* cb) {
 2049   return ImmModel::instance(&cb->immModel)->syncComplete(false);
 2050 }
 2051 
 2052 bool immModel_ccbsTerminated(IMMND_CB* cb, bool allowEmpty) {
 2053   return ImmModel::instance(&cb->immModel)->ccbsTerminated(allowEmpty);
 2054 }
 2055 
 2056 bool immModel_immNotWritable(IMMND_CB* cb) {
 2057   if (cb->preLoadPid > 0) {
 2058     TRACE("immModel_immNotWritable: WRITABLE in preload");
 2059     return false;
 2060   }
 2061   return ImmModel::instance(&cb->immModel)->immNotWritable();
 2062 }
 2063 
 2064 bool immModel_pbeNotWritable(IMMND_CB* cb) {
 2065   // Assumption: this call arrives only from ccb related code in immnd_evt.c
 2066   // Not from PRTO related code.
 2067   // Hence the argument 'isPrtoClient' is set to false here---vvv
 2068   return ImmModel::instance(&cb->immModel)->immNotPbeWritable(false);
 2069 }
 2070 
 2071 bool immModel_pbeIsInSync(IMMND_CB* cb, bool checkCriticalCcbs) {
 2072   return ImmModel::instance(&cb->immModel)->pbeIsInSync(checkCriticalCcbs);
 2073 }
 2074 
 2075 SaImmRepositoryInitModeT immModel_getRepositoryInitMode(IMMND_CB* cb) {
 2076   return (SaImmRepositoryInitModeT)ImmModel::instance(&cb->immModel)
 2077       ->getRepositoryInitMode();
 2078 }
 2079 
 2080 SaTimeT immModel_getSyncrTimeout(IMMND_CB* cb) {
 2081   return ImmModel::instance(&cb->immModel)->getSyncrTimeout();
 2082 }
 2083 
 2084 unsigned int immModel_getMaxSyncBatchSize(IMMND_CB* cb) {
 2085   return ImmModel::instance(&cb->immModel)->getMaxSyncBatchSize();
 2086 }
 2087 
 2088 void immModel_prepareForSync(IMMND_CB* cb, bool isJoining) {
 2089   ImmModel::instance(&cb->immModel)->prepareForSync(isJoining);
 2090 }
 2091 
 2092 void immModel_discardContinuations(IMMND_CB* cb, SaUint32T deadConn) {
 2093   ImmModel::instance(&cb->immModel)->discardContinuations(deadConn);
 2094 }
 2095 
 2096 SaAisErrorT immModel_objectSync(IMMND_CB* cb,
 2097                                 const struct ImmsvOmObjectSync* req) {
 2098   return ImmModel::instance(&cb->immModel)->objectSync(req);
 2099 }
 2100 
 2101 SaAisErrorT immModel_finalizeSync(IMMND_CB* cb, struct ImmsvOmFinalizeSync* req,
 2102                                   bool isCoord, bool isSyncClient) {
 2103   return ImmModel::instance(&cb->immModel)
 2104       ->finalizeSync(req, isCoord, isSyncClient, &cb->mLatestCcbId);
 2105 }
 2106 
 2107 SaUint32T immModel_adjustEpoch(IMMND_CB* cb, SaUint32T suggestedEpoch,
 2108                                SaUint32T* continuationId, SaUint32T* pbeConn,
 2109                                SaClmNodeIdT* pbeNodeId, bool increment) {
 2110   return ImmModel::instance(&cb->immModel)
 2111       ->adjustEpoch(suggestedEpoch, continuationId, pbeConn, pbeNodeId,
 2112                     increment);
 2113 }
 2114 
 2115 SaUint32T immModel_adminOwnerChange(IMMND_CB* cb,
 2116                                     const struct immsv_a2nd_admown_set* req,
 2117                                     bool isRelease) {
 2118   return ImmModel::instance(&cb->immModel)->adminOwnerChange(req, isRelease);
 2119 }
 2120 
 2121 SaAisErrorT immModel_rtObjectCreate(IMMND_CB* cb,
 2122                                     struct ImmsvOmCcbObjectCreate* req,
 2123                                     SaUint32T implConn, SaClmNodeIdT implNodeId,
 2124                                     SaUint32T* continuationId,
 2125                                     SaUint32T* pbeConn, SaClmNodeIdT* pbeNodeId,
 2126                                     SaUint32T* spApplConn, SaUint32T* pbe2BConn,
 2127                                     bool isObjectDnUsed)
 2128 
 2129 {
 2130   if (req->attrValues && (req->attrValues->n.attrName.size == 0 ||
 2131                           req->attrValues->n.attrValueType == 0)) {
 2132     LOG_NO(
 2133         "ERR_INVALID_PARAM: Attribute name or attribute type is not properly set");
 2134     return SA_AIS_ERR_INVALID_PARAM;
 2135   }
 2136 
 2137   /* Find RDN and parent DN */
 2138   if (isObjectDnUsed) {
 2139     std::string parentName;
 2140 
 2141     if (req->parentOrObjectDn.size == 0) {
 2142       LOG_NO("ERR_INVALID_PARAM: Object DN cannot be empty string");
 2143       return SA_AIS_ERR_INVALID_PARAM;
 2144     }
 2145 
 2146     uint32_t n;
 2147     /* start from second character. The first character cannot be comma */
 2148     for (n = 1; n < req->parentOrObjectDn.size; n++) {
 2149       if (req->parentOrObjectDn.buf[n] == ',' &&
 2150           req->parentOrObjectDn.buf[n - 1] != '\\') {
 2151         break;
 2152       }
 2153     }
 2154 
 2155     if (n + 1 < req->parentOrObjectDn.size) {
 2156       parentName.append(req->parentOrObjectDn.buf + n + 1,
 2157                         strnlen(req->parentOrObjectDn.buf + n + 1,
 2158                                 req->parentOrObjectDn.size - (n + 1)));
 2159     }
 2160 
 2161     // Add RDN attribute to req->attrValues
 2162     IMMSV_ATTR_VALUES_LIST* attr =
 2163         (IMMSV_ATTR_VALUES_LIST*)calloc(1, sizeof(IMMSV_ATTR_VALUES_LIST));
 2164     osafassert(attr);
 2165     attr->n.attrName.buf = NULL;
 2166     attr->n.attrName.size = 0;
 2167     /* Temporary setting type to SA_IMM_ATTR_SASTRINGT, which will be later set
 2168      * to the right type */
 2169     attr->n.attrValueType = SA_IMM_ATTR_SASTRINGT;
 2170     attr->n.attrValuesNumber = 1;
 2171     attr->n.attrValue.val.x.buf = strndup(req->parentOrObjectDn.buf, n);
 2172     attr->n.attrValue.val.x.size = strlen(attr->n.attrValue.val.x.buf) + 1;
 2173     attr->next = req->attrValues;
 2174     req->attrValues = attr;
 2175 
 2176     // Add parent to req
 2177     req->parentOrObjectDn.size = parentName.size() + 1;
 2178     memcpy(req->parentOrObjectDn.buf, parentName.c_str(),
 2179            req->parentOrObjectDn.size);
 2180   }
 2181 
 2182   return ImmModel::instance(&cb->immModel)
 2183       ->rtObjectCreate(req, implConn, (unsigned int)implNodeId, continuationId,
 2184                        pbeConn, pbeNodeId, spApplConn, pbe2BConn,
 2185                        isObjectDnUsed);
 2186 }
 2187 
 2188 SaAisErrorT immModel_rtObjectDelete(
 2189     IMMND_CB* cb, const struct ImmsvOmCcbObjectDelete* req, SaUint32T implConn,
 2190     SaClmNodeIdT implNodeId, SaUint32T* continuationId, SaUint32T* pbeConn,
 2191     SaClmNodeIdT* pbeNodeId, SaStringT** objNameArr, SaUint32T* arrSizePtr,
 2192     SaUint32T* spApplConn, SaUint32T* pbe2BConn) {
 2193   ObjectNameVector ov;
 2194   ObjectNameVector::iterator oni;
 2195   unsigned int ix = 0;
 2196   osafassert(arrSizePtr);
 2197 
 2198   SaAisErrorT err =
 2199       ImmModel::instance(&cb->immModel)
 2200           ->rtObjectDelete(req, implConn, (unsigned int)implNodeId,
 2201                            continuationId, pbeConn, pbeNodeId, ov, spApplConn,
 2202                            pbe2BConn);
 2203 
 2204   (*arrSizePtr) = (SaUint32T)ov.size();
 2205   if ((err == SA_AIS_OK) && (*arrSizePtr)) {
 2206     *objNameArr = (SaStringT*)malloc((*arrSizePtr) * sizeof(SaStringT));
 2207 
 2208     for (oni = ov.begin(); oni != ov.end(); ++oni, ++ix) {
 2209       std::string delObjName = (*oni);
 2210       (*objNameArr)[ix] = (SaStringT)malloc(delObjName.size() + 1);
 2211       strncpy((*objNameArr)[ix], delObjName.c_str(), delObjName.size() + 1);
 2212     }
 2213   }
 2214   osafassert(ix == (*arrSizePtr));
 2215   return err;
 2216 }
 2217 
 2218 SaAisErrorT immModel_rtObjectUpdate(
 2219     IMMND_CB* cb, const struct ImmsvOmCcbObjectModify* req, SaUint32T implConn,
 2220     SaClmNodeIdT implNodeId, unsigned int* isPureLocal,
 2221     SaUint32T* continuationId, SaUint32T* pbeConn, SaClmNodeIdT* pbeNodeId,
 2222     SaUint32T* spApplConn, SaUint32T* pbe2BConn) {
 2223   SaAisErrorT err = SA_AIS_OK;
 2224   TRACE_ENTER();
 2225   bool isPl = *isPureLocal;
 2226   TRACE_5("on enter isPl:%u", isPl);
 2227   err = ImmModel::instance(&cb->immModel)
 2228             ->rtObjectUpdate(req, implConn, (unsigned int)implNodeId, &isPl,
 2229                              continuationId, pbeConn, pbeNodeId, spApplConn,
 2230                              pbe2BConn);
 2231   TRACE_5("on leave isPl:%u", isPl);
 2232   *isPureLocal = isPl;
 2233   TRACE_LEAVE();
 2234   return err;
 2235 }
 2236 
 2237 void immModel_deferRtUpdate(IMMND_CB* cb, struct ImmsvOmCcbObjectModify* req,
 2238                             SaUint64T msgNo) {
 2239   ImmModel::instance(&cb->immModel)->deferRtUpdate(req, msgNo);
 2240 }
 2241 
 2242 bool immModel_fetchRtUpdate(IMMND_CB* cb, struct ImmsvOmObjectSync* syncReq,
 2243                             struct ImmsvOmCcbObjectModify* rtModReq,
 2244                             SaUint64T syncFevsBase) {
 2245   return ImmModel::instance(&cb->immModel)
 2246       ->fetchRtUpdate(syncReq, rtModReq, syncFevsBase);
 2247 }
 2248 
 2249 SaAisErrorT immModel_resourceDisplay(
 2250     IMMND_CB* cb, const struct ImmsvAdminOperationParam* reqparams,
 2251     struct ImmsvAdminOperationParam** rparams) {
 2252   const struct ImmsvAdminOperationParam* params = reqparams;
 2253   SaStringT opName = NULL;
 2254   SaUint64T searchcount = 0;
 2255 
 2256   while (params) {
 2257     if ((strcmp(params->paramName.buf, SA_IMM_PARAM_ADMOP_NAME)) == 0) {
 2258       opName = params->paramBuffer.val.x.buf;
 2259       break;
 2260     }
 2261     params = params->next;
 2262   }
 2263 
 2264   if ((strcmp(opName, "display") == 0)) {
 2265     IMMND_OM_SEARCH_NODE* searchOp;
 2266     IMMND_IMM_CLIENT_NODE* cl_node =
 2267         (IMMND_IMM_CLIENT_NODE*)ncs_patricia_tree_getnext(&cb->client_info_db,
 2268                                                           NULL);
 2269     while (cl_node) {
 2270       searchOp = cl_node->searchOpList;
 2271       while (searchOp) {
 2272         searchcount++;
 2273         searchOp = searchOp->next;
 2274       }
 2275       cl_node = (IMMND_IMM_CLIENT_NODE*)ncs_patricia_tree_getnext(
 2276           &cb->client_info_db, cl_node->patnode.key_info);
 2277     }
 2278   }
 2279 
 2280   return ImmModel::instance(&cb->immModel)
 2281       ->resourceDisplay(reqparams, rparams, searchcount);
 2282 }
 2283 
 2284 void immModel_setCcbErrorString(IMMND_CB* cb, SaUint32T ccbId,
 2285                                 const char* errorString, ...) {
 2286   CcbVector::iterator cvi;
 2287   va_list vl;
 2288 
 2289   cvi = std::find_if(sCcbVector.begin(), sCcbVector.end(), CcbIdIs(ccbId));
 2290   if (cvi == sCcbVector.end()) {
 2291     /* Cannot find CCB. Error string will be ignored.
 2292      * This case should never happen. */
 2293     return;
 2294   }
 2295 
 2296   va_start(vl, errorString);
 2297   ImmModel::instance(&cb->immModel)->setCcbErrorString(*cvi, errorString, vl);
 2298   va_end(vl);
 2299 }
 2300 
 2301 void immModel_implementerDelete(IMMND_CB *cb, const char *implementerName) {
 2302   ImmModel::instance(&cb->immModel)->implementerDelete(implementerName);
 2303 }
 2304 
 2305 void immModel_sendSyncAbortAt(IMMND_CB *cb, struct timespec time) {
 2306   ImmModel::instance(&cb->immModel)->sendSyncAbortAt(time);
 2307 }
 2308 
 2309 void immModel_getSyncAbortRsp(IMMND_CB *cb) {
 2310   ImmModel::instance(&cb->immModel)->getSyncAbortRsp();
 2311 }
 2312 
 2313 /*====================================================================*/
 2314 
 2315 ImmModel::ImmModel() : loaderPid(-1) {}
 2316 
 2317 //>
 2318 // When sSyncAbortingAt != {0,0}, it means the SYNC has been aborted
 2319 // by coord and that abort message not yet broadcasted to IMMNDs.
 2320 // Therefore, NODE STATE at IMMND coord (IMM_NODE_FULLY_AVAILABLE) is
 2321 // different with veteran node(s) (IMM_NODE_R_AVAILABLE) at the moment.
 2322 // So, any change to IMM data model at the coord will result data mismatchs
 2323 // comparing with veterans, and lead to veterans restarted at sync finalize.
 2324 //
 2325 // In addition, we check the time here to avoid the worst cases
 2326 // such as the abort message arrived at active IMMD, but later on
 2327 // it fails to send the response (e.g: hang IMMD, or reboot IMMD, etc.)
 2328 // For that reason, if we don't receive the response within 6 seconds,
 2329 // consider sending abort failed.
 2330 //
 2331 // And we just do the check for rsp messages come from active IMMD.
 2332 //<
 2333 
 2334 // Store the start time of sync abort sent
 2335 static struct timespec sSyncAbortSentAt;
 2336 
 2337 void ImmModel::sendSyncAbortAt(timespec& time) {
 2338   sSyncAbortSentAt = time;
 2339 }
 2340 
 2341 void ImmModel::getSyncAbortRsp() {
 2342   sSyncAbortSentAt.tv_sec  = 0;
 2343   sSyncAbortSentAt.tv_nsec = 0;
 2344 }
 2345 
 2346 static bool is_sync_aborting() {
 2347   bool unset = (sSyncAbortSentAt.tv_nsec == 0 &&
 2348                 sSyncAbortSentAt.tv_sec == 0);
 2349 
 2350   if (unset) return false;
 2351 
 2352   time_t duration_in_second = 0xffffffff;
 2353   struct timespec now, duration;
 2354   osaf_clock_gettime(CLOCK_MONOTONIC, &now);
 2355   osaf_timespec_subtract(&now, &sSyncAbortSentAt, &duration);
 2356   duration_in_second = duration.tv_sec;
 2357   if (duration_in_second > DEFAULT_TIMEOUT_SEC) {
 2358     sSyncAbortSentAt.tv_sec  = 0;
 2359     sSyncAbortSentAt.tv_nsec = 0;
 2360   }
 2361 
 2362   return (duration_in_second <= DEFAULT_TIMEOUT_SEC);
 2363 }
 2364 
 2365 bool ImmModel::immNotWritable() {
 2366   switch (sImmNodeState) {
 2367     case IMM_NODE_R_AVAILABLE:
 2368     case IMM_NODE_UNKNOWN:
 2369     case IMM_NODE_ISOLATED:
 2370       return true;
 2371 
 2372     case IMM_NODE_W_AVAILABLE:
 2373     case IMM_NODE_FULLY_AVAILABLE:
 2374     case IMM_NODE_LOADING:
 2375       return false;
 2376 
 2377     default:
 2378       LOG_ER("Impossible node state, will terminate");
 2379   }
 2380   abort();
 2381 }
 2382 
 2383 /* immNotPbeWritable returning true means:
 2384    (1) immNotWriteable is true OR...
 2385    (2) immNotWritable is false (imm service is writable), but according to
 2386    configuration there should be a persistent back-end (Pbe) and the Pbe is
 2387    currently not operational. OR..
 2388    (3) PBE is operational, but backlog on PRTOs or Ccbs is large enough to
 2389    warant back-presure (TRY_AGAIN) towards the application.
 2390 
 2391    Pbe is dynamically disabled by setting immInitMode to SA_IMM_INIT_FROM_FILE.
 2392 */
 2393 bool ImmModel::immNotPbeWritable(bool isPrtoClient) {
 2394   SaUint32T dummyCon;
 2395   unsigned int dummyNode;
 2396 
 2397   /* Not writable => Not persitent writable. */
 2398   if (immNotWritable() || is_sync_aborting()) {
 2399     return true;
 2400   }
 2401 
 2402   /* INIT_FROM_FILE => no PBE => Writable => PersistentWritable */
 2403   if (immInitMode == SA_IMM_INIT_FROM_FILE) {
 2404     return false;
 2405   }
 2406 
 2407   if (immInitMode != SA_IMM_KEEP_REPOSITORY) {
 2408     LOG_ER("Illegal value on RepositoryInitMode:%u", immInitMode);
 2409     immInitMode = SA_IMM_INIT_FROM_FILE;
 2410     return false;
 2411   }
 2412 
 2413   /* immInitMode == SA_IMM_KEEP_REPOSITORY */
 2414   /* Check if PBE OI is available and making progress. */
 2415 
 2416   if (!getPbeOi(&dummyCon, &dummyNode) || !sFileSystemAvailable) {
 2417     /* Pbe SHOULD be present but is NOT */
 2418     return true;
 2419   }
 2420 
 2421   if (pbeBSlaveHasExisted() && !getPbeBSlave(&dummyCon, &dummyNode)) {
 2422     /* Pbe slave SHOULD be present but is NOT. Normally this
 2423        means immNotPbeWritable() returns true. But if oneSafe2PBEAllowed()
 2424        is true, (indicating SC repair or similar) then the unavailability
 2425        of the slave is accepted, otherwise not. By default
 2426        oneSafePBEAllowed() is false. So normally we will exit with
 2427        reject (true) here.
 2428     */
 2429     if (!oneSafe2PBEAllowed()) {
 2430       return true;
 2431     }
 2432   }
 2433 
 2434   /* Pbe is present but Check also for backlog. */
 2435 
 2436   unsigned int ccbsInCritical = 0;
 2437   CcbVector::iterator i3 = sCcbVector.begin();
 2438   for (; i3 != sCcbVector.end(); ++i3) {
 2439     if ((*i3)->mState == IMM_CCB_CRITICAL) {
 2440       ccbsInCritical++;
 2441 
 2442       if ((*i3)->mPbeRestartId) {
 2443         /* PBE was restarted with a ccb in critical. */
 2444         return true;
 2445       }
 2446     }
 2447   }
 2448 
 2449   /* If too many ccbs are already critical then delay new ccbs. */
 2450   if (ccbsInCritical > CCB_CRIT_THRESHOLD) {
 2451     return true;
 2452   }
 2453 
 2454   /* Finally, be extra stringent PRTO/PRTA changes:
 2455      PrtCreate, PrtUpdate, PrtDelete
 2456      (will also cover classCreate and classDelete).
 2457   */
 2458   if (isPrtoClient) {
 2459     SaUint32T prtoBacklog = (SaUint32T)sPbeRtMutations.size();
 2460 
 2461     static bool prtoHighReached = false; /* Note *static*, for hysteresis */
 2462 
 2463     if (prtoHighReached && (prtoBacklog > PRT_LOW_THRESHOLD)) {
 2464       return true;
 2465     }
 2466 
 2467     prtoHighReached = false;
 2468 
 2469     if (prtoBacklog > PRT_HIGH_THRESHOLD) {
 2470       prtoHighReached = true;
 2471       return true;
 2472     }
 2473   }
 2474 
 2475   return false; /* Pbe IS present & backlog is contained */
 2476 }
 2477 
 2478 void ImmModel::prepareForLoading() {
 2479   switch (sImmNodeState) {
 2480     case IMM_NODE_UNKNOWN:
 2481       sImmNodeState = IMM_NODE_LOADING;
 2482       LOG_NO("NODE STATE-> IMM_NODE_LOADING");
 2483       break;
 2484 
 2485     case IMM_NODE_ISOLATED:
 2486       LOG_IN(
 2487           "Node is not ready to participate in loading, "
 2488           "will wait and be synced instead.");
 2489       break;
 2490     case IMM_NODE_LOADING:
 2491     case IMM_NODE_FULLY_AVAILABLE:
 2492     case IMM_NODE_W_AVAILABLE:
 2493     case IMM_NODE_R_AVAILABLE:
 2494       LOG_ER(
 2495           "Node is in a state that cannot accept start "
 2496           "of loading, will terminate");
 2497       abort();
 2498     default:
 2499       LOG_ER("Impossible node state, will terminate");
 2500       abort();
 2501   }
 2502 }
 2503 
 2504 bool ImmModel::readyForLoading() { return sImmNodeState == IMM_NODE_LOADING; }
 2505 
 2506 void ImmModel::recognizedIsolated() {
 2507   switch (sImmNodeState) {
 2508     case IMM_NODE_UNKNOWN:
 2509       sImmNodeState = IMM_NODE_ISOLATED;
 2510       LOG_NO("NODE STATE-> IMM_NODE_ISOLATED");
 2511       break;
 2512 
 2513     case IMM_NODE_ISOLATED:
 2514       LOG_IN("Redundant sync request, when IMM_NODE_ISOLATED");
 2515       break;
 2516     case IMM_NODE_W_AVAILABLE:
 2517       LOG_WA("Redundant sync request, when IMM_NODE_W_AVAILABLE");
 2518       break;
 2519 
 2520     case IMM_NODE_FULLY_AVAILABLE:
 2521     case IMM_NODE_LOADING:
 2522     case IMM_NODE_R_AVAILABLE:
 2523       LOG_ER("Node is in a state that cannot request sync, will terminate");
 2524       abort();
 2525     default:
 2526       LOG_ER("Impossible node state, will terminate");
 2527       abort();
 2528   }
 2529 }
 2530 
 2531 void ImmModel::prepareForSync(bool isJoining) {
 2532   switch (sImmNodeState) {
 2533     case IMM_NODE_ISOLATED:
 2534       osafassert(isJoining);
 2535       sImmNodeState = IMM_NODE_W_AVAILABLE;  // accept the sync messages
 2536       LOG_NO("NODE STATE-> IMM_NODE_W_AVAILABLE");
 2537       break;
 2538 
 2539     case IMM_NODE_FULLY_AVAILABLE:
 2540       osafassert(!isJoining);
 2541       sImmNodeState = IMM_NODE_R_AVAILABLE;  // Stop mutations.
 2542       LOG_NO("NODE STATE-> IMM_NODE_R_AVAILABLE");
 2543       break;
 2544 
 2545     case IMM_NODE_UNKNOWN:
 2546       LOG_IN(
 2547           "Node is not ready to participate in sync, "
 2548           "will wait and be synced later.");
 2549       break;
 2550 
 2551     case IMM_NODE_LOADING:
 2552     case IMM_NODE_W_AVAILABLE:
 2553     case IMM_NODE_R_AVAILABLE:
 2554       LOG_ER(
 2555           "Node is in a state that cannot accept start of sync, "
 2556           "will terminate");
 2557       abort();
 2558     default:
 2559       LOG_ER("Impossible node state, will terminate");
 2560       abort();
 2561   }
 2562 }
 2563 
 2564 bool ImmModel::syncComplete(bool isJoining) {
 2565   // Dont need the isJoining argument for now.
 2566 
 2567   return sImmNodeState == IMM_NODE_FULLY_AVAILABLE;
 2568 }
 2569 
 2570 void ImmModel::pbePrtoPurgeMutations(unsigned int nodeId,
 2571                                      ConnVector& connVector) {
 2572   ObjectMutationMap::iterator omuti;
 2573   ObjectMap::iterator oi;
 2574   SaInvocationT inv;
 2575   ContinuationMap2::iterator ci;
 2576   ImmAttrValueMap::iterator oavi;
 2577   ObjectInfo* afim = NULL;
 2578   std::set<SaUint32T> connSet;
 2579   TRACE_ENTER();
 2580   bool dummy = false;
 2581   bool dummy2 = false;
 2582 
 2583   for (omuti = sPbeRtMutations.begin(); omuti != sPbeRtMutations.end();
 2584        ++omuti) {
 2585     ObjectInfo* grandParent = NULL;
 2586     ObjectMutation* oMut = omuti->second;
 2587     oi = sObjectMap.find(omuti->first);
 2588     osafassert(oi != sObjectMap.end() || (oMut->mOpType == IMM_CREATE_CLASS) ||
 2589                (oMut->mOpType == IMM_DELETE_CLASS) ||
 2590                (oMut->mOpType == IMM_UPDATE_EPOCH));
 2591 
 2592     inv = m_IMMSV_PACK_HANDLE(oMut->mContinuationId, nodeId);
 2593     ci = sPbeRtReqContinuationMap.find(inv);
 2594 
 2595     if (ci != sPbeRtReqContinuationMap.end()) {
 2596       if (oi != sObjectMap.end()) {
 2597         /* Only reply the default reply of TRY_AGAIN on failed
 2598            RTO ops, not failed class ops. The RTO ops are
 2599            reverted on fauilure here, which is consistent with
 2600            a reply of TRY_AGAIN. The class ops are NOT reverted,
 2601            so a reply of TRY_AGAIN would be incorrect and a
 2602            reply of OK would be premature. For class ops
 2603            that have trouble with the PBE, ERR_TIMEOUT would
 2604            be the only proper reply, so we let the client
 2605            timeout by not replying.
 2606         */
 2607         if(connSet.find(ci->second.mConn) == connSet.end()) {
 2608           /* Don't add a connection more that once */
 2609           connSet.insert(ci->second.mConn);
 2610           connVector.push_back(ci->second.mConn);
 2611         }
 2612       }
 2613       sPbeRtReqContinuationMap.erase(ci);
 2614     }
 2615 
 2616     /* Fall back. */
 2617     switch (oMut->mOpType) {
 2618       case IMM_CREATE:
 2619         osafassert(oi->second == oMut->mAfterImage);
 2620 
 2621         oMut->mAfterImage->mObjFlags &= ~IMM_CREATE_LOCK;
 2622         /* Decrement mChildCount for all parents of the reverted
 2623            PRTO create. Note: There could be several PRTO creates to
 2624            process in this purge, but none can be the parent of another
 2625            in this purge. This because a PRTO create of a subobject
 2626            to a parent object is not allowed if the create of the parent
 2627            has not yet been ack'ed by the PBE. So one can never have
 2628            both parent and child being an un-acked PRTO create.
 2629         */
 2630         grandParent = oMut->mAfterImage->mParent;
 2631         while (grandParent) {
 2632           std::string gpDn;
 2633           getObjectName(grandParent, gpDn);
 2634           grandParent->mChildCount--;
 2635           LOG_IN(
 2636               "Childcount for (grand)parent %s of purged create prto %s adjusted to %u",
 2637               gpDn.c_str(), omuti->first.c_str(), grandParent->mChildCount);
 2638           grandParent = grandParent->mParent;
 2639         }
 2640         oMut->mAfterImage = NULL;
 2641         LOG_WA("Create of PERSISTENT runtime object '%s' REVERTED ",
 2642                omuti->first.c_str());
 2643         osafassert(deleteRtObject(oi, true, NULL, dummy, dummy2) == SA_AIS_OK);
 2644         break;
 2645 
 2646       case IMM_DELETE:
 2647         osafassert(oi->second == oMut->mAfterImage);
 2648 
 2649         oMut->mAfterImage->mObjFlags &= ~IMM_DELETE_LOCK;
 2650         oMut->mAfterImage = NULL;
 2651         /* A delete may delete a tree including both persistent
 2652            and non persistent RTOs. The roll back here has to
 2653            revert all the deletes, not just the persistent RTOs.
 2654         */
 2655         LOG_WA("Delete of runtime object '%s' REVERTED ", omuti->first.c_str());
 2656         break;
 2657 
 2658       case IMM_MODIFY:
 2659         osafassert(oi->second != oMut->mAfterImage); /* NOT equal */
 2660         oi->second->mObjFlags &= ~IMM_RT_UPDATE_LOCK;
 2661         afim = oMut->mAfterImage;
 2662         for (oavi = afim->mAttrValueMap.begin();
 2663              oavi != afim->mAttrValueMap.end(); ++oavi) {
 2664           delete oavi->second;
 2665         }
 2666         afim->mAttrValueMap.clear();
 2667         delete afim;
 2668         oMut->mAfterImage = NULL;
 2669         LOG_WA(
 2670             "update of PERSISTENT runtime attributes in object '%s' REVERTED.",
 2671             omuti->first.c_str());
 2672         break;
 2673 
 2674       case IMM_CREATE_CLASS:
 2675         LOG_WA("PBE failed in persistification of class create %s",
 2676                omuti->first.c_str());
 2677         /* The PBE should have aborted when this happened.
 2678            The existence of this mutation would prevent a restart
 2679            with --recover. Instead a restart will regenerate the
 2680            PBE file, forcing it in line with the imms runtime
 2681            state.
 2682         */
 2683         break;
 2684 
 2685       case IMM_DELETE_CLASS:
 2686         LOG_WA("PBE failed in persistification of class delete %s",
 2687                omuti->first.c_str());
 2688         /* The PBE should have aborted when this happened.
 2689            The existence of this mutation would prevent a restart
 2690            with --recover. Instead a restart will regenerate the
 2691            PBE file, forcing it in line with the imms runtime
 2692            state.
 2693         */
 2694 
 2695         break;
 2696 
 2697       case IMM_UPDATE_EPOCH:
 2698         LOG_WA("PBE failed in persistification of update epoch");
 2699         /* The PBE should have aborted when this happened.
 2700            The existence of this mutation would prevent a restart
 2701            with --recover. Instead a restart will regenerate the
 2702            PBE file, forcing it in line with the imms runtime
 2703            state.
 2704         */
 2705 
 2706         break;
 2707 
 2708       default:
 2709         abort();
 2710     }
 2711     delete oMut;
 2712   }
 2713 
 2714   sPbeRtMutations.clear();
 2715   sPbeRtReqContinuationMap.clear();
 2716   TRACE_LEAVE();
 2717 }
 2718 
 2719 void ImmModel::abortSync() {
 2720   ClassMap::iterator ci;
 2721   switch (sImmNodeState) {
 2722     case IMM_NODE_R_AVAILABLE:
 2723       sImmNodeState = IMM_NODE_FULLY_AVAILABLE;
 2724       sNodesDeadDuringSync.clear();
 2725       sImplsDeadDuringSync.clear();
 2726       osafassert(sAdmosDeadDuringSync.empty());
 2727 
 2728       LOG_NO("NODE STATE-> IMM_NODE_FULLY_AVAILABLE (%u)", __LINE__);
 2729       break;
 2730 
 2731     case IMM_NODE_UNKNOWN:
 2732     case IMM_NODE_ISOLATED:
 2733       break;
 2734 
 2735     case IMM_NODE_FULLY_AVAILABLE:
 2736       LOG_WA(
 2737           "Abort sync received while being fully available, "
 2738           "should not happen.");
 2739       break;
 2740 
 2741     case IMM_NODE_W_AVAILABLE:
 2742       sImmNodeState = IMM_NODE_UNKNOWN;
 2743       LOG_NO("NODE STATE-> IMM_NODE_UNKNOW %u", __LINE__);
 2744       /* Aborting a started but not completed sync. */
 2745       LOG_NO("Abort sync: Discarding synced objects");
 2746       // Remove all NO_DANGLING references
 2747       sReverseRefsNoDanglingMMap.clear();
 2748       while (!sObjectMap.empty()) {
 2749         ObjectMap::iterator oi = sObjectMap.begin();
 2750         TRACE("sObjectmap.size:%u delete: %s", (unsigned int)sObjectMap.size(),
 2751               oi->first.c_str());
 2752         commitDelete(oi->first);
 2753       }
 2754 
 2755       LOG_NO("Abort sync: Discarding synced classes");
 2756       ci = sClassMap.begin();
 2757       while (ci != sClassMap.end()) {
 2758         TRACE("Removing Class:%s", ci->first.c_str());
 2759         osafassert(ci->second->mExtent.empty());
 2760 
 2761         AttrMap::iterator ai = ci->second->mAttrMap.begin();
 2762         while (ai != ci->second->mAttrMap.end()) {
 2763           TRACE("Remove Attr:%s", ai->first.c_str());
 2764           AttrInfo* ainfo = ai->second;
 2765           osafassert(ainfo);
 2766           delete (ainfo);
 2767           ++ai;
 2768         }
 2769         ci->second->mAttrMap.clear();
 2770 
 2771         delete ci->second;
 2772         updateImmObject(ci->first, true);
 2773         ++ci;
 2774       }
 2775       sClassMap.clear();
 2776 
 2777       if (!sDeferredObjUpdatesMap.empty()) {
 2778         LOG_NO("Abort sync: discarding deferred RTA updates");
 2779 
 2780         DeferredObjUpdatesMap::iterator doumIter =
 2781             sDeferredObjUpdatesMap.begin();
 2782         while (doumIter != sDeferredObjUpdatesMap.end()) {
 2783           DeferredRtAUpdateList* attrUpdList = doumIter->second;
 2784 
 2785           DeferredRtAUpdateList::iterator drtauIter = attrUpdList->begin();
 2786           while (drtauIter != attrUpdList->end()) {
 2787             immsv_free_attrmods(drtauIter->attrModsList);
 2788             drtauIter->attrModsList = NULL;
 2789             ++drtauIter;
 2790           }
 2791           attrUpdList->clear();
 2792 
 2793           delete attrUpdList;
 2794           ++doumIter;
 2795         }
 2796         sDeferredObjUpdatesMap.clear();
 2797       }
 2798 
 2799       sNodesDeadDuringSync.clear();
 2800       sImplsDeadDuringSync.clear();
 2801       sAdmosDeadDuringSync.clear();
 2802       sImplDetachTime.clear();
 2803 
 2804       if (!sImplementerVector.empty()) {
 2805         ImplementerVector::iterator i;
 2806         for (i = sImplementerVector.begin(); i != sImplementerVector.end();
 2807              ++i) {
 2808           ImplementerInfo* info = (*i);
 2809           delete info;
 2810         }
 2811         sImplementerVector.clear();
 2812       }
 2813 
 2814       osafassert(sOwnerVector.empty());
 2815       osafassert(sCcbVector.empty());
 2816 
 2817       sMissingParents.clear();
 2818       break;
 2819 
 2820     case IMM_NODE_LOADING:
 2821 
 2822       LOG_ER(
 2823           "Node is in a state %u that cannot accept abort "
 2824           " of sync, will terminate",
 2825           sImmNodeState);
 2826       abort();
 2827     default:
 2828       LOG_ER("Impossible node state, will terminate");
 2829       abort();
 2830   }
 2831 }
 2832 
 2833 /**
 2834  * Sets the pid for the loader process. Bars other processes
 2835  * from accessing the IMM model during loading.
 2836  *
 2837  */
 2838 void ImmModel::setLoader(int pid) {
 2839   loaderPid = pid;
 2840   if (pid == 0) {
 2841     sImmNodeState = IMM_NODE_FULLY_AVAILABLE;
 2842     LOG_NO("NODE STATE-> IMM_NODE_FULLY_AVAILABLE %u", __LINE__);
 2843 
 2844     immInitMode = getRepositoryInitMode();
 2845     if (immInitMode == SA_IMM_KEEP_REPOSITORY) {
 2846       LOG_NO("RepositoryInitModeT is SA_IMM_KEEP_REPOSITORY");
 2847     } else {
 2848       LOG_NO("RepositoryInitModeT is SA_IMM_INIT_FROM_FILE");
 2849       immInitMode = SA_IMM_INIT_FROM_FILE; /* Ensure valid value*/
 2850     }
 2851 
 2852     if (accessControlMode() == ACCESS_CONTROL_DISABLED) {
 2853       LOG_WA("IMM Access Control mode is DISABLED!");
 2854     } else if (accessControlMode() == ACCESS_CONTROL_PERMISSIVE) {
 2855       LOG_WA("IMM Access Control mode is PERMISSIVE");
 2856     } else {
 2857       LOG_NO("IMM Access Control mode is ENFORCING");
 2858     }
 2859 
 2860   } else {
 2861     TRACE_5("Loading starts, pid:%u", pid);
 2862   }
 2863 }
 2864 
 2865 /**
 2866  * Returns the pid for the loader process. Used to check if loading is
 2867  * currently in progress.
 2868  *
 2869  */
 2870 int ImmModel::getLoader() { return loaderPid; }
 2871 
 2872 /**
 2873  * Changes the current epoch to either suggestedEpoch or to
 2874  * the epoch fetched from the imm-object.
 2875  * The former case is expected to be after a sync. The latter
 2876  * case is expected after a reload.
 2877  * Normally the epoch is incremented when suggestedEpoch is <=
 2878  * than current epoch. But if the 'inrement' arg is false then
 2879  * no incrementing is done here. This is used when only the side
 2880  * effects of adjustEpoch are desired (pushing epoch to IMMD and PBE).
 2881  */
 2882 int ImmModel::adjustEpoch(int suggestedEpoch, SaUint32T* continuationIdPtr,
 2883                           SaUint32T* pbeConnPtr, unsigned int* pbeNodeIdPtr,
 2884                           bool increment) {
 2885   int restoredEpoch = 0;
 2886   ImmAttrValueMap::iterator avi;
 2887   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 2888   osafassert(oi != sObjectMap.end() && oi->second);
 2889 
 2890   ObjectInfo* immObject = oi->second;
 2891   osafassert(immObject != nullptr);
 2892   avi = immObject->mAttrValueMap.find(immAttrEpoch);
 2893   osafassert(avi != immObject->mAttrValueMap.end());
 2894   osafassert(!avi->second->isMultiValued());
 2895 
 2896   restoredEpoch = avi->second->getValue_int();
 2897 
 2898   if (restoredEpoch < 1) {
 2899     restoredEpoch = 1;
 2900   }
 2901 
 2902   if (suggestedEpoch <= restoredEpoch) {
 2903     suggestedEpoch = restoredEpoch;
 2904     if (increment) {
 2905       ++suggestedEpoch;
 2906     }
 2907   }
 2908 
 2909   if ((increment) && (avi != immObject->mAttrValueMap.end())) {
 2910     avi->second->setValue_int(suggestedEpoch);
 2911     LOG_NO("Epoch set to %u in ImmModel", suggestedEpoch);
 2912   }
 2913 
 2914   if (pbeNodeIdPtr) {
 2915     /* Generate global continuation if PBE is enabled, regardless if
 2916        PBE is currently present or not. This is necessary since
 2917        ImmModel::adjustEpoch is not always invoked in the context of
 2918        a fevs message. Thus even though getPbeOi below is fevs safe
 2919        in that it is based on current fevs context, that fevs context
 2920        may be a different fevs context on other nodes by the time they
 2921        get the message that triggers adjustEpoch, for example in
 2922        immnd_abortSync().
 2923     */
 2924 
 2925     if (++sLastContinuationId >= 0xfffffffe) {
 2926       sLastContinuationId = 1;
 2927     }
 2928     *continuationIdPtr = sLastContinuationId;
 2929     TRACE("continuation generated: %u", *continuationIdPtr);
 2930 
 2931     if (getPbeOi(pbeConnPtr, pbeNodeIdPtr)) {
 2932       if (sPbeRtMutations.find(immObjectDn) == sPbeRtMutations.end()) {
 2933         ObjectMutation* oMut = new ObjectMutation(IMM_UPDATE_EPOCH);
 2934         oMut->mContinuationId = (*continuationIdPtr);
 2935         oMut->mAfterImage = NULL;
 2936         sPbeRtMutations[immObjectDn] = oMut;
 2937       } else {
 2938         LOG_WA("Continuation for Pbe mutation on %s already exists",
 2939                immObjectDn.c_str());
 2940       }
 2941     }
 2942   }
 2943 
 2944   return suggestedEpoch;
 2945 }
 2946 
 2947 bool ImmModel::getRegenerateDbFlag() {
 2948   return sRegenerateDb;
 2949 }
 2950 
 2951 void ImmModel::setRegenerateDbFlag(bool value) {
 2952   sRegenerateDb = value;
 2953 }
 2954 
 2955 /**
 2956  * Fetches the SaImmRepositoryInitT value of the attribute
 2957  * 'saImmRepositoryInit' in the object immManagementDn.
 2958  * If not found then return SA_IMM_INIT_FROM_FILE as default.
 2959  */
 2960 SaImmRepositoryInitModeT ImmModel::getRepositoryInitMode() {
 2961   ImmAttrValueMap::iterator avi;
 2962   ObjectInfo* immMgObject = NULL;
 2963   ObjectMap::iterator oi = sObjectMap.find(immManagementDn);
 2964   if (oi != sObjectMap.end()) {
 2965     immMgObject = oi->second;
 2966     avi = immMgObject->mAttrValueMap.find(saImmRepositoryInit);
 2967 
 2968     if (avi != immMgObject->mAttrValueMap.end()) {
 2969       osafassert(!avi->second->isMultiValued());
 2970       return (SaImmRepositoryInitModeT)avi->second->getValue_int();
 2971     }
 2972   }
 2973 
 2974   TRACE_2("%s not found or %s not found, returning INIT_FROM_FILE",
 2975           immManagementDn.c_str(), saImmRepositoryInit.c_str());
 2976   return SA_IMM_INIT_FROM_FILE;
 2977 }
 2978 
 2979 SaTimeT ImmModel::getSyncrTimeout() {
 2980   ImmAttrValueMap::iterator avi;
 2981   ObjectInfo* immMgObject = NULL;
 2982   ObjectMap::iterator oi = sObjectMap.find(immManagementDn);
 2983   if (oi != sObjectMap.end()) {
 2984     immMgObject = oi->second;
 2985     avi = immMgObject->mAttrValueMap.find(saImmSyncrTimeout);
 2986 
 2987     if (avi != immMgObject->mAttrValueMap.end()) {
 2988       osafassert(!avi->second->isMultiValued());
 2989       return avi->second->getValue_satimet();
 2990     }
 2991   }
 2992   return 0;
 2993 }
 2994 
 2995 unsigned int ImmModel::getMaxSyncBatchSize() {
 2996   TRACE_ENTER();
 2997   unsigned int mbSize = 0;
 2998   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 2999   if (oi == sObjectMap.end()) {
 3000     TRACE_LEAVE();
 3001     return 0;
 3002   }
 3003 
 3004   ObjectInfo* immObject = oi->second;
 3005   ImmAttrValueMap::iterator avi =
 3006       immObject->mAttrValueMap.find(immSyncBatchSize);
 3007   if (avi != immObject->mAttrValueMap.end()) {
 3008     osafassert(!(avi->second->isMultiValued()));
 3009     ImmAttrValue* valuep = avi->second;
 3010     mbSize = valuep->getValue_int();
 3011   }
 3012   TRACE_LEAVE();
 3013   return mbSize;
 3014 }
 3015 
 3016 void ImmModel::getLocalImplementers(ConnVector& cv, IdVector& idv) {
 3017   TRACE_ENTER();
 3018   ImplementerVector::iterator i;
 3019   for (i = sImplementerVector.begin(); i != sImplementerVector.end(); ++i) {
 3020     ImplementerInfo* info = (*i);
 3021     if (info->mConn) {
 3022       cv.push_back(info->mConn);
 3023       idv.push_back(info->mId);
 3024     }
 3025   }
 3026   TRACE_LEAVE();
 3027 }
 3028 
 3029 bool ImmModel::getLongDnsAllowed(ObjectInfo* immObject) {
 3030   TRACE_ENTER();
 3031   bool longDnsAllowed = false;
 3032   if (sCcbIdLongDnGuard) {
 3033     /* A ccb is currently mutating longDnsAllowed */
 3034     return false;
 3035   }
 3036 
 3037   if ((sImmNodeState > IMM_NODE_LOADING) && !protocol45Allowed()) {
 3038     LOG_IN("Long DNs not allowed before upgrade to OpenSAF 4.5 is complete");
 3039     return false;
 3040   }
 3041 
 3042   ObjectMap::iterator oi;
 3043   if (immObject == NULL) {
 3044     oi = sObjectMap.find(immObjectDn);
 3045     if (oi == sObjectMap.end()) {
 3046       TRACE_LEAVE();
 3047       return sImmNodeState == IMM_NODE_LOADING;
 3048     }
 3049     immObject = oi->second;
 3050   }
 3051 
 3052   ImmAttrValueMap::iterator avi =
 3053       immObject->mAttrValueMap.find(immLongDnsAllowed);
 3054   if (avi != immObject->mAttrValueMap.end()) {
 3055     osafassert(!(avi->second->isMultiValued()));
 3056     ImmAttrValue* valuep = avi->second;
 3057     longDnsAllowed = (valuep->getValue_int() != 0);
 3058   }
 3059   TRACE_LEAVE();
 3060   return longDnsAllowed;
 3061 }
 3062 
 3063 /**
 3064  * Fetches the nodeId and possibly connection id for the
 3065  * implementer connected to the class OPENSAF_IMM_CLASS_NAME.
 3066  * This is used both when testing for the presence of the PBE
 3067  * and for locating the PBE when a message/upcall is to be sent
 3068  * to it.
 3069  *
 3070  * If fevsSafe is true, then a PBE-OI detected as dying at this node
 3071  * is still treated as if it exists. This to get uniformity of state
 3072  * change across all nodes. The connection is still returned as NULL
 3073  * if it is dead, which means ALL nodes will believe the PBE is at
 3074  * some another node, whereas it is really not attached anywhere.
 3075  * This typically means that all nodes will wait for the PBE to
 3076  * re-attach.
 3077  */
 3078 void* /*default true*/
 3079     ImmModel::getPbeOi(SaUint32T* pbeConn, unsigned int* pbeNode,
 3080                        bool fevsSafe) {
 3081   *pbeConn = 0;
 3082   *pbeNode = 0;
 3083   ClassMap::iterator ci = sClassMap.find(immClassName);
 3084   osafassert(ci != sClassMap.end());
 3085   ClassInfo* classInfo = ci->second;
 3086   if (classInfo->mImplementer == NULL || classInfo->mImplementer->mId == 0) {
 3087     return NULL;
 3088   }
 3089 
 3090   /* PBE-OI exists but could be dying. */
 3091   if (classInfo->mImplementer->mDying) {
 3092     if (!fevsSafe) {
 3093       /* Not fevsSafe => immediately inform about dying PBE.*/
 3094       LOG_NO("ImmModel::getPbeOi reports missing PbeOi locally => unsafe");
 3095       return NULL;
 3096     }
 3097   } else {
 3098     /* Only assign conn when PBE is not dying. */
 3099     *pbeConn = classInfo->mImplementer->mConn;
 3100   }
 3101 
 3102   *pbeNode = classInfo->mImplementer->mNodeId;
 3103 
 3104   return classInfo->mImplementer;
 3105 }
 3106 
 3107 /**
 3108  * Fetches a special Applier, if one is attached at the local node.
 3109  * See README and ticket #2873.
 3110  */
 3111 ImplementerInfo* ImmModel::getSpecialApplier() {
 3112   TRACE_ENTER();
 3113   const std::string spApplierA(OPENSAF_IMM_REPL_A_NAME);
 3114   const std::string spApplierB(OPENSAF_IMM_REPL_B_NAME);
 3115 
 3116   ImplementerInfo* specialApplier = findImplementer(spApplierA);
 3117 
 3118   if (!specialApplier || specialApplier->mDying || !(specialApplier->mConn)) {
 3119     specialApplier = findImplementer(spApplierB);
 3120     if (specialApplier &&
 3121         (specialApplier->mDying || !(specialApplier->mConn))) {
 3122       specialApplier = NULL;
 3123     }
 3124   }
 3125 
 3126   TRACE_LEAVE();
 3127   return specialApplier;
 3128 }
 3129 
 3130 bool ImmModel::specialApplyForClass(ClassInfo* classInfo) {
 3131   TRACE_ENTER();
 3132   osafassert(classInfo);
 3133   AttrMap::iterator atti;
 3134 
 3135   if (getSpecialApplier()) {
 3136     for (atti = classInfo->mAttrMap.begin(); atti != classInfo->mAttrMap.end();
 3137          ++atti) {
 3138       if (atti->second->mFlags & SA_IMM_ATTR_NOTIFY) {
 3139         return true;
 3140       }
 3141     }
 3142   }
 3143 
 3144   TRACE_LEAVE();
 3145   return false;
 3146 }
 3147 
 3148 bool ImmModel::pbeBSlaveHasExisted() {
 3149   /* An IMMND never explicitly discard implementer names or applier names.
 3150      At IMMND process start, implementer names are synced *including* applier
 3151      names. But second level map for appliers is not synced (applier=>class
 3152      etc). The existence of the slave PBE applier-name indicates that this IMMND
 3153      has participated in a cluster where the slave PBE has been present.
 3154      If slave PBE is or is not present currently is answered by getPbeBSlave().
 3155    */
 3156   return findImplementer(immPbeBSlaveName) != NULL;
 3157 }
 3158 
 3159 void* ImmModel::getPbeBSlave(SaUint32T* pbeConn, unsigned int* pbeNode,
 3160                              bool fevsSafe) {
 3161   *pbeConn = 0;
 3162   *pbeNode = 0;
 3163   ImplementerInfo* pbeBSlave = findImplementer(immPbeBSlaveName);
 3164   if (pbeBSlave == NULL || pbeBSlave->mId == 0) {
 3165     return NULL;
 3166   }
 3167 
 3168   if (pbeBSlave->mDying) {
 3169     if (!fevsSafe) {
 3170       LOG_NO(
 3171           "ImmModel::getPbeBSlave reports missing PbeBSlave locally => unsafe");
 3172       return NULL;
 3173     }
 3174   } else {
 3175     *pbeConn = pbeBSlave->mConn;
 3176   }
 3177 
 3178   *pbeNode = pbeBSlave->mNodeId;
 3179 
 3180   return pbeBSlave;
 3181 }
 3182 
 3183 /**
 3184  * Returns the only instance of ImmModel.
 3185  */
 3186 ImmModel* ImmModel::instance(void** sInstancep) {
 3187   // static ImmModel* sInstance = 0;
 3188 
 3189   if (*sInstancep == NULL) {
 3190     *sInstancep = new ImmModel();
 3191   }
 3192 
 3193   return (ImmModel*)*sInstancep;
 3194 }
 3195 
 3196 bool ImmModel::nocaseCompare(const std::string& str1,
 3197                              const std::string& str2) const {
 3198   size_t pos;
 3199   size_t len = str1.length();
 3200 
 3201   if (len != str2.length()) return false;
 3202 
 3203   for (pos = 0; pos < len; ++pos) {
 3204     if (toupper(str1.at(pos)) != toupper(str2.at(pos))) return false;
 3205   }
 3206 
 3207   return true;
 3208 }
 3209 
 3210 /**
 3211  * Creates a class.
 3212  */
 3213 SaAisErrorT ImmModel::classCreate(const ImmsvOmClassDescr* req,
 3214                                   SaUint32T reqConn, unsigned int nodeId,
 3215                                   SaUint32T* continuationIdPtr,
 3216                                   SaUint32T* pbeConnPtr,
 3217                                   unsigned int* pbeNodeIdPtr) {
 3218   int rdns = 0;
 3219   int illegal = 0;
 3220   bool persistentRt = false;
 3221   bool persistentRdn = false;
 3222   bool useUnknownFlag = false;
 3223   ClassInfo* classInfo = NULL;
 3224   ClassInfo* prevClassInfo = NULL;
 3225   ClassInfo dummyClass(req->classCategory);
 3226   bool schemaChange = false;
 3227   AttrMap newAttrs;
 3228   AttrMap changedAttrs;
 3229   ImmsvAttrDefList* list = req->attrDefinitions;
 3230   bool isLoading =
 3231       (sImmNodeState == IMM_NODE_LOADING || /* LOADING-SEVER, LOADING-CLIENT */
 3232        sImmNodeState == IMM_NODE_W_AVAILABLE); /* SYNC-CLIENT */
 3233 
 3234   TRACE_ENTER2("cont:%p connp:%p nodep:%p", continuationIdPtr, pbeConnPtr,
 3235                pbeNodeIdPtr);
 3236   size_t sz = strnlen((char*)req->className.buf, (size_t)req->className.size);
 3237 
 3238   std::string className((const char*)req->className.buf, sz);
 3239   SaAisErrorT err = SA_AIS_OK;
 3240 
 3241   if (immNotPbeWritable()) {
 3242     return SA_AIS_ERR_TRY_AGAIN;
 3243   }
 3244 
 3245   if (!schemaNameCheck(className)) {
 3246     LOG_NO("ERR_INVALID_PARAM: Not a proper class name %s", className.c_str());
 3247     return SA_AIS_ERR_INVALID_PARAM;
 3248   }
 3249 
 3250   ObjectMap::iterator oit = sObjectMap.find(immObjectDn);
 3251   if (protocol51Allowed() && oit != sObjectMap.end() && !isLoading) {
 3252     ObjectInfo* immObject = oit->second;
 3253     ImmAttrValueMap::iterator avi =
 3254         immObject->mAttrValueMap.find(immMaxClasses);
 3255     osafassert(avi != immObject->mAttrValueMap.end());
 3256     osafassert(!(avi->second->isMultiValued()));
 3257     ImmAttrValue* valuep = avi->second;
 3258     unsigned int maxClasses = valuep->getValue_int();
 3259     if (sClassMap.size() >= maxClasses) {
 3260       LOG_NO(
 3261           "ERR_NO_RESOURCES: maximum class limit %d has been reched for the cluster",
 3262           maxClasses);
 3263       return SA_AIS_ERR_NO_RESOURCES;
 3264     }
 3265   }
 3266   ClassMap::iterator i = sClassMap.find(className);
 3267   if (i == sClassMap.end()) {
 3268     /* Class-name is unique case-sensitive.
 3269        Verify class-name unique case-insensitive. See #1846. */
 3270     for (i = sClassMap.begin(); i != sClassMap.end(); ++i) {
 3271       if (nocaseCompare(className, i->first)) {
 3272         LOG_NO(
 3273             "ERR_EXIST: New class-name:%s identical to existing class-name %s "
 3274             "(case insensitive)",
 3275             className.c_str(), i->first.c_str());
 3276         return SA_AIS_ERR_EXIST;
 3277       }
 3278     }
 3279     /*Class-name is unique case-insensitive.*/
 3280 
 3281     TRACE_5("CREATE CLASS '%s' category:%u", className.c_str(),
 3282             req->classCategory);
 3283     classInfo = new ClassInfo(req->classCategory);
 3284   } else {
 3285     /* Class name exists */
 3286 
 3287     /* First check for prior create of same class in progress. */
 3288     if (sPbeRtMutations.find(className) != sPbeRtMutations.end()) {
 3289       LOG_NO(
 3290           "ERR_BUSY: Create of class %s received while class "
 3291           "with same name is already being mutated",
 3292           className.c_str());
 3293       err = SA_AIS_ERR_BUSY;
 3294       goto done;
 3295     }
 3296 
 3297     /* Second, check for schema upgrade.*/
 3298     if (schemaChangeAllowed()) {
 3299       /* New non-standard upgrade behavior. */
 3300       LOG_NO("Class '%s' exist - check implied schema upgrade",
 3301              className.c_str());
 3302       schemaChange = true;
 3303       classInfo =
 3304           &dummyClass; /* New class created as dummy, do all normal checks */
 3305       prevClassInfo = i->second;
 3306     } else {
 3307       /* Standard behavior, reject. */
 3308       TRACE_7("ERR_EXIST: class '%s' exist", className.c_str());
 3309       err = SA_AIS_ERR_EXIST;
 3310       goto done;
 3311     }
 3312   }
 3313 
 3314   /* The entire while loop below is independent of whether this is an upgrade
 3315      or not. Each attrdef is checked for fundamental correctness.
 3316      A proposed upgrade of a class def has to pass all the checks it would
 3317      face, had it been the first version of the class def.
 3318      Additional checks, specific to upgrade are done, later (after this loop).
 3319   */
 3320   while (list) {
 3321     ImmsvAttrDefinition* attr = &list->d;
 3322     sz = strnlen((char*)attr->attrName.buf, (size_t)attr->attrName.size);
 3323     std::string attrName((const char*)attr->attrName.buf, sz);
 3324     const char* attNm = attrName.c_str();
 3325 
 3326     if ((attr->attrFlags & SA_IMM_ATTR_CONFIG) &&
 3327         (attr->attrFlags & SA_IMM_ATTR_RUNTIME)) {
 3328       LOG_NO(
 3329           "ERR_INVALID_PARAM: Attribute '%s' can not be both SA_IMM_ATTR_CONFIG "
 3330           "and SA_IMM_ATTR_RUNTIME",
 3331           attNm);
 3332       illegal = 1;
 3333     }
 3334 
 3335     if ((attr->attrFlags & SA_IMM_ATTR_NO_DUPLICATES) &&
 3336         !(attr->attrFlags & SA_IMM_ATTR_MULTI_VALUE)) {
 3337       LOG_NO(
 3338           "ERR_INVALID_PARAM: Attribute '%s' can not have SA_IMM_ATTR_NO_DUPLICATES "
 3339           "when not SA_IMM_ATTR_MULTI_VALUE",
 3340           attNm);
 3341       illegal = 1;
 3342     }
 3343 
 3344     if (attr->attrFlags & SA_IMM_ATTR_CONFIG) {
 3345       if (req->classCategory == SA_IMM_CLASS_RUNTIME) {
 3346         LOG_NO(
 3347             "ERR_INVALID_PARAM: Runtime objects can not have config "
 3348             "attributes '%s'",
 3349             attNm);
 3350         illegal = 1;
 3351       }
 3352 
 3353       if (attr->attrFlags & SA_IMM_ATTR_PERSISTENT) {
 3354         LOG_NO(
 3355             "ERR_INVALID_PARAM: Config attribute '%s' can not be declared "
 3356             "SA_IMM_ATTR_PERSISTENT",
 3357             attNm);
 3358         illegal = 1;
 3359       }
 3360 
 3361       if (attr->attrFlags & SA_IMM_ATTR_CACHED) {
 3362         LOG_NO(
 3363             "ERR_INVALID_PARAM: Config attribute '%s' can not be declared "
 3364             "SA_IMM_ATTR_CACHED",
 3365             attNm);
 3366         illegal = 1;
 3367       }
 3368 
 3369     } else if (attr->attrFlags & SA_IMM_ATTR_RUNTIME) {
 3370       if ((attr->attrFlags & SA_IMM_ATTR_PERSISTENT) &&
 3371           !(attr->attrFlags & SA_IMM_ATTR_CACHED)) {
 3372         attr->attrFlags |= SA_IMM_ATTR_CACHED;
 3373         LOG_NO(
 3374             "persistent implies cached as of SAI-AIS-IMM-A.02.01 "
 3375             "class:%s atrName:%s - corrected",
 3376             className.c_str(), attNm);
 3377       }
 3378 
 3379       if (attr->attrFlags & SA_IMM_ATTR_WRITABLE) {
 3380         LOG_NO(
 3381             "ERR_INVALID_PARAM: Runtime attribute '%s' can not be declared "
 3382             "SA_IMM_ATTR_WRITABLE",
 3383             attNm);
 3384         illegal = 1;
 3385       }
 3386 
 3387       if (attr->attrFlags & SA_IMM_ATTR_INITIALIZED) {
 3388         LOG_NO(
 3389             "ERR_INVALID_PARAM: Runtime attribute '%s' can not be declared "
 3390             "SA_IMM_ATTR_INITIALIZED",
 3391             attNm);
 3392         illegal = 1;
 3393       }
 3394 
 3395       if ((req->classCategory == SA_IMM_CLASS_RUNTIME) &&
 3396           (attr->attrFlags & SA_IMM_ATTR_PERSISTENT)) {
 3397         TRACE_5("PERSISTENT RT %s:%s", className.c_str(), attNm);
 3398         persistentRt = true;
 3399         if (attr->attrFlags & SA_IMM_ATTR_RDN) {
 3400           TRACE_5("PERSISTENT RT && PERSISTENT RDN %s:%s", className.c_str(),
 3401                   attNm);
 3402           persistentRdn = true;
 3403         }
 3404       }
 3405 
 3406       if ((attr->attrFlags & SA_IMM_ATTR_NOTIFY) &&
 3407           !(attr->attrFlags & SA_IMM_ATTR_CACHED)) {
 3408         LOG_NO(
 3409             "ERR_INVALID_PARAM: Runtime attribute:%s is not cached =>"
 3410             "can not be delcared SA_IMM_ATTR_NOTIFY",
 3411             attNm);
 3412         illegal = 1;
 3413       }
 3414     } else {
 3415       LOG_NO(
 3416           "ERR_INVALID_PARAM: Attribute '%s' is neither SA_IMM_ATTR_CONFIG nor "
 3417           "SA_IMM_ATTR_RUNTIME",
 3418           attNm);
 3419       illegal = 1;
 3420     }
 3421 
 3422     if (attr->attrFlags & SA_IMM_ATTR_RDN) {
 3423       ++rdns;
 3424 
 3425       if ((req->classCategory == SA_IMM_CLASS_CONFIG) &&
 3426           (attr->attrFlags & SA_IMM_ATTR_RUNTIME)) {
 3427         LOG_NO(
 3428             "ERR_INVALID_PARAM: RDN '%s' of a configuration object "
 3429             "can not be a runtime attribute",
 3430             attNm);
 3431         illegal = 1;
 3432       }
 3433 
 3434       if (attr->attrFlags & SA_IMM_ATTR_WRITABLE) {
 3435         LOG_NO(
 3436             "ERR_INVALID_PARAM: RDN attribute '%s' can not be SA_IMM_ATTR_WRITABLE",
 3437             attNm);
 3438         illegal = 1;
 3439       }
 3440 
 3441       if ((req->classCategory == SA_IMM_CLASS_RUNTIME) &&
 3442           !(attr->attrFlags & SA_IMM_ATTR_CACHED)) {
 3443         LOG_NO(
 3444             "ERR_INVALID_PARAM: RDN '%s' of a runtime object must be declared "
 3445             "cached",
 3446             attNm);
 3447         illegal = 1;
 3448       }
 3449 
 3450       if (attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) {
 3451         LOG_NO("ERR_INVALID_PARAM: RDN '%s' cannot have NO_DANGLING flag",
 3452                attNm);
 3453         illegal = 1;
 3454       }
 3455 
 3456       if (attr->attrFlags & SA_IMM_ATTR_DEFAULT_REMOVED) {
 3457         LOG_NO(
 3458             "ERR_INVALID_PARAM: RDN '%s' cannot have SA_IMM_ATTR_DEFAULT_REMOVED flag",
 3459             attNm);
 3460         illegal = 1;
 3461       }
 3462 
 3463       if (attr->attrFlags & SA_IMM_ATTR_STRONG_DEFAULT) {
 3464         LOG_NO(
 3465             "ERR_INVALID_PARAM: RDN '%s' cannot have SA_IMM_ATTR_STRONG_DEFAULT flag",
 3466             attNm);
 3467         illegal = 1;
 3468       }
 3469     }
 3470 
 3471     if (attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) {
 3472       if (req->classCategory == SA_IMM_CLASS_RUNTIME) {
 3473         LOG_NO(
 3474             "ERR_INVALID_PARAM: Runtime object '%s' cannot have NO_DANGLING "
 3475             "attribute",
 3476             attNm);
 3477         illegal = 1;
 3478       }
 3479 
 3480       if (attr->attrValueType != SA_IMM_ATTR_SANAMET &&
 3481           !((attr->attrFlags & SA_IMM_ATTR_DN) &&
 3482             (attr->attrValueType == SA_IMM_ATTR_SASTRINGT))) {
 3483         LOG_NO(
 3484             "ERR_INVALID_PARAM: Attribute '%s' must be of type SaNameT, "
 3485             "or of type SaStringT with DN flag",
 3486             attNm);
 3487         illegal = 1;
 3488       }
 3489 
 3490       if (attr->attrFlags & SA_IMM_ATTR_RUNTIME) {
 3491         LOG_NO(
 3492             "ERR_INVALID_PARAM: Runtime attribute '%s' cannot have "
 3493             "NO_DANGLING flag",
 3494             attNm);
 3495         illegal = 1;
 3496       }
 3497     }
 3498 
 3499     if ((attr->attrFlags & SA_IMM_ATTR_DN) &&
 3500         (attr->attrValueType != SA_IMM_ATTR_SASTRINGT)) {
 3501       LOG_NO(
 3502           "ERR_INVALID_PARAM: Attribute '%s' has SA_IMM_ATTR_DN flag, "
 3503           "but the attribute is not of type SaStringT",
 3504           attNm);
 3505       illegal = 1;
 3506     }
 3507 
 3508     if ((attr->attrFlags & SA_IMM_ATTR_DEFAULT_REMOVED) && !isLoading &&
 3509         !schemaChange) {
 3510       LOG_NO(
 3511           "ERR_INVALID_PARAM: Attribute '%s' has SA_IMM_ATTR_DEFAULT_REMOVED flag, "
 3512           "but this flag is only available for schema changes",
 3513           attNm);
 3514       illegal = 1;
 3515     }
 3516 
 3517     if (attr->attrFlags & SA_IMM_ATTR_STRONG_DEFAULT) {
 3518       if (!attr->attrDefaultValue) {
 3519         LOG_NO(
 3520             "ERR_INVALID_PARAM: Attribute '%s' can not have SA_IMM_ATTR_STRONG_DEFAULT flag "
 3521             "without having a default value",
 3522             attNm);
 3523         illegal = 1;
 3524       }
 3525 
 3526       if (attr->attrFlags & SA_IMM_ATTR_DEFAULT_REMOVED) {
 3527         LOG_NO(
 3528             "ERR_INVALID_PARAM: Attribute '%s' can not have both SA_IMM_ATTR_STRONG_DEFAULT flag "
 3529             "and SA_IMM_ATTR_DEFAULT_REMOVED flag",
 3530             attNm);
 3531         illegal = 1;
 3532       }
 3533     }
 3534 
 3535     if (attr->attrDefaultValue) {
 3536       if (attr->attrFlags & SA_IMM_ATTR_RDN) {
 3537         LOG_NO("ERR_INVALID_PARAM: RDN '%s' can not have a default", attNm);
 3538         illegal = 1;
 3539       }
 3540 
 3541       if ((attr->attrFlags & SA_IMM_ATTR_RUNTIME) &&
 3542           !(attr->attrFlags & SA_IMM_ATTR_CACHED) &&
 3543           !(attr->attrFlags & SA_IMM_ATTR_PERSISTENT)) {
 3544         LOG_NO(
 3545             "ERR_INVALID_PARAM: Runtime attribute '%s' is neither cached nor "
 3546             "persistent => can not have a default",
 3547             attNm);
 3548         illegal = 1;
 3549       }
 3550 
 3551       if (attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) {
 3552         if (isLoading) {
 3553           LOG_WA(
 3554               "Attribute '%s' of class '%s' has a default no-dangling reference, "
 3555               "the class definition should be corrected",
 3556               attNm, className.c_str());
 3557         } else {
 3558           LOG_NO(
 3559               "ERR_INVALID_PARAM: No dangling attribute '%s' can not have a default",
 3560               attNm);
 3561           illegal = 1;
 3562         }
 3563       }
 3564 
 3565       if (attr->attrFlags & SA_IMM_ATTR_INITIALIZED) {
 3566         LOG_NO(
 3567             "ERR_INVALID_PARAM: Attribute %s declared as SA_IMM_ATTR_INITIALIZED "
 3568             "inconsistent with having default",
 3569             attNm);
 3570         illegal = 1;
 3571       }
 3572 
 3573       if (attr->attrFlags & SA_IMM_ATTR_DEFAULT_REMOVED) {
 3574         LOG_NO(
 3575             "ERR_INVALID_PARAM: Attribute '%s' can not have a default with SA_IMM_ATTR_DEFAULT_REMOVED",
 3576             attNm);
 3577         illegal = 1;
 3578       }
 3579 
 3580       if (attr->attrValueType == SA_IMM_ATTR_SANAMET) {
 3581         immsv_edu_attr_val* v = attr->attrDefaultValue;
 3582         if (!getLongDnsAllowed() &&
 3583             v->val.x.size >= SA_MAX_UNEXTENDED_NAME_LENGTH) {
 3584           LOG_NO(
 3585               "ERR_LIBRARY: attr '%s' of type SaNameT is too long:%u. "
 3586               "Extended names is not enabled",
 3587               attNm, v->val.x.size - 1);
 3588           err = SA_AIS_ERR_LIBRARY;
 3589           illegal = 1;
 3590         } else if (v->val.x.size > kOsafMaxDnLength) {
 3591           LOG_NO("ERR_LIBRARY: attr '%s' of type SaNameT is too long:%u", attNm,
 3592                  v->val.x.size - 1);
 3593           err = SA_AIS_ERR_LIBRARY;
 3594           illegal = 1;
 3595         } else {
 3596           std::string tmpName(v->val.x.buf,
 3597                               v->val.x.size ? v->val.x.size - 1 : 0);
 3598           if (!(nameCheck(tmpName) || nameToInternal(tmpName))) {
 3599             LOG_NO(
 3600                 "ERR_INVALID_PARAM: attr '%s' of type SaNameT contains non "
 3601                 "printable characters",
 3602                 attNm);
 3603             err = SA_AIS_ERR_INVALID_PARAM;
 3604             illegal = 1;
 3605           }
 3606         }
 3607       } else if (attr->attrValueType == SA_IMM_ATTR_SASTRINGT) {
 3608         immsv_edu_attr_val* v = attr->attrDefaultValue;
 3609         if (v->val.x.size && !(osaf_is_valid_utf8(v->val.x.buf))) {
 3610           LOG_NO(
 3611               "ERR_INVALID_PARAM: Attribute '%s' defined on type SaStringT "
 3612               "has a default value that is not valid UTF-8",
 3613               attrName.c_str());
 3614           illegal = 1;
 3615         }
 3616       }
 3617     }
 3618     err = attrCreate(classInfo, attr, attrName);
 3619     if (err == SA_AIS_ERR_NOT_SUPPORTED) {
 3620       useUnknownFlag = true;
 3621       err = SA_AIS_OK;
 3622     } else if (err != SA_AIS_OK) {
 3623       illegal = 1;
 3624     }
 3625     list = list->next;
 3626   }  // while(list)
 3627 
 3628   if (persistentRt && !persistentRdn) {
 3629     LOG_NO(
 3630         "ERR_INVALID_PARAM: Class for persistent runtime object requires "
 3631         "persistent RDN");
 3632     illegal = 1;
 3633   }
 3634 
 3635   if (rdns != 1) {
 3636     LOG_NO(
 3637         "ERR_INVALID_PARAM: ONE and only ONE RDN attribute must be defined!");
 3638     illegal = 1;
 3639   }
 3640 
 3641   if (schemaChange && !illegal) {
 3642     /*
 3643      If all basic checks passed and this is an upgrade, do upgrade specific
 3644      checks.
 3645     */
 3646     if (verifySchemaChange(className, prevClassInfo, classInfo, newAttrs,
 3647                            changedAttrs)) {
 3648       LOG_NO(
 3649           "Schema change for class %s ACCEPTED. Adding %u and changing %u attribute defs",
 3650           className.c_str(), (unsigned int)newAttrs.size(),
 3651           (unsigned int)changedAttrs.size());
 3652     } else {
 3653       LOG_NO("ERR_EXIST: Class '%s' exist - possible failed schema upgrade",
 3654              className.c_str());
 3655       err = SA_AIS_ERR_EXIST;
 3656       illegal = 1;
 3657     }
 3658   }
 3659 
 3660   if (illegal) {
 3661     if (err == SA_AIS_OK) {
 3662       LOG_NO("ERR_INVALID_PARAM: Problem with new class '%s'",
 3663              className.c_str());
 3664       err = SA_AIS_ERR_INVALID_PARAM;
 3665     }
 3666 
 3667     AttrMap::iterator ai = classInfo->mAttrMap.begin();
 3668     while (ai != classInfo->mAttrMap.end()) {
 3669       AttrInfo* ainfo = ai->second;
 3670       osafassert(ainfo);
 3671       delete (ainfo);
 3672       ++ai;
 3673     }
 3674     classInfo->mAttrMap.clear();
 3675 
 3676     if (!schemaChange) {
 3677       delete classInfo;
 3678     }
 3679     classInfo = NULL;
 3680     goto done;
 3681   }
 3682 
 3683   if (useUnknownFlag) {
 3684     LOG_NO("At least one attribute in class %s has unsupported attribute flag",
 3685            className.c_str());
 3686   }
 3687 
 3688   /* All checks passed, now install the class def. */
 3689 
 3690   if (!schemaChange) {
 3691     /* Normal case, install the brand new class. */
 3692     sClassMap[className] = classInfo;
 3693     updateImmObject(className);
 3694   } else {
 3695     /* Schema upgrade case, Change the attr defs. */
 3696     AttrMap::iterator ai;
 3697     AttrMap::iterator pcai;  // for prevClassInfo->mAttrMap
 3698     AttrInfo* ainfo = NULL;
 3699     ObjectSet::iterator oi;
 3700     bool hasNoDanglingRefChanges = false;
 3701     osafassert(prevClassInfo);
 3702 
 3703     /* Add NO_DANGLING flag changes */
 3704     for (ai = newAttrs.begin(); ai != newAttrs.end(); ++ai) {
 3705       if (ai->second->mFlags & SA_IMM_ATTR_NO_DANGLING) {
 3706         hasNoDanglingRefChanges = true;
 3707         break;
 3708       }
 3709     }
 3710     if (!hasNoDanglingRefChanges) {
 3711       for (ai = changedAttrs.begin(); ai != changedAttrs.end(); ++ai) {
 3712         if (ai->second->mFlags & SA_IMM_ATTR_NO_DANGLING) {
 3713           hasNoDanglingRefChanges = true;
 3714           break;
 3715         }
 3716         // Check NO_DANGLING flag of the attribute in the previous class
 3717         if ((pcai = prevClassInfo->mAttrMap.find(ai->first)) !=
 3718                 prevClassInfo->mAttrMap.end() &&
 3719             (pcai->second->mFlags & SA_IMM_ATTR_NO_DANGLING)) {
 3720           hasNoDanglingRefChanges = true;
 3721           break;
 3722         }
 3723       }
 3724     }
 3725 
 3726     if (hasNoDanglingRefChanges) {
 3727       // Remove all no dangling references from all objects of the class
 3728       for (oi = prevClassInfo->mExtent.begin();
 3729            oi != prevClassInfo->mExtent.end(); ++oi) {
 3730         removeNoDanglingRefs(*oi, *oi);
 3731       }
 3732     }
 3733 
 3734     /* Remove old attr defs. */
 3735     ai = prevClassInfo->mAttrMap.begin();
 3736     while (ai != prevClassInfo->mAttrMap.end()) {
 3737       TRACE_5("Removing old attribute %s:%s", className.c_str(),
 3738               ai->first.c_str());
 3739       ainfo = ai->second;
 3740       osafassert(ainfo);
 3741       delete (ainfo);
 3742       ++ai;
 3743     }
 3744     prevClassInfo->mAttrMap.clear();
 3745 
 3746     /* Move new attr defs from dummyClass to existing ClassInfo object.
 3747        This leaves references from existing instances to the ClassInfo intact.
 3748     */
 3749     for (ai = dummyClass.mAttrMap.begin(); ai != dummyClass.mAttrMap.end();
 3750          ++ai) {
 3751       TRACE_5("Inserting attribute %s:%s", className.c_str(),
 3752               ai->first.c_str());
 3753       prevClassInfo->mAttrMap[ai->first] = ai->second;
 3754     }
 3755     dummyClass.mAttrMap.clear();
 3756 
 3757     /* Migrate instances. */
 3758     if ((prevClassInfo->mExtent.empty())) {
 3759       LOG_NO("No instances to migrate - schema change could have been avoided");
 3760     } else { /* There are instances. */
 3761       CcbVector::iterator ci;
 3762       ObjectMutationMap::iterator omit;
 3763       ObjectMutation* omut = NULL;
 3764 
 3765       /* Migrate current version of instances. */
 3766       for (oi = prevClassInfo->mExtent.begin();
 3767            oi != prevClassInfo->mExtent.end(); ++oi) {
 3768         osafassert((*oi)->mClassInfo == prevClassInfo);
 3769         migrateObj(*oi, className, newAttrs, changedAttrs);
 3770       }
 3771 
 3772       /* Migrate new versions of modify of instances, in active CCBs */
 3773       for (ci = sCcbVector.begin(); ci != sCcbVector.end(); ++ci) {
 3774         CcbInfo* ccb = (*ci);
 3775         if (ccb->isActive()) {
 3776           for (omit = ccb->mMutations.begin(); omit != ccb->mMutations.end();
 3777                ++omit) {
 3778             omut = omit->second;
 3779             if (omut->mOpType == IMM_MODIFY && omut->mAfterImage &&
 3780                 omut->mAfterImage->mClassInfo == prevClassInfo) {
 3781               migrateObj(omut->mAfterImage, className, newAttrs, changedAttrs);
 3782             }
 3783           }
 3784         }
 3785       }
 3786 
 3787       /* Migrate new versions of modify of instances for ongoing PBE PRTA data
 3788        * updates */
 3789       for (omit = sPbeRtMutations.begin(); omit != sPbeRtMutations.end();
 3790            ++omit) {
 3791         omut = omit->second;
 3792         if (omut->mOpType == IMM_MODIFY && omut->mAfterImage &&
 3793             omut->mAfterImage->mClassInfo == prevClassInfo) {
 3794           migrateObj(omut->mAfterImage, className, newAttrs, changedAttrs);
 3795         }
 3796       }
 3797 
 3798       if (hasNoDanglingRefChanges) {
 3799         // Set back no dangling references for all objects
 3800         for (oi = prevClassInfo->mExtent.begin();
 3801              oi != prevClassInfo->mExtent.end(); ++oi) {
 3802           addNoDanglingRefs(*oi);
 3803         }
 3804       }
 3805     }
 3806 
 3807     LOG_NO("Schema change completed for class %s %s", className.c_str(),
 3808            pbeNodeIdPtr ? "(PBE changes still pending)." : "");
 3809   } /* end of schema upgrade case. */
 3810 
 3811   if (pbeNodeIdPtr) {
 3812     if (!getPbeOi(pbeConnPtr, pbeNodeIdPtr)) {
 3813       LOG_ER("Pbe is not available, can not happen here");
 3814       abort();
 3815     }
 3816     if (++sLastContinuationId >= 0xfffffffe) {
 3817       sLastContinuationId = 1;
 3818     }
 3819     (*continuationIdPtr) = sLastContinuationId;
 3820 
 3821     osafassert(sPbeRtMutations.find(className) == sPbeRtMutations.end());
 3822     /* Create a mutation record to bar pbe restart --recover  */
 3823 
 3824     ObjectMutation* oMut = new ObjectMutation(IMM_CREATE_CLASS);
 3825     oMut->mContinuationId = (*continuationIdPtr);
 3826     oMut->mAfterImage = NULL;
 3827     sPbeRtMutations[className] = oMut;
 3828 
 3829     if (reqConn) {
 3830       SaInvocationT tmp_hdl = m_IMMSV_PACK_HANDLE((*continuationIdPtr), nodeId);
 3831       sPbeRtReqContinuationMap[tmp_hdl] =
 3832           ContinuationInfo2(reqConn, DEFAULT_TIMEOUT_SEC);
 3833     }
 3834   }
 3835 
 3836 done:
 3837   TRACE_LEAVE();
 3838   return err;
 3839 }
 3840 
 3841 void ImmModel::migrateObj(ObjectInfo* object, std::string className,
 3842                           AttrMap& newAttrs, AttrMap& changedAttrs) {
 3843   AttrMap::iterator ai;
 3844   ImmAttrValue* attrValue = NULL;
 3845   std::string
 3846       objectDn; /* objectDn only used for trace/log => external rep ok. */
 3847   getObjectName(object, objectDn);
 3848 
 3849   TRACE_5("Migrating %s object %s", className.c_str(), objectDn.c_str());
 3850 
 3851   /* Add new attributes to instances. */
 3852   for (ai = newAttrs.begin(); ai != newAttrs.end(); ++ai) {
 3853     AttrInfo* attr = ai->second;
 3854 
 3855     if (attr->mFlags & SA_IMM_ATTR_MULTI_VALUE) {
 3856       if (attr->mDefaultValue.empty()) {
 3857         attrValue = new ImmAttrMultiValue();
 3858       } else {
 3859         attrValue = new ImmAttrMultiValue(attr->mDefaultValue);
 3860       }
 3861     } else {
 3862       if (attr->mDefaultValue.empty()) {
 3863         attrValue = new ImmAttrValue();
 3864       } else {
 3865         attrValue = new ImmAttrValue(attr->mDefaultValue);
 3866       }
 3867     }
 3868     object->mAttrValueMap[ai->first] = attrValue;
 3869   }
 3870 
 3871   /* Adjust existing attributes.*/
 3872   ImmAttrValueMap::iterator oavi;
 3873   for (oavi = object->mAttrValueMap.begin();
 3874        oavi != object->mAttrValueMap.end(); ++oavi) {
 3875     /*
 3876        TRACE_5("CHECKING existing attribute %s:%s for object %s",
 3877        className.c_str(), oavi->first.c_str(), objectDn.c_str());
 3878     */
 3879 
 3880     /* Change from single to multi-value requires change of value rep.*/
 3881     ai = changedAttrs.find(oavi->first);
 3882     if (ai != changedAttrs.end()) {
 3883       if ((ai->second->mFlags & SA_IMM_ATTR_MULTI_VALUE) &&
 3884           (!oavi->second->isMultiValued())) {
 3885         attrValue = new ImmAttrMultiValue(*(oavi->second));
 3886         TRACE_5(
 3887             "Schema change adjusted attribute %s in object:%s "
 3888             "to be multivalued",
 3889             oavi->first.c_str(), objectDn.c_str());
 3890         delete oavi->second;
 3891         object->mAttrValueMap[ai->first] = attrValue;
 3892       }
 3893     }
 3894 
 3895     /* Correct object->mAdminOwnerAttrVal. */
 3896     if (oavi->first == std::string(SA_IMM_ATTR_ADMIN_OWNER_NAME)) {
 3897       object->mAdminOwnerAttrVal = oavi->second;
 3898       TRACE_5("Schema change corrected attr %s in object:%s",
 3899               oavi->first.c_str(), objectDn.c_str());
 3900     }
 3901   }
 3902 }
 3903 
 3904 bool ImmModel::oneSafe2PBEAllowed() {
 3905   // TRACE_ENTER();
 3906   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 3907   if (oi == sObjectMap.end()) {
 3908     // TRACE_LEAVE();
 3909     return false;
 3910   }
 3911 
 3912   ObjectInfo* immObject = oi->second;
 3913   ImmAttrValueMap::iterator avi =
 3914       immObject->mAttrValueMap.find(immAttrNostFlags);
 3915   osafassert(avi != immObject->mAttrValueMap.end());
 3916   osafassert(!(avi->second->isMultiValued()));
 3917   ImmAttrValue* valuep = avi->second;
 3918   unsigned int noStdFlags = valuep->getValue_int();
 3919 
 3920   // TRACE_LEAVE();
 3921   return noStdFlags & OPENSAF_IMM_FLAG_2PBE1_ALLOW;
 3922 }
 3923 
 3924 bool ImmModel::protocol43Allowed() {
 3925   // TRACE_ENTER();
 3926   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 3927   if (oi == sObjectMap.end()) {
 3928     // TRACE_LEAVE();
 3929     return false;
 3930   }
 3931 
 3932   ObjectInfo* immObject = oi->second;
 3933   ImmAttrValueMap::iterator avi =
 3934       immObject->mAttrValueMap.find(immAttrNostFlags);
 3935   osafassert(avi != immObject->mAttrValueMap.end());
 3936   osafassert(!(avi->second->isMultiValued()));
 3937   ImmAttrValue* valuep = avi->second;
 3938   unsigned int noStdFlags = valuep->getValue_int();
 3939 
 3940   // TRACE_LEAVE();
 3941   return noStdFlags & OPENSAF_IMM_FLAG_PRT43_ALLOW;
 3942 }
 3943 
 3944 bool ImmModel::protocol45Allowed() {
 3945   // TRACE_ENTER();
 3946   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 3947   if (oi == sObjectMap.end()) {
 3948     // TRACE_LEAVE();
 3949     return false;
 3950   }
 3951 
 3952   ObjectInfo* immObject = oi->second;
 3953   ImmAttrValueMap::iterator avi =
 3954       immObject->mAttrValueMap.find(immAttrNostFlags);
 3955   osafassert(avi != immObject->mAttrValueMap.end());
 3956   osafassert(!(avi->second->isMultiValued()));
 3957   ImmAttrValue* valuep = avi->second;
 3958   unsigned int noStdFlags = valuep->getValue_int();
 3959 
 3960   // TRACE_LEAVE();
 3961   return noStdFlags & OPENSAF_IMM_FLAG_PRT45_ALLOW;
 3962 }
 3963 
 3964 bool ImmModel::protocol46Allowed() {
 3965   // TRACE_ENTER();
 3966   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 3967   if (oi == sObjectMap.end()) {
 3968     // TRACE_LEAVE();
 3969     return false;
 3970   }
 3971 
 3972   ObjectInfo* immObject = oi->second;
 3973   ImmAttrValueMap::iterator avi =
 3974       immObject->mAttrValueMap.find(immAttrNostFlags);
 3975   osafassert(avi != immObject->mAttrValueMap.end());
 3976   osafassert(!(avi->second->isMultiValued()));
 3977   ImmAttrValue* valuep = avi->second;
 3978   unsigned int noStdFlags = valuep->getValue_int();
 3979 
 3980   // TRACE_LEAVE();
 3981   return noStdFlags & OPENSAF_IMM_FLAG_PRT46_ALLOW;
 3982 }
 3983 
 3984 bool ImmModel::protocol47Allowed() {
 3985   // TRACE_ENTER();
 3986   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 3987   if (oi == sObjectMap.end()) {
 3988     // TRACE_LEAVE();
 3989     return false;
 3990   }
 3991 
 3992   ObjectInfo* immObject = oi->second;
 3993   ImmAttrValueMap::iterator avi =
 3994       immObject->mAttrValueMap.find(immAttrNostFlags);
 3995   osafassert(avi != immObject->mAttrValueMap.end());
 3996   osafassert(!(avi->second->isMultiValued()));
 3997   ImmAttrValue* valuep = avi->second;
 3998   unsigned int noStdFlags = valuep->getValue_int();
 3999 
 4000   // TRACE_LEAVE();
 4001   return noStdFlags & OPENSAF_IMM_FLAG_PRT47_ALLOW;
 4002 }
 4003 
 4004 bool ImmModel::protocol50Allowed() {
 4005   // TRACE_ENTER();
 4006   /* Assume that all nodes are running the same version when loading */
 4007   if (sImmNodeState == IMM_NODE_LOADING) {
 4008     return true;
 4009   }
 4010   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4011   if (oi == sObjectMap.end()) {
 4012     // TRACE_LEAVE();
 4013     return false;
 4014   }
 4015 
 4016   ObjectInfo* immObject = oi->second;
 4017   ImmAttrValueMap::iterator avi =
 4018       immObject->mAttrValueMap.find(immAttrNostFlags);
 4019   osafassert(avi != immObject->mAttrValueMap.end());
 4020   osafassert(!(avi->second->isMultiValued()));
 4021   ImmAttrValue* valuep = avi->second;
 4022   unsigned int noStdFlags = valuep->getValue_int();
 4023 
 4024   // TRACE_LEAVE();
 4025   return noStdFlags & OPENSAF_IMM_FLAG_PRT50_ALLOW;
 4026 }
 4027 
 4028 bool ImmModel::protocol51Allowed() {
 4029   // TRACE_ENTER();
 4030   /* Assume that all nodes are running the same version when loading */
 4031   if (sImmNodeState == IMM_NODE_LOADING) {
 4032     return true;
 4033   }
 4034   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4035   if (oi == sObjectMap.end()) {
 4036     // TRACE_LEAVE();
 4037     return false;
 4038   }
 4039 
 4040   ObjectInfo* immObject = oi->second;
 4041   ImmAttrValueMap::iterator avi =
 4042       immObject->mAttrValueMap.find(immAttrNostFlags);
 4043   osafassert(avi != immObject->mAttrValueMap.end());
 4044   osafassert(!(avi->second->isMultiValued()));
 4045   ImmAttrValue* valuep = avi->second;
 4046   unsigned int noStdFlags = valuep->getValue_int();
 4047 
 4048   // TRACE_LEAVE();
 4049   return noStdFlags & OPENSAF_IMM_FLAG_PRT51_ALLOW;
 4050 }
 4051 
 4052 bool ImmModel::protocol51710Allowed() {
 4053   // TRACE_ENTER();
 4054   /* Assume that all nodes are running the same version when loading */
 4055   if (sImmNodeState == IMM_NODE_LOADING) {
 4056     return true;
 4057   }
 4058   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4059   if (oi == sObjectMap.end()) {
 4060     // TRACE_LEAVE();
 4061     return false;
 4062   }
 4063 
 4064   ObjectInfo* immObject = oi->second;
 4065   ImmAttrValueMap::iterator avi =
 4066       immObject->mAttrValueMap.find(immAttrNostFlags);
 4067   osafassert(avi != immObject->mAttrValueMap.end());
 4068   osafassert(!(avi->second->isMultiValued()));
 4069   ImmAttrValue* valuep = avi->second;
 4070   unsigned int noStdFlags = valuep->getValue_int();
 4071 
 4072   // TRACE_LEAVE();
 4073   return noStdFlags & OPENSAF_IMM_FLAG_PRT51710_ALLOW;
 4074 }
 4075 
 4076 bool ImmModel::protocol51906Allowed() {
 4077   /* Assume that all nodes are running the same version when loading */
 4078   if (sImmNodeState == IMM_NODE_LOADING) {
 4079     return true;
 4080   }
 4081   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4082   if (oi == sObjectMap.end()) {
 4083     return false;
 4084   }
 4085 
 4086   ObjectInfo* immObject = oi->second;
 4087   ImmAttrValueMap::iterator avi =
 4088       immObject->mAttrValueMap.find(immAttrNostFlags);
 4089   osafassert(avi != immObject->mAttrValueMap.end());
 4090   osafassert(!(avi->second->isMultiValued()));
 4091   ImmAttrValue* valuep = avi->second;
 4092   unsigned int noStdFlags = valuep->getValue_int();
 4093 
 4094   return noStdFlags & OPENSAF_IMM_FLAG_PRT51906_ALLOW;
 4095 }
 4096 
 4097 bool ImmModel::protocol41Allowed() {
 4098   // TRACE_ENTER();
 4099   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4100   if (oi == sObjectMap.end()) {
 4101     // TRACE_LEAVE();
 4102     return false;
 4103   }
 4104 
 4105   ObjectInfo* immObject = oi->second;
 4106   ImmAttrValueMap::iterator avi =
 4107       immObject->mAttrValueMap.find(immAttrNostFlags);
 4108   osafassert(avi != immObject->mAttrValueMap.end());
 4109   osafassert(!(avi->second->isMultiValued()));
 4110   ImmAttrValue* valuep = avi->second;
 4111   unsigned int noStdFlags = valuep->getValue_int();
 4112 
 4113   // TRACE_LEAVE();
 4114   return noStdFlags & OPENSAF_IMM_FLAG_PRT41_ALLOW;
 4115 }
 4116 
 4117 bool ImmModel::schemaChangeAllowed() {
 4118   TRACE_ENTER();
 4119   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4120   if (oi == sObjectMap.end()) {
 4121     TRACE_LEAVE();
 4122     return false;
 4123   }
 4124 
 4125   ObjectInfo* immObject = oi->second;
 4126   ImmAttrValueMap::iterator avi =
 4127       immObject->mAttrValueMap.find(immAttrNostFlags);
 4128   osafassert(avi != immObject->mAttrValueMap.end());
 4129   osafassert(!(avi->second->isMultiValued()));
 4130   ImmAttrValue* valuep = avi->second;
 4131   unsigned int noStdFlags = valuep->getValue_int();
 4132 
 4133   TRACE_LEAVE();
 4134   return noStdFlags & OPENSAF_IMM_FLAG_SCHCH_ALLOW;
 4135 }
 4136 
 4137 OsafImmAccessControlModeT ImmModel::accessControlMode() {
 4138   TRACE_ENTER();
 4139   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4140   if (oi == sObjectMap.end()) {
 4141     TRACE_LEAVE();
 4142     return ACCESS_CONTROL_DISABLED;
 4143   }
 4144 
 4145   ObjectInfo* immObject = oi->second;
 4146   ImmAttrValueMap::iterator avi =
 4147       immObject->mAttrValueMap.find(immAccessControlMode);
 4148   if (avi == immObject->mAttrValueMap.end()) {
 4149     return ACCESS_CONTROL_DISABLED;
 4150   }
 4151   osafassert(!(avi->second->isMultiValued()));
 4152   ImmAttrValue* valuep = avi->second;
 4153   OsafImmAccessControlModeT accessControlMode =
 4154       static_cast<OsafImmAccessControlModeT>(valuep->getValue_int());
 4155 
 4156   TRACE_LEAVE2("%u", accessControlMode);
 4157   return accessControlMode;
 4158 }
 4159 
 4160 const char* ImmModel::authorizedGroup() {
 4161   TRACE_ENTER();
 4162   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 4163   if (oi == sObjectMap.end()) {
 4164     TRACE_LEAVE();
 4165     return NULL;
 4166   }
 4167 
 4168   ObjectInfo* immObject = oi->second;
 4169   ImmAttrValueMap::iterator avi =
 4170       immObject->mAttrValueMap.find(immAuthorizedGroup);
 4171   if (avi == immObject->mAttrValueMap.end()) {
 4172     return NULL;
 4173   }
 4174   osafassert(!(avi->second->isMultiValued()));
 4175   ImmAttrValue* valuep = avi->second;
 4176   const char* adminGroupName = valuep->getValueC_str();
 4177 
 4178   TRACE_LEAVE();
 4179   return adminGroupName;
 4180 }
 4181 
 4182 /**
 4183  * Verify that a class create with same name as an existing class is a legal
 4184  * schema upgrade.
 4185  */
 4186 bool ImmModel::verifySchemaChange(const std::string& className,
 4187                                   ClassInfo* oldClassInfo,
 4188                                   ClassInfo* newClassInfo, AttrMap& newAttrs,
 4189                                   AttrMap& changedAttrs) {
 4190   AttrMap::iterator iold;
 4191   AttrMap::iterator inew;
 4192   bool verifyFailed = false;
 4193   TRACE_ENTER2("ClassName:%s", className.c_str());
 4194   osafassert(oldClassInfo && newClassInfo);
 4195   unsigned int oldCount = (unsigned int)oldClassInfo->mAttrMap.size();
 4196   unsigned int newCount = (unsigned int)newClassInfo->mAttrMap.size();
 4197   if (oldCount > newCount) {
 4198     LOG_NO(
 4199         "Impossible upgrade, new class descr for '%s' has fewer "
 4200         "attributes %u than existing %u.",
 4201         className.c_str(), newCount, oldCount);
 4202     return false;
 4203   }
 4204 
 4205   if (oldClassInfo->mCategory != newClassInfo->mCategory) {
 4206     LOG_NO(
 4207         "Impossible upgrade, new class descr for '%s' not of "
 4208         "same category as existing.",
 4209         className.c_str());
 4210     return false;
 4211   }
 4212 
 4213   /* Verify that all old attrs exist in new. */
 4214 
 4215   for (iold = oldClassInfo->mAttrMap.begin();
 4216        iold != oldClassInfo->mAttrMap.end(); ++iold) {
 4217     std::string attName = iold->first;
 4218     inew = newClassInfo->mAttrMap.find(attName);
 4219     if (inew == newClassInfo->mAttrMap.end()) {
 4220       LOG_NO("Attribute %s missing in new class def.", attName.c_str());
 4221       verifyFailed = true;
 4222     } else {
 4223       --oldCount;
 4224     }
 4225   }
 4226 
 4227   if (verifyFailed) {
 4228     return false;
 4229   }
 4230 
 4231   osafassert(oldCount == 0); /* Yes this check is redundant. */
 4232 
 4233   /* Check compatibility for all attrdefs in new class def. */
 4234   for (inew = newClassInfo->mAttrMap.begin();
 4235        inew != newClassInfo->mAttrMap.end(); ++inew) {
 4236     std::string attName = inew->first;
 4237     AttrInfo* newAttr = inew->second;
 4238     iold = oldClassInfo->mAttrMap.find(attName);
 4239     if (iold == oldClassInfo->mAttrMap.end()) {
 4240       LOG_NO("New attribute %s added by new class def", attName.c_str());
 4241       verifyFailed = notCompatibleAtt(className, newClassInfo, attName, NULL,
 4242                                       newAttr, NULL) ||
 4243                      verifyFailed;
 4244       newAttrs[inew->first] = newAttr;
 4245       if (!verifyFailed && (className == immClassName)) {
 4246         unsigned int val;
 4247         if (attName == immMaxClasses) {
 4248           val = newAttr->mDefaultValue.getValue_int();
 4249           if (sClassMap.size() > val) {
 4250             LOG_NO(
 4251                 "The Number of classes in the cluster %zu greater than the schema change"
 4252                 "value %d",
 4253                 sClassMap.size(), val);
 4254             verifyFailed = true;
 4255           }
 4256         }
 4257 
 4258         if (!verifyFailed && attName == immMaxImp) {
 4259           val = newAttr->mDefaultValue.getValue_int();
 4260           if (sImplementerVector.size() > val) {
 4261             LOG_NO(
 4262                 "The Number of Implementers in the cluster %zu greater than the schema change"
 4263                 "value %d",
 4264                 sImplementerVector.size(), val);
 4265             verifyFailed = true;
 4266           }
 4267         }
 4268 
 4269         if (!verifyFailed && attName == immMaxAdmOwn) {
 4270           val = newAttr->mDefaultValue.getValue_int();
 4271           if (sOwnerVector.size() > val) {
 4272             LOG_NO(
 4273                 "The Number of AdminOwners in the cluster %zu greater than the schema change"
 4274                 "value %d",
 4275                 sOwnerVector.size(), val);
 4276             verifyFailed = true;
 4277           }
 4278         }
 4279 
 4280         if (!verifyFailed && attName == immMaxCcbs) {
 4281           val = newAttr->mDefaultValue.getValue_int();
 4282           if ((sCcbVector.size() - sTerminatedCcbcount) > val) {
 4283             LOG_NO(
 4284                 "The Number of Ccbs in the cluster %zu greater than the schema change"
 4285                 "value %d",
 4286                 sCcbVector.size(), val);
 4287             verifyFailed = true;
 4288           }
 4289         }
 4290       }
 4291     } else {
 4292       TRACE_5("Existing attribute %s", attName.c_str());
 4293       verifyFailed = notCompatibleAtt(className, newClassInfo, attName,
 4294                                       iold->second, newAttr, &changedAttrs) ||
 4295                      verifyFailed;
 4296     }
 4297   }
 4298 
 4299   if (!verifyFailed && newAttrs.empty() && changedAttrs.empty()) {
 4300     LOG_WA("New class def is same as old, not a real schema upgrade");
 4301     verifyFailed = true;
 4302   }
 4303 
 4304   TRACE_LEAVE();
 4305   return !verifyFailed;
 4306 }
 4307 
 4308 bool ImmModel::notCompatibleAtt(const std::string& className,
 4309                                 ClassInfo* newClassInfo,
 4310                                 const std::string& attName,
 4311                                 const AttrInfo* oldAttr, AttrInfo* newAttr,
 4312                                 AttrMap* changedAttrs) {
 4313   if (oldAttr) {
 4314     /* Existing attribute, possibly changed. */
 4315     bool change = false;
 4316     bool checkCcb = false;
 4317     bool checkNoDup = false;
 4318     bool checkNoDanglingRefs = false;
 4319     bool checkStrongDefault = false;
 4320     osafassert(changedAttrs);
 4321     if (oldAttr->mValueType != newAttr->mValueType) {
 4322       LOG_NO("Impossible upgrade, attribute %s:%s changes value type",
 4323              className.c_str(), attName.c_str());
 4324       return true;
 4325     }
 4326 
 4327     if (oldAttr->mFlags != newAttr->mFlags) {
 4328       if ((oldAttr->mFlags & SA_IMM_ATTR_RUNTIME) !=
 4329           (newAttr->mFlags & SA_IMM_ATTR_RUNTIME)) {
 4330         LOG_NO(
 4331             "Impossible upgrade, attribute %s:%s changes flag "
 4332             "SA_IMM_ATTR_RUNTIME",
 4333             className.c_str(), attName.c_str());
 4334         return true;
 4335       }
 4336 
 4337       if ((oldAttr->mFlags & SA_IMM_ATTR_CONFIG) !=
 4338           (newAttr->mFlags & SA_IMM_ATTR_CONFIG)) {
 4339         LOG_NO(
 4340             "Impossible upgrade, attribute %s:%s changes flag "
 4341             "SA_IMM_ATTR_CONFIG",
 4342             className.c_str(), attName.c_str());
 4343         return true;
 4344       }
 4345 
 4346       if ((oldAttr->mFlags & SA_IMM_ATTR_CACHED) !=
 4347           (newAttr->mFlags & SA_IMM_ATTR_CACHED)) {
 4348         LOG_NO(
 4349             "Impossible upgrade, attribute %s:%s changes flag "
 4350             "SA_IMM_ATTR_CACHED",
 4351             className.c_str(), attName.c_str());
 4352         return true;
 4353       }
 4354 
 4355       if ((oldAttr->mFlags & SA_IMM_ATTR_RDN) !=
 4356           (newAttr->mFlags & SA_IMM_ATTR_RDN)) {
 4357         LOG_NO(
 4358             "Impossible upgrade, attribute %s:%s changes flag "
 4359             "SA_IMM_ATTR_RDN",
 4360             className.c_str(), attName.c_str());
 4361         return true;
 4362       }
 4363 
 4364       if ((oldAttr->mFlags & SA_IMM_ATTR_MULTI_VALUE) &&
 4365           !(newAttr->mFlags & SA_IMM_ATTR_MULTI_VALUE)) {
 4366         LOG_NO(
 4367             "Impossible upgrade, attribute %s:%s removes flag "
 4368             "SA_IMM_ATTR_MULTI_VALUE",
 4369             className.c_str(), attName.c_str());
 4370         return true;
 4371       }
 4372 
 4373       if (!(oldAttr->mFlags & SA_IMM_ATTR_MULTI_VALUE) &&
 4374           (newAttr->mFlags & SA_IMM_ATTR_MULTI_VALUE)) {
 4375         LOG_NO(
 4376             "Allowed upgrade, attribute %s:%s adds flag "
 4377             "SA_IMM_ATTR_MULTI_VALUE",
 4378             className.c_str(), attName.c_str());
 4379 
 4380         change = true; /* Instances NEED migration. */
 4381       }
 4382 
 4383       if ((oldAttr->mFlags & SA_IMM_ATTR_NO_DUPLICATES) &&
 4384           !(newAttr->mFlags & SA_IMM_ATTR_NO_DUPLICATES)) {
 4385         LOG_NO(
 4386             "Allowed upgrade, attribute %s:%s removes flag "
 4387             "SA_IMM_ATTR_NO_DUPLICATES",
 4388             className.c_str(), attName.c_str());
 4389         change = true; /* Instances dont need migration. */
 4390       }
 4391 
 4392       if (!(oldAttr->mFlags & SA_IMM_ATTR_NO_DUPLICATES) &&
 4393           (newAttr->mFlags & SA_IMM_ATTR_NO_DUPLICATES)) {
 4394         LOG_NO(
 4395             "Allowed upgrade, attribute %s:%s adds flag "
 4396             "SA_IMM_ATTR_NO_DUPLICATES",
 4397             className.c_str(), attName.c_str());
 4398 
 4399         change = true;     /* Instances dont need migration. */
 4400         checkCcb = true;   /* Check for ccb interference. */
 4401         checkNoDup = true; /* Instances need validation of no dup */
 4402       }
 4403 
 4404       if ((oldAttr->mFlags & SA_IMM_ATTR_WRITABLE) &&
 4405           !(newAttr->mFlags & SA_IMM_ATTR_WRITABLE)) {
 4406         LOG_NO(
 4407             "Impossible upgrade, attribute %s:%s removes flag "
 4408             "SA_IMM_ATTR_WRITABLE",
 4409             className.c_str(), attName.c_str());
 4410         return true;
 4411       }
 4412 
 4413       if (!(oldAttr->mFlags & SA_IMM_ATTR_WRITABLE) &&
 4414           (newAttr->mFlags & SA_IMM_ATTR_WRITABLE)) {
 4415         LOG_NO(
 4416             "Allowed upgrade, attribute %s:%s adds flag "
 4417             "SA_IMM_ATTR_WRITABLE",
 4418             className.c_str(), attName.c_str());
 4419 
 4420         change = true; /* Instances dont need migration. */
 4421       }
 4422 
 4423       if (!(oldAttr->mFlags & SA_IMM_ATTR_INITIALIZED) &&
 4424           (newAttr->mFlags & SA_IMM_ATTR_INITIALIZED)) {
 4425         LOG_NO(
 4426             "Impossible upgrade, attribute %s:%s adds flag "
 4427             "SA_IMM_ATTR_INITIALIZED",
 4428             className.c_str(), attName.c_str());
 4429         return true;
 4430       }
 4431 
 4432       if ((oldAttr->mFlags & SA_IMM_ATTR_INITIALIZED) &&
 4433           !(newAttr->mFlags & SA_IMM_ATTR_INITIALIZED)) {
 4434         LOG_NO(
 4435             "Allowed upgrade, attribute %s:%s removes flag "
 4436             "SA_IMM_ATTR_INITIALIZED",
 4437             className.c_str(), attName.c_str());
 4438 
 4439         change = true; /* Instances dont need migration. */
 4440       }
 4441 
 4442       if (!(oldAttr->mFlags & SA_IMM_ATTR_PERSISTENT) &&
 4443           (newAttr->mFlags & SA_IMM_ATTR_PERSISTENT)) {
 4444         LOG_NO(
 4445             "Impossible upgrade, attribute %s:%s adds flag "
 4446             "SA_IMM_ATTR_PERSISTENT",
 4447             className.c_str(), attName.c_str());
 4448         return true;
 4449       }
 4450 
 4451       if ((oldAttr->mFlags & SA_IMM_ATTR_PERSISTENT) &&
 4452           !(newAttr->mFlags & SA_IMM_ATTR_PERSISTENT)) {
 4453         LOG_NO(
 4454             "Allowed upgrade, attribute %s:%s removes flag "
 4455             "SA_IMM_ATTR_PERSISTENT",
 4456             className.c_str(), attName.c_str());
 4457 
 4458         change = true;   /* Instances dont need migration. */
 4459         checkCcb = true; /* Check for ccb interference. */
 4460       }
 4461 
 4462       if (!(oldAttr->mFlags & SA_IMM_ATTR_NOTIFY) &&
 4463           (newAttr->mFlags & SA_IMM_ATTR_NOTIFY)) {
 4464         /* Check for CACHED on RTAs done in basic check. */
 4465         LOG_NO(
 4466             "Allowed upgrade, attribute %s:%s adds flag "
 4467             "SA_IMM_ATTR_NOTIFY",
 4468             className.c_str(), attName.c_str());
 4469         change = true;   /* Instances dont need migration. */
 4470         checkCcb = true; /* Check for ccb interference. */
 4471       }
 4472 
 4473       if ((oldAttr->mFlags & SA_IMM_ATTR_NOTIFY) &&
 4474           !(newAttr->mFlags & SA_IMM_ATTR_NOTIFY)) {
 4475         LOG_NO(
 4476             "Allowed upgrade, attribute %s:%s removes flag "
 4477             "SA_IMM_ATTR_NOTIFY",
 4478             className.c_str(), attName.c_str());
 4479         change = true;   /* Instances dont need migration. */
 4480         checkCcb = true; /* Check for ccb interference. */
 4481       }
 4482 
 4483       if (!(oldAttr->mFlags & SA_IMM_ATTR_NO_DANGLING) &&
 4484           (newAttr->mFlags & SA_IMM_ATTR_NO_DANGLING)) {
 4485         LOG_NO(
 4486             "Allowed upgrade, attribute %s:%s adds flag "
 4487             "SA_IMM_ATTR_NO_DANGLING",
 4488             className.c_str(), attName.c_str());
 4489         change = true;
 4490         checkCcb = true;
 4491         checkNoDanglingRefs = true;
 4492       }
 4493 
 4494       if ((oldAttr->mFlags & SA_IMM_ATTR_NO_DANGLING) &&
 4495           !(newAttr->mFlags & SA_IMM_ATTR_NO_DANGLING)) {
 4496         LOG_NO(
 4497             "Allowed upgrade, attribute %s:%s removes flag "
 4498             "SA_IMM_ATTR_NO_DANGLING",
 4499             className.c_str(), attName.c_str());
 4500         change = true;
 4501         checkCcb = true;
 4502         checkNoDanglingRefs = true;
 4503       }
 4504 
 4505       if ((oldAttr->mFlags & SA_IMM_ATTR_DN) !=
 4506           (newAttr->mFlags & SA_IMM_ATTR_DN)) {
 4507         LOG_NO(
 4508             "Impossible upgrade, attribute %s:%s changes flag "
 4509             "SA_IMM_ATTR_DN",
 4510             className.c_str(), attName.c_str());
 4511         return true;
 4512       }
 4513 
 4514       if (!(oldAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED) &&
 4515           (newAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED)) {
 4516         if (oldAttr->mDefaultValue.empty()) {
 4517           LOG_NO(
 4518               "Impossible upgrade, attribute %s:%s doesn't have default, "
 4519               "can not add SA_IMM_ATTR_DEFAULT_REMOVED",
 4520               className.c_str(), attName.c_str());
 4521           return true;
 4522         } else {
 4523           LOG_NO(
 4524               "Allowed upgrade, attribute %s:%s adds flag "
 4525               "SA_IMM_ATTR_DEFAULT_REMOVED",
 4526               className.c_str(), attName.c_str());
 4527           change = true;
 4528         }
 4529       }
 4530 
 4531       if ((oldAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED) &&
 4532           !(newAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED)) {
 4533         if (newAttr->mDefaultValue.empty()) {
 4534           LOG_NO(
 4535               "Impossible upgrade, can not remove SA_IMM_ATTR_DEFAULT_REMOVED "
 4536               "without adding new default for attribute %s:%s",
 4537               className.c_str(), attName.c_str());
 4538           return true;
 4539         } else {
 4540           LOG_NO(
 4541               "Allowed upgrade, attribute %s:%s removes flag "
 4542               "SA_IMM_ATTR_DEFAULT_REMOVED",
 4543               className.c_str(), attName.c_str());
 4544           change = true;
 4545         }
 4546       }
 4547 
 4548       if (!(oldAttr->mFlags & SA_IMM_ATTR_STRONG_DEFAULT) &&
 4549           (newAttr->mFlags & SA_IMM_ATTR_STRONG_DEFAULT) &&
 4550           protocol50Allowed()) {
 4551         LOG_NO(
 4552             "Allowed upgrade, attribute %s:%s adds flag "
 4553             "SA_IMM_ATTR_STRONG_DEFAULT",
 4554             className.c_str(), attName.c_str());
 4555         checkCcb = true;
 4556         checkStrongDefault = true;
 4557         change = true;
 4558       }
 4559 
 4560       if ((oldAttr->mFlags & SA_IMM_ATTR_STRONG_DEFAULT) &&
 4561           !(newAttr->mFlags & SA_IMM_ATTR_STRONG_DEFAULT)) {
 4562         LOG_NO(
 4563             "Allowed upgrade, attribute %s:%s removes flag "
 4564             "SA_IMM_ATTR_STRONG_DEFAULT",
 4565             className.c_str(), attName.c_str());
 4566         change = true;
 4567       }
 4568     }
 4569 
 4570     osafassert(!checkNoDup || checkCcb);  // Duplicate-check implies ccb-check
 4571 
 4572     if (checkCcb) {
 4573       /* Check for ccb-interference. Changing ATTR_NOTIFY or ATTR_PERSISTENT
 4574          or adding NO_DUPLICATES when there is an on-going ccb that is still
 4575          open (not critical) and is operating on instances of the class could
 4576          cause partial and incomplete notification/persistification/unique-check
 4577          relative to the CCB. Abort the ccb in that case. NO_DUPLICATES also
 4578          need to check for interference in ccbs that are in critical (waiting on
 4579          PBE) because such a CCB can not be aborted and could be adding
 4580          duplicates just as NO_DUPLICATES is added to an attribute by this
 4581          schema change.
 4582       */
 4583       CcbVector::iterator i;
 4584       ClassMap::iterator i3 = sClassMap.find(className);
 4585       osafassert(i3 != sClassMap.end());
 4586       ClassInfo* oldClassInfo = i3->second;
 4587       ObjectInfo* obj = NULL;
 4588 
 4589       for (i = sCcbVector.begin(); i != sCcbVector.end(); ++i) {
 4590         CcbInfo* ccb = (*i);
 4591         if (ccb->mState <= IMM_CCB_CRITICAL && ccb->mVeto == SA_AIS_OK) {
 4592           ObjectMutationMap::iterator omit;
 4593           for (omit = ccb->mMutations.begin(); omit != ccb->mMutations.end();
 4594                ++omit) {
 4595             ObjectMap::iterator oi = sObjectMap.find(omit->first);
 4596             osafassert(oi != sObjectMap.end());
 4597             obj = oi->second;
 4598             if (obj->mClassInfo == oldClassInfo) {
 4599               if (ccb->mState < IMM_CCB_CRITICAL) {
 4600                 LOG_NO(
 4601                     "Ccb %u is active on object '%s', interferes with "
 4602                     "class change for class: %s attr: %s. Aborting Ccb.",
 4603                     ccb->mId, omit->first.c_str(), className.c_str(),
 4604                     attName.c_str());
 4605                 setCcbErrorString(ccb,
 4606                                   IMM_RESOURCE_ABORT
 4607                                   "Class change for class: %s, attr: %s",
 4608                                   className.c_str(), attName.c_str());
 4609                 ccb->mVeto = SA_AIS_ERR_FAILED_OPERATION;
 4610               } else {
 4611                 osafassert(ccb->mState == IMM_CCB_CRITICAL);
 4612                 LOG_NO(
 4613                     "Ccb %u in critical state (can not abort) is active "
 4614                     "on object '%s', interferes with class change for "
 4615                     "class: %s attr: %s. Aborting class change",
 4616                     ccb->mId, omit->first.c_str(), className.c_str(),
 4617                     attName.c_str());
 4618                 return true;
 4619               }
 4620               break; /* Out of inner loop. */
 4621             }        // if
 4622           }          // for
 4623         }            // if
 4624       }              // for
 4625 
 4626       if (checkNoDup) {
 4627         /* Screen all instances of class for no duplicates on attr. */
 4628         ObjectSet::iterator osi = oldClassInfo->mExtent.begin();
 4629         for (; osi != oldClassInfo->mExtent.end(); ++osi) {
 4630           obj = *osi;
 4631           ImmAttrValueMap::iterator oavi = obj->mAttrValueMap.find(attName);
 4632           osafassert(oavi != obj->mAttrValueMap.end());
 4633           osafassert(oavi->second->isMultiValued());
 4634           if (oavi->second->hasDuplicates()) {
 4635             std::string objName;
 4636             getObjectName(obj, objName);
 4637             LOG_NO(
 4638                 "Impossible upgrade, attribute %s:%s adds flag "
 4639                 "SA_IMM_ATTR_NO_DUPLICATE, but object '%s' has "
 4640                 "duplicate values in that attribute",
 4641                 className.c_str(), attName.c_str(), objName.c_str());
 4642             return true;
 4643           }
 4644         }
 4645       }
 4646 
 4647       if (checkStrongDefault) {
 4648         /* Screen all instances of the class.
 4649          * If there's an instance with the attribute being NULL, abort the
 4650          * schema change. */
 4651         ObjectSet::iterator osi = oldClassInfo->mExtent.begin();
 4652         for (; osi != oldClassInfo->mExtent.end(); ++osi) {
 4653           obj = *osi;
 4654           ImmAttrValueMap::iterator oavi = obj->mAttrValueMap.find(attName);
 4655           osafassert(oavi != obj->mAttrValueMap.end());
 4656           if (oavi->second->empty()) {
 4657             std::string objName;
 4658             getObjectName(obj, objName);
 4659             LOG_NO(
 4660                 "Impossible upgrade, attribute %s:%s adds SA_IMM_ATTR_STRONG_DEFAULT flag, "
 4661                 "but that attribute of object '%s' has NULL value",
 4662                 className.c_str(), attName.c_str(), objName.c_str());
 4663             return true;
 4664           }
 4665         }
 4666       }
 4667     }
 4668 
 4669     /* "changedAttrs != NULL" ensures that this check is only for the schema
 4670      * update */
 4671     if (checkNoDanglingRefs && changedAttrs) {
 4672       if (newAttr->mValueType != SA_IMM_ATTR_SANAMET &&
 4673           !(newAttr->mValueType == SA_IMM_ATTR_SASTRINGT &&
 4674             (newAttr->mFlags & SA_IMM_ATTR_DN))) {
 4675         LOG_NO(
 4676             "Impossible upgrade, attribute %s:%s adds/removes SA_IMM_ATTR_NO_DANGLING flag, ",
 4677             className.c_str(), attName.c_str());
 4678         return true;
 4679       }
 4680 
 4681       ClassMap::iterator cmi = sClassMap.find(className);
 4682       osafassert(cmi != sClassMap.end());
 4683 
 4684       ClassInfo* oldClassInfo = cmi->second;
 4685 
 4686       // Collect attributes with added NO_DANGLING flags
 4687       for (ObjectSet::iterator osi = oldClassInfo->mExtent.begin();
 4688            osi != oldClassInfo->mExtent.end(); ++osi) {
 4689         // Check if there is any create or delete CCB operation on objects in
 4690         // the attribute with NO_DANGLING flag
 4691         ImmAttrValueMap::iterator avmi = (*osi)->mAttrValueMap.find(attName);
 4692         osafassert(avmi != (*osi)->mAttrValueMap.end());
 4693         ObjectMap::iterator omi;
 4694         ImmAttrValue* av = avmi->second;
 4695         while (av) {
 4696           if (av->getValueC_str()) {
 4697             omi = sObjectMap.find(av->getValueC_str());
 4698             if (omi == sObjectMap.end()) {
 4699               std::string objName;
 4700               getObjectName(*osi, objName);
 4701               LOG_WA(
 4702                   "Object %s attribute %s has a reference to a non-existing object %s. "
 4703                   "Schema change to add NO_DANGLING is not possible",
 4704                   objName.c_str(), attName.c_str(), av->getValueC_str());
 4705               return true;
 4706             }
 4707             if (omi->second->mClassInfo->mCategory == SA_IMM_CLASS_RUNTIME &&
 4708                 std::find_if(omi->second->mClassInfo->mAttrMap.begin(),
 4709                              omi->second->mClassInfo->mAttrMap.end(),
 4710                              AttrFlagIncludes(SA_IMM_ATTR_PERSISTENT)) ==
 4711                     omi->second->mClassInfo->mAttrMap.end()) {
 4712               std::string objName;
 4713               getObjectName(*osi, objName);
 4714               LOG_WA(
 4715                   "Object %s attribute %s has a reference to a non-persistent runtime object %s. "
 4716                   "Schema change to add NO_DANGLING is not possible",
 4717                   objName.c_str(), attName.c_str(), av->getValueC_str());
 4718               return true;
 4719             }
 4720             if (omi->second->mObjFlags & (IMM_CREATE_LOCK | IMM_DELETE_LOCK)) {
 4721               std::string objName;
 4722               getObjectName(*osi, objName);
 4723               LOG_WA(
 4724                   "CCB in progress operating on object %s attribute %s referenced by object %s is being upgraded. "
 4725                   "Schema change to add NO_DANGLING is not possible",
 4726                   objName.c_str(), attName.c_str(), av->getValueC_str());
 4727               return true;
 4728             }
 4729           }
 4730 
 4731           if (av->isMultiValued()) {
 4732             av = ((ImmAttrMultiValue*)av)->getNextAttrValue();
 4733           } else {
 4734             break;
 4735           }
 4736         }
 4737       }
 4738     }
 4739 
 4740     if (oldAttr->mDefaultValue.empty() && !newAttr->mDefaultValue.empty()) {
 4741       if (protocol45Allowed()) {
 4742         LOG_NO("Allowed upgrade, attribute %s:%s adds default value",
 4743                className.c_str(), attName.c_str());
 4744         change = true;
 4745       } else {
 4746         LOG_NO("Impossible upgrade, attribute %s:%s adds default value",
 4747                className.c_str(), attName.c_str());
 4748         return true;
 4749       }
 4750     }
 4751 
 4752     if (!oldAttr->mDefaultValue.empty() && newAttr->mDefaultValue.empty()) {
 4753       if (newAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED) {
 4754         LOG_NO("Allowed upgrade, attribute %s:%s removes default value",
 4755                className.c_str(), attName.c_str());
 4756         change = true;
 4757       } else {
 4758         LOG_NO("Impossible upgrade, attribute %s:%s removes default value",
 4759                className.c_str(), attName.c_str());
 4760         return true;
 4761       }
 4762     }
 4763 
 4764     /* Default value may change, this will only affect new instances. */
 4765     if (!oldAttr->mDefaultValue.empty() && !newAttr->mDefaultValue.empty()) {
 4766       IMMSV_EDU_ATTR_VAL oldval;
 4767       IMMSV_OCTET_STRING tmpos;
 4768       oldAttr->mDefaultValue.copyValueToEdu(
 4769           &oldval, (SaImmValueTypeT)oldAttr->mValueType);
 4770       eduAtValToOs(&tmpos, &oldval, (SaImmValueTypeT)oldAttr->mValueType);
 4771       if (newAttr->mDefaultValue.hasMatchingValue(tmpos)) {
 4772         TRACE_5("Unchanged default value for %s:%s", className.c_str(),
 4773                 attName.c_str());
 4774       } else {
 4775         LOG_NO("Allowed upgrade, attribute %s:%s changes default value",
 4776                className.c_str(), attName.c_str());
 4777         change = true;
 4778       }
 4779       immsv_evt_free_att_val(&oldval, (SaImmValueTypeT)oldAttr->mValueType);
 4780     }
 4781 
 4782     if (change) {
 4783       (*changedAttrs)[attName] = newAttr;
 4784     }
 4785   } else {
 4786     /* This a new attribute apended to the class. */
 4787     if (newAttr->mFlags & SA_IMM_ATTR_INITIALIZED) {
 4788       LOG_NO(
 4789           "Impossible upgrade, new attribute %s:%s has SA_IMM_ATTR_INITIALIZED "
 4790           "flag set",
 4791           className.c_str(), attName.c_str());
 4792       return true;
 4793     }
 4794 
 4795     if ((newAttr->mFlags & SA_IMM_ATTR_CACHED) &&
 4796         (newClassInfo->mCategory == SA_IMM_CLASS_RUNTIME) &&
 4797         newAttr->mDefaultValue.empty()) {
 4798       LOG_NO(
 4799           "Impossible upgrade, runtime class has new attribute %s:%s with"
 4800           " SA_IMM_ATTR_CACHED flag set, but no default value",
 4801           className.c_str(), attName.c_str());
 4802       return true;
 4803     }
 4804 
 4805     if (newAttr->mFlags & SA_IMM_ATTR_DEFAULT_REMOVED) {
 4806       LOG_NO(
 4807           "Impossible upgrade, new attribute %s:%s has SA_IMM_ATTR_DEFAULT_REMOVED "
 4808           "flag set",
 4809           className.c_str(), attName.c_str());
 4810       return true;
 4811     }
 4812   }
 4813 
 4814   return false;
 4815 }
 4816 
 4817 /**
 4818  * Deletes a class.
 4819  */
 4820 SaAisErrorT ImmModel::classDelete(const ImmsvOmClassDescr* req,
 4821                                   SaUint32T reqConn, unsigned int nodeId,
 4822                                   SaUint32T* continuationIdPtr,
 4823                                   SaUint32T* pbeConnPtr,
 4824                                   unsigned int* pbeNodeIdPtr) {
 4825   TRACE_ENTER();
 4826 
 4827   size_t sz = strnlen((char*)req->className.buf, (size_t)req->className.size);
 4828   std::string className((const char*)req->className.buf, sz);
 4829 
 4830   SaAisErrorT err = SA_AIS_OK;
 4831 
 4832   if (immNotPbeWritable()) {
 4833     err = SA_AIS_ERR_TRY_AGAIN;
 4834   } else if (!schemaNameCheck(className)) {
 4835     LOG_NO("ERR_INVALID_PARAM: Not a proper class name: %s", className.c_str());
 4836     err = SA_AIS_ERR_INVALID_PARAM;
 4837   } else {
 4838     ClassMap::iterator i = sClassMap.find(className);
 4839     if (i == sClassMap.end()) {
 4840       TRACE_7("ERR_NOT_EXIST: class '%s' does not exist", className.c_str());
 4841       err = SA_AIS_ERR_NOT_EXIST;
 4842     } else if (!(i->second->mExtent.empty())) {
 4843       LOG_WA("ERR_BUSY: class '%s' busy, refCount:%u", className.c_str(),
 4844              (unsigned int)i->second->mExtent.size());
 4845       err = SA_AIS_ERR_BUSY;
 4846     } else if (sPbeRtMutations.find(className) != sPbeRtMutations.end()) {
 4847       LOG_NO(
 4848           "ERR_BUSY: Delete of class %s received while class "
 4849           "with same name is already being mutated",
 4850           className.c_str());
 4851       err = SA_AIS_ERR_BUSY;
 4852     } else {
 4853       AttrMap::iterator ai = i->second->mAttrMap.begin();
 4854       while (ai != i->second->mAttrMap.end()) {
 4855         AttrInfo* ainfo = ai->second;
 4856         osafassert(ainfo);
 4857         delete (ainfo);
 4858         ++ai;
 4859       }
 4860       i->second->mAttrMap.clear();
 4861       delete i->second;
 4862       sClassMap.erase(i);
 4863       updateImmObject(className, true);
 4864       TRACE_5("class %s deleted", className.c_str());
 4865 
 4866       if (pbeNodeIdPtr) {
 4867         if (!getPbeOi(pbeConnPtr, pbeNodeIdPtr)) {
 4868           LOG_ER("Pbe is not available, can not happen here");
 4869           abort();
 4870         }
 4871         if (++sLastContinuationId >= 0xfffffffe) {
 4872           sLastContinuationId = 1;
 4873         }
 4874         (*continuationIdPtr) = sLastContinuationId;
 4875 
 4876         osafassert(sPbeRtMutations.find(className) == sPbeRtMutations.end());
 4877         /* Create a mutation record to bar pbe restart --recover  */
 4878         ObjectMutation* oMut = new ObjectMutation(IMM_DELETE_CLASS);
 4879         oMut->mContinuationId = (*continuationIdPtr);
 4880         oMut->mAfterImage = NULL;
 4881         sPbeRtMutations[className] = oMut;
 4882 
 4883         if (reqConn) {
 4884           SaInvocationT tmp_hdl =
 4885               m_IMMSV_PACK_HANDLE((*continuationIdPtr), nodeId);
 4886           sPbeRtReqContinuationMap[tmp_hdl] =
 4887               ContinuationInfo2(reqConn, DEFAULT_TIMEOUT_SEC);
 4888         }
 4889       }
 4890     }
 4891   }
 4892   TRACE_LEAVE();
 4893   return err;
 4894 }
 4895 
 4896 /**
 4897  * Creates an attribute.
 4898  */
 4899 SaAisErrorT ImmModel::attrCreate(ClassInfo* classInfo,
 4900                                  const ImmsvAttrDefinition* attr,
 4901                                  const std::string& attrName) {
 4902   SaAisErrorT err = SA_AIS_OK;
 4903   // TRACE_ENTER();
 4904 
 4905   if (!schemaNameCheck(attrName)) {
 4906     LOG_NO("ERR_INVALID_PARAM: Not a proper attribute name: %s",
 4907            attrName.c_str());
 4908     err = SA_AIS_ERR_INVALID_PARAM;
 4909   } else {
 4910     AttrMap::iterator i = classInfo->mAttrMap.find(attrName);
 4911     if (i != classInfo->mAttrMap.end()) {
 4912       LOG_NO("ERR_INVALID_PARAM: attr def for '%s' is duplicated",
 4913              attrName.c_str());
 4914       err = SA_AIS_ERR_INVALID_PARAM;
 4915       goto done;
 4916     }
 4917 
 4918     /* Verify attribute name is unique within class case-insensitive. */
 4919     for (i = classInfo->mAttrMap.begin(); i != classInfo->mAttrMap.end(); ++i) {
 4920       if (nocaseCompare(attrName, i->first)) {
 4921         LOG_NO(
 4922             "ERR_INVALID_PARAM: attr name '%s'/'%s' is duplicated "
 4923             "(case insensitive)",
 4924             attrName.c_str(), i->first.c_str());
 4925         err = SA_AIS_ERR_INVALID_PARAM;
 4926         goto done;
 4927       }
 4928     }
 4929 
 4930     SaImmAttrFlagsT unknownFlags =
 4931         attr->attrFlags &
 4932         ~(SA_IMM_ATTR_MULTI_VALUE | SA_IMM_ATTR_RDN | SA_IMM_ATTR_CONFIG |
 4933           SA_IMM_ATTR_WRITABLE | SA_IMM_ATTR_INITIALIZED | SA_IMM_ATTR_RUNTIME |
 4934           SA_IMM_ATTR_PERSISTENT | SA_IMM_ATTR_CACHED |
 4935           SA_IMM_ATTR_NO_DUPLICATES | SA_IMM_ATTR_NOTIFY |
 4936           SA_IMM_ATTR_NO_DANGLING | SA_IMM_ATTR_DN |
 4937           SA_IMM_ATTR_DEFAULT_REMOVED | SA_IMM_ATTR_STRONG_DEFAULT);
 4938 
 4939     if (unknownFlags) {
 4940       /* This error means that at least one attribute flag is not supported by
 4941          this OpenSAF release. This release will still try to cope with such
 4942          flags by ignoring them (e.g. not failing to load the rest of the data).
 4943          This can only be done if either the XSD pointed at by the file can be
 4944          loaded and the unsupported flag is confirmed as a valid flag name in
 4945          that XSD; or if the recognition of the unsupported flag has been
 4946          hardcoded into this older release. Hardcoding is only done for
 4947          non-integrity related flags such as SA_IMM_ATTR_NOTIFY and allows the
 4948          flag to pass through this system (e.g. be included in a dump).
 4949       */
 4950       err = SA_AIS_ERR_NOT_SUPPORTED;
 4951       TRACE_5(
 4952           "create attribute '%s' with unknown flag(s), attribute flag: %llu",
 4953           attrName.c_str(), attr->attrFlags);
 4954     } else {
 4955       TRACE_5("create attribute '%s'", attrName.c_str());
 4956     }
 4957 
 4958     AttrInfo* attrInfo = new AttrInfo;
 4959     attrInfo->mValueType = attr->attrValueType;
 4960     attrInfo->mFlags = attr->attrFlags;
 4961     attrInfo->mNtfId = attr->attrNtfId;
 4962     if (attr->attrDefaultValue) {
 4963       IMMSV_OCTET_STRING tmpos;  // temporary octet string
 4964       eduAtValToOs(&tmpos, attr->attrDefaultValue,
 4965                    (SaImmValueTypeT)attr->attrValueType);
 4966       attrInfo->mDefaultValue.setValue(tmpos);
 4967     }
 4968     classInfo->mAttrMap[attrName] = attrInfo;
 4969   }
 4970 done:
 4971   // TRACE_LEAVE();
 4972   return err;
 4973 }
 4974 
 4975 struct AttrDescriptionGet {
 4976   explicit AttrDescriptionGet(ImmsvOmClassDescr*& s) : classDescription(s) {}
 4977 
 4978   AttrMap::value_type operator()(const AttrMap::value_type& item) {
 4979     ImmsvAttrDefList* p =
 4980         (ImmsvAttrDefList*)calloc(1, sizeof(ImmsvAttrDefList)); /*Alloc-X*/
 4981     const std::string& attrName = item.first;
 4982     p->d.attrName.size = (int)attrName.length() + 1; /*Alloc-Y*/
 4983     p->d.attrName.buf = (char*)malloc(p->d.attrName.size);
 4984     strncpy(p->d.attrName.buf, attrName.c_str(), p->d.attrName.size);
 4985     p->d.attrValueType = item.second->mValueType;
 4986     p->d.attrFlags = item.second->mFlags;
 4987     p->d.attrNtfId = item.second->mNtfId;
 4988     if (item.second->mDefaultValue.empty()) {
 4989       p->d.attrDefaultValue = NULL;
 4990     } else {
 4991       p->d.attrDefaultValue = (IMMSV_EDU_ATTR_VAL*)/*alloc-Z*/
 4992           calloc(1, sizeof(IMMSV_EDU_ATTR_VAL));
 4993 
 4994       item.second->mDefaultValue.copyValueToEdu(p->d.attrDefaultValue,
 4995                                                 (SaImmValueTypeT) /*alloc-ZZ*/
 4996                                                 p->d.attrValueType);
 4997     }
 4998     p->next = classDescription->attrDefinitions;
 4999     classDescription->attrDefinitions = p;
 5000     return item;
 5001   }
 5002 
 5003   ImmsvOmClassDescr*& classDescription;  // Data member
 5004 };
 5005 
 5006 /**
 5007  * Returns a class description.
 5008  */
 5009 SaAisErrorT ImmModel::classDescriptionGet(const IMMSV_OCTET_STRING* clName,
 5010                                           ImmsvOmClassDescr* res) {
 5011   TRACE_ENTER();
 5012   size_t sz = strnlen((char*)clName->buf, (size_t)clName->size);
 5013   std::string className((const char*)clName->buf, sz);
 5014 
 5015   SaAisErrorT err = SA_AIS_OK;
 5016 
 5017   if (!schemaNameCheck(className)) {
 5018     LOG_NO("ERR_INVALID_PARAM: Not a proper class name");
 5019     err = SA_AIS_ERR_INVALID_PARAM;
 5020   } else {
 5021     ClassMap::iterator i = sClassMap.find(className);
 5022     if (i == sClassMap.end()) {
 5023       TRACE_7("ERR_NOT_EXIST: class '%s' does not exist", className.c_str());
 5024       err = SA_AIS_ERR_NOT_EXIST;
 5025     } else {
 5026       ClassInfo* classInfo = i->second;
 5027       res->classCategory = classInfo->mCategory;
 5028 
 5029       std::for_each(classInfo->mAttrMap.begin(), classInfo->mAttrMap.end(),
 5030                     AttrDescriptionGet(res));
 5031     }
 5032   }
 5033   TRACE_LEAVE();
 5034   return err;
 5035 }
 5036 
 5037 /**
 5038  * Creates an admin owner.
 5039  */
 5040 SaAisErrorT ImmModel::adminOwnerCreate(const ImmsvOmAdminOwnerInitialize* req,
 5041                                        SaUint32T ownerId, SaUint32T conn,
 5042                                        unsigned int nodeId) {
 5043   SaAisErrorT err = SA_AIS_OK;
 5044   bool isLoading = (sImmNodeState == IMM_NODE_LOADING);
 5045 
 5046   TRACE_ENTER();
 5047   if (immNotWritable() || is_sync_aborting()) {
 5048     TRACE_LEAVE();
 5049     return SA_AIS_ERR_TRY_AGAIN;
 5050   }
 5051 
 5052   if (strcmp("IMMLOADER", osaf_extended_name_borrow(&req->adminOwnerName)) ==
 5053       0) {
 5054     if (sImmNodeState != IMM_NODE_LOADING) {
 5055       LOG_NO(
 5056           "ERR_INVALID_PARAM: Admin Owner 'IMMLOADER' only allowed for loading");
 5057       TRACE_LEAVE();
 5058       return SA_AIS_ERR_INVALID_PARAM;
 5059     }
 5060   }
 5061 
 5062   ObjectMap::iterator oi = sObjectMap.find(immObjectDn);
 5063   if (protocol51Allowed() && oi != sObjectMap.end() && !isLoading) {
 5064     ObjectInfo* immObject = oi->second;
 5065     ImmAttrValueMap::iterator avi = immObject->mAttrValueMap.find(immMaxAdmOwn);
 5066     osafassert(avi != immObject->mAttrValueMap.end());
 5067     osafassert(!(avi->second->isMultiValued()));
 5068     ImmAttrValue* valuep = avi->second;
 5069     unsigned int maxAdmOwn = valuep->getValue_int();
 5070     if (sOwnerVector.size() >= maxAdmOwn) {
 5071       LOG_NO(
 5072           "ERR_NO_RESOURCES: maximum AdminOwners limit %d has been reached for the cluster",
 5073           maxAdmOwn);
 5074       <