2008-04-13 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Rewritten choking algorithm.
	* src/PeerChokeCommand.{cc, h}
	* src/BtInterestedMessage.cc
	* src/PeerSessionResource.{cc, h}
	* src/DefaultPeerStorage.{cc, h}
	* src/BtNotInterestedMessage.cc
	* src/DefaultBtMessageDispatcher.{cc, h}
	* src/BtMessageDispatcher.h
	* src/Peer.{cc, h}
	* src/BtLeecherStateChoke.{cc, h}
	* src/BtSetup.cc
	* src/BtSeederStateChoke.{cc, h}
	* src/PeerStorage.h
	* test/MockPeerStorage.h
	* test/MockBtMessageDispatcher.h
pull/1/head
Tatsuhiro Tsujikawa 2008-04-13 01:25:36 +00:00
parent 8b91d22ca4
commit d13c416a94
24 changed files with 638 additions and 141 deletions

View File

@ -1,3 +1,21 @@
2008-04-13 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten choking algorithm.
* src/PeerChokeCommand.{cc, h}
* src/BtInterestedMessage.cc
* src/PeerSessionResource.{cc, h}
* src/DefaultPeerStorage.{cc, h}
* src/BtNotInterestedMessage.cc
* src/DefaultBtMessageDispatcher.{cc, h}
* src/BtMessageDispatcher.h
* src/Peer.{cc, h}
* src/BtLeecherStateChoke.{cc, h}
* src/BtSetup.cc
* src/BtSeederStateChoke.{cc, h}
* src/PeerStorage.h
* test/MockPeerStorage.h
* test/MockBtMessageDispatcher.h
2008-04-09 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Fixed compilation error on x84-64 platform.

View File

@ -37,6 +37,9 @@
#include "DlAbortEx.h"
#include "message.h"
#include "Peer.h"
#include "BtRegistry.h"
#include "BtContext.h"
#include "PeerStorage.h"
namespace aria2 {
@ -54,6 +57,9 @@ BtInterestedMessageHandle BtInterestedMessage::create(const unsigned char* data,
void BtInterestedMessage::doReceivedAction() {
peer->peerInterested(true);
if(!peer->amChoking()) {
PEER_STORAGE(btContext)->executeChoke();
}
}
bool BtInterestedMessage::sendPredicate() const {

179
src/BtLeecherStateChoke.cc Normal file
View File

@ -0,0 +1,179 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "BtLeecherStateChoke.h"
#include "Peer.h"
#include "Logger.h"
#include "LogFactory.h"
#include "a2time.h"
#include <algorithm>
namespace aria2 {
BtLeecherStateChoke::BtLeecherStateChoke():
_round(0),
_lastRound(0),
_logger(LogFactory::getInstance()) {}
BtLeecherStateChoke::~BtLeecherStateChoke() {}
class PeerFilter {
private:
bool _amChoking;
bool _peerInterested;
public:
PeerFilter(bool amChoking, bool peerInterested):
_amChoking(amChoking),
_peerInterested(peerInterested) {}
bool operator()(const Peer* peer) const
{
return peer->amChoking() == _amChoking &&
peer->peerInterested() == _peerInterested;
}
};
class RegularUnchoker {
public:
bool operator()(const Peer* peer) const
{
// peer must be interested to us and sent block in the last 30 seconds
return peer->peerInterested() && !peer->getLastDownloadUpdate().elapsed(30);
}
};
class DownloadFaster {
private:
const struct timeval _now;
public:
DownloadFaster(const struct timeval& now):_now(now) {}
bool operator() (Peer* left, Peer* right) const
{
return left->calculateDownloadSpeed(_now) > right->calculateDownloadSpeed(_now);
}
};
class SnubbedPeer {
public:
bool operator() (const Peer* peer) const
{
return peer->snubbing();
}
};
void BtLeecherStateChoke::plannedOptimisticUnchoke(std::deque<Peer*>& peers)
{
std::for_each(peers.begin(), peers.end(),
std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::optUnchoking), false));
std::deque<Peer*>::iterator i = std::partition(peers.begin(), peers.end(), PeerFilter(true, true));
if(i != peers.begin()) {
std::random_shuffle(peers.begin(), i);
(*peers.begin())->optUnchoking(true);
_logger->info("POU: %s", (*peers.begin())->ipaddr.c_str());
}
}
void BtLeecherStateChoke::regularUnchoke(std::deque<Peer*>& peers)
{
std::deque<Peer*>::iterator rest = std::partition(peers.begin(), peers.end(), RegularUnchoker());
struct timeval now;
gettimeofday(&now, 0);
std::sort(peers.begin(), rest, DownloadFaster(now));
// the number of regular unchokers
int count = 3;
bool fastOptUnchoker = false;
std::deque<Peer*>::iterator peerIter = peers.begin();
for(;peerIter != rest && count; ++peerIter, --count) {
(*peerIter)->chokingRequired(false);
_logger->info("RU: %s, dlspd=%u", (*peerIter)->ipaddr.c_str(), (*peerIter)->calculateDownloadSpeed(now));
if((*peerIter)->optUnchoking()) {
fastOptUnchoker = true;
(*peerIter)->optUnchoking(false);
}
}
if(fastOptUnchoker) {
std::random_shuffle(peerIter, peers.end());
for(std::deque<Peer*>::iterator i = peerIter; i != peers.end(); ++i) {
if((*i)->peerInterested()) {
(*i)->optUnchoking(true);
_logger->info("OU: %s", (*i)->ipaddr.c_str());
break;
} else {
(*i)->chokingRequired(false);
_logger->info("OU: %s", (*i)->ipaddr.c_str());
}
}
}
}
void
BtLeecherStateChoke::executeChoke(const std::deque<SharedHandle<Peer> >& peerSet)
{
_logger->info("Leecher state, %d choke round started", _round);
_lastRound.reset();
std::deque<Peer*> peers;
std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peers),
std::mem_fun_ref(&SharedHandle<Peer>::get));
peers.erase(std::remove_if(peers.begin(), peers.end(), SnubbedPeer()),
peers.end());
std::for_each(peers.begin(), peers.end(),
std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true));
// planned optimistic unchoke
if(_round == 0) {
plannedOptimisticUnchoke(peers);
}
regularUnchoke(peers);
if(++_round == 3) {
_round = 0;
}
}
const Time& BtLeecherStateChoke::getLastRound() const
{
return _lastRound;
}
} // namespace aria2

