📄 bttracker.java
字号:
/*
* @(#)BTTracker.java ver 1.2 6/20/2005
*
* Copyright 2005 Weishuai Yang (wyang@cs.binghamton.edu).
* All rights reserved.
*
*/
package gps.protocol.BT;
import gps.Simulator;
import gps.event.SimEvent;
import gps.protocol.Server;
import gps.protocol.BT.algorithm.BTAlgorithmPeerSelectionAtTracker;
import gps.protocol.BT.param.BTGetRequest;
import gps.protocol.BT.param.BTTorrent;
import gps.protocol.BT.param.BTTrackerResponse;
import gps.util.PowerLaw;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.logging.Logger;
/**
* BT Tracker
*
* @author Weishuai Yang
* @version 1.2, 6/20/2005
*
* In Bram Cohen's BT protocol, all logistical problems of file
* downloading are handled in the interactions between peers.
* Some information about upload and download rates is sent to
* the tracker, but that's just for statistics gathering. The
* tracker's responsibilities are strictly limited to helping
* peers find each other.
*
* The standard tracker algorithm is to return a random list of peers.
*
*/
public class BTTracker extends Server {
/**
* document records
*/
private class BTDocRecord{
public String mDocHashKey=null;
public BTTorrent mTorrent=null;
public LinkedHashSet mPeerList=null;
public int mPopularity=0;
BTDocRecord(String key, BTTorrent t){
mDocHashKey=key;
mTorrent=t;
mPeerList=new LinkedHashSet();
mPopularity=t.mPopularity;
}
public boolean addPeer(BTPeer p){
return mPeerList.add(p);
}
}
/**
* document records comparator
*/
private class DocRecordComparator implements Comparator
{
//sort the max at the head
public int compare(Object o1, Object o2) {
BTDocRecord r1=(BTDocRecord)docDB.get(o1);;
BTDocRecord r2=(BTDocRecord)docDB.get(o2);;
if(r1.mPopularity<r2.mPopularity)
return 1;
else if(r1.mPopularity>r2.mPopularity)
return -1;
else
return 0;
}
}
/**
* peer records
*/
private class BTPeerRecord{
public BTPeer mNode=null;
public double mUploaded=0;
public double mDownloaded=0;
public double mInBandwidth=0;
public double mOutBandwidth=0;
BTPeerRecord(BTPeer n){
mNode=n;
}
}
/**
* collection of documents published on this tracker
*/
protected HashMap docDB=null;
/**
* collection of peers downloading from this tracker, providing reference for selection peer list;
*/
protected HashMap peerDB=null;
//peer selection algorithm
private BTAlgorithmPeerSelectionAtTracker mPeerSelection=new BTAlgorithmPeerSelectionAtTracker(getID());
//debug logger
public static Logger mDebugLog = Logger.getLogger("Debug");
public static PowerLaw mPowerLaw=new PowerLaw(new Random(Integer.parseInt(Simulator.getInstance().getProperties().getProperty("RandomSeed"))));
/**
* Method Server initialization
*/
public BTTracker() {}
public BTTracker(int i) {
super(i);
docDB=new LinkedHashMap();
peerDB=new LinkedHashMap();
}
public void reset(){
super.reset();
docDB.clear();
peerDB.clear();
mPowerLaw=new PowerLaw(new Random(Integer.parseInt(Simulator.getInstance().getProperties().getProperty("RandomSeed"))));
}
//do some BTTracker specific drawing on the graph
public void agentDraw(Graphics g, int x, int y){
g.setColor( Color.magenta );
g.fillOval( x-5, y-5, 10, 10 );
g.drawString("Tracker("+mAgentID+")",x-16,y-6 );
}
public boolean addTorrent(BTTorrent btpt){
if(docDB.get(btpt.mDocHashKey)!=null){
mDebugLog.warning("duplicated document hash key when adding torrent!");
return false;
}
docDB.put(btpt.mDocHashKey, new BTDocRecord(btpt.mDocHashKey, btpt));
return true;
}
public BTTorrent getTorrent(String key){
if(docDB.isEmpty())
return null;
BTDocRecord btdr=(BTDocRecord)docDB.get(key);
if(btdr!=null){
return btdr.mTorrent;
}
return null;
}
public BTTorrent getRandomTorrent(HashMap db){
if(docDB.isEmpty())
return null;
ArrayList tmpDB=new ArrayList(docDB.keySet());
tmpDB.removeAll(db.keySet());
if(tmpDB.isEmpty()) return null;
//sort keys according to doc rank
Collections.sort(tmpDB, new DocRecordComparator());
BTDocRecord btdr=null;
int index=mPowerLaw.zipf(tmpDB.size());
btdr=(BTDocRecord)docDB.get(tmpDB.get(index));
return btdr.mTorrent;
}
public HashSet getNodesAssociatedWithDoc(String docHashKey){
if(docDB.isEmpty())
return null;
BTDocRecord btdr=(BTDocRecord)docDB.get(docHashKey);
if(btdr!=null){
return btdr.mPeerList;
}
return null;
}
public boolean addNodeAssociatedWithDoc(String docHashKey, BTPeer peer){
/**
* for performance, the reference to peer rather than peer id
* is directly added into hashmap
*/
if(getTorrent(docHashKey)==null){
mDebugLog.warning("trying to add nodes associated with a document, but the torrent doesn't exist!");
return false;
}
BTDocRecord btdr=(BTDocRecord)docDB.get(docHashKey);
return btdr.addPeer(peer);
}
/**
* handles tracker level events
*/
public boolean handle(SimEvent e){
if(super.handle(e))
return true;
switch(e.getType()){
case BTEvent.TRACKER_GET_REQUEST:
handleGetRequest((BTEvent)e);
return true;
default:
mDebugLog.warning("received event "+e+" unprocessed");
}
return false;
}
public void handleGetRequest(BTEvent e){
BTGetRequest btgr=(BTGetRequest)e.getAddParam();
mDebugLog.info(""+mScheduler.getCurrent()+" "+this+" receiving request from " +
btgr.mBTPeer+" for "+btgr.mDocHashKey+" Event: "+
btgr.eventToString()+" left: "+ btgr.mLeft);
//TODO:update peer record in peerDB
/**
* if it's completed or stopped, don't have to reply,
* but may need to addjusted the node list sequense in peerDB
* such as sort according to finished length
* it's possible to let tracker remember each peer's status
*
* if it's started, but the left size is 0, that means this
* is the original seed. don't have to reply either
*/
if(btgr.mEvent==BTGetRequest.COMPLETED){
addNodeAssociatedWithDoc(btgr.mDocHashKey, btgr.mBTPeer);
return;
}
if(btgr.mEvent==BTGetRequest.STOPPED)
return;
else if(btgr.mLeft==0){
addNodeAssociatedWithDoc(btgr.mDocHashKey, btgr.mBTPeer);
return;
}
BTPeer btp=(BTPeer)e.getParam();
ArrayList nodeList=new ArrayList(getNodesAssociatedWithDoc(btgr.mDocHashKey));
//elements in this nodeList are supposed to be unique since it's from a set
BTTrackerResponse bttr=new BTTrackerResponse(btgr.mDocHashKey, mPeerSelection.selectPeers(nodeList));
double t=mScheduler.getCurrent()+BT.getInstance().getDelayAgent(this,btp);
//the event is to be handled by the session instance after the network delay
BTEvent bte=new BTEvent(t, BTEvent.SESSION_TRACKER_RESPONSE, btgr.mBTSession, this);
//first param is the tracker object, additional param is tracker response
bte.setAddParam(bttr);
mScheduler.enqueue(bte);
//add the requesting peer into database, it's possible the nodelist including
//the new peer is retrieved by somebody else before the new peer receive the
//reply, but it does no harm.
addNodeAssociatedWithDoc(btgr.mDocHashKey, btp);
}
public String toString(){
return "BTTracker("+mAgentID+")";
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -