/// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="self"></param>
        /// <param name="protocol"></param>
        /// <param name="k"></param>
        public KFixedRoutingTable(TKNodeId self, IKNodeProtocol <TKNodeId, TKNodeData> protocol, int k = 20)
        {
            this.self     = self;
            this.protocol = protocol;
            this.k        = k;

            if (self.DistanceSize % 8 != 0)
            {
                throw new ArgumentException("NodeId must have a distance size which is a multiple of 8.");
            }

            buckets = new KBucket <TKNodeId, TKNodeData> [self.DistanceSize];
            for (var i = 0; i < buckets.Length; i++)
            {
                buckets[i] = new KBucket <TKNodeId, TKNodeData>(k);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Updates the position of the node in the bucket.
        /// </summary>
        /// <typeparam name="TKNetwork"></typeparam>
        /// <param name="nodeId"></param>
        /// <param name="nodeData"></param>
        /// <param name="nodeEvents"></param>
        /// <param name="protocol"></param>
        /// <param name="cancellationToken"></param>
        internal async ValueTask TouchAsync(TKNodeId nodeId, TKNodeData nodeData, IKNodeEvents nodeEvents, IKNodeProtocol <TKNodeId, TKNodeData> protocol, CancellationToken cancellationToken)
        {
            var lk = rw.BeginUpgradableReadLock();

            try
            {
                var i = GetNode(nodeId);
                if (i != null)
                {
                    using (rw.BeginWriteLock())
                    {
                        // item already exists, move to tail
                        l.Remove(i);
                        l.AddLast(i.Value);
                    }
                }
                else if (l.Count < k)
                {
                    using (rw.BeginWriteLock())
                    {
                        // item does not exist, but bucket has room, insert at tail
                        l.AddLast(new KBucketItem <TKNodeId, TKNodeData>(nodeId, nodeData, nodeEvents));
                    }
                }
                else
                {
                    // item does not exist, but bucket does not have room, ping first entry
                    var n = l.First;

                    // start ping, check for async completion
                    KNodePingResponse r;
                    var t = protocol.PingAsync(n.Value.Id, n.Value.Data, cancellationToken);

                    // completed synchronously (or immediately)
                    if (t.IsCompleted)
                    {
                        r = t.Result;
                    }
                    else
                    {
                        // temporarily release lock and wait for completion
                        lk.Dispose();
                        r  = await t;
                        lk = rw.BeginUpgradableReadLock();
                    }

                    // was able to successfully ping the node
                    if (r.Status == KNodeResponseStatus.OK)
                    {
                        // entry had response, move to tail, discard new entry
                        if (l.Count > 1)
                        {
                            using (rw.BeginWriteLock())
                            {
                                // remove from list if not already done (async operation could have overlapped)
                                if (n.List != null)
                                {
                                    l.Remove(n);
                                }

                                // node goes to end
                                l.AddLast(n.Value);
                            }
                        }
                    }
                    else
                    {
                        using (rw.BeginWriteLock())
                        {
                            // first entry had no response, remove, insert new at tail
                            l.Remove(n);
                            l.AddLast(new KBucketItem <TKNodeId, TKNodeData>(nodeId, nodeData, nodeEvents));
                        }
                    }
                }
            }
            finally
            {
                lk.Dispose();
            }
        }