1
0
mirror of https://github.com/Rogiel/torrent4j synced 2025-12-05 23:22:49 +00:00

Scoring algorithm

This commit is contained in:
rogiel
2011-04-28 14:30:33 -03:00
parent 209cfb9deb
commit 6bf0be8fca
16 changed files with 498 additions and 92 deletions

30
pom.xml
View File

@@ -5,7 +5,7 @@
<artifactId>libtorrent</artifactId>
<packaging>jar</packaging>
<name>libtorrent</name>
<version>1.0</version>
<version>1.0.0-alpha2</version>
<description>Java library used for downloading and uploading torrent files</description>
<url>http://code.google.com/p/libtorrent-java</url>
@@ -97,6 +97,34 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pdf-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>pdf</id>
<phase>package</phase>
<goals>
<goal>pdf</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>clean</id>
<phase>package</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>

View File

@@ -21,6 +21,8 @@ import net.torrent.protocol.algorithm.TorrentPeerAlgorithm;
import net.torrent.protocol.algorithm.TorrentPieceDownloadAlgorithm;
import net.torrent.protocol.algorithm.TorrentPieceUploadAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.piece.PieceSelector;
import net.torrent.torrent.piece.ScoredPieceSelector;
/**
* Standard torrent algorithm
@@ -28,15 +30,21 @@ import net.torrent.protocol.peerwire.manager.TorrentManager;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentStdAlgorithm implements TorrentAlgorithm {
private final PieceSelector pieceSelector;
private final TorrentPeerAlgorithm peerAlgorithm;
private final TorrentInterestAlgorithm interestAlgorithm;
private final TorrentPieceDownloadAlgorithm downloadAlgorithm;
private final TorrentPieceUploadAlgorithm uploadAlgorithm;
public TorrentStdAlgorithm(final TorrentManager manager) {
pieceSelector = new ScoredPieceSelector(manager);
peerAlgorithm = new TorrentStdPeerAlgorithm(manager);
interestAlgorithm = new TorrentStdInterestAlgorithm(manager);
downloadAlgorithm = new TorrentStdPieceDownloadAlgorithm(manager);
interestAlgorithm = new TorrentStdInterestAlgorithm(manager,
pieceSelector);
downloadAlgorithm = new TorrentStdPieceDownloadAlgorithm(manager,
pieceSelector);
uploadAlgorithm = new TorrentStdPieceUploadAlgorithm(manager);
}

View File

@@ -20,6 +20,7 @@ import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
import net.torrent.torrent.context.TorrentPeer.InterestState;
import net.torrent.torrent.piece.PieceSelector;
/**
* Standard torrent interest algorithm
@@ -29,15 +30,29 @@ import net.torrent.torrent.context.TorrentPeer.InterestState;
public class TorrentStdInterestAlgorithm implements TorrentInterestAlgorithm {
@SuppressWarnings("unused")
private final TorrentManager manager;
private final PieceSelector selector;
public TorrentStdInterestAlgorithm(TorrentManager manager) {
/**
* Creates a new instance
*
* @param manager
* the manager
* @param pieceSelector
* the piece selector
*/
public TorrentStdInterestAlgorithm(TorrentManager manager,
PieceSelector pieceSelector) {
this.manager = manager;
this.selector = pieceSelector;
}
@Override
public InterestState interested(TorrentPeer peer) {
// if(peer.getPort() == 25944)
// return InterestState.UNINTERESTED;
int pieces = selector.countPieces(peer);
if(pieces >= 5)
return InterestState.INTERESTED;
return InterestState.INTERESTED;
}

View File

