package org.klomp.snark;
import java.util.HashSet;
import java.util.Set;
/**
* This class is used solely by PeerCoordinator.
* Caller must synchronize on many of these methods.
*/
class Piece implements Comparable<Piece> {
private final int id;
private final Set<PeerID> peers;
/** @since 0.8.3 */
private volatile Set<PeerID> requests;
/** @since 0.8.1 */
private int priority;
public Piece(int id) {
this.id = id;
this.peers = new HashSet<PeerID>(I2PSnarkUtil.MAX_CONNECTIONS / 2);
// defer creating requests to save memory
}
/**
* Highest priority first,
* then rarest first
*/
public int compareTo(Piece op) {
int pdiff = op.priority - this.priority; // reverse
if (pdiff != 0)
return pdiff;
return this.peers.size() - op.peers.size();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o instanceof Piece) {
return this.id == ((Piece)o).id;
}
return false;
}
@Override
public int hashCode() {
int hash = 5;
hash = 31 * hash + this.id;
return hash;
}
public int getId() { return this.id; }
/** caller must synchronize */
public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); }
/**
* Caller must synchronize.
* @return true if removed
*/
public boolean removePeer(Peer peer) { return this.peers.remove(peer.getPeerID()); }
/**
* How many peers have this piece?
* Caller must synchronize
* @since 0.9.1
*/
public int getPeerCount() {
return this.peers.size();
}
/** caller must synchronize */
public boolean isRequested() {
return this.requests != null && !this.requests.isEmpty();
}
/**
* Since 0.8.3, keep track of who is requesting here,
* to avoid deadlocks from querying each peer.
* Caller must synchronize
*/
public void setRequested(Peer peer, boolean requested) {
if (requested) {
if (this.requests == null)
this.requests = new HashSet<PeerID>(2);
this.requests.add(peer.getPeerID());
} else {
if (this.requests != null)
this.requests.remove(peer.getPeerID());
}
}
/**
* Is peer requesting this piece?
* Caller must synchronize
* @since 0.8.3
*/
public boolean isRequestedBy(Peer peer) {
return this.requests != null && this.requests.contains(peer.getPeerID());
}
/**
* How many peers are requesting this piece?
* Caller must synchronize
* @since 0.8.3
*/
public int getRequestCount() {
return this.requests == null ? 0 : this.requests.size();
}
/**
* Clear all knowledge of peers
* Caller must synchronize
* @since 0.9.3
*/
public void clear() {
peers.clear();
if (requests != null)
requests.clear();
}
/** @return default 0 @since 0.8.1 */
public int getPriority() { return this.priority; }
/** @since 0.8.1 */
public void setPriority(int p) { this.priority = p; }
/** @since 0.8.1 */
public boolean isDisabled() { return this.priority < 0; }
/** @since 0.8.1 */
public void setDisabled() { this.priority = -1; }
@Override
public String toString() {
return String.valueOf(id);
}
}