Package net.tomp2p.relay

Source Code of net.tomp2p.relay.PeerMapUpdateTask

package net.tomp2p.relay;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;

import net.tomp2p.futures.BaseFuture;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureResponse;
import net.tomp2p.message.Message;
import net.tomp2p.message.Message.Type;
import net.tomp2p.message.NeighborSet;
import net.tomp2p.p2p.builder.BootstrapBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMapChangeListener;
import net.tomp2p.peers.PeerStatistic;
import net.tomp2p.rpc.RPC;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The PeerMapUpdateTask is responsible for periodically sending the unreachable
* peer's PeerMap to its relays. This is important as the relay peers respond to
* routing requests on behalf of the unreachable peers
*
*/
public class PeerMapUpdateTask extends TimerTask implements PeerMapChangeListener {

  private static final Logger LOG = LoggerFactory.getLogger(PeerMapUpdateTask.class);
  private static final long BOOTSTRAP_TIMEOUT_MS = 10000;

  private final RelayRPC relayRPC;
  private final BootstrapBuilder bootstrapBuilder;
  private final DistributedRelay distributedRelay;
  private final Collection<PeerAddress> manualRelays;
  private final int maxFail;

  // status whether the map has been updated in the meantime
  private final AtomicBoolean updated;

  /**
   * Create a new peer map update task.
   *
   * @param relayRPC
   *            the RelayRPC of this peer
   * @param bootstrapBuilder
   *            bootstrap builder used to find neighbors of this peer
   * @param distributedRelay
   *            set of the relay addresses
   */
  public PeerMapUpdateTask(RelayRPC relayRPC, BootstrapBuilder bootstrapBuilder, DistributedRelay distributedRelay,
      Collection<PeerAddress> manualRelays, int maxFail) {
    this.relayRPC = relayRPC;
    this.bootstrapBuilder = bootstrapBuilder;
    this.distributedRelay = distributedRelay;
    this.manualRelays = manualRelays;
    this.maxFail = maxFail;

    // register to peer map events
    this.updated = new AtomicBoolean(true);
    relayRPC.peer().peerBean().peerMap().addPeerMapChangeListener(this);
  }

  @Override
  public void run() {
    // don't cancel, as we can be relayed again in future, only cancel if this peer shuts down.
    if (relayRPC.peer().isShutdown()) {
      this.cancel();
      return;
    }

    if (bootstap() && updated.get()) {
      // reset the status since it is now sent to all relay peers
       updated.set(false);

      // send the peer map to the relays
    }
    updatePeerMap();

    if(relayRPC.peer().peerAddress().isSlow()) {
      // TODO: add digest to the relay peer, but this can lead to consistency problems
    }

    // try to add more relays
    final FutureRelay futureRelay2 = new FutureRelay();
    distributedRelay.setupRelays(futureRelay2, manualRelays, maxFail);
    relayRPC.peer().notifyAutomaticFutures(futureRelay2);
  }

  @Override
  public boolean cancel() {
    // unregister from peer map events
    relayRPC.peer().peerBean().peerMap().removePeerMapChangeListener(this);
    return super.cancel();
  }

  @Override
  public void peerInserted(PeerAddress peerAddress, boolean verified) {
    updated.set(true);
  }

  @Override
  public void peerRemoved(PeerAddress peerAddress, PeerStatistic storedPeerAddress) {
    updated.set(true);
  }

  @Override
  public void peerUpdated(PeerAddress peerAddress, PeerStatistic storedPeerAddress) {
    updated.set(true);
  }

  private boolean bootstap() {
    // bootstrap to get updated peer map and then push it to the relay peers
    return bootstrapBuilder.start().awaitUninterruptibly(BOOTSTRAP_TIMEOUT_MS);
  }

  /**
   * Bootstrap to get the latest peer map and then update all relays with the newest version
   */
  private void updatePeerMap() {
    List<Map<Number160, PeerStatistic>> peerMapVerified = relayRPC.peer().peerBean().peerMap().peerMapVerified();

    // send the map to all relay peers
    for (final BaseRelayConnection relay : distributedRelay.relays()) {
      sendPeerMap(relay, peerMapVerified);
    }
  }

  /**
   * Send the peer map of an unreachable peer to a relay peer, so that the
   * relay peer can reply to neighbor requests on behalf of the unreachable
   * peer.
   *
   * @param connection
   *            The connection to the relay peer
   * @param map
   *            The unreachable peer's peer map.
   */
  private void sendPeerMap(final BaseRelayConnection connection, List<Map<Number160, PeerStatistic>> map) {
    LOG.debug("Sending current routing table to relay {}", connection.relayAddress());

    final Message message = relayRPC
        .createMessage(connection.relayAddress(), RPC.Commands.RELAY.getNr(), Type.REQUEST_3);
    // TODO: neighbor size limit is 256, we might have more here
    message.neighborsSet(new NeighborSet(-1, RelayUtils.flatten(map)));

    final FutureResponse fr = connection.sendToRelay(message);
    fr.addListener(new BaseFutureAdapter<BaseFuture>() {
      public void operationComplete(BaseFuture future) throws Exception {
        if (future.isFailed()) {
          LOG.warn("Failed to update routing table on relay peer {}. Reason: {}", connection.relayAddress(),
              future.failedReason());
          connection.onMapUpdateFailed();
        } else {
          LOG.trace("Updated routing table on relay {}", connection.relayAddress());
          connection.onMapUpdateSuccess();
        }
      }
    });
  }
}
TOP

Related Classes of net.tomp2p.relay.PeerMapUpdateTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.