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
|
2006-09-21 15:31:24 +00:00
|
|
|
* 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.
|
2006-02-17 13:35:04 +00:00
|
|
|
*/
|
|
|
|
/* copyright --> */
|
|
|
|
#include "SegmentMan.h"
|
|
|
|
#include "DlAbortEx.h"
|
|
|
|
#include "Util.h"
|
|
|
|
#include "File.h"
|
|
|
|
#include "message.h"
|
2006-02-22 11:18:47 +00:00
|
|
|
#include "prefs.h"
|
2006-04-17 16:17:20 +00:00
|
|
|
#include "LogFactory.h"
|
2006-12-24 06:25:21 +00:00
|
|
|
#include "BitfieldManFactory.h"
|
2006-04-17 16:17:20 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2006-09-19 14:52:59 +00:00
|
|
|
SegmentMan::SegmentMan():bitfield(0),
|
|
|
|
totalSize(0),
|
2006-05-09 15:54:14 +00:00
|
|
|
isSplittable(true),
|
|
|
|
downloadStarted(false),
|
|
|
|
dir("."),
|
2006-06-18 09:23:25 +00:00
|
|
|
errors(0),
|
2006-09-19 14:52:59 +00:00
|
|
|
diskWriter(0) {
|
2006-04-17 16:17:20 +00:00
|
|
|
logger = LogFactory::getInstance();
|
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2006-05-09 15:54:14 +00:00
|
|
|
SegmentMan::~SegmentMan() {
|
2006-09-19 14:52:59 +00:00
|
|
|
delete bitfield;
|
|
|
|
delete diskWriter;
|
2006-05-09 15:54:14 +00:00
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2006-02-21 12:27:17 +00:00
|
|
|
bool SegmentMan::segmentFileExists() const {
|
2006-02-17 13:35:04 +00:00
|
|
|
if(!isSplittable) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
string segFilename = getSegmentFilePath();
|
|
|
|
File f(segFilename);
|
|
|
|
if(f.isFile()) {
|
|
|
|
logger->info(MSG_SEGMENT_FILE_EXISTS, segFilename.c_str());
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, segFilename.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::load() {
|
|
|
|
if(!isSplittable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
string segFilename = getSegmentFilePath();
|
|
|
|
logger->info(MSG_LOADING_SEGMENT_FILE, segFilename.c_str());
|
|
|
|
FILE* segFile = openSegFile(segFilename, "r+");
|
2006-04-20 15:58:05 +00:00
|
|
|
try {
|
|
|
|
read(segFile);
|
|
|
|
fclose(segFile);
|
|
|
|
} catch(string ex) {
|
|
|
|
fclose(segFile);
|
|
|
|
throw new DlAbortEx(EX_SEGMENT_FILE_READ,
|
|
|
|
segFilename.c_str(), strerror(errno));
|
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
logger->info(MSG_LOADED_SEGMENT_FILE);
|
|
|
|
}
|
|
|
|
|
2006-02-21 12:27:17 +00:00
|
|
|
void SegmentMan::save() const {
|
|
|
|
if(!isSplittable || totalSize == 0) {
|
2006-02-17 13:35:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
string segFilename = getSegmentFilePath();
|
|
|
|
logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str());
|
|
|
|
FILE* segFile = openSegFile(segFilename, "w");
|
2006-04-20 15:58:05 +00:00
|
|
|
try {
|
|
|
|
if(fwrite(&totalSize, sizeof(totalSize), 1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
int segmentLength = bitfield->getBlockLength();
|
|
|
|
if(fwrite(&segmentLength, sizeof(segmentLength), 1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
|
|
|
if(bitfield) {
|
|
|
|
int bitfieldLength = bitfield->getBitfieldLength();
|
|
|
|
if(fwrite(&bitfieldLength, sizeof(bitfieldLength), 1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
|
|
|
if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(),
|
|
|
|
1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int i = 0;
|
|
|
|
if(fwrite(&i, sizeof(i), 1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int usedSegmentCount = usedSegmentEntries.size();
|
|
|
|
if(fwrite(&usedSegmentCount, sizeof(usedSegmentCount), 1, segFile) < 1) {
|
|
|
|
throw string("writeError");
|
|
|
|
}
|
|
|
|
for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
|
|
|
|
itr != usedSegmentEntries.end(); itr++) {
|
2006-09-21 06:56:54 +00:00
|
|
|
if(fwrite(&(*itr)->segment, sizeof(Segment), 1, segFile) < 1) {
|
2006-04-20 15:58:05 +00:00
|
|
|
throw string("writeError");
|
|
|
|
}
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
2006-04-20 15:58:05 +00:00
|
|
|
fclose(segFile);
|
|
|
|
logger->info(MSG_SAVED_SEGMENT_FILE);
|
|
|
|
} catch(string ex) {
|
|
|
|
fclose(segFile);
|
|
|
|
throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
|
|
|
|
segFilename.c_str(), strerror(errno));
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-19 17:49:03 +00:00
|
|
|
FILE* SegmentMan::openSegFile(const string& segFilename, const string& mode) const {
|
2006-02-17 13:35:04 +00:00
|
|
|
FILE* segFile = fopen(segFilename.c_str(), mode.c_str());
|
|
|
|
if(segFile == NULL) {
|
2006-04-20 15:58:05 +00:00
|
|
|
throw new DlAbortEx(EX_SEGMENT_FILE_OPEN,
|
|
|
|
segFilename.c_str(), strerror(errno));
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
return segFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::read(FILE* file) {
|
|
|
|
assert(file != NULL);
|
2006-02-21 12:27:17 +00:00
|
|
|
if(fread(&totalSize, sizeof(totalSize), 1, file) < 1) {
|
2006-04-20 15:58:05 +00:00
|
|
|
throw string("readError");
|
2006-02-21 12:27:17 +00:00
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
int segmentSize;
|
|
|
|
if(fread(&segmentSize, sizeof(segmentSize), 1, file) < 1) {
|
|
|
|
throw string("readError");
|
|
|
|
}
|
|
|
|
int bitfieldLength;
|
|
|
|
if(fread(&bitfieldLength, sizeof(bitfieldLength), 1, file) < 1) {
|
|
|
|
throw string("readError");
|
|
|
|
}
|
|
|
|
if(bitfieldLength > 0) {
|
|
|
|
initBitfield(segmentSize, totalSize);
|
|
|
|
unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()];
|
|
|
|
if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) {
|
|
|
|
delete [] savedBitfield;
|
|
|
|
throw string("readError");
|
|
|
|
} else {
|
|
|
|
bitfield->setBitfield(savedBitfield, bitfield->getBitfieldLength());
|
|
|
|
delete [] savedBitfield;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int segmentCount;
|
|
|
|
if(fread(&segmentCount, sizeof(segmentCount), 1, file) < 1) {
|
|
|
|
throw string("readError");
|
|
|
|
}
|
|
|
|
while(segmentCount--) {
|
2006-02-17 13:35:04 +00:00
|
|
|
Segment seg;
|
|
|
|
if(fread(&seg, sizeof(Segment), 1, file) < 1) {
|
2006-09-19 14:52:59 +00:00
|
|
|
throw string("readError");
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
2006-09-21 06:56:54 +00:00
|
|
|
usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(0, seg)));
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-21 12:27:17 +00:00
|
|
|
void SegmentMan::remove() const {
|
2006-02-17 13:35:04 +00:00
|
|
|
if(!isSplittable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(segmentFileExists()) {
|
|
|
|
File f(getSegmentFilePath());
|
|
|
|
f.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-21 12:27:17 +00:00
|
|
|
bool SegmentMan::finished() const {
|
2006-09-19 14:52:59 +00:00
|
|
|
if(!downloadStarted) {
|
2006-02-17 13:35:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
if(!bitfield) {
|
|
|
|
return false;
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
assert(bitfield);
|
|
|
|
return bitfield->isAllBitSet();
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2006-02-21 12:27:17 +00:00
|
|
|
void SegmentMan::removeIfFinished() const {
|
2006-02-17 13:35:04 +00:00
|
|
|
if(finished()) {
|
|
|
|
remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-18 17:06:17 +00:00
|
|
|
void SegmentMan::init() {
|
|
|
|
totalSize = 0;
|
|
|
|
isSplittable = false;
|
|
|
|
downloadStarted = false;
|
2006-06-12 16:55:08 +00:00
|
|
|
errors = 0;
|
2006-09-19 14:52:59 +00:00
|
|
|
//segments.clear();
|
|
|
|
usedSegmentEntries.clear();
|
|
|
|
delete bitfield;
|
2006-09-21 06:56:54 +00:00
|
|
|
bitfield = 0;
|
2006-09-19 14:52:59 +00:00
|
|
|
peerStats.clear();
|
2006-04-19 17:23:58 +00:00
|
|
|
diskWriter->closeFile();
|
2006-09-19 14:52:59 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::initBitfield(int segmentLength, long long int totalLength) {
|
2006-12-24 06:25:21 +00:00
|
|
|
this->bitfield = BitfieldManFactory::getNewFactory()->createBitfieldMan(segmentLength, totalLength);
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class FindSegmentEntryByIndex {
|
|
|
|
private:
|
|
|
|
int index;
|
|
|
|
public:
|
|
|
|
FindSegmentEntryByIndex(int index):index(index) {}
|
|
|
|
|
2006-09-21 06:56:54 +00:00
|
|
|
bool operator()(const SegmentEntryHandle& entry) {
|
|
|
|
return entry->segment.index == index;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class FindSegmentEntryByCuid {
|
|
|
|
private:
|
|
|
|
int cuid;
|
|
|
|
public:
|
|
|
|
FindSegmentEntryByCuid(int cuid):cuid(cuid) {}
|
|
|
|
|
2006-09-21 06:56:54 +00:00
|
|
|
bool operator()(const SegmentEntryHandle& entry) {
|
|
|
|
return entry->cuid == cuid;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Segment SegmentMan::checkoutSegment(int cuid, int index) {
|
|
|
|
logger->debug("Attach segment#%d to CUID#%d.", index, cuid);
|
|
|
|
bitfield->setUseBit(index);
|
|
|
|
|
|
|
|
SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
|
|
|
|
usedSegmentEntries.end(),
|
|
|
|
FindSegmentEntryByIndex(index));
|
|
|
|
Segment segment;
|
|
|
|
if(itr == usedSegmentEntries.end()) {
|
|
|
|
segment = Segment(index, bitfield->getBlockLength(index),
|
|
|
|
bitfield->getBlockLength());
|
2006-09-21 06:56:54 +00:00
|
|
|
SegmentEntryHandle entry =
|
|
|
|
SegmentEntryHandle(new SegmentEntry(cuid, segment));
|
2006-09-19 14:52:59 +00:00
|
|
|
usedSegmentEntries.push_back(entry);
|
|
|
|
} else {
|
2006-09-21 06:56:54 +00:00
|
|
|
(*itr)->cuid = cuid;
|
|
|
|
segment = (*itr)->segment;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
logger->debug("index=%d, length=%d, segmentLength=%d, writtenLength=%d",
|
|
|
|
segment.index, segment.length, segment.segmentLength,
|
|
|
|
segment.writtenLength);
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::onNullBitfield(Segment& segment, int cuid) {
|
|
|
|
if(usedSegmentEntries.size() == 0) {
|
|
|
|
segment = Segment(0, 0, 0);
|
2006-09-21 06:56:54 +00:00
|
|
|
usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(cuid, segment)));
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
2006-09-21 06:56:54 +00:00
|
|
|
SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
|
|
|
|
usedSegmentEntries.end(),
|
|
|
|
FindSegmentEntryByCuid(cuid));
|
|
|
|
if(itr == usedSegmentEntries.end()) {
|
2006-09-19 14:52:59 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
2006-09-21 06:56:54 +00:00
|
|
|
segment = (*itr)->segment;
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-21 06:56:54 +00:00
|
|
|
SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peerStat) const {
|
|
|
|
int speed = (int)(peerStat->getAvgDownloadSpeed()*0.8);
|
|
|
|
SegmentEntryHandle slowSegmentEntry(0);
|
|
|
|
for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
|
|
|
|
itr != usedSegmentEntries.end(); itr++) {
|
|
|
|
const SegmentEntryHandle& segmentEntry = *itr;
|
|
|
|
if(segmentEntry->cuid == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
PeerStatHandle p = getPeerStat(segmentEntry->cuid);
|
2006-11-08 16:25:38 +00:00
|
|
|
if(!p.get() || p->getCuid() == peerStat->getCuid() ||
|
|
|
|
p->getStatus() != PeerStat::ACTIVE ||
|
|
|
|
!p->getDownloadStartTime().elapsed(option->getAsInt(PREF_STARTUP_IDLE_TIME))) {
|
2006-09-21 06:56:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-11-08 16:25:38 +00:00
|
|
|
int pSpeed = p->calculateDownloadSpeed();
|
|
|
|
if(pSpeed < speed) {
|
2006-09-21 06:56:54 +00:00
|
|
|
speed = pSpeed;
|
|
|
|
slowSegmentEntry = segmentEntry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return slowSegmentEntry;
|
|
|
|
}
|
|
|
|
|
2006-09-19 14:52:59 +00:00
|
|
|
bool SegmentMan::getSegment(Segment& segment, int cuid) {
|
|
|
|
if(!bitfield) {
|
|
|
|
return onNullBitfield(segment, cuid);
|
|
|
|
}
|
2006-09-21 06:56:54 +00:00
|
|
|
SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
|
|
|
|
usedSegmentEntries.end(),
|
|
|
|
FindSegmentEntryByCuid(cuid));
|
|
|
|
if(itr != usedSegmentEntries.end()) {
|
|
|
|
segment = (*itr)->segment;
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
int index = bitfield->getSparseMissingUnusedIndex();
|
|
|
|
if(index == -1) {
|
2006-09-21 06:56:54 +00:00
|
|
|
PeerStatHandle myPeerStat = getPeerStat(cuid);
|
|
|
|
if(!myPeerStat.get()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SegmentEntryHandle slowSegmentEntry = findSlowerSegmentEntry(myPeerStat);
|
|
|
|
if(slowSegmentEntry.get()) {
|
|
|
|
logger->info("CUID#%d cancels segment index=%d. CUID#%d handles it instead.",
|
|
|
|
slowSegmentEntry->cuid,
|
|
|
|
slowSegmentEntry->segment.index,
|
|
|
|
cuid);
|
|
|
|
PeerStatHandle slowPeerStat = getPeerStat(slowSegmentEntry->cuid);
|
|
|
|
slowPeerStat->requestIdle();
|
|
|
|
cancelSegment(slowSegmentEntry->cuid);
|
|
|
|
segment = checkoutSegment(cuid, slowSegmentEntry->segment.index);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2006-09-19 14:52:59 +00:00
|
|
|
} else {
|
|
|
|
segment = checkoutSegment(cuid, index);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::getSegment(Segment& segment, int cuid, int index) {
|
|
|
|
if(!bitfield) {
|
|
|
|
return onNullBitfield(segment, cuid);
|
|
|
|
}
|
2006-12-24 15:55:59 +00:00
|
|
|
if(index < 0 || (int32_t)bitfield->countBlock() <= index) {
|
2006-09-19 14:52:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(bitfield->isBitSet(index) || bitfield->isUseBitSet(index)) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
segment = checkoutSegment(cuid, index);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::updateSegment(int cuid, const Segment& segment) {
|
|
|
|
if(segment.isNull()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
|
|
|
|
usedSegmentEntries.end(),
|
|
|
|
FindSegmentEntryByCuid(cuid));
|
|
|
|
if(itr == usedSegmentEntries.end()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
2006-09-21 06:56:54 +00:00
|
|
|
(*itr)->segment = segment;
|
2006-09-19 14:52:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class CancelSegment {
|
|
|
|
private:
|
|
|
|
int cuid;
|
|
|
|
BitfieldMan* bitfield;
|
|
|
|
public:
|
|
|
|
CancelSegment(int cuid, BitfieldMan* bitfield):cuid(cuid),
|
|
|
|
bitfield(bitfield) {}
|
|
|
|
|
2006-09-21 06:56:54 +00:00
|
|
|
void operator()(SegmentEntryHandle& entry) {
|
|
|
|
if(entry->cuid == cuid) {
|
|
|
|
bitfield->unsetUseBit(entry->segment.index);
|
|
|
|
entry->cuid = 0;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void SegmentMan::cancelSegment(int cuid) {
|
|
|
|
if(bitfield) {
|
|
|
|
for_each(usedSegmentEntries.begin(), usedSegmentEntries.end(),
|
|
|
|
CancelSegment(cuid, bitfield));
|
|
|
|
} else {
|
|
|
|
usedSegmentEntries.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::completeSegment(int cuid, const Segment& segment) {
|
|
|
|
if(segment.isNull()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(bitfield) {
|
|
|
|
bitfield->unsetUseBit(segment.index);
|
|
|
|
bitfield->setBit(segment.index);
|
|
|
|
} else {
|
|
|
|
initBitfield(option->getAsInt(PREF_SEGMENT_SIZE), segment.writtenLength);
|
|
|
|
bitfield->setAllBit();
|
|
|
|
}
|
|
|
|
SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
|
|
|
|
usedSegmentEntries.end(),
|
|
|
|
FindSegmentEntryByCuid(cuid));
|
|
|
|
if(itr == usedSegmentEntries.end()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
usedSegmentEntries.erase(itr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::hasSegment(int index) const {
|
|
|
|
if(bitfield) {
|
|
|
|
return bitfield->isBitSet(index);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long long int SegmentMan::getDownloadLength() const {
|
|
|
|
long long int dlLength = 0;
|
|
|
|
if(bitfield) {
|
|
|
|
dlLength += bitfield->getCompletedLength();
|
|
|
|
}
|
|
|
|
for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
|
|
|
|
itr != usedSegmentEntries.end(); itr++) {
|
2006-09-21 06:56:54 +00:00
|
|
|
dlLength += (*itr)->segment.writtenLength;
|
2006-09-19 14:52:59 +00:00
|
|
|
}
|
|
|
|
return dlLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) {
|
|
|
|
PeerStatHandle temp = getPeerStat(peerStat->getCuid());
|
|
|
|
if(!temp.get()) {
|
|
|
|
peerStats.push_back(peerStat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int SegmentMan::calculateDownloadSpeed() const {
|
|
|
|
int speed = 0;
|
|
|
|
for(PeerStats::const_iterator itr = peerStats.begin();
|
|
|
|
itr != peerStats.end(); itr++) {
|
|
|
|
const PeerStatHandle& peerStat = *itr;
|
|
|
|
if(peerStat->getStatus() == PeerStat::ACTIVE) {
|
|
|
|
speed += peerStat->calculateDownloadSpeed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return speed;
|
2006-04-18 17:06:17 +00:00
|
|
|
}
|
2007-01-11 16:32:31 +00:00
|
|
|
|
|
|
|
bool SegmentMan::fileExists() {
|
|
|
|
return File(getFilePath()).exists();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentMan::shouldCancelDownloadForSafety() {
|
|
|
|
return fileExists() && !segmentFileExists() &&
|
|
|
|
option->get(PREF_FORCE_TRUNCATE) != V_TRUE;
|
|
|
|
}
|