mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-09-03 16:05:57 +00:00
All mtproto downloads using DownloadMtprotoTask.
This commit is contained in:
@@ -23,210 +23,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
|
||||
namespace Storage {
|
||||
namespace {
|
||||
|
||||
// How much time without download causes additional session kill.
|
||||
constexpr auto kKillSessionTimeout = 15 * crl::time(1000);
|
||||
|
||||
// Max 16 file parts downloaded at the same time, 128 KB each.
|
||||
constexpr auto kMaxFileQueries = 16;
|
||||
|
||||
constexpr auto kMaxWaitedInConnection = 512 * 1024;
|
||||
|
||||
// Max 8 http[s] files downloaded at the same time.
|
||||
constexpr auto kMaxWebFileQueries = 8;
|
||||
|
||||
constexpr auto kStartSessionsCount = 1;
|
||||
constexpr auto kMaxSessionsCount = 8;
|
||||
constexpr auto kResetDownloadPrioritiesTimeout = crl::time(200);
|
||||
|
||||
} // namespace
|
||||
|
||||
void DownloadManager::Queue::enqueue(not_null<Downloader*> loader) {
|
||||
const auto i = ranges::find(_loaders, loader);
|
||||
if (i != end(_loaders)) {
|
||||
return;
|
||||
}
|
||||
_loaders.push_back(loader);
|
||||
_previousGeneration.erase(
|
||||
ranges::remove(_previousGeneration, loader),
|
||||
end(_previousGeneration));
|
||||
}
|
||||
|
||||
void DownloadManager::Queue::remove(not_null<Downloader*> loader) {
|
||||
_loaders.erase(ranges::remove(_loaders, loader), end(_loaders));
|
||||
_previousGeneration.erase(
|
||||
ranges::remove(_previousGeneration, loader),
|
||||
end(_previousGeneration));
|
||||
}
|
||||
|
||||
void DownloadManager::Queue::resetGeneration() {
|
||||
if (!_previousGeneration.empty()) {
|
||||
_loaders.reserve(_loaders.size() + _previousGeneration.size());
|
||||
std::copy(
|
||||
begin(_previousGeneration),
|
||||
end(_previousGeneration),
|
||||
std::back_inserter(_loaders));
|
||||
_previousGeneration.clear();
|
||||
}
|
||||
std::swap(_loaders, _previousGeneration);
|
||||
}
|
||||
|
||||
bool DownloadManager::Queue::empty() const {
|
||||
return _loaders.empty() && _previousGeneration.empty();
|
||||
}
|
||||
|
||||
Downloader *DownloadManager::Queue::nextLoader() const {
|
||||
auto &&all = ranges::view::concat(_loaders, _previousGeneration);
|
||||
const auto i = ranges::find(all, true, &Downloader::readyToRequest);
|
||||
return (i != all.end()) ? i->get() : nullptr;
|
||||
}
|
||||
|
||||
DownloadManager::DownloadManager(not_null<ApiWrap*> api)
|
||||
: _api(api)
|
||||
, _resetGenerationTimer([=] { resetGeneration(); })
|
||||
, _killDownloadSessionsTimer([=] { killDownloadSessions(); }) {
|
||||
}
|
||||
|
||||
DownloadManager::~DownloadManager() {
|
||||
killDownloadSessions();
|
||||
}
|
||||
|
||||
void DownloadManager::enqueue(not_null<Downloader*> loader) {
|
||||
const auto dcId = loader->dcId();
|
||||
(dcId ? _mtprotoLoaders[dcId] : _webLoaders).enqueue(loader);
|
||||
if (!_resetGenerationTimer.isActive()) {
|
||||
_resetGenerationTimer.callOnce(kResetDownloadPrioritiesTimeout);
|
||||
}
|
||||
checkSendNext();
|
||||
}
|
||||
|
||||
void DownloadManager::remove(not_null<Downloader*> loader) {
|
||||
const auto dcId = loader->dcId();
|
||||
(dcId ? _mtprotoLoaders[dcId] : _webLoaders).remove(loader);
|
||||
crl::on_main(&_api->session(), [=] { checkSendNext(); });
|
||||
}
|
||||
|
||||
void DownloadManager::resetGeneration() {
|
||||
_resetGenerationTimer.cancel();
|
||||
for (auto &[dcId, queue] : _mtprotoLoaders) {
|
||||
queue.resetGeneration();
|
||||
}
|
||||
_webLoaders.resetGeneration();
|
||||
}
|
||||
|
||||
void DownloadManager::checkSendNext() {
|
||||
for (auto &[dcId, queue] : _mtprotoLoaders) {
|
||||
if (queue.empty()) {
|
||||
continue;
|
||||
}
|
||||
const auto bestIndex = [&] {
|
||||
const auto i = _requestedBytesAmount.find(dcId);
|
||||
if (i == end(_requestedBytesAmount)) {
|
||||
_requestedBytesAmount[dcId].resize(kStartSessionsCount);
|
||||
return 0;
|
||||
}
|
||||
const auto j = ranges::min_element(i->second);
|
||||
const auto already = *j;
|
||||
return (already + kDownloadPartSize <= kMaxWaitedInConnection)
|
||||
? (j - begin(i->second))
|
||||
: -1;
|
||||
}();
|
||||
if (bestIndex < 0) {
|
||||
continue;
|
||||
}
|
||||
if (const auto loader = queue.nextLoader()) {
|
||||
loader->loadPart(bestIndex);
|
||||
}
|
||||
}
|
||||
if (_requestedBytesAmount[0].empty()) {
|
||||
_requestedBytesAmount[0] = std::vector<int>(1, 0);
|
||||
}
|
||||
if (_requestedBytesAmount[0][0] < kMaxWebFileQueries) {
|
||||
if (const auto loader = _webLoaders.nextLoader()) {
|
||||
loader->loadPart(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadManager::requestedAmountIncrement(
|
||||
MTP::DcId dcId,
|
||||
int index,
|
||||
int amount) {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
auto it = _requestedBytesAmount.find(dcId);
|
||||
if (it == _requestedBytesAmount.end()) {
|
||||
it = _requestedBytesAmount.emplace(
|
||||
dcId,
|
||||
std::vector<int>(dcId ? kStartSessionsCount : 1, 0)
|
||||
).first;
|
||||
}
|
||||
it->second[index] += amount;
|
||||
if (!dcId) {
|
||||
return; // webLoaders.
|
||||
}
|
||||
if (amount > 0) {
|
||||
killDownloadSessionsStop(dcId);
|
||||
} else if (ranges::find_if(it->second, _1 > 0) == end(it->second)) {
|
||||
killDownloadSessionsStart(dcId);
|
||||
checkSendNext();
|
||||
}
|
||||
}
|
||||
|
||||
int DownloadManager::chooseDcIndexForRequest(MTP::DcId dcId) {
|
||||
const auto i = _requestedBytesAmount.find(dcId);
|
||||
return (i != end(_requestedBytesAmount))
|
||||
? (ranges::min_element(i->second) - begin(i->second))
|
||||
: 0;
|
||||
}
|
||||
|
||||
void DownloadManager::killDownloadSessionsStart(MTP::DcId dcId) {
|
||||
if (!_killDownloadSessionTimes.contains(dcId)) {
|
||||
_killDownloadSessionTimes.emplace(
|
||||
dcId,
|
||||
crl::now() + kKillSessionTimeout);
|
||||
}
|
||||
if (!_killDownloadSessionsTimer.isActive()) {
|
||||
_killDownloadSessionsTimer.callOnce(kKillSessionTimeout + 5);
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadManager::killDownloadSessionsStop(MTP::DcId dcId) {
|
||||
_killDownloadSessionTimes.erase(dcId);
|
||||
if (_killDownloadSessionTimes.empty()
|
||||
&& _killDownloadSessionsTimer.isActive()) {
|
||||
_killDownloadSessionsTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadManager::killDownloadSessions() {
|
||||
const auto now = crl::now();
|
||||
auto left = kKillSessionTimeout;
|
||||
for (auto i = _killDownloadSessionTimes.begin(); i != _killDownloadSessionTimes.end(); ) {
|
||||
if (i->second <= now) {
|
||||
const auto j = _requestedBytesAmount.find(i->first);
|
||||
if (j != end(_requestedBytesAmount)) {
|
||||
for (auto index = 0; index != int(j->second.size()); ++index) {
|
||||
MTP::stopSession(MTP::downloadDcId(i->first, index));
|
||||
}
|
||||
}
|
||||
i = _killDownloadSessionTimes.erase(i);
|
||||
} else {
|
||||
if (i->second - now < left) {
|
||||
left = i->second - now;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (!_killDownloadSessionTimes.empty()) {
|
||||
_killDownloadSessionsTimer.callOnce(left);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
FileLoader::FileLoader(
|
||||
const QString &toFile,
|
||||
int32 size,
|
||||
@@ -445,7 +241,9 @@ void FileLoader::cancel() {
|
||||
|
||||
void FileLoader::cancel(bool fail) {
|
||||
const auto started = (currentOffset() > 0);
|
||||
cancelRequests();
|
||||
|
||||
cancelHook();
|
||||
|
||||
_cancelled = true;
|
||||
_finished = true;
|
||||
if (_fileIsOpen) {
|
||||
|
Reference in New Issue
Block a user