2006-02-17 13:35:04 +00:00
|
|
|
/* <!-- copyright */
|
|
|
|
/*
|
2006-09-21 15:31:24 +00:00
|
|
|
* aria2 - The high speed download utility
|
2006-02-17 13:35:04 +00:00
|
|
|
*
|
|
|
|
* 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
|
2010-01-05 16:01:46 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2006-09-21 15:31:24 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2006-02-17 13:35:04 +00:00
|
|
|
*/
|
|
|
|
/* copyright --> */
|
|
|
|
#include "SegmentMan.h"
|
2009-03-19 13:42:10 +00:00
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <numeric>
|
|
|
|
|
2009-10-22 15:35:33 +00:00
|
|
|
#include "util.h"
|
2006-02-17 13:35:04 +00:00
|
|
|
#include "message.h"
|
2006-02-22 11:18:47 +00:00
|
|
|
#include "prefs.h"
|
2007-10-11 16:58:24 +00:00
|
|
|
#include "PiecedSegment.h"
|
|
|
|
#include "GrowSegment.h"
|
2006-04-17 16:17:20 +00:00
|
|
|
#include "LogFactory.h"
|
2008-02-08 15:53:45 +00:00
|
|
|
#include "Logger.h"
|
2007-10-11 16:58:24 +00:00
|
|
|
#include "PieceStorage.h"
|
|
|
|
#include "PeerStat.h"
|
|
|
|
#include "Option.h"
|
|
|
|
#include "DownloadContext.h"
|
|
|
|
#include "Piece.h"
|
2009-06-23 15:35:45 +00:00
|
|
|
#include "FileEntry.h"
|
2010-03-06 08:29:53 +00:00
|
|
|
#include "wallclock.h"
|
2010-11-20 08:21:36 +00:00
|
|
|
#include "fmt.h"
|
2008-02-08 15:53:45 +00:00
|
|
|
|
|
|
|
namespace aria2 {
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2010-11-14 07:17:55 +00:00
|
|
|
SegmentEntry::SegmentEntry(cuid_t cuid, const SharedHandle<Segment>& segment)
|
|
|
|
: cuid(cuid), segment(segment)
|
|
|
|
{}
|
|
|
|
|
|
|
|
SegmentEntry::~SegmentEntry() {}
|
|
|
|
|
2010-11-20 08:21:36 +00:00
|
|
|
SegmentMan::SegmentMan
|
|
|
|
(const Option* option,
|
|
|
|
const SharedHandle<DownloadContext>& downloadContext,
|
|
|
|
const PieceStorageHandle& pieceStorage)
|
|
|
|
: option_(option),
|
|
|
|
downloadContext_(downloadContext),
|
|
|
|
pieceStorage_(pieceStorage),
|
|
|
|
lastPeerStatDlspdMapUpdated_(0),
|
|
|
|
cachedDlspd_(0),
|
|
|
|
ignoreBitfield_(downloadContext->getPieceLength(),
|
|
|
|
downloadContext->getTotalLength())
|
2009-06-23 15:35:45 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
ignoreBitfield_.enableFilter();
|
2009-06-23 15:35:45 +00:00
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2007-10-11 16:58:24 +00:00
|
|
|
SegmentMan::~SegmentMan() {}
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2007-10-11 16:58:24 +00:00
|
|
|
bool SegmentMan::downloadFinished() const
|
|
|
|
{
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!pieceStorage_) {
|
2006-02-17 13:35:04 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->downloadFinished();
|
2007-09-01 16:10:30 +00:00
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2007-10-11 16:58:24 +00:00
|
|
|
void SegmentMan::init()
|
|
|
|
{
|
2010-06-12 13:49:39 +00:00
|
|
|
// TODO Do we have to do something about DownloadContext and
|
|
|
|
// PieceStorage here?
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2008-03-08 10:33:56 +00:00
|
|
|
uint64_t SegmentMan::getTotalLength() const
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!pieceStorage_) {
|
2007-10-11 16:58:24 +00:00
|
|
|
return 0;
|
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->getTotalLength();
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-11 16:58:24 +00:00
|
|
|
void SegmentMan::setPieceStorage(const PieceStorageHandle& pieceStorage)
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_ = pieceStorage;
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2009-06-28 10:37:15 +00:00
|
|
|
void SegmentMan::setDownloadContext
|
|
|
|
(const SharedHandle<DownloadContext>& downloadContext)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
downloadContext_ = downloadContext;
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2010-02-28 12:30:11 +00:00
|
|
|
SharedHandle<Segment> SegmentMan::checkoutSegment
|
|
|
|
(cuid_t cuid, const SharedHandle<Piece>& piece)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!piece) {
|
2008-04-20 00:50:22 +00:00
|
|
|
return SharedHandle<Segment>();
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
2010-11-20 12:12:06 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Attach segment#%lu to CUID#%lld.",
|
2010-10-28 14:19:29 +00:00
|
|
|
static_cast<unsigned long>(piece->getIndex()),
|
2010-11-20 12:12:06 +00:00
|
|
|
cuid));
|
2010-02-28 12:30:11 +00:00
|
|
|
SharedHandle<Segment> segment;
|
2007-10-11 16:58:24 +00:00
|
|
|
if(piece->getLength() == 0) {
|
2008-04-20 00:50:22 +00:00
|
|
|
segment.reset(new GrowSegment(piece));
|
2006-09-19 14:52:59 +00:00
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
segment.reset(new PiecedSegment(downloadContext_->getPieceLength(), piece));
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
2008-04-20 00:50:22 +00:00
|
|
|
SegmentEntryHandle entry(new SegmentEntry(cuid, segment));
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.push_back(entry);
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("index=%lu, length=%lu, segmentLength=%lu,"
|
2010-10-28 14:19:29 +00:00
|
|
|
" writtenLength=%lu",
|
|
|
|
static_cast<unsigned long>(segment->getIndex()),
|
|
|
|
static_cast<unsigned long>(segment->getLength()),
|
|
|
|
static_cast<unsigned long>(segment->getSegmentLength()),
|
2010-11-20 08:21:36 +00:00
|
|
|
static_cast<unsigned long>(segment->getWrittenLength())));
|
2009-06-23 15:35:45 +00:00
|
|
|
if(piece->getLength() > 0) {
|
|
|
|
std::map<size_t, size_t>::iterator positr =
|
2010-06-21 13:51:56 +00:00
|
|
|
segmentWrittenLengthMemo_.find(segment->getIndex());
|
|
|
|
if(positr != segmentWrittenLengthMemo_.end()) {
|
2009-06-23 15:35:45 +00:00
|
|
|
const size_t writtenLength = (*positr).second;
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("writtenLength(in memo)=%lu, writtenLength=%lu",
|
2010-10-28 14:19:29 +00:00
|
|
|
static_cast<unsigned long>(writtenLength),
|
2010-11-20 08:21:36 +00:00
|
|
|
static_cast<unsigned long>(segment->getWrittenLength()))
|
|
|
|
);
|
2009-06-23 15:35:45 +00:00
|
|
|
// If the difference between cached writtenLength and segment's
|
|
|
|
// writtenLength is less than one block, we assume that these
|
|
|
|
// missing bytes are already downloaded.
|
|
|
|
if(segment->getWrittenLength() < writtenLength &&
|
2010-01-05 16:01:46 +00:00
|
|
|
writtenLength-segment->getWrittenLength() < piece->getBlockLength()) {
|
|
|
|
segment->updateWrittenLength(writtenLength-segment->getWrittenLength());
|
2009-06-23 15:35:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2010-02-28 12:30:11 +00:00
|
|
|
void SegmentMan::getInFlightSegment
|
|
|
|
(std::vector<SharedHandle<Segment> >& segments, cuid_t cuid)
|
2007-10-17 16:26:51 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
for(SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end(); itr != eoi; ++itr) {
|
2007-10-17 16:26:51 +00:00
|
|
|
const SegmentEntryHandle& segmentEntry = *itr;
|
|
|
|
if(segmentEntry->cuid == cuid) {
|
2008-05-11 10:46:52 +00:00
|
|
|
segments.push_back(segmentEntry->segment);
|
2007-10-17 16:26:51 +00:00
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
2007-10-17 16:26:51 +00:00
|
|
|
}
|
|
|
|
|
2010-07-17 14:36:18 +00:00
|
|
|
SharedHandle<Segment> SegmentMan::getSegment(cuid_t cuid, size_t minSplitSize)
|
|
|
|
{
|
2010-02-28 12:30:11 +00:00
|
|
|
SharedHandle<Piece> piece =
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_->getSparseMissingUnusedPiece
|
2010-07-17 14:36:18 +00:00
|
|
|
(minSplitSize,
|
|
|
|
ignoreBitfield_.getFilterBitfield(), ignoreBitfield_.getBitfieldLength());
|
2009-06-29 15:18:21 +00:00
|
|
|
return checkoutSegment(cuid, piece);
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
2010-02-28 12:30:11 +00:00
|
|
|
void SegmentMan::getSegment
|
|
|
|
(std::vector<SharedHandle<Segment> >& segments,
|
|
|
|
cuid_t cuid,
|
2010-07-17 14:36:18 +00:00
|
|
|
size_t minSplitSize,
|
2010-02-28 12:30:11 +00:00
|
|
|
const SharedHandle<FileEntry>& fileEntry,
|
|
|
|
size_t maxSegments)
|
2009-06-30 17:03:57 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
BitfieldMan filter(ignoreBitfield_);
|
2009-06-30 17:03:57 +00:00
|
|
|
filter.enableFilter();
|
|
|
|
filter.addNotFilter(fileEntry->getOffset(), fileEntry->getLength());
|
2010-02-28 12:30:11 +00:00
|
|
|
std::vector<SharedHandle<Segment> > pending;
|
2009-06-30 17:03:57 +00:00
|
|
|
while(segments.size() < maxSegments) {
|
|
|
|
SharedHandle<Segment> segment =
|
|
|
|
checkoutSegment(cuid,
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_->getSparseMissingUnusedPiece
|
2010-07-17 14:36:18 +00:00
|
|
|
(minSplitSize,
|
|
|
|
filter.getFilterBitfield(), filter.getBitfieldLength()));
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!segment) {
|
2009-06-30 17:03:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(segment->getPositionToWrite() < fileEntry->getOffset() ||
|
|
|
|
fileEntry->getLastOffset() <= segment->getPositionToWrite()) {
|
|
|
|
pending.push_back(segment);
|
|
|
|
} else {
|
|
|
|
segments.push_back(segment);
|
|
|
|
}
|
|
|
|
}
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::vector<SharedHandle<Segment> >::const_iterator i = pending.begin(),
|
|
|
|
eoi = pending.end(); i != eoi; ++i) {
|
2009-06-30 17:03:57 +00:00
|
|
|
cancelSegment(cuid, *i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-17 14:36:18 +00:00
|
|
|
SharedHandle<Segment> SegmentMan::getSegmentWithIndex
|
|
|
|
(cuid_t cuid, size_t index) {
|
2010-06-21 13:51:56 +00:00
|
|
|
if(index > 0 && downloadContext_->getNumPieces() <= index) {
|
2008-04-20 00:50:22 +00:00
|
|
|
return SharedHandle<Segment>();
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
return checkoutSegment(cuid, pieceStorage_->getMissingPiece(index));
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
2010-03-28 07:23:33 +00:00
|
|
|
SharedHandle<Segment> SegmentMan::getCleanSegmentIfOwnerIsIdle
|
|
|
|
(cuid_t cuid, size_t index)
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
if(index > 0 && downloadContext_->getNumPieces() <= index) {
|
2010-03-28 07:23:33 +00:00
|
|
|
return SharedHandle<Segment>();
|
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
for(SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end(); itr != eoi; ++itr) {
|
2010-03-28 07:23:33 +00:00
|
|
|
const SharedHandle<SegmentEntry>& segmentEntry = *itr;
|
|
|
|
if(segmentEntry->segment->getIndex() == index) {
|
|
|
|
if(segmentEntry->segment->getWrittenLength() > 0) {
|
|
|
|
return SharedHandle<Segment>();
|
|
|
|
}
|
2010-06-26 12:41:07 +00:00
|
|
|
if(segmentEntry->cuid == cuid) {
|
|
|
|
return segmentEntry->segment;
|
|
|
|
}
|
2010-03-28 07:23:33 +00:00
|
|
|
cuid_t owner = segmentEntry->cuid;
|
|
|
|
SharedHandle<PeerStat> ps = getPeerStat(owner);
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!ps || ps->getStatus() == PeerStat::IDLE) {
|
2010-03-28 07:23:33 +00:00
|
|
|
cancelSegment(owner);
|
2010-07-17 14:36:18 +00:00
|
|
|
return getSegmentWithIndex(cuid, index);
|
2010-03-28 07:23:33 +00:00
|
|
|
} else {
|
|
|
|
return SharedHandle<Segment>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-06-21 14:02:51 +00:00
|
|
|
return SharedHandle<Segment>();
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
|
2009-06-30 17:03:57 +00:00
|
|
|
void SegmentMan::cancelSegment(const SharedHandle<Segment>& segment)
|
|
|
|
{
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Canceling segment#%lu",
|
|
|
|
static_cast<unsigned long>(segment->getIndex())));
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_->cancelPiece(segment->getPiece());
|
|
|
|
segmentWrittenLengthMemo_[segment->getIndex()] = segment->getWrittenLength();
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Memorized segment index=%lu, writtenLength=%lu",
|
2010-10-28 14:19:29 +00:00
|
|
|
static_cast<unsigned long>(segment->getIndex()),
|
2010-11-20 08:21:36 +00:00
|
|
|
static_cast<unsigned long>(segment->getWrittenLength())));
|
2009-06-30 17:03:57 +00:00
|
|
|
}
|
|
|
|
|
2009-03-19 13:54:09 +00:00
|
|
|
void SegmentMan::cancelSegment(cuid_t cuid) {
|
2010-06-21 13:51:56 +00:00
|
|
|
for(SegmentEntries::iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end(); itr != eoi;) {
|
2007-10-11 16:58:24 +00:00
|
|
|
if((*itr)->cuid == cuid) {
|
2009-06-30 17:03:57 +00:00
|
|
|
cancelSegment((*itr)->segment);
|
2010-06-21 13:51:56 +00:00
|
|
|
itr = usedSegmentEntries_.erase(itr);
|
|
|
|
eoi = usedSegmentEntries_.end();
|
2009-06-30 17:03:57 +00:00
|
|
|
} else {
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::cancelSegment
|
|
|
|
(cuid_t cuid, const SharedHandle<Segment>& segment)
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
for(SegmentEntries::iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end(); itr != eoi;) {
|
2010-11-11 07:33:43 +00:00
|
|
|
if((*itr)->cuid == cuid && *(*itr)->segment == *segment) {
|
2009-06-30 17:03:57 +00:00
|
|
|
cancelSegment((*itr)->segment);
|
2010-06-21 13:51:56 +00:00
|
|
|
itr = usedSegmentEntries_.erase(itr);
|
|
|
|
//eoi = usedSegmentEntries_.end();
|
2009-06-30 17:03:57 +00:00
|
|
|
break;
|
2007-10-17 16:26:51 +00:00
|
|
|
} else {
|
|
|
|
++itr;
|
2007-03-15 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To handle Segment as SegmentHandle:
* src/AbstractCommand.cc (execute): Rewritten.
* src/SegmentMan.h: Segment -> SegmentHandle
Introducded HttpResponse class, HttpRequest class to improve
code
extensiveness and make it clear:
* src/HttpDownloadCommand.cc: transfer encoders are now managed
by
HttpResponse class.
* src/HttpRequest.h, src/HttpRequest.cc: New class.
* src/HttpResponse.h, src/HttpResponse.cc: New class.
* src/HttpConnection.cc: Contruction of http request were moved
to
HttpRequest class.
* src/HttpResponseCommand.h, src/HttpResponseCommand.cc:
Refactored.
* src/HttpRequestCommand.cc (executeInternal): Rewritten.
* src/HttpAuthConfig.h: New class.
* src/Range.h: New class.
To make FtpTunnel{Request, Response}Command and
HttpProxy{Request, Response}Command derived from
AbstractProxy{Request, Response}Command:
* src/FtpTunnelResponseCommand.h,
src/FtpTunnelResponseCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/FtpTunnelRequestCommand.h, src/FtpTunnelRequestCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/HttpProxyRequestCommand.h, src/HttpProxyRequestCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/HttpProxyResponseCommand.h,
src/HttpProxyResponseCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/AbstractProxyRequestCommand.h,
src/AbstractProxyRequestCommand.cc
: New class.
* src/AbstractProxyResponseCommand.h,
src/AbstractProxyResponseCommand.cc: New class.
To add netrc support:
* src/Netrc.h, src/Netrc.cc: New class.
* src/Util.h, src/Util.cc (split): New function.
* src/HttpHeader.cc (getRange): Fixed so that it inspects
"Content-Range" header instead of "Range" header.
* src/HttpHeader.h
(getStatus): Removed.
(setStatus): Removed.
* src/Segment.h
(getPositionToWrite): New function.
2007-03-15 15:07:18 +00:00
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-28 07:23:33 +00:00
|
|
|
void SegmentMan::cancelAllSegments()
|
|
|
|
{
|
|
|
|
for(std::deque<SharedHandle<SegmentEntry> >::iterator itr =
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.begin(), eoi = usedSegmentEntries_.end();
|
2010-03-28 07:23:33 +00:00
|
|
|
itr != eoi; ++itr) {
|
|
|
|
cancelSegment((*itr)->segment);
|
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.clear();
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::eraseSegmentWrittenLengthMemo()
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
segmentWrittenLengthMemo_.clear();
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
|
2010-08-31 13:33:05 +00:00
|
|
|
namespace {
|
2008-01-06 16:37:25 +00:00
|
|
|
class FindSegmentEntry {
|
|
|
|
private:
|
2010-06-21 13:51:56 +00:00
|
|
|
SharedHandle<Segment> segment_;
|
2008-01-06 16:37:25 +00:00
|
|
|
public:
|
2010-06-21 13:51:56 +00:00
|
|
|
FindSegmentEntry(const SharedHandle<Segment>& segment):segment_(segment) {}
|
2008-01-06 16:37:25 +00:00
|
|
|
|
|
|
|
bool operator()(const SegmentEntryHandle& segmentEntry) const
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
return segmentEntry->segment->getIndex() == segment_->getIndex();
|
2008-01-06 16:37:25 +00:00
|
|
|
}
|
|
|
|
};
|
2010-10-30 14:53:40 +00:00
|
|
|
} // namespace
|
2008-01-06 16:37:25 +00:00
|
|
|
|
2010-02-28 12:30:11 +00:00
|
|
|
bool SegmentMan::completeSegment
|
|
|
|
(cuid_t cuid, const SharedHandle<Segment>& segment) {
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_->completePiece(segment->getPiece());
|
|
|
|
pieceStorage_->advertisePiece(cuid, segment->getPiece()->getIndex());
|
|
|
|
SegmentEntries::iterator itr = std::find_if(usedSegmentEntries_.begin(),
|
|
|
|
usedSegmentEntries_.end(),
|
2010-01-05 16:01:46 +00:00
|
|
|
FindSegmentEntry(segment));
|
2010-06-21 13:51:56 +00:00
|
|
|
if(itr == usedSegmentEntries_.end()) {
|
2006-09-19 14:52:59 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.erase(itr);
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-08 10:33:56 +00:00
|
|
|
bool SegmentMan::hasSegment(size_t index) const {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->hasPiece(index);
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
2008-03-08 10:33:56 +00:00
|
|
|
uint64_t SegmentMan::getDownloadLength() const {
|
2010-11-12 12:48:48 +00:00
|
|
|
if(!pieceStorage_) {
|
2007-10-11 16:58:24 +00:00
|
|
|
return 0;
|
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->getCompletedLength();
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:18:21 +00:00
|
|
|
void SegmentMan::registerPeerStat(const SharedHandle<PeerStat>& peerStat)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
for(std::vector<SharedHandle<PeerStat> >::iterator i = peerStats_.begin(),
|
|
|
|
eoi = peerStats_.end(); i != eoi; ++i) {
|
2009-07-02 16:26:04 +00:00
|
|
|
if((*i)->getStatus() == PeerStat::IDLE) {
|
|
|
|
*i = peerStat;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStats_.push_back(peerStat);
|
2007-10-11 16:58:24 +00:00
|
|
|
}
|
|
|
|
|
2010-03-28 07:23:33 +00:00
|
|
|
SharedHandle<PeerStat> SegmentMan::getPeerStat(cuid_t cuid) const
|
|
|
|
{
|
|
|
|
for(std::vector<SharedHandle<PeerStat> >::const_iterator i =
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStats_.begin(), eoi = peerStats_.end(); i != eoi; ++i) {
|
2010-03-28 07:23:33 +00:00
|
|
|
if((*i)->getCuid() == cuid) {
|
|
|
|
return *i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SharedHandle<PeerStat>();
|
|
|
|
}
|
|
|
|
|
2010-08-31 13:33:05 +00:00
|
|
|
namespace {
|
2009-07-02 16:26:04 +00:00
|
|
|
class PeerStatHostProtoEqual {
|
|
|
|
private:
|
2010-06-21 13:51:56 +00:00
|
|
|
const SharedHandle<PeerStat>& peerStat_;
|
2009-07-02 16:26:04 +00:00
|
|
|
public:
|
|
|
|
PeerStatHostProtoEqual(const SharedHandle<PeerStat>& peerStat):
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStat_(peerStat) {}
|
2009-07-02 16:26:04 +00:00
|
|
|
|
|
|
|
bool operator()(const SharedHandle<PeerStat>& p) const
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
return peerStat_->getHostname() == p->getHostname() &&
|
|
|
|
peerStat_->getProtocol() == p->getProtocol();
|
2009-07-02 16:26:04 +00:00
|
|
|
}
|
|
|
|
};
|
2010-10-30 14:53:40 +00:00
|
|
|
} // namespace
|
2009-07-02 16:26:04 +00:00
|
|
|
|
|
|
|
void SegmentMan::updateFastestPeerStat(const SharedHandle<PeerStat>& peerStat)
|
|
|
|
{
|
2010-02-28 12:30:11 +00:00
|
|
|
std::vector<SharedHandle<PeerStat> >::iterator i =
|
2010-06-21 13:51:56 +00:00
|
|
|
std::find_if(fastestPeerStats_.begin(), fastestPeerStats_.end(),
|
2010-01-05 16:01:46 +00:00
|
|
|
PeerStatHostProtoEqual(peerStat));
|
2010-06-21 13:51:56 +00:00
|
|
|
if(i == fastestPeerStats_.end()) {
|
|
|
|
fastestPeerStats_.push_back(peerStat);
|
2009-07-02 16:26:04 +00:00
|
|
|
} else if((*i)->getAvgDownloadSpeed() < peerStat->getAvgDownloadSpeed()) {
|
2009-07-15 12:36:58 +00:00
|
|
|
// *i's SessionDownloadLength must be added to peerStat
|
2009-07-04 13:10:40 +00:00
|
|
|
peerStat->addSessionDownloadLength((*i)->getSessionDownloadLength());
|
2009-07-02 16:26:04 +00:00
|
|
|
*i = peerStat;
|
2009-07-15 12:36:58 +00:00
|
|
|
} else {
|
|
|
|
// peerStat's SessionDownloadLength must be added to *i
|
|
|
|
(*i)->addSessionDownloadLength(peerStat->getSessionDownloadLength());
|
2009-07-02 16:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-19 13:42:10 +00:00
|
|
|
unsigned int SegmentMan::calculateDownloadSpeed()
|
|
|
|
{
|
2008-03-08 10:33:56 +00:00
|
|
|
unsigned int speed = 0;
|
2010-06-21 13:51:56 +00:00
|
|
|
if(lastPeerStatDlspdMapUpdated_.differenceInMillis(global::wallclock) >= 250){
|
|
|
|
lastPeerStatDlspdMapUpdated_ = global::wallclock;
|
|
|
|
peerStatDlspdMap_.clear();
|
2010-02-28 12:30:11 +00:00
|
|
|
for(std::vector<SharedHandle<PeerStat> >::const_iterator i =
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStats_.begin(), eoi = peerStats_.end(); i != eoi; ++i) {
|
2009-03-19 13:42:10 +00:00
|
|
|
if((*i)->getStatus() == PeerStat::ACTIVE) {
|
2010-01-05 16:01:46 +00:00
|
|
|
unsigned int s = (*i)->calculateDownloadSpeed();
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStatDlspdMap_[(*i)->getCuid()] = s;
|
2010-01-05 16:01:46 +00:00
|
|
|
speed += s;
|
2009-03-19 13:42:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
cachedDlspd_ = speed;
|
2009-03-19 13:42:10 +00:00
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
speed = cachedDlspd_;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
return speed;
|
2006-04-18 17:06:17 +00:00
|
|
|
}
|
2007-01-11 16:32:31 +00:00
|
|
|
|
2009-03-19 13:42:10 +00:00
|
|
|
void SegmentMan::updateDownloadSpeedFor(const SharedHandle<PeerStat>& pstat)
|
|
|
|
{
|
2009-03-20 13:29:33 +00:00
|
|
|
unsigned int newspd = pstat->calculateDownloadSpeed();
|
2010-06-21 13:51:56 +00:00
|
|
|
unsigned int oldSpd = peerStatDlspdMap_[pstat->getCuid()];
|
|
|
|
if(cachedDlspd_ > oldSpd) {
|
|
|
|
cachedDlspd_ -= oldSpd;
|
|
|
|
cachedDlspd_ += newspd;
|
2009-03-20 13:29:33 +00:00
|
|
|
} else {
|
2010-06-21 13:51:56 +00:00
|
|
|
cachedDlspd_ = newspd;
|
2009-03-20 13:29:33 +00:00
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStatDlspdMap_[pstat->getCuid()] = newspd;
|
2009-03-19 13:42:10 +00:00
|
|
|
}
|
|
|
|
|
2010-08-31 13:33:05 +00:00
|
|
|
namespace {
|
2008-09-10 14:56:44 +00:00
|
|
|
class PeerStatDownloadLengthOperator {
|
|
|
|
public:
|
|
|
|
uint64_t operator()(uint64_t total, const SharedHandle<PeerStat>& ps)
|
|
|
|
{
|
|
|
|
return ps->getSessionDownloadLength()+total;
|
|
|
|
}
|
|
|
|
};
|
2010-10-30 14:53:40 +00:00
|
|
|
} // namespace
|
2008-09-10 14:56:44 +00:00
|
|
|
|
|
|
|
uint64_t SegmentMan::calculateSessionDownloadLength() const
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
return std::accumulate(fastestPeerStats_.begin(), fastestPeerStats_.end(),
|
2010-01-05 16:01:46 +00:00
|
|
|
0LL, PeerStatDownloadLengthOperator());
|
2008-09-10 14:56:44 +00:00
|
|
|
}
|
|
|
|
|
2008-03-08 10:33:56 +00:00
|
|
|
size_t SegmentMan::countFreePieceFrom(size_t index) const
|
2007-10-17 16:26:51 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
size_t numPieces = downloadContext_->getNumPieces();
|
2008-03-08 10:33:56 +00:00
|
|
|
for(size_t i = index; i < numPieces; ++i) {
|
2010-06-21 13:51:56 +00:00
|
|
|
if(pieceStorage_->hasPiece(i) || pieceStorage_->isPieceUsed(i)) {
|
2007-10-17 16:26:51 +00:00
|
|
|
return i-index;
|
|
|
|
}
|
|
|
|
}
|
2010-06-21 13:51:56 +00:00
|
|
|
return downloadContext_->getNumPieces()-index;
|
2007-10-17 16:26:51 +00:00
|
|
|
}
|
|
|
|
|
2009-06-23 15:35:45 +00:00
|
|
|
void SegmentMan::ignoreSegmentFor(const SharedHandle<FileEntry>& fileEntry)
|
|
|
|
{
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("ignoring segment for path=%s, offset=%s, length=%s",
|
2010-06-12 13:49:39 +00:00
|
|
|
fileEntry->getPath().c_str(),
|
|
|
|
util::itos(fileEntry->getOffset()).c_str(),
|
2010-11-20 08:21:36 +00:00
|
|
|
util::uitos(fileEntry->getLength()).c_str()));
|
2010-06-21 13:51:56 +00:00
|
|
|
ignoreBitfield_.addFilter(fileEntry->getOffset(), fileEntry->getLength());
|
2009-06-23 15:35:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::recognizeSegmentFor(const SharedHandle<FileEntry>& fileEntry)
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
ignoreBitfield_.removeFilter(fileEntry->getOffset(), fileEntry->getLength());
|
2009-06-23 15:35:45 +00:00
|
|
|
}
|
|
|
|
|
2009-07-13 15:02:32 +00:00
|
|
|
bool SegmentMan::allSegmentsIgnored() const
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
return ignoreBitfield_.isAllFilterBitSet();
|
2009-07-13 15:02:32 +00:00
|
|
|
}
|
|
|
|
|
2008-02-08 15:53:45 +00:00
|
|
|
} // namespace aria2
|