72
src/BtLeecherStateChoke.h Normal file
View File

@ -0,0 +1,72 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_BT_LEECHER_STATE_CHOKE_H_
#define _D_BT_LEECHER_STATE_CHOKE_H_
#include "common.h"
#include "SharedHandle.h"
#include "TimeA2.h"
#include <deque>
namespace aria2 {
class Peer;
class Logger;
class BtLeecherStateChoke {
private:
int _round;
Time _lastRound;
const Logger* _logger;
void plannedOptimisticUnchoke(std::deque<Peer*>& peers);
void regularUnchoke(std::deque<Peer*>& peers);
public:
BtLeecherStateChoke();
~BtLeecherStateChoke();
void executeChoke(const std::deque<SharedHandle<Peer> >& peerSet);
const Time& getLastRound() const;
};
} // namespace aria2
#endif // _D_BT_LEECHER_STATE_CHOKE_H_

View File

@ -81,6 +81,8 @@ public:
virtual void removeOutstandingRequest(const RequestSlot& slot) = 0;
virtual void addOutstandingRequest(const RequestSlot& slot) = 0;
virtual size_t countOutstandingUpload() = 0;
};
typedef SharedHandle<BtMessageDispatcher> BtMessageDispatcherHandle;

View File

@ -37,6 +37,9 @@
#include "DlAbortEx.h"
#include "message.h"
#include "Peer.h"
#include "BtRegistry.h"
#include "BtContext.h"
#include "PeerStorage.h"
namespace aria2 {
@ -54,6 +57,9 @@ BtNotInterestedMessageHandle BtNotInterestedMessage::create(const unsigned char*
void BtNotInterestedMessage::doReceivedAction() {
peer->peerInterested(false);
if(!peer->amChoking()) {
PEER_STORAGE(btContext)->executeChoke();
}
}
bool BtNotInterestedMessage::sendPredicate() const {

151
src/BtSeederStateChoke.cc Normal file
View File

@ -0,0 +1,151 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "BtSeederStateChoke.h"
#include "BtContext.h"
#include "Peer.h"
#include "BtRegistry.h"
#include "PeerObject.h"
#include "BtMessageDispatcher.h"
#include "BtMessageFactory.h"
#include "BtRequestFactory.h"
#include "BtMessageReceiver.h"
#include "PeerConnection.h"
#include "ExtensionMessageFactory.h"
#include "Logger.h"
#include "LogFactory.h"
#include "a2time.h"
#include <algorithm>
namespace aria2 {
BtSeederStateChoke::BtSeederStateChoke(const SharedHandle<BtContext>& btContext):
_btContext(btContext),
_round(0),
_lastRound(0),
_logger(LogFactory::getInstance()) {}
BtSeederStateChoke::~BtSeederStateChoke() {}
class RecentUnchoke {
private:
SharedHandle<BtContext> _btContext;
const struct timeval _now;
public:
RecentUnchoke(const SharedHandle<BtContext>& btContext,
const struct timeval& now):
_btContext(btContext), _now(now) {}
bool operator()(Peer* left, Peer* right) const
{
size_t leftUpload = BT_MESSAGE_DISPATCHER(_btContext, left)->countOutstandingRequest();
size_t rightUpload = BT_MESSAGE_DISPATCHER(_btContext, right)->countOutstandingRequest();
if(leftUpload && !rightUpload) {
return true;
} else if(!leftUpload && rightUpload) {
return false;
}
const int TIME_FRAME = 20;
if(!left->getLastAmUnchoking().elapsed(TIME_FRAME) &&
left->getLastAmUnchoking().isNewer(right->getLastAmUnchoking())) {
return true;
} else if(!right->getLastAmUnchoking().elapsed(TIME_FRAME) &&
right->getLastAmUnchoking().isNewer(left->getLastAmUnchoking())) {
return false;
} else {
return left->calculateUploadSpeed(_now) > right->calculateUploadSpeed(_now);
}
}
};
class NotInterestedPeer {
public:
bool operator()(const Peer* peer) const
{
return !peer->peerInterested();
}
};
void BtSeederStateChoke::unchoke(std::deque<Peer*>& peers)
{
int count = (_round == 2) ? 4 : 3;
struct timeval now;
gettimeofday(&now, 0);
std::sort(peers.begin(), peers.end(), RecentUnchoke(_btContext, now));
std::deque<Peer*>::iterator r = peers.begin();
for(; r != peers.end() && count; ++r, --count) {
(*r)->chokingRequired(false);
_logger->info("RU: %s, ulspd=%u", (*r)->ipaddr.c_str(),
(*r)->calculateUploadSpeed(now));
}
if(_round == 2 && r != peers.end()) {
std::random_shuffle(r, peers.end());
(*r)->optUnchoking(true);
_logger->info("POU: %s", (*r)->ipaddr.c_str());
}
}
void
BtSeederStateChoke::executeChoke(const std::deque<SharedHandle<Peer> >& peerSet)
{
_logger->info("Seeder state, %d choke round started", _round);
_lastRound.reset();
std::deque<Peer*> peers;
std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peers),
std::mem_fun_ref(&SharedHandle<Peer>::get));
std::for_each(peers.begin(), peers.end(),
std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true));
peers.erase(std::remove_if(peers.begin(), peers.end(), NotInterestedPeer()),
peers.end());
unchoke(peers);
if(++_round == 3) {
_round = 0;
}
}
const Time& BtSeederStateChoke::getLastRound() const
{
return _lastRound;
}
} // namespace aria2

