kget
advancedchokealgorithm.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "advancedchokealgorithm.h"
00021 #include <util/functions.h>
00022 #include <interfaces/torrentinterface.h>
00023 #include <diskio/chunkmanager.h>
00024 #include <peer/peer.h>
00025 #include <peer/peermanager.h>
00026 #include <peer/packetwriter.h>
00027 #include <krandom.h>
00028
00029
00030 namespace bt
00031 {
00032
00033
00034 const Uint32 OPT_SEL_INTERVAL = 30*1000;
00035 const double NEWBIE_BONUS = 1.0;
00036 const double SNUB_PENALTY = 10.0;
00037 const double ONE_MB = 1024*1024;
00038
00039
00040 AdvancedChokeAlgorithm::AdvancedChokeAlgorithm()
00041 : ChokeAlgorithm()
00042 {
00043 last_opt_sel_time = 0;
00044 }
00045
00046
00047 AdvancedChokeAlgorithm::~AdvancedChokeAlgorithm()
00048 {}
00049
00050 bool AdvancedChokeAlgorithm::calcACAScore(Peer* p,ChunkManager & cman,const TorrentStats & stats)
00051 {
00052 const PeerInterface::Stats & s = p->getStats();
00053 if (p->isSeeder())
00054 {
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 p->setACAScore(0.0);
00065 return false;
00066 }
00067
00068 bool should_be_interested = false;
00069 bool should_we_be_interested = false;
00070
00071 const BitSet & ours = cman.getBitSet();
00072 const BitSet & theirs = p->getBitSet();
00073 for (Uint32 i = 0;i < ours.getNumBits();i++)
00074 {
00075 if (ours.get(i) && !theirs.get(i))
00076 {
00077 should_be_interested = true;
00078 break;
00079 }
00080 }
00081
00082 if (!should_be_interested || !p->isInterested())
00083 {
00084
00085 p->setACAScore(-50.0);
00086 return false;
00087 }
00088
00089
00090
00091 double nb = 0.0;
00092 double cp = 0.0;
00093 double sp = 0.0;
00094 double lb = s.local ? 10.0 : 0.0;
00095 double bd = s.bytes_downloaded;
00096 double tbd = stats.trk_bytes_downloaded;
00097 double ds = s.download_rate;
00098 double tds = stats.download_rate;
00099
00100
00101 if (p->percentAvailable() < 0.5 && stats.total_bytes * p->percentAvailable() < 1024*1024)
00102 {
00103 nb = NEWBIE_BONUS;
00104 }
00105
00106 if (p->isChoked())
00107 {
00108 cp = NEWBIE_BONUS;
00109 }
00110
00111
00112 if (s.evil)
00113 {
00114 sp = SNUB_PENALTY;
00115 }
00116
00117
00118 double K = 5.0;
00119 double L = 5.0;
00120 double aca = lb + nb + (tbd > 0 ? K * (bd/tbd) : 0.0) + (tds > 0 ? L* (ds / tds) : 0.0) - cp - sp;
00121
00122 p->setACAScore(aca);
00123 return true;
00124 }
00125
00126 static int ACACmp(Peer* a,Peer* b)
00127 {
00128 if (a->getStats().aca_score < b->getStats().aca_score)
00129 return 1;
00130 else if (a->getStats().aca_score > b->getStats().aca_score)
00131 return -1;
00132 else
00133 return 0;
00134 }
00135
00136
00137 void AdvancedChokeAlgorithm::doChokingLeechingState(PeerManager & pman,ChunkManager & cman,const TorrentStats & stats)
00138 {
00139 PeerPtrList ppl;
00140 Uint32 np = pman.getNumConnectedPeers();
00141
00142 for (Uint32 i = 0;i < np;i++)
00143 {
00144 Peer* p = pman.getPeer(i);
00145 if (p)
00146 {
00147 if (calcACAScore(p,cman,stats))
00148 ppl.append(p);
00149 else
00150
00151 p->choke();
00152 }
00153 }
00154
00155
00156 ppl.setCompareFunc(ACACmp);
00157 qSort(ppl.begin(), ppl.end());
00158
00159 doUnchoking(ppl,updateOptimisticPeer(pman,ppl));
00160 }
00161
00162 void AdvancedChokeAlgorithm::doUnchoking(PeerPtrList & ppl,Peer* poup)
00163 {
00164
00165 Uint32 num_slots = Choker::getNumUploadSlots();
00166
00167 Uint32 num_unchoked = 0;
00168 for (Uint32 i = 0;i < ppl.count();i++)
00169 {
00170 Peer* p = ppl.at(i);
00171 if (!poup && num_unchoked < num_slots)
00172 {
00173 p->getPacketWriter().sendUnchoke();
00174 num_unchoked++;
00175 }
00176 else if (num_unchoked < num_slots -1 || p == poup)
00177 {
00178 p->getPacketWriter().sendUnchoke();
00179 if (p != poup)
00180 num_unchoked++;
00181 }
00182 else
00183 {
00184 p->choke();
00185 }
00186 }
00187 }
00188
00189 static int UpRateCmp(Peer* a,Peer* b)
00190 {
00191 if (a->getStats().upload_rate < b->getStats().upload_rate)
00192 return -1;
00193 else if (a->getStats().upload_rate > b->getStats().upload_rate)
00194 return 1;
00195 else
00196 return 0;
00197 }
00198
00199 void AdvancedChokeAlgorithm::doChokingSeedingState(PeerManager & pman,ChunkManager & cman,const TorrentStats & stats)
00200 {
00201 PeerPtrList ppl;
00202 Uint32 np = pman.getNumConnectedPeers();
00203
00204 for (Uint32 i = 0;i < np;i++)
00205 {
00206 Peer* p = pman.getPeer(i);
00207 if (p)
00208 {
00209
00210 if (calcACAScore(p,cman,stats))
00211 ppl.append(p);
00212 else
00213
00214 p->choke();
00215 }
00216 }
00217
00218 ppl.setCompareFunc(UpRateCmp);
00219 qSort(ppl.begin(), ppl.end());
00220
00221 doUnchoking(ppl,updateOptimisticPeer(pman,ppl));
00222 }
00223
00224 static Uint32 FindPlannedOptimisticUnchokedPeer(PeerManager& pman,const PeerPtrList & ppl)
00225 {
00226 Uint32 num_peers = pman.getNumConnectedPeers();
00227 if (num_peers == 0)
00228 return UNDEFINED_ID;
00229
00230
00231 Uint32 start = KRandom::random() % num_peers;
00232 Uint32 i = (start + 1) % num_peers;
00233 while (i != start)
00234 {
00235 Peer* p = pman.getPeer(i);
00236 if (p && p->isChoked() && p->isInterested() && !p->isSeeder() && ppl.contains(p))
00237 return p->getID();
00238 i = (i + 1) % num_peers;
00239 }
00240
00241
00242 return UNDEFINED_ID;
00243 }
00244
00245 Peer* AdvancedChokeAlgorithm::updateOptimisticPeer(PeerManager & pman,const PeerPtrList & ppl)
00246 {
00247
00248 Peer* poup = pman.findPeer(opt_unchoked_peer_id);
00249 TimeStamp now = GetCurrentTime();
00250 if (now - last_opt_sel_time > OPT_SEL_INTERVAL || !poup)
00251 {
00252 opt_unchoked_peer_id = FindPlannedOptimisticUnchokedPeer(pman,ppl);
00253 last_opt_sel_time = now;
00254 poup = pman.findPeer(opt_unchoked_peer_id);
00255 }
00256 return poup;
00257 }
00258 }