package freenet.node;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import freenet.node.PeerNode;
/**
* For any single UID, we should only route to the same node once, even if
* the request comes back to us in a loop. Loop detection with rejection is
* dangerous, and we can't easily disentangle the various failure modes, so
* we allow a request to loop back to us and then relay it forward, RNFing
* if appropriate. So we keep a UIDRoutingContext for each UID that has live
* UIDTag's.
*
* @author toad
*/
public class UIDRoutingContextTracker {
private final HashMap<Long,UIDRoutingContext> routingContexts =
new HashMap<Long,UIDRoutingContext>();
public class UIDRoutingContext {
/** The UID of all the tags */
public final Long uid;
/** If true, tags will be for inserts, and no offer tags. */
public final boolean insert;
/** Request or insert tags */
private final ArrayList<UIDTag> tags;
/** The set of nodes this UID has been routed to. This will always
* be very small. */
private final Set<WeakReference<PeerNode>> routedTo;
private boolean finished;
UIDRoutingContext(long uid, boolean insert) {
this.uid = uid;
this.insert = insert;
tags = new ArrayList<UIDTag>();
routedTo = new HashSet<WeakReference<PeerNode>>();
finished = false;
}
public void add(UIDTag tag) {
synchronized(UIDRoutingContextTracker.this) {
if(finished) throw new IllegalStateException();
if(!tags.contains(tag))
tags.add(tag);
}
}
public void remove(UIDTag tag) {
synchronized(UIDRoutingContextTracker.this) {
tags.remove(tag);
if(tags.isEmpty())
removeMe();
}
}
private void removeMe() {
finished = true;
routingContexts.remove(uid);
}
}
}