72
src/BtSeederStateChoke.h Normal file
View File

@ -0,0 +1,72 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_BT_SEEDER_STATE_CHOKE_H_
#define _D_BT_SEEDER_STATE_CHOKE_H_
#include "common.h"
#include "SharedHandle.h"
#include "TimeA2.h"
#include <deque>
namespace aria2 {
class BtContext;
class Peer;
class Logger;
class BtSeederStateChoke {
private:
SharedHandle<BtContext> _btContext;
int _round;
Time _lastRound;
const Logger* _logger;
void unchoke(std::deque<Peer*>& peers);
public:
BtSeederStateChoke(const SharedHandle<BtContext>& btContext);
~BtSeederStateChoke();
void executeChoke(const std::deque<SharedHandle<Peer> >& peerSet);
const Time& getLastRound() const;
};
} // namespace aria2
#endif // _D_BT_SEEDER_STATE_CHOKE_H_

View File

@ -76,10 +76,8 @@ Commands BtSetup::setup(RequestGroup* requestGroup,
e,
btContext));
commands.push_back(new PeerChokeCommand(CUIDCounterSingletonHolder::instance()->newID(),
requestGroup,
e,
btContext,
10));
btContext));
commands.push_back(new ActivePeerConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(),
requestGroup, e, btContext, 10));

