#include "deluge.h"
void
strategy(Torrent *t)
{
Peer *p;
int new;
if(bitnhave(t->haves) == t->npieces)
new = Seeding;
else if(bithaveall(t->reqpieces))
new = Endgame;
else if(bitnhave(t->haves) > 0)
new = Rarestfirst;
else
new = Random;
if(t->strategy == new)
return;
if(new == Seeding){
if(t->dl != 0)
trackrequest(t, "completed");
DEBUG(2, "DOWNLOAD COMPLETED %R\n", t->rate);
}
if(new == Endgame){
t->strategy = new;
for(p = t->peers; p; p = p->next)
if(!IsChoking(p))
piecepeerschedule(t, p);
}else{
t->strategy = new;
}
}
void
bitesrequested(Peer *p, Piece *pc, Bits *bits)
{
Bite *b;
bitclear(bits);
for(b = p->lreq; b; b = b->next)
if(b->piecen == pc->n)
bitset(bits, b->n);
}
Piece *
nextpiece(Torrent *t, Peer *p)
{
Piece *r, *n;
int start;
int i, index;
Bits *bits;
switch(t->strategy){
case Random:
assert(!bithaveall(t->reqpieces));
start = rand() % t->npieces;
for(i = 0; i < bitlen(t->reqpieces); i++){
index = (start+i) % t->npieces;
n = &t->pieces[index];
if(!bitget(t->haves, index) && !bitget(t->reqpieces, index) && n->nids > 0)
return n;
}
DEBUG(2, "nextpiece: no random piece to start on\n");
return nil;
break;
case Rarestfirst:
r = nil;
for(i = 0; i < t->npieces; i++){
n = &t->pieces[i];
if(!bitget(t->haves, i) && !bitget(t->reqpieces, i) && n->nids > 0 && (r == nil || n->nids < r->nids)){
r = n;
if(r->nids == 1)
break;
}
}
return r;
case Endgame:
start = rand() % t->npieces;
bits = bitnew((t->piecelen+Bitelength-1) / Bitelength, nil);
for(i = 0; i < t->npieces; i++){
index = (start+i) % t->npieces;
if(bitget(t->haves, index))
continue;
bitesrequested(p, &t->pieces[index], bits);
if(!bithaveall(bits)){
bitfree(bits);
return &t->pieces[index];
}
}
bitfree(bits);
return nil;
case Seeding:
DEBUG(2, "nextpiece: called when in state Seeding\n");
return nil;
default:
sysfatal("nextpiece: cannot happen");
}
return nil;
}
Bite *
piecenextbite(Torrent *t, Peer *p, Piece *pc)
{
int i;
int bitelen;
Bits *bits;
if(bithaveall(pc->bites))
return nil;
switch(t->strategy){
case Random:
case Rarestfirst:
if(bitnhave(pc->bites) + bitnhave(pc->reqbites) >= bitlen(pc->reqbites))
return nil;
for(i = 0; i < bitlen(pc->reqbites); i++){
if(!bitget(pc->bites, i) && !bitget(pc->reqbites, i)){
bitelen = MIN(Bitelength, t->length - pc->n * t->piecelen - i*Bitelength);
return bitenew(i, pc->n, i*Bitelength, bitelen);
}
}
sysfatal("piecenextbite: cannot happen, no bite in piece after all (rarest/random)");
case Endgame:
bits = bitnew(bitlen(pc->reqbites), nil);
bitesrequested(p, pc, bits);
if(bitnhave(pc->bites) + bitnhave(bits) >= bitlen(bits)){
bitfree(bits);
return nil;
}
for(i = 0; i < bitlen(bits); i++){
if(!bitget(pc->bites, i) && !bitget(bits, i)){
bitfree(bits);
bitelen = MIN(Bitelength, t->length - pc->n * t->piecelen - i*Bitelength);
return bitenew(i, pc->n, i*Bitelength, bitelen);
}
}
sysfatal("piecenextbite: cannot happen, no bite in piece after all (endgame)");
case Seeding:
DEBUG(2, "piecenextbite: next bite requested for strategy Seeding\n");
return nil;
default:
sysfatal("piecenextbite: cannot happen");
}
return nil;
}
Bite *
nextbite(Torrent *t, Peer *p)
{
Bite *b, *rb;
Piece *pc;
for(b = p->lreq; b; b = b->next){
pc = &t->pieces[b->piecen];
rb = piecenextbite(t, p, pc);
if(rb)
return rb;
}
pc = nextpiece(t, p);
if(pc){
return piecenextbite(t, p, pc);
}
DEBUG(2, "nextbite: no new pieces to start on\n");
return nil;
}
void
piecepeerschedule(Torrent *t, Peer *p)
{
Bite *b;
strategy(t);
while(bitelen(p->lreq) < Minscheduled){
b = nextbite(t, p);
if(b == nil){
DEBUG(2, "no more bites to schedule\n");
return;
}
request(t, p, b);
strategy(t);
}
}
|