void FolderDownloadRequest::handle() { uint32 microsecondsPassed = Networking::ConnectionManager::getCloudRequestsPeriodInMicroseconds(); uint64 currentDownloadedBytes = getDownloadedBytes(); uint64 downloadedThisPeriod = currentDownloadedBytes - _wasDownloadedBytes; _currentDownloadSpeed = downloadedThisPeriod * (1000000L / microsecondsPassed); _wasDownloadedBytes = currentDownloadedBytes; }
Segment QueueItem::getNextSegment(int64_t blockSize, int64_t wantedSize) const { if(getSize() == -1 || blockSize == 0) { return Segment(0, -1); } if(!BOOLSETTING(SEGMENTED_DL) && !downloads.empty()) { return Segment(0, 0); } int64_t remaining = getSize() - getDownloadedBytes(); int64_t targetSize; if(BOOLSETTING(SEGMENTED_DL)) { double done = static_cast<double>(getDownloadedBytes()) / getSize(); // We want smaller blocks at the end of the transfer, squaring gives a nice curve... targetSize = wantedSize * std::max(0.25, (1. - (done * done))); if(targetSize > blockSize) { // Round off to nearest block size targetSize = ((targetSize + (blockSize / 2)) / blockSize) * blockSize; } else { targetSize = blockSize; } } else { targetSize = remaining; } int64_t start = 0; int64_t curSize = targetSize; while(start < getSize()) { int64_t end = std::min(getSize(), start + curSize); Segment block(start, end - start); bool overlaps = false; for(SegmentIter i = done.begin(); !overlaps && i != done.end(); ++i) { if(curSize <= blockSize) { int64_t dstart = i->getStart(); int64_t dend = i->getEnd(); // We accept partial overlaps, only consider the block done if it is fully consumed by the done block if(dstart <= start && dend >= end) { overlaps = true; } } else { overlaps = block.overlaps(*i); } } for(DownloadList::const_iterator i = downloads.begin(); !overlaps && i !=downloads.end(); ++i) { overlaps = block.overlaps((*i)->getSegment()); } if(!overlaps) { return block; } if(curSize > blockSize) { curSize -= blockSize; } else { start = end; curSize = targetSize; } } return Segment(0, 0); }
double FolderDownloadRequest::getProgress() const { if (_totalFiles == 0 || _totalBytes == 0) return 0; return (double)getDownloadedBytes() / (double)getTotalBytesToDownload(); }
Segment QueueItem::getNextSegment(int64_t blockSize, int64_t wantedSize, int64_t lastSpeed, const PartialSource::Ptr partialSource) const { if(getSize() == -1 || blockSize == 0) { return Segment(0, -1); } if(!BOOLSETTING(MULTI_CHUNK)) { if(!downloads.empty()) { return Segment(-1, 0); } int64_t start = 0; int64_t end = getSize(); if(!done.empty()) { const Segment& first = *done.begin(); if(first.getStart() > 0) { end = Util::roundUp(first.getStart(), blockSize); } else { start = Util::roundDown(first.getEnd(), blockSize); if(done.size() > 1) { const Segment& second = *(++done.begin()); end = Util::roundUp(second.getStart(), blockSize); } } } return Segment(start, std::min(getSize(), end) - start); } if(downloads.size() >= maxSegments || (BOOLSETTING(DONT_BEGIN_SEGMENT) && (size_t)(SETTING(DONT_BEGIN_SEGMENT_SPEED) * 1024) < getAverageSpeed())) { // no other segments if we have reached the speed or segment limit return Segment(-1, 0); } /* added for PFS */ vector<int64_t> posArray; vector<Segment> neededParts; if(partialSource) { posArray.reserve(partialSource->getPartialInfo().size()); // Convert block index to file position for(PartsInfo::const_iterator i = partialSource->getPartialInfo().begin(); i != partialSource->getPartialInfo().end(); i++) posArray.push_back(min(getSize(), (int64_t)(*i) * blockSize)); } /***************************/ double donePart = static_cast<double>(getDownloadedBytes()) / getSize(); // We want smaller blocks at the end of the transfer, squaring gives a nice curve... int64_t targetSize = static_cast<int64_t>(static_cast<double>(wantedSize) * std::max(0.25, (1. - (donePart * donePart)))); if(targetSize > blockSize) { // Round off to nearest block size targetSize = Util::roundDown(targetSize, blockSize); } else { targetSize = blockSize; } int64_t start = 0; int64_t curSize = targetSize; while(start < getSize()) { int64_t end = std::min(getSize(), start + curSize); Segment block(start, end - start); bool overlaps = false; for(SegmentConstIter i = done.begin(); !overlaps && i != done.end(); ++i) { if(curSize <= blockSize) { int64_t dstart = i->getStart(); int64_t dend = i->getEnd(); // We accept partial overlaps, only consider the block done if it is fully consumed by the done block if(dstart <= start && dend >= end) { overlaps = true; } } else { overlaps = block.overlaps(*i); } } for(auto i = downloads.begin(); !overlaps && i != downloads.end(); ++i) { overlaps = block.overlaps((*i)->getSegment()); } if(!overlaps) { if(partialSource) { // store all chunks we could need for(vector<int64_t>::const_iterator j = posArray.begin(); j < posArray.end(); j += 2){ if( (*j <= start && start < *(j+1)) || (start <= *j && *j < end) ) { int64_t b = max(start, *j); int64_t e = min(end, *(j+1)); // segment must be blockSize aligned dcassert(b % blockSize == 0); dcassert(e % blockSize == 0 || e == getSize()); neededParts.push_back(Segment(b, e - b)); } } } else { return block; } } if(overlaps && (curSize > blockSize)) { curSize -= blockSize; } else { start = end; curSize = targetSize; } } if(!neededParts.empty()) { // select random chunk for download dcdebug("Found chunks: %d\n", neededParts.size()); Segment& selected = neededParts[Util::rand(0, neededParts.size())]; selected.setSize(std::min(selected.getSize(), targetSize)); // request only wanted size return selected; } if(partialSource == NULL && BOOLSETTING(OVERLAP_CHUNKS) && lastSpeed > 0) { // overlap slow running chunk for(auto i = downloads.begin(); i != downloads.end(); ++i) { Download* d = *i; // current chunk mustn't be already overlapped if(d->getOverlapped()) continue; // current chunk must be running at least for 4 seconds if(d->getStart() == 0 || GET_TICK() - d->getStart() < 4000) continue; // current chunk mustn't be finished in next 20 seconds if(d->getSecondsLeft() < 20) continue; // overlap current chunk at last block boundary int64_t pos = d->getPos() - (d->getPos() % blockSize); int64_t size = d->getSize() - pos; // new user should finish this chunk more than 2x faster int64_t newChunkLeft = size / lastSpeed; if(2 * newChunkLeft < d->getSecondsLeft()) { dcdebug("Overlapping... old user: %I64d s, new user: %I64d s\n", d->getSecondsLeft(), newChunkLeft); return Segment(d->getStartPos() + pos, size, true); } } } return Segment(0, 0); }