View File

@ -49,6 +49,7 @@
#include "Piece.h"
#include "LogFactory.h"
#include "Logger.h"
#include "a2functional.h"
#include <algorithm>
namespace aria2 {
@ -266,6 +267,12 @@ void DefaultBtMessageDispatcher::addOutstandingRequest(const RequestSlot& reques
}
}
size_t DefaultBtMessageDispatcher::countOutstandingUpload()
{
return std::count_if(messageQueue.begin(), messageQueue.end(),
mem_fun_sh(&BtMessage::isUploading));
}
std::deque<SharedHandle<BtMessage> >&
DefaultBtMessageDispatcher::getMessageQueue()
{

View File

@ -101,6 +101,8 @@ public:
virtual void addOutstandingRequest(const RequestSlot& requestSlot);
virtual size_t countOutstandingUpload();
std::deque<SharedHandle<BtMessage> >& getMessageQueue();
RequestSlots& getRequestSlots();

View File

@ -41,6 +41,9 @@
#include "Peer.h"
#include "BtContext.h"
#include "BtRuntime.h"
#include "BtSeederStateChoke.h"
#include "BtLeecherStateChoke.h"
#include "PieceStorage.h"
#include <algorithm>
namespace aria2 {
@ -52,12 +55,18 @@ DefaultPeerStorage::DefaultPeerStorage(const BtContextHandle& btContext,
maxPeerListSize(MAX_PEER_LIST_SIZE),
btRuntime(BT_RUNTIME(btContext)),
removedPeerSessionDownloadLength(0),
removedPeerSessionUploadLength(0)
removedPeerSessionUploadLength(0),
_seederStateChoke(new BtSeederStateChoke(btContext)),
_leecherStateChoke(new BtLeecherStateChoke())
{
logger = LogFactory::getInstance();
}
DefaultPeerStorage::~DefaultPeerStorage() {}
DefaultPeerStorage::~DefaultPeerStorage()
{
delete _seederStateChoke;
delete _leecherStateChoke;
}
class FindIdenticalPeer {
private:
@ -246,4 +255,23 @@ void DefaultPeerStorage::returnPeer(const PeerHandle& peer)
}
}
bool DefaultPeerStorage::chokeRoundIntervalElapsed()
{
const time_t CHOKE_ROUND_INTERVAL = 10;
if(PIECE_STORAGE(btContext)->downloadFinished()) {
return _seederStateChoke->getLastRound().elapsed(CHOKE_ROUND_INTERVAL);
} else {
return _leecherStateChoke->getLastRound().elapsed(CHOKE_ROUND_INTERVAL);
}
}
void DefaultPeerStorage::executeChoke()
{
if(PIECE_STORAGE(btContext)->downloadFinished()) {
return _seederStateChoke->executeChoke(getActivePeers());
} else {
return _leecherStateChoke->executeChoke(getActivePeers());
}
}
} // namespace aria2

View File

@ -46,6 +46,8 @@ class BtContext;
class Option;
class Logger;
class BtRuntime;
class BtSeederStateChoke;
class BtLeecherStateChoke;
class DefaultPeerStorage : public PeerStorage {
private:
@ -58,6 +60,9 @@ private:
uint64_t removedPeerSessionDownloadLength;
uint64_t removedPeerSessionUploadLength;
BtSeederStateChoke* _seederStateChoke;
BtLeecherStateChoke* _leecherStateChoke;
bool isPeerAlreadyAdded(const SharedHandle<Peer>& peer);
public:
DefaultPeerStorage(const SharedHandle<BtContext>& btContext,
@ -91,6 +96,10 @@ public:
virtual void returnPeer(const SharedHandle<Peer>& peer);
virtual bool chokeRoundIntervalElapsed();
virtual void executeChoke();
void setMaxPeerListSize(size_t size) { this->maxPeerListSize = size; }
size_t getMaxPeerListSize() const { return maxPeerListSize; }

View File

@ -367,7 +367,9 @@ SRCS += MetaEntry.h\
LibsslARC4Decryptor.h\
LibsslARC4Encryptor.h\
LibsslDHKeyExchange.h\
BtConstants.h
BtConstants.h\
BtLeecherStateChoke.cc BtLeecherStateChoke.h\
BtSeederStateChoke.cc BtSeederStateChoke.h
endif # ENABLE_BITTORRENT
if ENABLE_METALINK

View File

@ -221,7 +221,9 @@ bin_PROGRAMS = aria2c$(EXEEXT)
@ENABLE_BITTORRENT_TRUE@ LibsslARC4Decryptor.h\
@ENABLE_BITTORRENT_TRUE@ LibsslARC4Encryptor.h\
@ENABLE_BITTORRENT_TRUE@ LibsslDHKeyExchange.h\
@ENABLE_BITTORRENT_TRUE@ BtConstants.h
@ENABLE_BITTORRENT_TRUE@ BtConstants.h\
@ENABLE_BITTORRENT_TRUE@ BtLeecherStateChoke.cc BtLeecherStateChoke.h\
@ENABLE_BITTORRENT_TRUE@ BtSeederStateChoke.cc BtSeederStateChoke.h
@ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\
@ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\
@ -522,7 +524,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
LibgcryptARC4Decryptor.h LibgcryptARC4Encryptor.h \
LibgcryptDHKeyExchange.h LibsslARC4Context.h \
LibsslARC4Decryptor.h LibsslARC4Encryptor.h \
LibsslDHKeyExchange.h BtConstants.h Metalinker.cc Metalinker.h \
LibsslDHKeyExchange.h BtConstants.h BtLeecherStateChoke.cc \
BtLeecherStateChoke.h BtSeederStateChoke.cc \
BtSeederStateChoke.h Metalinker.cc Metalinker.h \
MetalinkEntry.cc MetalinkEntry.h MetalinkResource.cc \
MetalinkResource.h MetalinkProcessor.h \
MetalinkProcessorFactory.cc MetalinkProcessorFactory.h \
@ -667,7 +671,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
@ENABLE_BITTORRENT_TRUE@ DHTRegistry.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ InitiatorMSEHandshakeCommand.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ ReceiverMSEHandshakeCommand.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ MSEHandshake.$(OBJEXT)
@ENABLE_BITTORRENT_TRUE@ MSEHandshake.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ BtLeecherStateChoke.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ BtSeederStateChoke.$(OBJEXT)
@ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \
@ -1234,6 +1240,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveNoneMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtInterestedMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtKeepAliveMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtLeecherStateChoke.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtNotInterestedMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPieceMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPortMessage.Po@am__quote@
@ -1241,6 +1248,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistry.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRejectMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRequestMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSeederStateChoke.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSetup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessage.Po@am__quote@

View File

@ -442,4 +442,16 @@ const Time& Peer::getBadConditionStartTime() const
return _badConditionStartTime;
}
const Time& Peer::getLastDownloadUpdate() const
{
assert(_res);
return _res->getLastDownloadUpdate();
}
const Time& Peer::getLastAmUnchoking() const
{
assert(_res);
return _res->getLastAmUnchoking();
}
} // namespace aria2

View File

@ -231,6 +231,10 @@ public:
std::string getExtensionName(uint8_t id) const;
void setExtension(const std::string& name, uint8_t id);
const Time& getLastDownloadUpdate() const;
const Time& getLastAmUnchoking() const;
};
typedef SharedHandle<Peer> PeerHandle;

