Example #1
0
File: Dht.cs Project: pcbing/brunet
        /// <summary>This helps us leave the Get early if we either have no results or
        /// our remaining results will not reach a majority due to too many nodes
        /// missing data.  This closes the clients returns queue.</summary>
        /// <param name="adgs">The AsDhtGetState to qualify for leaving early</param>
        protected void GetLeaveEarly(AsDhtGetState adgs)
        {
            int left = adgs.queueMapping.Count;
            // Maybe we can leave early
            bool got_all_values = true;

            foreach (DictionaryEntry de in adgs.results)
            {
                int val = ((Hashtable)de.Value).Count;
                if (val < MAJORITY && ((val + left) >= MAJORITY))
                {
                    got_all_values = false;
                    break;
                }
            }

            // If we got to leave early, we must clean up
            if (got_all_values)
            {
                if (Dht.DhtLog.Enabled)
                {
                    ProtocolLog.Write(Dht.DhtLog, String.Format(
                                          "GetLeaveEarly found:left:total = {0}:{1}:{2}",
                                          adgs.results.Count, left, DEGREE));
                }
                adgs.returns.Close();
                adgs.GotToLeaveEarly = true;
            }
        }
Example #2
0
File: Dht.cs Project: pcbing/brunet
        /// <summary>Restores any of the Dht results that don't return all their
        /// values.  We only get here at the end of a Dht return operation.</summary>
        /// <remarks>This analyzes the holes and fills them in individually.  This only
        /// fills holes where there was a positive result (MAJORITY of results
        /// received).</remarks>
        /// <param name="adgs">The AsDhtGetState to analyze for follow up.</param>
        protected void GetFollowUp(AsDhtGetState adgs)
        {
            foreach (DictionaryEntry de in adgs.results)
            {
                if (de.Value == null || de.Key == null)
                {
                    continue;
                }

                Hashtable res = (Hashtable)de.Value;
                if (res.Count < MAJORITY || res.Count == DEGREE)
                {
                    if (res.Count < MAJORITY)
                    {
                        if (Dht.DhtLog.Enabled)
                        {
                            ProtocolLog.Write(Dht.DhtLog, String.Format(
                                                  "Failed get count:total = {0}:{1}", res.Count, DEGREE));
                        }
                    }
                    res.Clear();
                    continue;
                }
                MemBlock value = (MemBlock)de.Key;

                int ttl = (int)adgs.ttls[value] / res.Count;
                if (Dht.DhtLog.Enabled)
                {
                    ProtocolLog.Write(Dht.DhtLog, String.Format(
                                          "Doing follow up put count:total = {0}:{1}", res.Count, DEGREE));
                }
                for (int i = 0; i < DEGREE; i++)
                {
                    if (!res.Contains(i))
                    {
                        MemBlock key    = adgs.brunet_address_for_key[i];
                        Channel  queue  = new Channel();
                        Address  target = new AHAddress(key);
                        AHSender s      = new AHGreedySender(Node, target);
                        try {
                            _rpc.Invoke(s, queue, "dht.Put", key, value, ttl, false);
                        }
                        catch (Exception) {}
                    }
                }
                res.Clear();
            }
            adgs.ttls.Clear();
            adgs.results.Clear();
        }
Example #3
0
File: Dht.cs Project: pcbing/brunet
        /// <remarks>This starts the get process by sending dht.Get to all the remote
        /// end points that contain the key we're looking up.  The next step is
        /// is when the results are placed in the channel and GetEnqueueHandler is
        /// called or GetCloseHandler is called.  This means the get needs to be
        /// stateful, that information is stored in the _adgs_table.</remarks>
        public void AsyncGet(MemBlock key, Channel returns)
        {
            if (!_online)
            {
                throw new DhtException("The Node is (going) offline, DHT is offline.");
            }
            // create a GetState and map in our table map its queues to it
            // so when we get a GetHandler we know which state to load
            AsDhtGetState adgs = new AsDhtGetState(returns);

            Channel[] q = new Channel[DEGREE];
            lock (_adgs_table.SyncRoot) {
                for (int k = 0; k < DEGREE; k++)
                {
                    Channel queue = new Channel(1);
                    _adgs_table[queue] = adgs;
                    q[k] = queue;
                }
            }

            // Setting up our Channels
            for (int k = 0; k < DEGREE; k++)
            {
                Channel queue = q[k];
                queue.EnqueueEvent      += this.GetEnqueueHandler;
                queue.CloseEvent        += this.GetCloseHandler;
                adgs.queueMapping[queue] = k;
            }

            // Sending off the request!
            adgs.brunet_address_for_key = MapToRing(key);
            for (int k = 0; k < DEGREE; k++)
            {
                Address  target = new AHAddress(adgs.brunet_address_for_key[k]);
                AHSender s      = new AHGreedySender(Node, target);
                // 1024 is in there for backwards compatibility
                _rpc.Invoke(s, q[k], "dht.Get", adgs.brunet_address_for_key[k], 1024, null);
            }
        }
