/// <summary>This is the generic Put that is used by both the regular Put /// and Create methods. The use of the unique variable differentiates the /// two. This is asynchronous. Results are stored in the Channel returns. /// Creates and Puts return true if successful or exception if there are /// network errors in adding the entry, creates also fail if a previous /// entry exists. The work of determining success is handled in /// PutEnqueueHandler and PutCloseHandler.</summary> /// <param name="key">The index to store the value at.</param> /// <param name="value">The value to store.</param> /// <param name="ttl">The dht lease time for the key:value pair.</param> /// <param name="returns">The Channel where the result will be placed.</param> /// <param name="unique">True to do a create, false otherwise.</param> public void AsyncPut(MemBlock key, MemBlock value, int ttl, Channel returns, bool unique) { if (!_online) { throw new DhtException("The Node is (going) offline, DHT is offline."); } AsDhtPutState adps = new AsDhtPutState(returns); MemBlock[] brunet_address_for_key = MapToRing(key); Channel[] q = new Channel[DEGREE]; lock (_adps_table.SyncRoot) { for (int k = 0; k < DEGREE; k++) { Channel queue = new Channel(1); queue.CloseEvent += this.PutCloseHandler; _adps_table[queue] = adps; q[k] = queue; } } for (int k = 0; k < DEGREE; k++) { Address target = new AHAddress(brunet_address_for_key[k]); AHSender s = new AHGreedySender(Node, target); _rpc.Invoke(s, q[k], "dht.Put", brunet_address_for_key[k], value, ttl, unique); } }
/// <summary>Uses the channel to determine which Put this is processing. /// Returns true if we've received a MAJORITY of votes or an exception if a /// enough negative results come in. The returns are enqueued to the users /// returns Channel.<summary> /// <param name="o">The channel used by put.</param> /// <param name="args">Unused.</param> public void PutCloseHandler(Object o, EventArgs args) { Channel queue = (Channel)o; // Get our mapping AsDhtPutState adps = (AsDhtPutState)_adps_table[queue]; if (adps == null) { return; } lock (_adps_table.SyncRoot) { _adps_table.Remove(queue); } /* Check out results from our request and update the overall results * send a message to our client if we're done! */ bool result = false; try { RpcResult rpcResult = (RpcResult)queue.Dequeue(); result = (bool)rpcResult.Result; } catch (Exception) {} if (result) { // Once we get pcount to a majority, we ship off the result if (Interlocked.Increment(ref adps.pcount) == MAJORITY) { adps.returns.Enqueue(true); adps.returns.Close(); } } else { // Once we get to ncount to 1 less than a majority, we ship off the // result, because we can't get pcount equal to majority any more! if (Interlocked.Increment(ref adps.ncount) == MAJORITY - 1 || 1 == DEGREE) { adps.returns.Enqueue(new DhtPutException(DEGREE, adps.pcount, adps.ncount)); adps.returns.Close(); } } }
/// <summary>This is the generic Put that is used by both the regular Put /// and Create methods. The use of the unique variable differentiates the /// two. This is asynchronous. Results are stored in the Channel returns. /// Creates and Puts return true if successful or exception if there are /// network errors in adding the entry, creates also fail if a previous /// entry exists. The work of determining success is handled in /// PutEnqueueHandler and PutCloseHandler.</summary> /// <param name="key">The index to store the value at.</param> /// <param name="value">The value to store.</param> /// <param name="ttl">The dht lease time for the key:value pair.</param> /// <param name="returns">The Channel where the result will be placed.</param> /// <param name="unique">True to do a create, false otherwise.</param> public void AsyncPut(MemBlock key, MemBlock value, int ttl, Channel returns, bool unique) { if(!_online) { throw new DhtException("The Node is (going) offline, DHT is offline."); } AsDhtPutState adps = new AsDhtPutState(returns); MemBlock[] brunet_address_for_key = MapToRing(key); Channel[] q = new Channel[DEGREE]; lock(_adps_table.SyncRoot) { for (int k = 0; k < DEGREE; k++) { Channel queue = new Channel(1); queue.CloseEvent += this.PutCloseHandler; _adps_table[queue] = adps; q[k] = queue; } } for (int k = 0; k < DEGREE; k++) { Address target = new AHAddress(brunet_address_for_key[k]); AHSender s = new AHSender(Node, target, AHPacket.AHOptions.Greedy); _rpc.Invoke(s, q[k], "dht.Put", brunet_address_for_key[k], value, ttl, unique); } }
/** <summary>This is the generic Put that is used by both the regular Put and Create methods. The use of the unique variable differentiates the two. This is asynchronous. Results are stored in the Channel returns. Creates and Puts return true if successful or exception if there are network errors in adding the entry, creates also fail if a previous entry exists. The work of determining success is handled in PutEnqueueHandler and PutCloseHandler.</summary> <param name="key">The index to store the value at.</param> <param name="value">The value to store.</param> <param name="ttl">The dht lease time for the key:value pair.</param> <param name="returns">The Channel where the result will be placed.</param> <param name="unique">True to do a create, false otherwise.</param> */ public void AsPut(MemBlock key, MemBlock value, int ttl, Channel returns, bool unique) { if (!Activated) { throw new Exception("DhtClient: Not yet activated."); } returns.CloseAfterEnqueue(); AsDhtPutState adps = new AsDhtPutState(returns); MemBlock[] brunet_address_for_key = MapToRing(key); Channel[] q = new Channel[DEGREE]; lock(_adps_table.SyncRoot) { for (int k = 0; k < DEGREE; k++) { Channel queue = new Channel(); queue.CloseAfterEnqueue(); queue.CloseEvent += this.PutCloseHandler; _adps_table[queue] = adps; q[k] = queue; } } for (int k = 0; k < DEGREE; k++) { Address target = new AHAddress(brunet_address_for_key[k]); AHSender s = new AHSender(node, target, AHPacket.AHOptions.Greedy); _rpc.Invoke(s, q[k], "dht.Put", brunet_address_for_key[k], value, ttl, unique); } }