/// <summary> /// Replicate the local data store on a background thread. /// </summary> /// <param name="sender">The background worker thread this task is running on.</param> /// <param name="ea">Args (ignored).</param> private void ReplicateStorage(object sender, DoWorkEventArgs ea) { BackgroundWorker me = (BackgroundWorker)sender; while (!me.CancellationPending) { try { // replicate each key to the successor safely foreach (ulong key in this.m_DataStore.Keys) { // if the key is local (don't copy replicas) if (ChordServer.IsIDInRange(key, this.ID, this.Successor.ID)) { ChordServer.CallReplicateKey(this.Successor, key, this.m_DataStore[key]); } } } catch (Exception e) { // (overly safe here) ChordServer.Log(LogLevel.Error, "Maintenance", "Error occured during ReplicateStorage ({0})", e.Message); } // TODO: make this configurable via config file or passed in as an argument Thread.Sleep(30000); } }
/// <summary> /// Maintenance task to ensure that the local node has valid successor node. Roughly equivalent /// to what is called out in the Chord paper. /// </summary> /// <param name="sender">The worker thread the task is running on.</param> /// <param name="ea">Args (ignored here).</param> private void StabilizeSuccessors(object sender, DoWorkEventArgs ea) { BackgroundWorker me = (BackgroundWorker)sender; while (!me.CancellationPending) { try { // check in successor and if it's bad, replace it with // the next live entry in the successor cache ChordNode succPredNode = ChordServer.GetPredecessor(this.Successor); if (succPredNode != null) { if (ChordServer.IsIDInRange(succPredNode.ID, this.ID, this.Successor.ID)) { this.Successor = succPredNode; } // ignoring return because bad node will be detected on next invocation ChordServer.CallNotify(this.Successor, ChordServer.LocalNode); GetSuccessorCache(this.Successor); } else { bool successorCacheHelped = false; foreach (ChordNode entry in this.m_SuccessorCache) { ChordInstance instance = ChordServer.GetInstance(entry); if (ChordServer.IsInstanceValid(instance)) { this.Successor = entry; ChordServer.CallNotify(this.Successor, ChordServer.LocalNode); GetSuccessorCache(this.Successor); successorCacheHelped = true; break; } } // if we get here, then we got no help and have no other recourse than to re-join using the initial seed... if (!successorCacheHelped) { ChordServer.Log(LogLevel.Error, "StabilizeSuccessors", "Ring consistency error, Re-Joining Chord ring."); Join(this.m_SeedNode, this.Host, this.Port); return; } } } catch (Exception e) { ChordServer.Log(LogLevel.Error, "Maintenance", "Error occured during StabilizeSuccessors ({0})", e.Message); } // TODO: this could be tweaked and/or made configurable elsewhere or passed in as arguments Thread.Sleep(5000); } }
/// <summary> /// Find the node that is the rightful owner of a given id. /// </summary> /// <param name="id">The id whose successor should be found.</param> /// <param name="hopCount">The number of network hops taken in finding the successor.</param> /// <returns>The ChordNode that is the Successor of a given ID value.</returns> public ChordNode FindSuccessor(UInt64 id, int hopCountIn, out int hopCountOut) { // is the local node's successor the rightful owner? if (ChordServer.IsIDInRange(id, this.ID, this.Successor.ID)) { hopCountOut = hopCountIn; return(this.Successor); } else { // otherwise, find the nearest preceding finger, and ask that node. ChordNode predNode = FindClosestPrecedingFinger(id); return(ChordServer.CallFindSuccessor(predNode, id, 0, ++hopCountIn, out hopCountOut)); } }
/// <summary> /// Called by the predecessor to a remote node, this acts as a dual heartbeat mechanism and more importantly /// notification mechanism between predecessor and successor. /// </summary> /// <param name="node">A ChordNode instance indicating who the calling node (predecessor) is.</param> public void Notify(ChordNode node) { // if the node has absolutely no predecessor, take // the first one it finds if (this.Predecessor == null) { this.Predecessor = node; return; } // otherwise, ensure that the predecessor that is calling in // is indeed valid... if (ChordServer.IsIDInRange(node.ID, this.Predecessor.ID, this.ID)) { this.Predecessor = node; return; } }