Example #4
0
File: Dht.cs Project: pcbing/brunet
        /// <summary>This is called by the Get callbacks when all the results for a
        /// get have come in.  This looks at the results, finds holes, and does a
        /// follow up put to place the data back into the dht via GetFollowUp.
        /// </summary>
        /// <param name="o">The channel representing a specific get.</param>
        /// <param name="args">Unused.</param>
        protected void GetCloseHandler(object o, EventArgs args)
        {
            Channel queue = (Channel)o;

            queue.EnqueueEvent -= this.GetEnqueueHandler;
            queue.CloseEvent   -= this.GetCloseHandler;
            // Looking up state
            AsDhtGetState adgs = (AsDhtGetState)_adgs_table[queue];

            if (adgs == null)
            {
                return;
            }

            int count = 0;

            lock (adgs.SyncRoot) {
                adgs.queueMapping.Remove(queue);
                count = adgs.queueMapping.Count;
            }
            lock (_adgs_table.SyncRoot) {
                _adgs_table.Remove(queue);
            }
            if (count == 0)
            {
                adgs.returns.Close();
                GetFollowUp(adgs);
            }
            else if (count < MAJORITY && !adgs.GotToLeaveEarly)
            {
                lock (adgs.SyncRoot) {
                    if (!adgs.GotToLeaveEarly)
                    {
                        GetLeaveEarly(adgs);
                    }
                }
            }
        }
Example #5
0
File: Dht.cs Project: pcbing/brunet
        /// <summary>This is called as a result of a successful retrieval of data
        /// from a remote end point and performs follow up gets for remaining values
        /// </summary>
        /// <remarks>This adds the results to the entry in the _adgs_table.  Once a
        /// value has been received by a majority of nodes, it is enqueued into the
        /// requestors returns channel.  If not all results were retrieved follow up
        /// gets are performed, this is determined by looking at the state of the
        /// token, a non-null token implies there are remaining results.</remarks>
        /// <param name="o">The channel used to store the results.</param>
        /// <param name="args">Unused.</param>
        public void GetEnqueueHandler(Object o, EventArgs args)
        {
            Channel queue = (Channel)o;
            // Looking up state
            AsDhtGetState adgs = (AsDhtGetState)_adgs_table[queue];

            if (adgs == null)
            {
                return;
            }

            int idx = (int)adgs.queueMapping[queue];
            // Test to see if we got any results and place them into results if necessary
            ISender  sendto = null;
            MemBlock token  = null;

            try {
                RpcResult rpc_reply = (RpcResult)queue.Dequeue();
                ArrayList result    = (ArrayList)rpc_reply.Result;
                //Result may be corrupted
                if (result == null)
                {
                    throw new Exception("Invalid result");
                }
                ArrayList values    = (ArrayList)result[0];
                int       remaining = (int)result[1];
                if (remaining > 0)
                {
                    token  = MemBlock.Reference((byte[])result[2]);
                    sendto = rpc_reply.ResultSender;
                }

                // Going through the return values and adding them to our
                // results, if a majority of our servers say a data exists
                // we say it is a valid data and return it to the caller
                foreach (Hashtable ht in values)
                {
                    MemBlock  mbVal = MemBlock.Reference((byte[])ht["value"]);
                    int       count = 1;
                    Hashtable res   = null;
                    lock (adgs.SyncRoot) {
                        res = (Hashtable)adgs.results[mbVal];
                        if (res == null)
                        {
                            res = new Hashtable();
                            adgs.results[mbVal] = res;
                            adgs.ttls[mbVal]    = ht["ttl"];
                        }
                        else
                        {
                            adgs.ttls[mbVal] = (int)adgs.ttls[mbVal] + (int)ht["ttl"];
                        }

                        res[idx] = true;
                        count    = ((ICollection)adgs.results[mbVal]).Count;
                    }
                    if (count == MAJORITY)
                    {
                        ht["ttl"] = (int)adgs.ttls[mbVal] / MAJORITY;
                        adgs.returns.Enqueue(ht);
                    }
                }
            }
            catch (Exception) {
                sendto = null;
                token  = null;
            }

            // We were notified that more results were available!  Let's go get them!
            if (token != null && sendto != null)
            {
                Channel new_queue = new Channel(1);
                lock (adgs.SyncRoot) {
                    adgs.queueMapping[new_queue] = idx;
                }
                lock (_adgs_table.SyncRoot) {
                    _adgs_table[new_queue] = adgs;
                }
                new_queue.EnqueueEvent += this.GetEnqueueHandler;
                new_queue.CloseEvent   += this.GetCloseHandler;
                try {
                    _rpc.Invoke(sendto, new_queue, "dht.Get",
                                adgs.brunet_address_for_key[idx], token);
                }
                catch (Exception) {
                    lock (adgs.SyncRoot) {
                        adgs.queueMapping.Remove(new_queue);
                    }
                    lock (_adgs_table.SyncRoot) {
                        _adgs_table.Remove(new_queue);
                    }
                    new_queue.EnqueueEvent -= this.GetEnqueueHandler;
                    new_queue.CloseEvent   -= this.GetCloseHandler;
                }
            }
        }
