Pseudocode for the Gallagher-Humblet-Spira MST algorithm. (kjg 9/13/02) ASSUMPTIONS: Each edge has a unique cost. Each node has a unique integer identifier (UID). Each process knows the cost and neighbor UID for each of its incident edges. Processes can send messages over edges to their neighbors. Each message eventually arrives and contains the UID of the sender. STATE OF EACH PROCESS: Two integers: status: SLEEPING, SEARCHING, or FOUND (initially SLEEPING) level: the level number of this fragment (initially 0) Three lists of incident edges: basicEdges (initially contains all incident edges, sorted in increasing order of cost) rejectedEdges (edges determined not to be in the MST, initially empty) branchEdges (edges in the MST, initially empty) (Note: at the end, all edges will be either rejected or branch edges.) Three nodes: core: the root of the fragment (initially yourself) parent: the parent node in t (initially null) minChild: the child that reported the minimum edge so far (initially null) For bookkeeping: deferredTests: a list of pending Test messages (initially empty) mwoe: int cost of minimum weight outgoing edge found so far (used in search) MESSAGE TYPES: (Each has sender's UID plus any listed arguments.) 1) Wakeup -- starts the protocol at a sleeping node 2) Initiate(core,level) -- broadcast over a fragment from the core to notify them of the core and level of the fragment AND to tell nodes to search for the MWOE of the fragment 3) Test(core,level) -- sent across an edge to determine if that edge leads to another fragment 4) Accept -- response to a Test message indicating a different fragment 5) Reject -- response to a Test message indicating the same fragment 6) Report(cost) -- sent up the tree to inform parent of MWOE of subtree 7) ChangeRoot -- sent down tree from core to MWOE of subtree, in order to tell that incident node to connect along that MWOE 8) Connect(core,level) -- sent over an edge in order to combine the fragments of the incident nodes of that edge NOTE: Always sent to a fragment whose level is at least as high. 9) Inform(core,level) -- broadcast over a fragment from the core to notify them of the core and level of the fragment 10) AllDone -- broadcast over the tree to inform nodes of termination REACTING TO MESSAGES received (over edge E): Wakeup(): (may be an external input, not over an edge) if SLEEPING // MWOE must be the lowest cost basic edge send "Connect(core,level)" to first (lowest cost) basic edge Initiate(core,level): (if sent by self, there is no edge E) status = SEARCHING this.core = core; this.level = level; *processDeferredTests() this.parent = sender of the message this.minChild = null; let waitingForReport contain all branch edges (besides E, if sender != self) send "Initiate(core,level)" over all branch edges (besides E, sender != self) mwoe = INFINITY; while (basicEdges is not empty and (mwoe is null or cost(mwoe) > cost(first basicEdge))) { send "Test(core,level)" over the first (lowest cost) basicEdge wait for a response (Accept or Reject, see below) } when (waitingForReport is empty and the while loop is finished) if (parent != self) status = FOUND send "Report(mwoe)" to parent // this will be the minimum in subtree else if (mwoe != INFINITY) send "ChangeRoot" to self else send "AllDone" on all branchEdges Test(core,level): if (this.core == core) // in the same fragment send back "Reject" along E else if (this.level >= level) // can't be in the same fragment send back "Accept" along E else // don't know yet because we haven't reached that level put the message into deferredTests Accept(): // other endpoint is in a different fragment if (cost(E) < mwoe) minChild = null; mwoe = cost(E); Reject(): // other endpoint is in the same fragment move E brom basicEdge to rejectedEdges Report(cost): remove E from waitingForReport if (cost < mwoe) minChild = other endpoint of E mwoe = cost ChangeRoot(): status = FOUND if (minChild != null) send "ChangeRoot" to minChild else move first basicEdge to branchEdge send "Connect(core,level)" across that edge Connect(core,level): move E from basicEdges to branchEdges if (this.level > level) // *** ABSORB THE OTHER FRAGMENT *** if (status == FOUND) // MWOE can't be in the absorbed fragment send Inform(core,level) over E if (status == SEARCHING) // MWOE might be in the absorbed fragment add E to waitingForReport send Initiate(core,level) over E else // levels are the same, so *** MERGE WITH THE OTHER FRAGMENT *** // may be SLEEPING or may have sent Connect on E this.core = the maximum end point of E (either us or our neighbor) this.level++; *processDeferredTests() if (this.core == this) // WE'RE THE NEW ROOT, SO START THE MWOE SEARCH send Initiate(this.core,this.level) to self // start broadcast Inform(core,level): this.core = core; this.level = level; *processDeferredTests(); send "Inform(core,level)" over all other branch edges (besides E) AllDone(): note that the algorithm is over (use branchEdges as tree edges) forward "AllDone" along all other tree edges besides E SUBROUTINE: *processDeferredTests() // called whenever the level changes for each message M in deferredTests if (this.core == M.core) send "Reject" to M's sender remove M from deferredTests else if (this.level >= level) send "Accept" to M's sender remove M from deferredTests