/* */ #include "DefaultPieceStorage.h" #include "LogFactory.h" #include "prefs.h" #include "DirectDiskAdaptor.h" #include "MultiDiskAdaptor.h" #include "CopyDiskAdaptor.h" #include "DefaultDiskWriter.h" #include "DlAbortEx.h" #include "BitfieldManFactory.h" #include "FileAllocationMonitor.h" #include "DiskAdaptorWriter.h" #include "ChunkChecksumValidator.h" DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option* option): btContext(btContext), diskAdaptor(0), endGamePieceNum(END_GAME_PIECE_NUM), option(option) { bitfieldMan = BitfieldManFactory::getFactoryInstance()-> createBitfieldMan(btContext->getPieceLength(), btContext->getTotalLength()); logger = LogFactory::getInstance(); } DefaultPieceStorage::~DefaultPieceStorage() { delete bitfieldMan; } bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer) { return bitfieldMan->hasMissingPiece(peer->getBitfield(), peer->getBitfieldLength()); } bool DefaultPieceStorage::isEndGame() { return bitfieldMan->countMissingBlock() <= endGamePieceNum; } int DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) { int index = -1; if(isEndGame()) { index = bitfieldMan->getMissingIndex(peer->getBitfield(), peer->getBitfieldLength()); } else { index = bitfieldMan->getMissingUnusedIndex(peer->getBitfield(), peer->getBitfieldLength()); } return index; } PieceHandle DefaultPieceStorage::checkOutPiece(int index) { if(index == -1) { return 0; } bitfieldMan->setUseBit(index); PieceHandle piece = findUsedPiece(index); if(piece.isNull()) { piece = new Piece(index, bitfieldMan->getBlockLength(index)); addUsedPiece(piece); return piece; } else { return piece; } } /** * Newly instantiated piece is not added to usedPieces. * Because it is waste of memory and there is no chance to use them later. */ PieceHandle DefaultPieceStorage::getPiece(int index) { if(0 <= index && index <= bitfieldMan->getMaxIndex()) { PieceHandle piece = findUsedPiece(index); if(piece.isNull()) { piece = new Piece(index, bitfieldMan->getBlockLength(index)); if(hasPiece(index)) { piece->setAllBlock(); } } return piece; } else { return 0; } } void DefaultPieceStorage::addUsedPiece(const PieceHandle& piece) { usedPieces.push_back(piece); } class FindPiece { private: int index; public: FindPiece(int index):index(index) {} bool operator()(const PieceHandle& piece) { return piece->getIndex() == index; } }; PieceHandle DefaultPieceStorage::findUsedPiece(int index) const { Pieces::const_iterator itr = find_if(usedPieces.begin(), usedPieces.end(), FindPiece(index)); if(itr == usedPieces.end()) { return 0; } else { return *itr; } } PieceHandle DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) { int index = getMissingPieceIndex(peer); return checkOutPiece(index); } int DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) { int index = -1; if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) { BitfieldMan tempBitfield(bitfieldMan->getBlockLength(), bitfieldMan->getTotalLength()); for(Integers::const_iterator itr = peer->getFastSet().begin(); itr != peer->getFastSet().end(); itr++) { if(!bitfieldMan->isBitSet(index) && peer->hasPiece(*itr)) { tempBitfield.setBit(*itr); } } if(isEndGame()) { index = bitfieldMan->getMissingIndex(tempBitfield.getBitfield(), tempBitfield.getBitfieldLength()); } else { index = bitfieldMan->getMissingUnusedIndex(tempBitfield.getBitfield(), tempBitfield.getBitfieldLength()); } } return index; } PieceHandle DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) { int index = getMissingFastPieceIndex(peer); return checkOutPiece(index); } void DefaultPieceStorage::deleteUsedPiece(const PieceHandle& piece) { if(piece.isNull()) { return; } Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), piece); if(itr != usedPieces.end()) { usedPieces.erase(itr); } } void DefaultPieceStorage::reduceUsedPieces(int delMax) { int toDelete = usedPieces.size()-delMax; if(toDelete <= 0) { return; } int fillRate = 10; while(fillRate < 50) { int deleted = deleteUsedPiecesByFillRate(fillRate, toDelete); if(deleted == 0) { break; } toDelete -= deleted; fillRate += 10; } } int DefaultPieceStorage::deleteUsedPiecesByFillRate(int fillRate, int toDelete) { int deleted = 0; for(Pieces::iterator itr = usedPieces.begin(); itr != usedPieces.end() && deleted < toDelete;) { PieceHandle& piece = *itr; if(!bitfieldMan->isUseBitSet(piece->getIndex()) && piece->countCompleteBlock() <= piece->countBlock()*(fillRate/100.0)) { logger->debug("Deleting used piece index=%d, fillRate(%%)=%d<=%d", piece->getIndex(), (piece->countCompleteBlock()*100)/piece->countBlock(), fillRate); itr = usedPieces.erase(itr); deleted++; } else { itr++; } } return deleted; } void DefaultPieceStorage::completePiece(const PieceHandle& piece) { if(piece.isNull()) { return; } deleteUsedPiece(piece); if(!isEndGame()) { reduceUsedPieces(100); } if(allDownloadFinished()) { return; } bitfieldMan->setBit(piece->getIndex()); bitfieldMan->unsetUseBit(piece->getIndex()); if(downloadFinished()) { diskAdaptor->onDownloadComplete(); if(isSelectiveDownloadingMode()) { logger->notice(_("Download of selected files was complete.")); // following line was commented out in order to stop sending request // message after user-specified files were downloaded. //finishSelectiveDownloadingMode(); } else { logger->info(_("The download was complete.")); } } } bool DefaultPieceStorage::isSelectiveDownloadingMode() { return bitfieldMan->isFilterEnabled(); } void DefaultPieceStorage::finishSelectiveDownloadingMode() { bitfieldMan->clearFilter(); diskAdaptor->addAllDownloadEntry(); } // not unittested void DefaultPieceStorage::cancelPiece(const PieceHandle& piece) { if(piece.isNull()) { return; } bitfieldMan->unsetUseBit(piece->getIndex()); if(!isEndGame()) { if(piece->countCompleteBlock() == 0) { deleteUsedPiece(piece); } } } bool DefaultPieceStorage::hasPiece(int index) { return bitfieldMan->isBitSet(index); } long long int DefaultPieceStorage::getTotalLength() { return bitfieldMan->getTotalLength(); } long long int DefaultPieceStorage::getFilteredTotalLength() { return bitfieldMan->getFilteredTotalLength(); } long long int DefaultPieceStorage::getCompletedLength() { return bitfieldMan->getCompletedLength(); } long long int DefaultPieceStorage::getFilteredCompletedLength() { return bitfieldMan->getFilteredCompletedLength(); } // not unittested void DefaultPieceStorage::setFileFilter(const Strings& filePaths) { if(btContext->getFileMode() != BtContext::MULTI || filePaths.empty()) { return; } diskAdaptor->removeAllDownloadEntry(); for(Strings::const_iterator pitr = filePaths.begin(); pitr != filePaths.end(); pitr++) { if(!diskAdaptor->addDownloadEntry(*pitr)) { throw new DlAbortEx("No such file entry %s", (*pitr).c_str()); } FileEntryHandle fileEntry = diskAdaptor->getFileEntryFromPath(*pitr); bitfieldMan->addFilter(fileEntry->getOffset(), fileEntry->getLength()); } bitfieldMan->enableFilter(); } void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) { Strings filePaths; const FileEntries& entries = diskAdaptor->getFileEntries(); for(int i = 0; i < (int)entries.size(); i++) { if(find(fileIndexes.begin(), fileIndexes.end(), i+1) != fileIndexes.end()) { logger->debug("index=%d is %s", i+1, entries[i]->getPath().c_str()); filePaths.push_back(entries[i]->getPath()); } } setFileFilter(filePaths); } // not unittested void DefaultPieceStorage::clearFileFilter() { bitfieldMan->clearFilter(); diskAdaptor->addAllDownloadEntry(); } // not unittested bool DefaultPieceStorage::downloadFinished() { return bitfieldMan->isFilteredAllBitSet(); } // not unittested bool DefaultPieceStorage::allDownloadFinished() { return bitfieldMan->isAllBitSet(); } // not unittested void DefaultPieceStorage::initStorage() { if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) { if(btContext->getFileMode() == BtContext::SINGLE) { DefaultDiskWriterHandle writer = DefaultDiskWriter::createNewDiskWriter(option); DirectDiskAdaptorHandle directDiskAdaptor = new DirectDiskAdaptor(); directDiskAdaptor->setDiskWriter(writer); directDiskAdaptor->setTotalLength(btContext->getTotalLength()); this->diskAdaptor = directDiskAdaptor; } else { MultiDiskAdaptorHandle multiDiskAdaptor = new MultiDiskAdaptor(); multiDiskAdaptor->setPieceLength(btContext->getPieceLength()); multiDiskAdaptor->setTopDir(btContext->getName()); multiDiskAdaptor->setOption(option); this->diskAdaptor = multiDiskAdaptor; } } else { DefaultDiskWriterHandle writer = DefaultDiskWriter::createNewDiskWriter(option); CopyDiskAdaptorHandle copyDiskAdaptor = new CopyDiskAdaptor(); copyDiskAdaptor->setDiskWriter(writer); copyDiskAdaptor->setTempFilename(btContext->getName()+".a2tmp"); copyDiskAdaptor->setTotalLength(btContext->getTotalLength()); if(btContext->getFileMode() == BtContext::MULTI) { copyDiskAdaptor->setTopDir(btContext->getName()); } this->diskAdaptor = copyDiskAdaptor; } string storeDir = option->get(PREF_DIR); if(storeDir == "") { storeDir = "."; } diskAdaptor->setStoreDir(storeDir); diskAdaptor->setFileEntries(btContext->getFileEntries()); } void DefaultPieceStorage::setBitfield(const unsigned char* bitfield, int bitfieldLength) { bitfieldMan->setBitfield(bitfield, bitfieldLength); } int DefaultPieceStorage::getBitfieldLength() { return bitfieldMan->getBitfieldLength(); } const unsigned char* DefaultPieceStorage::getBitfield() { return bitfieldMan->getBitfield(); } DiskAdaptorHandle DefaultPieceStorage::getDiskAdaptor() { return diskAdaptor; } int DefaultPieceStorage::getPieceLength(int index) { return bitfieldMan->getBlockLength(index); } void DefaultPieceStorage::advertisePiece(int cuid, int index) { HaveEntry entry(cuid, index); haves.push_front(entry); } Integers DefaultPieceStorage::getAdvertisedPieceIndexes(int myCuid, const Time& lastCheckTime) { Integers indexes; for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) { const Haves::value_type& have = *itr; if(have.getCuid() == myCuid) { continue; } if(lastCheckTime.isNewer(have.getRegisteredTime())) { break; } indexes.push_back(have.getIndex()); } return indexes; } class FindElapsedHave { private: int elapsed; public: FindElapsedHave(int elapsed):elapsed(elapsed) {} bool operator()(const HaveEntry& have) { if(have.getRegisteredTime().elapsed(elapsed)) { return true; } else { return false; } } }; void DefaultPieceStorage::removeAdvertisedPiece(int elapsed) { Haves::iterator itr = find_if(haves.begin(), haves.end(), FindElapsedHave(elapsed)); if(itr != haves.end()) { logger->debug("Removed %d have entries.", haves.end()-itr); haves.erase(itr, haves.end()); } } void DefaultPieceStorage::markAllPiecesDone() { bitfieldMan->setAllBit(); } void DefaultPieceStorage::checkIntegrity() { logger->notice("Validating file %s", diskAdaptor->getFilePath().c_str()); ChunkChecksumValidator v; v.setDigestAlgo(DIGEST_ALGO_SHA1); v.setDiskWriter(new DiskAdaptorWriter(diskAdaptor)); v.setFileAllocationMonitor(FileAllocationMonitorFactory::getFactory()->createNewMonitor()); v.validate(bitfieldMan, btContext->getPieceHashes(), btContext->getPieceLength()); }