View File

@ -33,141 +33,29 @@
*/
/* copyright --> */
#include "PeerChokeCommand.h"
#include "Util.h"
#include "Peer.h"
#include "DownloadEngine.h"
#include "BtContext.h"
#include "BtRuntime.h"
#include "PieceStorage.h"
#include "PeerStorage.h"
#include "Logger.h"
#include <algorithm>
namespace aria2 {
PeerChokeCommand::PeerChokeCommand(int32_t cuid,
RequestGroup* requestGroup,
DownloadEngine* e,
const BtContextHandle& btContext,
time_t interval):
const BtContextHandle& btContext):
Command(cuid),
BtContextAwareCommand(btContext),
RequestGroupAware(requestGroup),
interval(interval),
e(e),
rotate(0)
e(e)
{}
PeerChokeCommand::~PeerChokeCommand() {}
class ChokePeer {
public:
ChokePeer() {}
void operator()(PeerHandle& peer) {
peer->chokingRequired(true);
}
};
void PeerChokeCommand::optUnchokingPeer(Peers& peers) const {
if(peers.empty()) {
return;
}
std::random_shuffle(peers.begin(), peers.end());
unsigned int optUnchokCount = 1;
for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
Peers::value_type peer = *itr;
if(optUnchokCount > 0 && !peer->snubbing()) {
optUnchokCount--;
peer->optUnchoking(true);
logger->debug("opt, unchoking %s, download speed=%d",
peer->ipaddr.c_str(), peer->calculateDownloadSpeed());
} else {
peer->optUnchoking(false);
}
}
}
class UploadFaster {
public:
bool operator() (const PeerHandle& left, const PeerHandle& right) const {
return left->calculateUploadSpeed() > right->calculateUploadSpeed();
}
};
void PeerChokeCommand::orderByUploadRate(Peers& peers) const {
std::sort(peers.begin(), peers.end(), UploadFaster());
}
class DownloadFaster {
public:
bool operator() (const PeerHandle& left, const PeerHandle& right) const {
return left->calculateDownloadSpeed() > right->calculateDownloadSpeed();
}
};
void PeerChokeCommand::orderByDownloadRate(Peers& peers) const {
std::sort(peers.begin(), peers.end(), DownloadFaster());
}
bool PeerChokeCommand::execute() {
if(btRuntime->isHalt()) {
return true;
}
if(checkPoint.elapsed(interval)) {
checkPoint.reset();
Peers peers = peerStorage->getActivePeers();
std::for_each(peers.begin(), peers.end(), ChokePeer());
if(pieceStorage->downloadFinished()) {
orderByUploadRate(peers);
} else {
orderByDownloadRate(peers);
}
unsigned int unchokingCount = 4;//peers.size() >= 4 ? 4 : peers.size();
for(Peers::iterator itr = peers.begin(); itr != peers.end() && unchokingCount > 0; ) {
PeerHandle peer = *itr;
if(peer->peerInterested() && !peer->snubbing()) {
unchokingCount--;
peer->chokingRequired(false);
peer->optUnchoking(false);
itr = peers.erase(itr);
if(pieceStorage->downloadFinished()) {
logger->debug("cat01, unchoking %s, upload speed=%d",
peer->ipaddr.c_str(),
peer->calculateUploadSpeed());
} else {
logger->debug("cat01, unchoking %s, download speed=%d",
peer->ipaddr.c_str(),
peer->calculateDownloadSpeed());
}
} else {
itr++;
}
}
for(Peers::iterator itr = peers.begin(); itr != peers.end(); ) {
PeerHandle peer = *itr;
if(!peer->peerInterested() && !peer->snubbing()) {
peer->chokingRequired(false);
peer->optUnchoking(false);
itr = peers.erase(itr);
if(pieceStorage->downloadFinished()) {
logger->debug("cat02, unchoking %s, upload speed=%d",
peer->ipaddr.c_str(),
peer->calculateUploadSpeed());
} else {
logger->debug("cat02, unchoking %s, download speed=%d",
peer->ipaddr.c_str(),
peer->calculateDownloadSpeed());
}
break;
} else {
itr++;
}
}
if(rotate%3 == 0) {
optUnchokingPeer(peers);
rotate = 0;
}
rotate++;
if(peerStorage->chokeRoundIntervalElapsed()) {
peerStorage->executeChoke();
}
e->commands.push_back(this);
return false;

View File

@ -37,34 +37,21 @@
#include "Command.h"
#include "BtContextAwareCommand.h"
#include "RequestGroupAware.h"
#include "TimeA2.h"
namespace aria2 {
class DownloadEngine;
class Peer;
class PeerChokeCommand : public Command,
public BtContextAwareCommand,
public RequestGroupAware
public BtContextAwareCommand
{
private:
time_t interval;
DownloadEngine* e;
unsigned int rotate;
Time checkPoint;
void orderByUploadRate(std::deque<SharedHandle<Peer> >& peers) const;
void orderByDownloadRate(std::deque<SharedHandle<Peer> >& peers) const;
void optUnchokingPeer(std::deque<SharedHandle<Peer> >& peers) const;
public:
PeerChokeCommand(int32_t cuid,
RequestGroup* requestGroup,
DownloadEngine* e,
const SharedHandle<BtContext>& btContext,
time_t interval);
const SharedHandle<BtContext>& btContext);
virtual ~PeerChokeCommand();

View File

@ -53,7 +53,9 @@ PeerSessionResource::PeerSessionResource(size_t pieceLength, uint64_t totalLengt
_dhtEnabled(false),
_latency(DEFAULT_LATENCY),
_uploadLength(0),
_downloadLength(0)
_downloadLength(0),
_lastDownloadUpdate(0),
_lastAmUnchoking(0)
{}
PeerSessionResource::~PeerSessionResource()
@ -69,6 +71,9 @@ bool PeerSessionResource::amChoking() const
void PeerSessionResource::amChoking(bool b)
{
_amChoking = b;
if(!b) {
_lastAmUnchoking.reset();
}
}
bool PeerSessionResource::amInterested() const
@ -137,6 +142,10 @@ bool PeerSessionResource::snubbing() const
void PeerSessionResource::snubbing(bool b)
{
_snubbing = b;
if(_snubbing) {
chokingRequired(true);
optUnchoking(false);
}
}
bool PeerSessionResource::hasAllPieces() const
@ -311,6 +320,18 @@ void PeerSessionResource::updateDownloadLength(size_t bytes)
{
_peerStat.updateDownloadLength(bytes);
_downloadLength += bytes;
_lastDownloadUpdate.reset();
}
const Time& PeerSessionResource::getLastDownloadUpdate() const
{
return _lastDownloadUpdate;
}
const Time& PeerSessionResource::getLastAmUnchoking() const
{
return _lastAmUnchoking;
}
} // namespace aria2

View File

@ -38,6 +38,7 @@
#include "common.h"
#include "BtConstants.h"
#include "PeerStat.h"
#include "TimeA2.h"
#include <string>
#include <deque>
@ -76,6 +77,10 @@ private:
uint64_t _uploadLength;
uint64_t _downloadLength;
Time _lastDownloadUpdate;
Time _lastAmUnchoking;
template<typename T>
bool indexIncluded(const std::deque<T>& c, T index) const;
public:
@ -179,6 +184,10 @@ public:
uint64_t downloadLength() const;
void updateDownloadLength(size_t bytes);
const Time& getLastDownloadUpdate() const;
const Time& getLastAmUnchoking() const;
};
} // namespace aria2

View File

@ -89,6 +89,10 @@ public:
* Tells PeerStorage object that peer is no longer used in the session.
*/
virtual void returnPeer(const SharedHandle<Peer>& peer) = 0;
virtual bool chokeRoundIntervalElapsed() = 0;
virtual void executeChoke() = 0;
};
typedef SharedHandle<PeerStorage> PeerStorageHandle;

View File

@ -57,6 +57,11 @@ public:
virtual void removeOutstandingRequest(const RequestSlot& slot) {}
virtual void addOutstandingRequest(const RequestSlot& slot) {}
virtual size_t countOutstandingUpload()
{
return 0;
}
};
} // namespace aria2

View File

@ -56,6 +56,13 @@ public:
virtual void returnPeer(const SharedHandle<Peer>& peer)
{
}
virtual bool chokeRoundIntervalElapsed()
{
return false;
}
virtual void executeChoke() {}
};
#endif // _D_MOCK_PEER_STORAGE_H_