Package net.tomp2p.p2p

Source Code of net.tomp2p.p2p.DistributedTask$Pair

/*
* Copyright 2012 Thomas Bocek
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package net.tomp2p.p2p;

import java.util.Map;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceArray;

import net.tomp2p.connection2.ChannelCreator;
import net.tomp2p.connection2.ConnectionReservation;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureAsyncTask;
import net.tomp2p.futures.FutureChannelCreator;
import net.tomp2p.futures.FutureForkJoin;
import net.tomp2p.futures.FutureRouting;
import net.tomp2p.futures.FutureTask;
import net.tomp2p.message.Message.Type;
import net.tomp2p.p2p.builder.RoutingBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.rpc.DigestInfo;
import net.tomp2p.storage.Data;
import net.tomp2p.task.AsyncTask;
import net.tomp2p.task.Worker;
import net.tomp2p.utils.Utils;

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

public class DistributedTask {
    final private static Logger logger = LoggerFactory.getLogger(DistributedTask.class);

    final private DistributedRouting routing;

    final private AsyncTask asyncTask;

    public DistributedTask(DistributedRouting routing, AsyncTask asyncTask) {
        this.routing = routing;
        this.asyncTask = asyncTask;
    }

    /**
     * Submit a task to the DHT. The node that is close to the locationKey will get the task. The routing process
     * returns a list of close peers with the current load. The peer with the lowest load will get the task.
     *
     * @param locationKey
     * @param dataMap
     * @param routingConfiguration
     * @param taskConfiguration
     * @param futureChannelCreator
     * @param signMessage
     * @param isAutomaticCleanup
     * @param connectionReservation
     * @return
     */
    public FutureTask submit(final Number160 locationKey, final Map<Number160, Data> dataMap, final Worker worker,
            final RoutingConfiguration routingConfiguration, final RequestP2PConfiguration requestP2PConfiguration,
            final FutureChannelCreator futureChannelCreator, final boolean signMessage, final boolean isManualCleanup,
            final ConnectionReservation connectionReservation) {
        final FutureTask futureTask = new FutureTask();
        futureChannelCreator.addListener(new BaseFutureAdapter<FutureChannelCreator>() {
            @Override
            public void operationComplete(FutureChannelCreator future) throws Exception {
                if (future.isSuccess()) {
                    final ChannelCreator channelCreator = future.getChannelCreator();
                    // routing, find close peers
                    final FutureRouting futureRouting = createRouting(locationKey, null, null, routingConfiguration,
                            requestP2PConfiguration, Type.REQUEST_4, channelCreator);
                    futureRouting.addListener(new BaseFutureAdapter<FutureRouting>() {
                        @Override
                        public void operationComplete(FutureRouting future) throws Exception {
                            if (futureRouting.isSuccess()) {
                                // direct hits mean that there
                                // is a task scheduled
                                SortedMap<PeerAddress, DigestInfo> map = future.getDirectHitsDigest();
                                // potential hits means that no
                                // task is scheduled
                                NavigableSet<Pair> queue = findBest(map, future.getPotentialHits(), locationKey);
                                parallelRequests(futureTask, queue, requestP2PConfiguration, channelCreator,
                                        locationKey, dataMap, worker, requestP2PConfiguration.isForceUPD(), signMessage);
                            } else {
                                futureTask.setFailed(futureRouting);
                            }
                        }
                    });
                }
                if (!isManualCleanup) {
                    Utils.addReleaseListenerAll(futureTask, connectionReservation, future.getChannelCreator());
                } else {
                    futureTask.setFailed(future);
                }
            }
        });
        return futureTask;
    }

    private void parallelRequests(FutureTask futureTask, NavigableSet<Pair> queue,
            RequestP2PConfiguration requestP2PConfiguration, ChannelCreator channelCreator, Number160 taskId,
            Map<Number160, Data> dataMap, Worker worker, boolean forceUDP, boolean sign) {
        FutureAsyncTask[] futures = new FutureAsyncTask[requestP2PConfiguration.getParallel()];
        loopRec(queue, requestP2PConfiguration.getMinimumResults(), new AtomicInteger(0),
                requestP2PConfiguration.getMaxFailure(), requestP2PConfiguration.getParallelDiff(),
                new AtomicReferenceArray<FutureAsyncTask>(futures), futureTask, true, channelCreator, taskId, dataMap,
                worker, forceUDP, sign);
    }

    private void loopRec(final NavigableSet<Pair> queue, final int min, final AtomicInteger nrFailure,
            final int maxFailure, final int parallelDiff, final AtomicReferenceArray<FutureAsyncTask> futures,
            final FutureTask futureTask, final boolean cancelOnFinish, final ChannelCreator channelCreator,
            final Number160 taskId, final Map<Number160, Data> dataMap, final Worker mapper, final boolean forceUDP,
            final boolean sign) {
        int active = 0;
        for (int i = 0; i < min + parallelDiff; i++) {
            if (futures.get(i) == null) {
                PeerAddress next = queue.pollFirst().peerAddress;
                if (next != null) {
                    active++;
                    FutureAsyncTask futureAsyncTask = asyncTask.submit(next, channelCreator, taskId, dataMap, mapper,
                            forceUDP, sign);
                    futures.set(i, futureAsyncTask);
                    futureTask.addRequests(futureAsyncTask);
                }
            } else {
                active++;
            }
        }
        if (active == 0) {
            futureTask.setDone();
            DistributedRouting.cancel(cancelOnFinish, min + parallelDiff, futures);
            return;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("fork/join status: " + min + "/" + active + " (" + parallelDiff + ")");
        }
        FutureForkJoin<FutureAsyncTask> fp = new FutureForkJoin<FutureAsyncTask>(Math.min(min, active), false, futures);
        fp.addListener(new BaseFutureAdapter<FutureForkJoin<FutureAsyncTask>>() {
            @Override
            public void operationComplete(FutureForkJoin<FutureAsyncTask> future) throws Exception {
                for (FutureAsyncTask futureAsyncTask : future.getCompleted()) {
                    futureTask.setProgress(futureAsyncTask);
                }
                // we are finished if forkjoin says so or we got too many
                // failures
                if (future.isSuccess() || nrFailure.incrementAndGet() > maxFailure) {
                    if (cancelOnFinish) {
                        DistributedRouting.cancel(cancelOnFinish, min + parallelDiff, futures);
                    }
                    futureTask.setDone();
                } else {
                    loopRec(queue, min - future.getSuccessCounter(), nrFailure, maxFailure, parallelDiff, futures,
                            futureTask, cancelOnFinish, channelCreator, taskId, dataMap, mapper, forceUDP, sign);
                }
            }
        });
    }

    private FutureRouting createRouting(Number160 locationKey, Number160 domainKey, Set<Number160> contentKeys,
            RoutingConfiguration routingConfiguration, RequestP2PConfiguration requestP2PConfiguration, Type type,
            ChannelCreator channelCreator) {
        return routing.route(new RoutingBuilder(locationKey, domainKey, contentKeys, routingConfiguration.getDirectHits(), routingConfiguration.getMaxNoNewInfo(requestP2PConfiguration.getMinimumResults()), routingConfiguration.getMaxFailures(), routingConfiguration.getMaxSuccess(), routingConfiguration.getParallel(),
                routingConfiguration.isForceTCP()), type, channelCreator);
    }

    static NavigableSet<Pair> findBest(SortedMap<PeerAddress, DigestInfo> map, NavigableSet<PeerAddress> navigableSet,
            Number160 locationKey) {
        NavigableSet<Pair> set = new TreeSet<DistributedTask.Pair>();
        for (Map.Entry<PeerAddress, DigestInfo> entry : map.entrySet()) {
            set.add(new Pair(entry.getKey(), entry.getValue().getSize(), locationKey));
        }
        for (PeerAddress peerAddress : navigableSet) {
            set.add(new Pair(peerAddress, 0, locationKey));
        }
        return set;
    }

    private static class Pair implements Comparable<Pair> {
        private final PeerAddress peerAddress;

        private final int queueSize;

        private final Number160 locationKey;

        public Pair(PeerAddress peerAddress, int queueSize, Number160 locationKey) {
            this.peerAddress = peerAddress;
            this.queueSize = queueSize;
            this.locationKey = locationKey;
        }

        @Override
        public int compareTo(Pair o) {
            int diff = queueSize - o.queueSize;
            if (diff != 0)
                return diff;
            return PeerMap.isKadCloser(locationKey, peerAddress, o.peerAddress);
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Pair))
                return false;
            return compareTo((Pair) obj) == 0;
        }
    }
}
TOP

Related Classes of net.tomp2p.p2p.DistributedTask$Pair

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.