@@ -24,7 +24,6 @@ import net.torrent.torrent.TorrentPart;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.piece.PieceSelector;
import net.torrent.torrent.piece.RandomPieceSelector;
/**
* This standard implementation of {@link TorrentPieceDownloadAlgorithm} chooses
@@ -39,8 +38,6 @@ public class TorrentStdPieceDownloadAlgorithm implements
* The torrent manager
*/
private final TorrentManager manager;
// private final TorrentContext context;
// private final Torrent torrent;
/**
* This selector is used to find the next piece to be downloaded. Parts are
@@ -61,12 +58,13 @@ public class TorrentStdPieceDownloadAlgorithm implements
* @param manager
* the torrent manager instance. With this object is possible to
* retrieve current downloads/uploads and connections.
* @param pieceSelector
* the piece selector
*/
public TorrentStdPieceDownloadAlgorithm(TorrentManager manager) {
public TorrentStdPieceDownloadAlgorithm(TorrentManager manager,
PieceSelector pieceSelector) {
this.manager = manager;
// this.context = this.manager.getContext();
// this.torrent = this.manager.getTorrent();
selector = new RandomPieceSelector(manager);
this.selector = pieceSelector;
}
@Override

View File

@@ -45,7 +45,7 @@ import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
import net.torrent.torrent.context.TorrentPeer.InterestState;
import net.torrent.torrent.context.TorrentPeerCapabilities.TorrentPeerCapability;
import net.torrent.util.PeerCallback;
import net.torrent.util.PeerWirePeerCallback;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
@@ -343,7 +343,7 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
if (datastore.checksum(part.getPiece())) {
manager.getContext().getBitfield().setPiece(part.getPiece(), true);
manager.getPeerManager().executeActive(new PeerCallback() {
manager.getPeerManager().executeActive(new PeerWirePeerCallback() {
@Override
public void callback(PeerWirePeer peer) {
peer.have(part.getPiece().getIndex());

View File

@@ -25,7 +25,7 @@ import java.util.Set;
import net.torrent.protocol.peerwire.PeerWirePeer;
import net.torrent.torrent.context.TorrentContext;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.util.PeerCallback;
import net.torrent.util.PeerWirePeerCallback;
import org.jboss.netty.channel.Channel;
@@ -140,21 +140,21 @@ public class PeerManager implements Iterable<PeerWirePeer> {
return Collections.unmodifiableSet(inactivePeers.keySet());
}
public void executeActive(PeerCallback callback) {
public void executeActive(PeerWirePeerCallback callback) {
for (final Entry<Channel, PeerWirePeer> entry : this.activePeers
.entrySet()) {
callback.callback(entry.getValue());
}
}
public void executeInactive(PeerCallback callback) {
public void executeInactive(PeerWirePeerCallback callback) {
for (final Entry<Channel, PeerWirePeer> entry : this.inactivePeers
.entrySet()) {
callback.callback(entry.getValue());
}
}
public void execute(PeerCallback callback) {
public void execute(PeerWirePeerCallback callback) {
executeActive(callback);
executeInactive(callback);
}

View File

@@ -40,7 +40,7 @@ public class TorrentContext {
private final TorrentPeerCapabilities capabilites = new TorrentPeerCapabilities(
TorrentPeerCapability.DHT, TorrentPeerCapability.FAST_PEERS);
private final Set<TorrentPeer> peers = new HashSet<TorrentPeer>();
private final TorrentSwarm swarm = new TorrentSwarm(this);
/**
* Unknown peers does not have their IDs, consequently they cannot be
* queried using their Id and must be done through IP.
@@ -103,8 +103,8 @@ public class TorrentContext {
*
* @return the list of peers
*/
public Set<TorrentPeer> getPeers() {
return Collections.unmodifiableSet(peers);
public TorrentSwarm getSwarm() {
return swarm;
}
/**
@@ -116,73 +116,15 @@ public class TorrentContext {
return Collections.unmodifiableSet(unknownPeers);
}
/**
* Get an peer by its PeerID
*
* @param peerId
* the peer id
* @return the found peer. Null if not found.
*/
public TorrentPeer getPeer(TorrentPeerID peerId) {
for (final TorrentPeer peer : peers) {
if (peer.getPeerID().equals(peerId))
return peer;
}
return null;
return swarm.getPeer(peerId);
}
/**
* Get an peer by its address
*
* @param address
* the address
* @return the found peer. Null if not found.
*/
public TorrentPeer getPeer(InetSocketAddress address) {
for (final TorrentPeer peer : peers) {
if (peer.getSocketAddress().equals(address))
return peer;
}
return null;
return swarm.getPeer(address);
}
/**
* Lookup for a peer first by its id, then by address, if still not found,
* creates a new entry.
*
* @param id
* the peer id
* @param address
* the address
* @return the found or newly created peer
*/
public TorrentPeer getPeer(TorrentPeerID id, InetSocketAddress address) {
TorrentPeer peer = getPeer(id);
if (peer == null) {
peer = getPeer(address);
if (peer != null) {
if (peers.remove(peer))
peer = peer.createWithID(id);
} else {
peer = new TorrentPeer(this, id, null);
}
peers.add(peer);
}
return peer;
}
/**
* If this peer already exists, will update its IP.
*
* @param peerInfo
* the peer info object, returned from the tracker
*/
public TorrentPeer addPeerByPeerInfo(PeerInfo peerInfo) {
final TorrentPeerID id = TorrentPeerID.create(peerInfo.getPeerId());
final InetSocketAddress address = new InetSocketAddress(
peerInfo.getIp(), peerInfo.getPort());
TorrentPeer peer = getPeer(id, address);
peer.setSocketAddress(address);
return peer;
return swarm.getPeer(id, address);
}
}

View File

@@ -0,0 +1,175 @@
/**
*
*/
package net.torrent.torrent.context;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.torrent.protocol.tracker.message.PeerListMessage.PeerInfo;
import net.torrent.torrent.TorrentPiece;
import net.torrent.util.SwarmCallback;
/**
* An torrent swarm is an set of all connected peers.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentSwarm implements Iterable<TorrentPeer> {
/**
* The torrent context
*/
private final TorrentContext context;
/**
* The list of active peers
*/
private List<TorrentPeer> peers = new ArrayList<TorrentPeer>();
/**
* Creates a new instance
*
* @param context
* the torrent context
*/
public TorrentSwarm(final TorrentContext context) {
this.context = context;
}
/**
* Add an given peer to the swarm
*
* @param peer
* the peer
* @return true if was not present in swarm
*/
public boolean add(TorrentPeer peer) {
return this.peers.add(peer);
}
/**
* Removes an given peer from the swarm
*
* @param peer
* the peer
* @return true if peer was in swarm
*/
public boolean remove(TorrentPeer peer) {
return this.peers.remove(peer);
}
/**
* Executes an callback on each peer in the swarm
*
* @param callback
* the callback
*/
public void execute(SwarmCallback callback) {
for (final TorrentPeer peer : this) {
callback.callback(peer);
}
}
/**
* Select the peers which have the <tt>piece</tt>
*
* @param piece
* the piece
* @return list of peers with piece
*/
public List<TorrentPeer> getPeersWithPiece(TorrentPiece piece) {
final List<TorrentPeer> hasPieces = new ArrayList<TorrentPeer>();
for (final TorrentPeer peer : peers) {
if (!peer.getBitfield().hasPiece(piece))
continue;
hasPieces.add(peer);
}
return hasPieces;
}
/**
* Get an peer by its PeerID
*
* @param peerId
* the peer id
* @return the found peer. Null if not found.
*/
public TorrentPeer getPeer(TorrentPeerID peerId) {
for (final TorrentPeer peer : peers) {
if (peer.getPeerID().equals(peerId))
return peer;
}
return null;
}
/**
* Get an peer by its address
*
* @param address
* the address
* @return the found peer. Null if not found.
*/
public TorrentPeer getPeer(InetSocketAddress address) {
for (final TorrentPeer peer : peers) {
if (peer.getSocketAddress().equals(address))
return peer;
}
return null;
}
/**
* Lookup for a peer first by its id, then by address, if still not found,
* creates a new entry.
*
* @param id
* the peer id
* @param address
* the address
* @return the found or newly created peer
*/
public TorrentPeer getPeer(TorrentPeerID id, InetSocketAddress address) {
TorrentPeer peer = getPeer(id);
if (peer == null) {
peer = getPeer(address);
if (peer != null) {
if (remove(peer))
peer = peer.createWithID(id);
} else {
peer = new TorrentPeer(context, id, null);
}
add(peer);
}
return peer;
}
/**
* If this peer already exists, will update its IP.
*
* @param peerInfo
* the peer info object, returned from the tracker
*/
public TorrentPeer addPeerByPeerInfo(PeerInfo peerInfo) {
final TorrentPeerID id = TorrentPeerID.create(peerInfo.getPeerId());
final InetSocketAddress address = new InetSocketAddress(
peerInfo.getIp(), peerInfo.getPort());
TorrentPeer peer = getPeer(id, address);
peer.setSocketAddress(address);
return peer;
}
@Override
public Iterator<TorrentPeer> iterator() {
return peers.iterator();
}
/**
* Get the torrent context
*
* @return the torrent context
*/
public TorrentContext getContext() {
return context;
}
}

View File

@@ -34,4 +34,11 @@ public interface PieceSelector {
* @return the {@link TorrentPiece piece} selected for download.
*/
public TorrentPiece select(TorrentPeer peer);
/**
* Return the amount of pieces available to select
*
* @return the amount of pieces available
*/
public int countPieces(TorrentPeer peer);
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* 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.torrent.torrent.piece;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.piece.score.PieceRarenessScoreAlgorithm;
import net.torrent.torrent.piece.score.ScoredPieceComparator;
/**
* Select pieces in sequential order. Can be used for streaming purposes.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class ScoredPieceSelector extends SortedListPieceSelector {
/**
* Sort again the list each <tt>n</tt> calls to {@link #select(TorrentPeer)}
*/
private static final int SORT_INTERVAL = 10;
/**
* Call counter. Used to sort the list.
*/
private int calls = 0;
/**
* The piece comparator
*/
private final ScoredPieceComparator comparator;
/**
* Creates a new instance
*
* @param manager
* the torrent manager
*/
public ScoredPieceSelector(TorrentManager manager) {
super(manager, Arrays.asList(manager.getTorrent().getPieces()));
this.comparator = new ScoredPieceComparator(manager.getContext()
.getSwarm(), new PieceRarenessScoreAlgorithm());
// initial sort will be skipped because comparator is null.
this.sort(pieces);
}
@Override
protected void sort(List<TorrentPiece> pieces) {
if (comparator != null)
Collections.sort(pieces, comparator);
System.out.println(pieces);
}
@Override
public synchronized TorrentPiece select(TorrentPeer peer) {
if (calls % SORT_INTERVAL == 0)
this.sort(pieces);
calls++;
return super.select(peer);
}
}

View File

@@ -32,11 +32,11 @@ public abstract class SortedListPieceSelector implements PieceSelector {
/**
* The torrent manager
*/
private final TorrentManager manager;
protected final TorrentManager manager;
/**
* The sorted list of pieces
*/
private final List<TorrentPiece> pieces;
protected final List<TorrentPiece> pieces;
/**
* Creates a new instance
@@ -53,6 +53,14 @@ public abstract class SortedListPieceSelector implements PieceSelector {
this.sort(this.pieces);
}
/**
* Sorts the set using an implementation specific algorithm.
*
* @param pieces
* the unsorted pieces list that will be sorted.
*/
protected abstract void sort(List<TorrentPiece> pieces);
@Override
public synchronized TorrentPiece select(TorrentPeer peer) {
for (int index = 0; index < pieces.size(); index++) {
@@ -68,11 +76,19 @@ public abstract class SortedListPieceSelector implements PieceSelector {
return null;
}
/**
* Sorts the set using an implementation specific algorithm.
*
* @param pieces
* the unsorted pieces list that will be sorted.
*/
protected abstract void sort(List<TorrentPiece> pieces);
@Override
public int countPieces(TorrentPeer peer) {
int count = 0;
for (int index = 0; index < pieces.size(); index++) {
final TorrentPiece piece = pieces.get(index);
if (manager.getContext().getBitfield().hasPiece(piece))
continue;
if (!peer.getBitfield().hasPiece(piece))
continue;
if (manager.getDownloadManager().isDownloading(piece))
continue;
count++;
}
return count;
}
}

View File

@@ -0,0 +1,34 @@
/**
*
*/
package net.torrent.torrent.piece.score;
import java.util.concurrent.atomic.AtomicInteger;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentSwarm;
import net.torrent.util.SwarmCallback;
/**
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class PieceRarenessScoreAlgorithm implements PieceScoreAlgorithm {
@Override
public int calculate(TorrentSwarm swarm, final TorrentPiece piece) {
final AtomicInteger score = new AtomicInteger();
swarm.execute(new SwarmCallback() {
@Override
public void callback(TorrentPeer peer) {
int peerScore = (int) (Math.random() * 10); // bit of randomness
if (!peer.isAccessible()) {
peerScore += 100;
}
if (!peer.getBitfield().hasPiece(piece))
peerScore += 1000;
score.addAndGet(peerScore);
}
});
return score.get();
}
}

View File

@@ -0,0 +1,23 @@
/**
*
*/
package net.torrent.torrent.piece.score;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentSwarm;
/**
* Computes the score of an piece inside the swarm.
* <p>
* Pieces with higher scores will be more suitable to download than others.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public interface PieceScoreAlgorithm {
/**
* Computes the score of an piece inside an swarm.
*
* @return
*/
int calculate(TorrentSwarm swarm, TorrentPiece piece);
}

View File

@@ -0,0 +1,27 @@
/**
*
*/
package net.torrent.torrent.piece.score;
import java.util.Comparator;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentSwarm;
/**
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class ScoredPieceComparator implements Comparator<TorrentPiece> {
private final PieceScoreAlgorithm score;
private final TorrentSwarm swarm;
public ScoredPieceComparator(TorrentSwarm swarm, PieceScoreAlgorithm score) {
this.swarm = swarm;
this.score = score;
}
@Override
public int compare(TorrentPiece piece1, TorrentPiece piece2) {
return score.calculate(swarm, piece1) - score.calculate(swarm, piece2);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* 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.torrent.util;
import net.torrent.protocol.peerwire.PeerWirePeer;
import net.torrent.protocol.peerwire.manager.PeerManager;
/**
* Callback used in {@link PeerManager#execute(PeerCallback)}
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public interface PeerWirePeerCallback {
/**
* Execute the desired action for <tt>peer</tt>
*
* @param peer
* the peer
*/
void callback(PeerWirePeer peer);
}

View File

@@ -0,0 +1,22 @@
/**
*
*/
package net.torrent.util;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentSwarm;
/**
* Callback used in {@link TorrentSwarm#execute(SwarmCallback)}
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public interface SwarmCallback {
/**
* Execute the desired action for <tt>peer</tt>
*
* @param peer
* the peer
*/
void callback(TorrentPeer peer);
}