/// <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));
     }
 }
Example #4
0
        /// <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;
            }
        }