Example #6
0
    /// <summary>Restores any of the Dht results that don't return all their
    /// values.  We only get here at the end of a Dht return operation.</summary>
    /// <remarks>This analyzes the holes and fills them in individually.  This only
    /// fills holes where there was a positive result (MAJORITY of results
    /// received).</remarks>
    /// <param name="adgs">The AsDhtGetState to analyze for follow up.</param>
    protected void GetFollowUp(AsDhtGetState adgs) {
      foreach (DictionaryEntry de in adgs.results) {
        if(de.Value == null || de.Key == null) {
          continue;
        }

        Hashtable res = (Hashtable) de.Value;
        if(res.Count < MAJORITY || res.Count == DEGREE) {
          if(res.Count < MAJORITY) {
            if(Dht.DhtLog.Enabled) {
              ProtocolLog.Write(Dht.DhtLog, String.Format(
                "Failed get count:total = {0}:{1}", res.Count, DEGREE));
            }
          }
          res.Clear();
          continue;
        }
        MemBlock value = (MemBlock) de.Key;

        int ttl = (int) adgs.ttls[value] / res.Count;
        if(Dht.DhtLog.Enabled) {
          ProtocolLog.Write(Dht.DhtLog, String.Format(
            "Doing follow up put count:total = {0}:{1}", res.Count, DEGREE));
        }
        for(int i = 0; i < DEGREE; i++) {
          if(!res.Contains(i)) {
            MemBlock key = adgs.brunet_address_for_key[i];
            Channel queue = new Channel();
            Address target = new AHAddress(key);
            AHSender s = new AHSender(Node, target, AHPacket.AHOptions.Greedy);
            try {
             _rpc.Invoke(s, queue, "dht.Put", key, value, ttl, false);
            }
            catch(Exception) {}
          }
        }
        res.Clear();
      }
      adgs.ttls.Clear();
      adgs.results.Clear();
    }
Example #7
0
    /// <summary>This helps us leave the Get early if we either have no results or
    /// our remaining results will not reach a majority due to too many nodes
    /// missing data.  This closes the clients returns queue.</summary>
    /// <param name="adgs">The AsDhtGetState to qualify for leaving early</param>
    protected void GetLeaveEarly(AsDhtGetState adgs) {
      int left = adgs.queueMapping.Count;
      // Maybe we can leave early
      bool got_all_values = true;
      foreach (DictionaryEntry de in adgs.results) {
        int val = ((Hashtable) de.Value).Count;
        if(val < MAJORITY && ((val + left) >= MAJORITY)) {
          got_all_values = false;
          break;
        }
      }

      // If we got to leave early, we must clean up
      if(got_all_values) {
        if(Dht.DhtLog.Enabled) {
          ProtocolLog.Write(Dht.DhtLog, String.Format(
            "GetLeaveEarly found:left:total = {0}:{1}:{2}", 
            adgs.results.Count, left, DEGREE));
        }
        adgs.returns.Close();
        adgs.GotToLeaveEarly = true;
      }
    }
Example #8
0
    /// <remarks>This starts the get process by sending dht.Get to all the remote
    /// end points that contain the key we're looking up.  The next step is
    /// is when the results are placed in the channel and GetEnqueueHandler is
    /// called or GetCloseHandler is called.  This means the get needs to be
    /// stateful, that information is stored in the _adgs_table.</remarks>
    public void AsyncGet(MemBlock key, Channel returns) {
      if(!_online) {
        throw new DhtException("The Node is (going) offline, DHT is offline.");
      }
      // create a GetState and map in our table map its queues to it
      // so when we get a GetHandler we know which state to load
      AsDhtGetState adgs = new AsDhtGetState(returns);
      Channel[] q = new Channel[DEGREE];
      lock(_adgs_table.SyncRoot) {
        for (int k = 0; k < DEGREE; k++) {
          Channel queue = new Channel(1);
          _adgs_table[queue] = adgs;
          q[k] = queue;
        }
      }

      // Setting up our Channels
      for (int k = 0; k < DEGREE; k++) {
        Channel queue = q[k];
        queue.EnqueueEvent += this.GetEnqueueHandler;
        queue.CloseEvent += this.GetCloseHandler;
        adgs.queueMapping[queue] = k;
      }

      // Sending off the request!
      adgs.brunet_address_for_key = MapToRing(key);
      for (int k = 0; k < DEGREE; k++) {
        Address target = new AHAddress(adgs.brunet_address_for_key[k]);
        AHSender s = new AHSender(Node, target, AHPacket.AHOptions.Greedy);
        // 1024 is in there for backwards compatibility
        _rpc.Invoke(s, q[k], "dht.Get", adgs.brunet_address_for_key[k], 1024, null);
      }
    }