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"
|
2012-12-05 16:16:28 +00:00
|
|
|
#include "WrDiskCacheEntry.h"
|
|
|
|
#include "DownloadFailureException.h"
|
2008-02-08 15:53:45 +00:00
|
|
|
|
|
|
|
namespace aria2 {
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
SegmentEntry::SegmentEntry(cuid_t cuid, const std::shared_ptr<Segment>& segment)
|
2015-12-27 09:39:47 +00:00
|
|
|
: cuid(cuid), segment(segment)
|
|
|
|
{
|
|
|
|
}
|
2010-11-14 07:17:55 +00:00
|
|
|
|
2016-07-31 00:18:43 +00:00
|
|
|
SegmentEntry::~SegmentEntry() = default;
|
2010-11-14 07:17:55 +00:00
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
SegmentMan::SegmentMan(const std::shared_ptr<DownloadContext>& downloadContext,
|
|
|
|
const std::shared_ptr<PieceStorage>& pieceStorage)
|
|
|
|
: downloadContext_(downloadContext),
|
|
|
|
pieceStorage_(pieceStorage),
|
|
|
|
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
|
|
|
|
2016-07-31 00:18:43 +00:00
|
|
|
SegmentMan::~SegmentMan() = default;
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2007-10-11 16:58:24 +00:00
|
|
|
bool SegmentMan::downloadFinished() const
|
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
if (!pieceStorage_) {
|
2006-02-17 13:35:04 +00:00
|
|
|
return false;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-06-25 14:35:24 +00:00
|
|
|
int64_t SegmentMan::getTotalLength() const
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
if (!pieceStorage_) {
|
2007-10-11 16:58:24 +00:00
|
|
|
return 0;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->getTotalLength();
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::setPieceStorage(
|
|
|
|
const std::shared_ptr<PieceStorage>& pieceStorage)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_ = pieceStorage;
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::setDownloadContext(
|
|
|
|
const std::shared_ptr<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
|
|
|
}
|
|
|
|
|
2012-12-05 16:16:28 +00:00
|
|
|
namespace {
|
|
|
|
void flushWrDiskCache(WrDiskCache* wrDiskCache,
|
2013-06-21 16:10:38 +00:00
|
|
|
const std::shared_ptr<Piece>& piece)
|
2012-12-05 16:16:28 +00:00
|
|
|
{
|
|
|
|
piece->flushWrCache(wrDiskCache);
|
2015-12-27 09:39:47 +00:00
|
|
|
if (piece->getWrDiskCacheEntry()->getError() !=
|
|
|
|
WrDiskCacheEntry::CACHE_ERR_SUCCESS) {
|
2012-12-05 16:16:28 +00:00
|
|
|
piece->clearAllBlock(wrDiskCache);
|
2015-12-27 09:39:47 +00:00
|
|
|
throw DOWNLOAD_FAILURE_EXCEPTION2(
|
|
|
|
fmt("Write disk cache flush failure index=%lu",
|
|
|
|
static_cast<unsigned long>(piece->getIndex())),
|
|
|
|
piece->getWrDiskCacheEntry()->getErrorCode());
|
2012-12-05 16:16:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
std::shared_ptr<Segment>
|
|
|
|
SegmentMan::checkoutSegment(cuid_t cuid, const std::shared_ptr<Piece>& piece)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
if (!piece) {
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
2012-06-25 13:43:33 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Attach segment#%lu to CUID#%" PRId64 ".",
|
2015-12-27 09:39:47 +00:00
|
|
|
static_cast<unsigned long>(piece->getIndex()), cuid));
|
2012-12-05 16:16:28 +00:00
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
if (piece->getWrDiskCacheEntry()) {
|
2012-12-05 16:16:28 +00:00
|
|
|
// Flush cached data here, because the cached data may be overlapped
|
|
|
|
// if BT peers are involved.
|
2015-12-27 09:39:47 +00:00
|
|
|
A2_LOG_DEBUG(fmt(
|
|
|
|
"Flushing cached data, size=%lu",
|
|
|
|
static_cast<unsigned long>(piece->getWrDiskCacheEntry()->getSize())));
|
2012-12-05 16:16:28 +00:00
|
|
|
flushWrDiskCache(pieceStorage_->getWrDiskCache(), piece);
|
|
|
|
}
|
|
|
|
|
2011-07-15 15:58:41 +00:00
|
|
|
piece->setUsedBySegment(true);
|
2013-06-21 16:10:38 +00:00
|
|
|
std::shared_ptr<Segment> segment;
|
2015-12-27 09:39:47 +00:00
|
|
|
if (piece->getLength() == 0) {
|
2014-09-13 09:37:57 +00:00
|
|
|
segment = std::make_shared<GrowSegment>(piece);
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = std::make_shared<PiecedSegment>(
|
|
|
|
downloadContext_->getPieceLength(), piece);
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
2014-09-13 09:37:57 +00:00
|
|
|
auto entry = std::make_shared<SegmentEntry>(cuid, segment);
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.push_back(entry);
|
2014-05-24 20:42:23 +00:00
|
|
|
A2_LOG_DEBUG(fmt("index=%lu, length=%" PRId64 ", segmentLength=%" PRId64 ","
|
|
|
|
" writtenLength=%" PRId64,
|
2010-10-28 14:19:29 +00:00
|
|
|
static_cast<unsigned long>(segment->getIndex()),
|
2015-12-27 09:39:47 +00:00
|
|
|
segment->getLength(), segment->getSegmentLength(),
|
2011-12-07 15:03:25 +00:00
|
|
|
segment->getWrittenLength()));
|
2012-12-05 16:16:28 +00:00
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
if (piece->getLength() > 0) {
|
2013-08-21 03:06:53 +00:00
|
|
|
auto positr = segmentWrittenLengthMemo_.find(segment->getIndex());
|
2015-12-27 09:39:47 +00:00
|
|
|
if (positr != segmentWrittenLengthMemo_.end()) {
|
2014-05-24 20:42:23 +00:00
|
|
|
const auto writtenLength = (*positr).second;
|
2015-12-27 09:39:47 +00:00
|
|
|
A2_LOG_DEBUG(fmt("writtenLength(in memo)=%" PRId64
|
|
|
|
", writtenLength=%" PRId64,
|
2011-12-07 15:03:25 +00:00
|
|
|
writtenLength, 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.
|
2015-12-27 09:39:47 +00:00
|
|
|
if (segment->getWrittenLength() < writtenLength &&
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::getInFlightSegment(
|
|
|
|
std::vector<std::shared_ptr<Segment>>& segments, cuid_t cuid)
|
2007-10-17 16:26:51 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
for (SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end();
|
|
|
|
itr != eoi; ++itr) {
|
2013-06-21 16:10:38 +00:00
|
|
|
const std::shared_ptr<SegmentEntry>& segmentEntry = *itr;
|
2015-12-27 09:39:47 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
std::shared_ptr<Segment> SegmentMan::getSegment(cuid_t cuid,
|
|
|
|
size_t minSplitSize)
|
2010-07-17 14:36:18 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
std::shared_ptr<Piece> piece = pieceStorage_->getMissingPiece(
|
|
|
|
minSplitSize, ignoreBitfield_.getFilterBitfield(),
|
|
|
|
ignoreBitfield_.getBitfieldLength(), cuid);
|
2009-06-29 15:18:21 +00:00
|
|
|
return checkoutSegment(cuid, piece);
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::getSegment(std::vector<std::shared_ptr<Segment>>& segments,
|
|
|
|
cuid_t cuid, size_t minSplitSize,
|
|
|
|
const std::shared_ptr<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());
|
2015-12-27 09:39:47 +00:00
|
|
|
std::vector<std::shared_ptr<Segment>> pending;
|
|
|
|
while (segments.size() < maxSegments) {
|
|
|
|
std::shared_ptr<Segment> segment = checkoutSegment(
|
|
|
|
cuid,
|
|
|
|
pieceStorage_->getMissingPiece(minSplitSize, filter.getFilterBitfield(),
|
|
|
|
filter.getBitfieldLength(), cuid));
|
|
|
|
if (!segment) {
|
2009-06-30 17:03:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-27 09:39:47 +00:00
|
|
|
if (segment->getPositionToWrite() < fileEntry->getOffset() ||
|
|
|
|
fileEntry->getLastOffset() <= segment->getPositionToWrite()) {
|
2009-06-30 17:03:57 +00:00
|
|
|
pending.push_back(segment);
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-06-30 17:03:57 +00:00
|
|
|
segments.push_back(segment);
|
|
|
|
}
|
|
|
|
}
|
2015-12-27 09:39:47 +00:00
|
|
|
for (std::vector<std::shared_ptr<Segment>>::const_iterator
|
|
|
|
i = pending.begin(),
|
|
|
|
eoi = pending.end();
|
|
|
|
i != eoi; ++i) {
|
2009-06-30 17:03:57 +00:00
|
|
|
cancelSegment(cuid, *i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
std::shared_ptr<Segment> SegmentMan::getSegmentWithIndex(cuid_t cuid,
|
|
|
|
size_t index)
|
|
|
|
{
|
|
|
|
if (index > 0 && downloadContext_->getNumPieces() <= index) {
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
2011-07-15 15:58:41 +00:00
|
|
|
return checkoutSegment(cuid, pieceStorage_->getMissingPiece(index, cuid));
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
std::shared_ptr<Segment> SegmentMan::getCleanSegmentIfOwnerIsIdle(cuid_t cuid,
|
|
|
|
size_t index)
|
2010-03-28 07:23:33 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
if (index > 0 && downloadContext_->getNumPieces() <= index) {
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
2015-12-27 09:39:47 +00:00
|
|
|
for (SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
|
|
|
|
eoi = usedSegmentEntries_.end();
|
|
|
|
itr != eoi; ++itr) {
|
2013-06-21 16:10:38 +00:00
|
|
|
const std::shared_ptr<SegmentEntry>& segmentEntry = *itr;
|
2015-12-27 09:39:47 +00:00
|
|
|
if (segmentEntry->segment->getIndex() == index) {
|
|
|
|
if (segmentEntry->segment->getWrittenLength() > 0) {
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
2015-12-27 09:39:47 +00:00
|
|
|
if (segmentEntry->cuid == cuid) {
|
2010-06-26 12:41:07 +00:00
|
|
|
return segmentEntry->segment;
|
|
|
|
}
|
2010-03-28 07:23:33 +00:00
|
|
|
cuid_t owner = segmentEntry->cuid;
|
2013-06-21 16:10:38 +00:00
|
|
|
std::shared_ptr<PeerStat> ps = getPeerStat(owner);
|
2015-12-27 09:39:47 +00:00
|
|
|
if (!ps || ps->getStatus() == NetStat::IDLE) {
|
2010-03-28 07:23:33 +00:00
|
|
|
cancelSegment(owner);
|
2010-07-17 14:36:18 +00:00
|
|
|
return getSegmentWithIndex(cuid, index);
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::cancelSegmentInternal(cuid_t cuid,
|
|
|
|
const std::shared_ptr<Segment>& segment)
|
2009-06-30 17:03:57 +00:00
|
|
|
{
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Canceling segment#%lu",
|
|
|
|
static_cast<unsigned long>(segment->getIndex())));
|
2013-06-21 16:10:38 +00:00
|
|
|
const std::shared_ptr<Piece>& piece = segment->getPiece();
|
2012-12-05 16:16:28 +00:00
|
|
|
// TODO In PieceStorage::cancelPiece(), WrDiskCacheEntry may be
|
2013-04-23 14:00:11 +00:00
|
|
|
// released. Flush first.
|
2015-12-27 09:39:47 +00:00
|
|
|
if (piece->getWrDiskCacheEntry()) {
|
2012-12-05 16:16:28 +00:00
|
|
|
// Flush cached data here, because the cached data may be overlapped
|
|
|
|
// if BT peers are involved.
|
2015-12-27 09:39:47 +00:00
|
|
|
A2_LOG_DEBUG(fmt(
|
|
|
|
"Flushing cached data, size=%lu",
|
|
|
|
static_cast<unsigned long>(piece->getWrDiskCacheEntry()->getSize())));
|
2012-12-05 16:16:28 +00:00
|
|
|
flushWrDiskCache(pieceStorage_->getWrDiskCache(), piece);
|
|
|
|
// TODO Exception may cause some segments (pieces) are not
|
|
|
|
// canceled.
|
|
|
|
}
|
2013-04-23 14:00:11 +00:00
|
|
|
piece->setUsedBySegment(false);
|
|
|
|
pieceStorage_->cancelPiece(piece, cuid);
|
|
|
|
segmentWrittenLengthMemo_[segment->getIndex()] = segment->getWrittenLength();
|
2014-05-24 20:42:23 +00:00
|
|
|
A2_LOG_DEBUG(fmt("Memorized segment index=%lu, writtenLength=%" PRId64,
|
2013-04-23 14:00:11 +00:00
|
|
|
static_cast<unsigned long>(segment->getIndex()),
|
|
|
|
segment->getWrittenLength()));
|
2009-06-30 17:03:57 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::cancelSegment(cuid_t cuid)
|
|
|
|
{
|
|
|
|
for (auto itr = usedSegmentEntries_.begin(), eoi = usedSegmentEntries_.end();
|
|
|
|
itr != eoi;) {
|
|
|
|
if ((*itr)->cuid == cuid) {
|
2011-07-15 15:58:41 +00:00
|
|
|
cancelSegmentInternal(cuid, (*itr)->segment);
|
2010-06-21 13:51:56 +00:00
|
|
|
itr = usedSegmentEntries_.erase(itr);
|
|
|
|
eoi = usedSegmentEntries_.end();
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-06-30 17:03:57 +00:00
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::cancelSegment(cuid_t cuid,
|
|
|
|
const std::shared_ptr<Segment>& segment)
|
2009-06-30 17:03:57 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
for (auto itr = usedSegmentEntries_.begin(), eoi = usedSegmentEntries_.end();
|
|
|
|
itr != eoi;) {
|
|
|
|
if ((*itr)->cuid == cuid && *(*itr)->segment == *segment) {
|
2011-07-15 15:58:41 +00:00
|
|
|
cancelSegmentInternal(cuid, (*itr)->segment);
|
2010-06-21 13:51:56 +00:00
|
|
|
itr = usedSegmentEntries_.erase(itr);
|
2009-06-30 17:03:57 +00:00
|
|
|
break;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2007-10-17 16:26:51 +00:00
|
|
|
++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()
|
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
for (auto& e : usedSegmentEntries_) {
|
2013-08-25 16:00:46 +00:00
|
|
|
cancelSegmentInternal(e->cuid, e->segment);
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
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:
|
2013-06-21 16:10:38 +00:00
|
|
|
std::shared_ptr<Segment> segment_;
|
2015-12-27 09:39:47 +00:00
|
|
|
|
2008-01-06 16:37:25 +00:00
|
|
|
public:
|
2015-12-27 09:39:47 +00:00
|
|
|
FindSegmentEntry(std::shared_ptr<Segment> segment)
|
|
|
|
: segment_(std::move(segment))
|
|
|
|
{
|
|
|
|
}
|
2008-01-06 16:37:25 +00:00
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
bool operator()(const std::shared_ptr<SegmentEntry>& segmentEntry) const
|
2008-01-06 16:37:25 +00:00
|
|
|
{
|
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
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
bool SegmentMan::completeSegment(cuid_t cuid,
|
|
|
|
const std::shared_ptr<Segment>& segment)
|
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
pieceStorage_->completePiece(segment->getPiece());
|
2016-07-10 13:42:49 +00:00
|
|
|
pieceStorage_->advertisePiece(cuid, segment->getPiece()->getIndex(),
|
|
|
|
global::wallclock());
|
2013-08-25 16:00:46 +00:00
|
|
|
auto itr = std::find_if(usedSegmentEntries_.begin(),
|
2015-12-27 09:39:47 +00:00
|
|
|
usedSegmentEntries_.end(), FindSegmentEntry(segment));
|
|
|
|
if (itr == usedSegmentEntries_.end()) {
|
2006-09-19 14:52:59 +00:00
|
|
|
return false;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-06-21 13:51:56 +00:00
|
|
|
usedSegmentEntries_.erase(itr);
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +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
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
int64_t SegmentMan::getDownloadLength() const
|
|
|
|
{
|
|
|
|
if (!pieceStorage_) {
|
2007-10-11 16:58:24 +00:00
|
|
|
return 0;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-06-21 13:51:56 +00:00
|
|
|
return pieceStorage_->getCompletedLength();
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
void SegmentMan::registerPeerStat(const std::shared_ptr<PeerStat>& peerStat)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
peerStats_.push_back(peerStat);
|
2007-10-11 16:58:24 +00:00
|
|
|
}
|
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
std::shared_ptr<PeerStat> SegmentMan::getPeerStat(cuid_t cuid) const
|
2010-03-28 07:23:33 +00:00
|
|
|
{
|
2015-12-27 09:39:47 +00:00
|
|
|
for (auto& e : peerStats_) {
|
|
|
|
if (e->getCuid() == cuid) {
|
2013-08-25 16:00:46 +00:00
|
|
|
return e;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
2013-07-04 12:44:09 +00:00
|
|
|
return nullptr;
|
2010-03-28 07:23:33 +00:00
|
|
|
}
|
|
|
|
|
2010-08-31 13:33:05 +00:00
|
|
|
namespace {
|
2009-07-02 16:26:04 +00:00
|
|
|
class PeerStatHostProtoEqual {
|
|
|
|
private:
|
2013-06-21 16:10:38 +00:00
|
|
|
const std::shared_ptr<PeerStat>& peerStat_;
|
2015-12-27 09:39:47 +00:00
|
|
|
|
2009-07-02 16:26:04 +00:00
|
|
|
public:
|
2015-12-27 09:39:47 +00:00
|
|
|
PeerStatHostProtoEqual(const std::shared_ptr<PeerStat>& peerStat)
|
|
|
|
: peerStat_(peerStat)
|
|
|
|
{
|
|
|
|
}
|
2009-07-02 16:26:04 +00:00
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
bool operator()(const std::shared_ptr<PeerStat>& p) const
|
2009-07-02 16:26:04 +00:00
|
|
|
{
|
2010-06-21 13:51:56 +00:00
|
|
|
return peerStat_->getHostname() == p->getHostname() &&
|
2015-12-27 09:39:47 +00:00
|
|
|
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
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::updateFastestPeerStat(
|
|
|
|
const std::shared_ptr<PeerStat>& peerStat)
|
2009-07-02 16:26:04 +00:00
|
|
|
{
|
2013-08-21 03:06:53 +00:00
|
|
|
auto i = std::find_if(fastestPeerStats_.begin(), fastestPeerStats_.end(),
|
|
|
|
PeerStatHostProtoEqual(peerStat));
|
2015-12-27 09:39:47 +00:00
|
|
|
if (i == fastestPeerStats_.end()) {
|
2010-06-21 13:51:56 +00:00
|
|
|
fastestPeerStats_.push_back(peerStat);
|
2015-12-27 09:39:47 +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;
|
2015-12-27 09:39:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-07-15 12:36:58 +00:00
|
|
|
// peerStat's SessionDownloadLength must be added to *i
|
|
|
|
(*i)->addSessionDownloadLength(peerStat->getSessionDownloadLength());
|
2009-07-02 16:26:04 +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();
|
2015-12-27 09:39:47 +00:00
|
|
|
for (size_t i = index; i < numPieces; ++i) {
|
|
|
|
if (pieceStorage_->hasPiece(i) || pieceStorage_->isPieceUsed(i)) {
|
|
|
|
return i - index;
|
2007-10-17 16:26:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-27 09:39:47 +00:00
|
|
|
return downloadContext_->getNumPieces() - index;
|
2007-10-17 16:26:51 +00:00
|
|
|
}
|
|
|
|
|
2013-06-21 16:10:38 +00:00
|
|
|
void SegmentMan::ignoreSegmentFor(const std::shared_ptr<FileEntry>& fileEntry)
|
2009-06-23 15:35:45 +00:00
|
|
|
{
|
2012-06-25 14:44:52 +00:00
|
|
|
A2_LOG_DEBUG(fmt("ignoring segment for path=%s, offset=%" PRId64
|
|
|
|
", length=%" PRId64 "",
|
2015-12-27 09:39:47 +00:00
|
|
|
fileEntry->getPath().c_str(), fileEntry->getOffset(),
|
2012-06-25 14:44:52 +00:00
|
|
|
fileEntry->getLength()));
|
2010-06-21 13:51:56 +00:00
|
|
|
ignoreBitfield_.addFilter(fileEntry->getOffset(), fileEntry->getLength());
|
2009-06-23 15:35:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-27 09:39:47 +00:00
|
|
|
void SegmentMan::recognizeSegmentFor(
|
|
|
|
const std::shared_ptr<FileEntry>& fileEntry)
|
2009-06-23 15:35:45 +00:00
|
|
|
{
|
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
|