void Shell::doMove( Id orig, ObjId newParent ) { if ( orig == Id() ) { cout << "Error: Shell::doMove: Cannot move root Element\n"; return; } if ( newParent.element() == 0 ) { cout << "Error: Shell::doMove: Cannot move object to null parent \n"; return; } if ( Neutral::isDescendant( newParent, orig ) ) { cout << "Error: Shell::doMove: Cannot move object to descendant in tree\n"; return; } const string& name = orig.element()->getName(); if ( Neutral::child( newParent.eref(), name ) != Id() ) { stringstream ss; ss << "Shell::doMove: Object with same name already present: '" << newParent.path() << "/" << name << "'. Move failed."; warning( ss.str() ); return; } SetGet2< Id, ObjId >::set( ObjId(), "move", orig, newParent ); // innerMove( orig, newParent ); }
void Shell::destroy( const Eref& e, ObjId oid) { Neutral *n = reinterpret_cast< Neutral* >( e.data() ); assert( n ); // cout << myNode_ << ": Shell::destroy done for element id: " << eid << ", name = " << eid.element()->getName() << endl; n->destroy( oid.eref(), 0 ); if ( cwe_.id == oid.id ) cwe_ = ObjId(); }
/// non-static func. Returns the Id found by traversing the specified path. ObjId Shell::doFind( const string& path ) const { if ( path == "/" || path == "/root" ) return ObjId(); ObjId curr; vector< string > names; vector< unsigned int > indices; bool isAbsolute = chopPath( path, names, indices ); assert( names.size() == indices.size() ); if ( !isAbsolute ) curr = cwe_; for ( unsigned int i = 0; i < names.size(); ++i ) { if ( names[i] == "." ) { } else if ( names[i] == ".." ) { curr = Neutral::parent( curr.eref() ); } else { ObjId pa = curr; curr = Neutral::child( curr.eref(), names[i] ); if ( curr == ObjId() ) // Neutral::child returned Id(), ie, bad. return ObjId( 0, BADINDEX ); if ( curr.element()->hasFields() ) { curr.dataIndex = pa.dataIndex; curr.fieldIndex = indices[i]; } else { curr.dataIndex = indices[i]; if ( curr.element()->numData() <= curr.dataIndex ) return ObjId( 0, BADINDEX ); } } } assert( curr.element() ); if ( curr.element()->numData() <= curr.dataIndex ) return ObjId( 0, BADINDEX ); if ( curr.fieldIndex > 0 && !curr.element()->hasFields() ) return ObjId( 0, BADINDEX ); return curr; }
// static function bool Neutral::isDescendant( Id me, Id ancestor ) { static const Finfo* pf = neutralCinfo->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); Eref e = me.eref(); while ( e.element()->id() != Id() && e.element()->id() != ancestor ) { ObjId mid = e.element()->findCaller( pafid ); assert( mid != ObjId() ); ObjId fid = Msg::getMsg( mid )->findOtherEnd( e.objId() ); e = fid.eref(); } return ( e.element()->id() == ancestor ); }
void Neutral::setName( const Eref& e, string name ) { if ( e.id().value() <= 3 ) { cout << "Warning: Neutral::setName on '" << e.id().path() << "'.Cannot rename core objects\n"; return; } ObjId pa = parent( e ); Id sibling = Neutral::child( pa.eref(), name ); if ( sibling == Id() ) { // OK, no existing object with same name. e.element()->setName( name ); } else { cout << "Warning: Neutral::setName: an object with the name '" << name << "'\n already exists on the same parent. Not changed\n"; } }
void NSDFWriter::writeModelTree() { vector< string > tokens; ObjId mRoot(modelRoot_); string rootPath = MODELTREEPATH + string("/") + mRoot.element()->getName(); hid_t rootGroup = require_group(filehandle_, rootPath); hid_t tmp; htri_t exists; herr_t status; deque<Id> nodeQueue; deque<hid_t> h5nodeQueue; nodeQueue.push_back(mRoot); h5nodeQueue.push_back(rootGroup); // TODO: need to clarify what happens with array elements. We can // have one node per vec and set a count field for the number of // elements while (nodeQueue.size() > 0){ ObjId node = nodeQueue.front(); nodeQueue.pop_front(); hid_t prev = h5nodeQueue.front();; h5nodeQueue.pop_front(); vector < Id > children; Neutral::children(node.eref(), children); for ( unsigned int ii = 0; ii < children.size(); ++ii){ string name = children[ii].element()->getName(); // skip the system elements if (children[ii].path() == "/Msgs" || children[ii].path() == "/clock" || children[ii].path() == "/classes" || children[ii].path() == "/postmaster"){ continue; } exists = H5Lexists(prev, name.c_str(), H5P_DEFAULT); if (exists > 0){ tmp = H5Gopen2(prev, name.c_str(), H5P_DEFAULT); } else { tmp = H5Gcreate2(prev, name.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); } writeScalarAttr< string >(tmp, "uid", children[ii].path()); nodeQueue.push_back(children[ii]); h5nodeQueue.push_back(tmp); } status = H5Gclose(prev); } }
// Static function string Neutral::path( const Eref& e ) { static const Finfo* pf = neutralCinfo->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); vector< ObjId > pathVec; ObjId curr = e.objId(); stringstream ss; pathVec.push_back( curr ); while ( curr.id != Id() ) { ObjId mid = curr.eref().element()->findCaller( pafid ); if ( mid == ObjId() ) { cout << "Error: Neutral::path:Cannot follow msg of ObjId: " << e.objId() << " for func: " << pafid << endl; break; } curr = Msg::getMsg( mid )->findOtherEnd( curr ); pathVec.push_back( curr ); } if ( pathVec.size() <= 1 ) return "/"; for ( unsigned int i = 1; i < pathVec.size(); ++i ) { ss << "/"; ObjId& oid = pathVec[ pathVec.size() - i - 1 ]; ss << oid.element()->getName(); if ( !oid.element()->hasFields() ) ss << "[" << oid.dataIndex << "]"; /* if ( !oid.element()->hasFields() ) ss << "[" << oid.dataIndex << "]"; if ( oid.element()->numData() > 1 ) ss << "[" << oid.dataIndex << "]"; */ } // Append braces if Eref was for a fieldElement. This should // work even if it is off-node. if ( e.element()->hasFields() ) { ss << "[" << e.fieldIndex() << "]"; } return ss.str(); }
bool Shell::innerMove( Id orig, ObjId newParent ) { static const Finfo* pf = Neutral::initCinfo()->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); static const Finfo* f1 = Neutral::initCinfo()->findFinfo( "childOut" ); assert( !( orig == Id() ) ); assert( !( newParent.element() == 0 ) ); ObjId mid = orig.element()->findCaller( pafid ); Msg::deleteMsg( mid ); Msg* m = new OneToAllMsg( newParent.eref(), orig.element(), 0 ); assert( m ); if ( !f1->addMsg( pf, m->mid(), newParent.element() ) ) { cout << "move: Error: unable to add parent->child msg from " << newParent.element()->getName() << " to " << orig.element()->getName() << "\n"; return 0; } return 1; }
/** * Static utility function. Attaches child element to parent element. * Must only be called from functions executing in parallel on all nodes, * as it does a local message addition * MsgIndex is needed to be sure that the same msg identifies parent-child * connection on all nodes. */ bool Shell::adopt( ObjId parent, Id child, unsigned int msgIndex ) { static const Finfo* pf = Neutral::initCinfo()->findFinfo( "parentMsg" ); // static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); // static const FuncId pafid = pf2->getFid(); static const Finfo* f1 = Neutral::initCinfo()->findFinfo( "childOut" ); assert( !( child.element() == 0 ) ); assert( !( child == Id() ) ); assert( !( parent.element() == 0 ) ); Msg* m = new OneToAllMsg( parent.eref(), child.element(), msgIndex ); assert( m ); // cout << myNode_ << ", Shell::adopt: mid = " << m->mid() << ", pa =" << parent << "." << parent()->getName() << ", kid=" << child << "." << child()->getName() << "\n"; if ( !f1->addMsg( pf, m->mid(), parent.element() ) ) { cout << "move: Error: unable to add parent->child msg from " << parent.element()->getName() << " to " << child.element()->getName() << "\n"; return 0; } return 1; }
/** * This is the version used by the parser. Acts as a blocking, * serial-like interface to a potentially multithread, multinode call. * Returns the new Id index upon success, otherwise returns Id(). * The data of the new Element is not necessarily allocated at this point, * that can be deferred till the global Instantiate or Reset calls. * Idea is that the model should be fully defined before load balancing. * */ Id Shell::doCreate( string type, ObjId parent, string name, unsigned int numData, NodePolicy nodePolicy, unsigned int preferredNode ) { #ifdef ENABLE_LOGGER clock_t t = clock(); #endif const Cinfo* c = Cinfo::find( type ); if ( !isNameValid( name ) ) { stringstream ss; ss << "Shell::doCreate: bad character in name'" << name << "'. No Element created"; warning( ss.str() ); return Id(); } if ( c ) { if ( c->banCreation() ) { stringstream ss; ss << "Shell::doCreate: Cannot create an object of class '" << type << "' because it is an abstract base class or a FieldElement.\n"; warning( ss.str() ); return Id(); } Element* pa = parent.element(); if ( !pa ) { stringstream ss; ss << "Shell::doCreate: Parent Element'" << parent << "' not found. No Element created"; warning( ss.str() ); return Id(); } if ( Neutral::child( parent.eref(), name ) != Id() ) { stringstream ss; ss << "Shell::doCreate: Object with same name already present: '" << parent.path() << "/" << name << "'. No Element created"; warning( ss.str() ); return Id(); } // Get the new Id ahead of time and pass to all nodes. Id ret = Id::nextId(); NodeBalance nb( numData, nodePolicy, preferredNode ); // Get the parent MsgIndex ahead of time and pass to all nodes. unsigned int parentMsgIndex = OneToAllMsg::numMsg(); SetGet6< string, ObjId, Id, string, NodeBalance, unsigned int >::set( ObjId(), // Apply command to Shell "create", // Function to call. type, // class of new object parent, // Parent ret, // id of new object name, // name of new object nb, // Node balance configuration parentMsgIndex // Message index of child-parent msg. ); // innerCreate( type, parent, ret, name, numData, isGlobal ); #ifdef ENABLE_LOGGER logger.creationTime.push_back((float(clock() - t)/CLOCKS_PER_SEC)); #endif return ret; } else { stringstream ss; ss << "Shell::doCreate: Class '" << type << "' not known. No Element created"; warning( ss.str() ); } #ifdef ENABLE_LOGGER logger.creationTime.push_back((float(clock() - t)/CLOCKS_PER_SEC)); #endif return Id(); }