package se.sics.gvod.ls.interas; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import se.sics.gvod.ls.interas.events.InterAsSetsExchangeCycle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.sics.asdistances.ASDistances; import se.sics.gvod.common.RetryComponentDelegator; import se.sics.gvod.common.Self; import se.sics.gvod.common.VodDescriptor; import se.sics.gvod.croupier.PeerSamplePort; import se.sics.gvod.croupier.events.CroupierSample; import se.sics.gvod.interas.msgs.InterAsGossipMsg; import se.sics.gvod.ls.interas.events.InterAsSample; import se.sics.gvod.ls.interas.snapshot.InterAsStats; import se.sics.gvod.ls.system.LSConfig; import se.sics.gvod.nat.common.MsgRetryComponent; import se.sics.gvod.net.VodAddress; import se.sics.gvod.net.VodAddress.NatType; import se.sics.gvod.net.msgs.ScheduleRetryTimeout; import se.sics.kompics.Handler; import se.sics.kompics.Negative; import se.sics.kompics.Stop; import se.sics.gvod.timer.SchedulePeriodicTimeout; import se.sics.gvod.timer.TimeoutId; import se.sics.kompics.Positive; /** * * @author jim, hooman, niklas */ public class InterAs extends MsgRetryComponent { public static final int SYSTEM_INTER_AS_OVERLAY_ID = 1000; private final Logger logger = LoggerFactory.getLogger(InterAs.class); private Negative<InterAsPort> interAs = negative(InterAsPort.class); private Positive<PeerSamplePort> croupier = positive(PeerSamplePort.class); private TimeoutId setsGossipingTimeoutId; private Self self; private long setsExchangeRto; private long setsExchangePeriod; private InterAsNeighbours neighbours; private Set<TimeoutId> receivedTimeoutIds; public InterAs() { this(null); } public InterAs(RetryComponentDelegator delegator) { super(delegator); this.delegator.doAutoSubscribe(); } Handler<InterAsInit> handleInit = new Handler<InterAsInit>() { @Override public void handle(InterAsInit init) { self = init.getSelf(); setsExchangeRto = init.getSetsExchangeRto(); setsExchangePeriod = init.getSetsExchangePeriod(); SchedulePeriodicTimeout periodicTimeout = new SchedulePeriodicTimeout(0, setsExchangePeriod); periodicTimeout.setTimeoutEvent(new InterAsSetsExchangeCycle(periodicTimeout)); setsGossipingTimeoutId = periodicTimeout.getTimeoutEvent().getTimeoutId(); delegator.doTrigger(periodicTimeout, timer); neighbours = new InterAsNeighbours(self, LSConfig.INTER_AS_MAX_NEIGHBOURS, InterAsNeighbours.ARRAY_LIST); InterAsStats.addNode(self.getAddress()); receivedTimeoutIds = new HashSet<TimeoutId>(); } }; Handler<InterAsSetsExchangeCycle> handleCycle = new Handler<InterAsSetsExchangeCycle>() { @Override public void handle(InterAsSetsExchangeCycle e) { if (!neighbours.isEmpty()) { // Find ~highest utility peer VodAddress dest = neighbours.getBestNeighbour().getVodAddress(); if (dest.getId() == self.getId()) { throw new IllegalArgumentException("Can't send Request to myself"); } else { // Initiate gossiping request InterAsStats.instance(self).incSentRequests(); InterAsGossipMsg.Request request = new InterAsGossipMsg.Request(self.getAddress(), dest); ScheduleRetryTimeout schedule = new ScheduleRetryTimeout(setsExchangeRto, 1); InterAsGossipMsg.RequestRetryTimeout requestTimeout = new InterAsGossipMsg.RequestRetryTimeout(schedule, request); delegator.doRetry(request, self.getOverlayId()); if (self.getAddress().getNatType().equals(NatType.NAT)) { logger.trace("{}: Sending Request from " + self.getAddress() + " to " + request.getDestination() + " TimeoutId=" + request.getTimeoutId(), self.getId()); } } neighbours.decreasePenalites(); // Send neighbour set to parent InterAsSample sample = new InterAsSample(new ArrayList(neighbours.getAsCollection())); delegator.doTrigger(sample, interAs); } InterAsStats.instance(self).incSelectedTimes(); } }; Handler<CroupierSample> handleCroupierSample = new Handler<CroupierSample>() { @Override public void handle(CroupierSample event) { neighbours.addAll(event.getNodes()); calculateAvgAsHops(); } }; Handler<InterAsGossipMsg.Request> handleInterAsGossipMsgRequest = new Handler<InterAsGossipMsg.Request>() { @Override public void handle(InterAsGossipMsg.Request request) { if (request.getSource().getId() == self.getId()) { logger.warn("{} Received Request from myself", self.getId()); } if (request.getVodSource().getNatType().equals(NatType.NAT)) { logger.trace("{}: Received Request from " + request.getSource() + " to " + request.getDestination() + " TimeoutId=" + request.getTimeoutId(), self.getId()); } InterAsStats.instance(self).incReceivedRequests(); InterAsGossipMsg.Response resp = new InterAsGossipMsg.Response(self.getAddress(), request, new ArrayList<VodDescriptor>(neighbours.getAsCollection())); InterAsGossipMsg.Response response = new InterAsGossipMsg.Response(self.getAddress(), request.getVodSource(), request.getVodSource(), request.getTimeoutId(), new ArrayList(neighbours.getAsCollection())); if (response.getVodDestination().getNatType().equals(NatType.NAT)) { logger.trace("{}: Sending Response from " + response.getSource() + " to " + response.getDestination() + " nextDest " + response.getNextDest() + " TimeoutId=" + response.getTimeoutId(), self.getId()); } delegator.doTrigger(response, network); // InterAsStats.instance(self).incSentResponses(); } }; Handler<InterAsGossipMsg.Response> handleInterAsGossipMsgResponse = new Handler<InterAsGossipMsg.Response>() { @Override public void handle(InterAsGossipMsg.Response response) { //if (cancelRetry(msg.getTimeoutId())) { // CancelTimeout ct = new CancelTimeout(response.getTimeoutId()); // delegator.doTrigger(ct, timer); if (response.getVodSource().getId() == self.getId()) { logger.warn("{}: Received Response from myself. TimeoutId={}", self.getId(), response.getTimeoutId()); } if (self.getAddress().getNatType().equals(NatType.NAT)) { logger.trace("{}: Received Response from " + response.getSource() + " to " + response.getDestination() + " TimeoutId=" + response.getTimeoutId(), self.getId()); } delegator.doCancelRetry(response.getTimeoutId()); neighbours.addAll(response.getInterAsNeighbours()); InterAsStats.instance(self).incReceivedResponses(); if (!receivedTimeoutIds.add(response.getTimeoutId())) { logger.warn("InterAsGossipMsg.Response: Received already received TimeoutId"); } //} } }; Handler<InterAsGossipMsg.RequestRetryTimeout> handleInterAsGossipMsgRequestRetryTimeout = new Handler<InterAsGossipMsg.RequestRetryTimeout>() { @Override public void handle(InterAsGossipMsg.RequestRetryTimeout rrt) { if (cancelRetry(rrt.getTimeoutId())) { InterAsStats.instance(self).incShuffleTimeout(); neighbours.punish(rrt.getRequestMsg().getVodDestination().getId()); } } }; Handler<InterAsGossipMsg.RequestTimeout> handleInterAsGossipMsgRequestTimeout = new Handler<InterAsGossipMsg.RequestTimeout>() { @Override public void handle(InterAsGossipMsg.RequestTimeout rt) { if (receivedTimeoutIds.add(rt.getTimeoutId())) { logger.warn("{}: RequestTimeout (TimeoutId " + rt.getTimeoutId() + ")", self.getId()); InterAsStats.instance(self).incShuffleTimeout(); } else { logger.warn("InterAsGossipMsg.RequestTimeout: Received already received TimeoutId"); } } }; @Override public void stop(Stop stop) { } private void calculateAvgAsHops() { int sumAsHops = 0; for (VodDescriptor d : neighbours.getAsCollection()) { ASDistances distances = ASDistances.getInstance(); sumAsHops += distances.getDistance(self.getAddress().getIp().getHostAddress(), d.getVodAddress().getIp().getHostAddress()); } InterAsStats.instance(self).setAvgAsHops((double) ((double) sumAsHops) / ((double) neighbours.size())); } }