mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 17:51:41 -05:00
Keep track of fully cached media files.
This commit is contained in:
parent
2255eb2c68
commit
04e3b250e7
20 changed files with 342 additions and 54 deletions
|
@ -816,6 +816,35 @@ bool DocumentData::uploading() const {
|
|||
return (uploadingData != nullptr);
|
||||
}
|
||||
|
||||
bool DocumentData::loadedInMediaCache() const {
|
||||
return (_flags & Flag::LoadedInMediaCache);
|
||||
}
|
||||
|
||||
void DocumentData::setLoadedInMediaCache(bool loaded) {
|
||||
const auto flags = loaded
|
||||
? (_flags | Flag::LoadedInMediaCache)
|
||||
: (_flags & ~Flag::LoadedInMediaCache);
|
||||
if (_flags == flags) {
|
||||
return;
|
||||
}
|
||||
_flags = flags;
|
||||
if (!this->loaded()) {
|
||||
if (loadedInMediaCache()) {
|
||||
Local::writeFileLocation(
|
||||
mediaKey(),
|
||||
FileLocation::InMediaCacheLocation());
|
||||
} else {
|
||||
Local::removeFileLocation(mediaKey());
|
||||
}
|
||||
owner().requestDocumentViewRepaint(this);
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentData::setLoadedInMediaCacheLocation() {
|
||||
_location = FileLocation();
|
||||
_flags |= Flag::LoadedInMediaCache;
|
||||
}
|
||||
|
||||
void DocumentData::setWaitingForAlbum() {
|
||||
if (uploading()) {
|
||||
uploadingData->waitingForAlbum = true;
|
||||
|
@ -1010,13 +1039,21 @@ QByteArray DocumentData::data() const {
|
|||
|
||||
const FileLocation &DocumentData::location(bool check) const {
|
||||
if (check && !_location.check()) {
|
||||
const_cast<DocumentData*>(this)->_location = Local::readFileLocation(mediaKey());
|
||||
const auto location = Local::readFileLocation(mediaKey());
|
||||
const auto that = const_cast<DocumentData*>(this);
|
||||
if (location.inMediaCache()) {
|
||||
that->setLoadedInMediaCacheLocation();
|
||||
} else {
|
||||
that->_location = location;
|
||||
}
|
||||
}
|
||||
return _location;
|
||||
}
|
||||
|
||||
void DocumentData::setLocation(const FileLocation &loc) {
|
||||
if (loc.check()) {
|
||||
if (loc.inMediaCache()) {
|
||||
setLoadedInMediaCacheLocation();
|
||||
} else if (loc.check()) {
|
||||
_location = loc;
|
||||
}
|
||||
}
|
||||
|
@ -1492,6 +1529,13 @@ void DocumentData::setRemoteLocation(
|
|||
Local::writeFileLocation(mediaKey(), _location);
|
||||
} else {
|
||||
_location = Local::readFileLocation(mediaKey());
|
||||
if (_location.inMediaCache()) {
|
||||
setLoadedInMediaCacheLocation();
|
||||
} else if (_location.isEmpty() && loadedInMediaCache()) {
|
||||
Local::writeFileLocation(
|
||||
mediaKey(),
|
||||
FileLocation::InMediaCacheLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1520,7 +1564,7 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
|
|||
ActiveCache().up(this);
|
||||
}
|
||||
}
|
||||
if (!local->_location.isEmpty()) {
|
||||
if (!local->_location.inMediaCache() && !local->_location.isEmpty()) {
|
||||
_location = local->_location;
|
||||
Local::writeFileLocation(mediaKey(), _location);
|
||||
}
|
||||
|
|
|
@ -115,6 +115,8 @@ public:
|
|||
[[nodiscard]] float64 progress() const;
|
||||
[[nodiscard]] int loadOffset() const;
|
||||
[[nodiscard]] bool uploading() const;
|
||||
[[nodiscard]] bool loadedInMediaCache() const;
|
||||
void setLoadedInMediaCache(bool loaded);
|
||||
|
||||
void setWaitingForAlbum();
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
@ -266,6 +268,7 @@ private:
|
|||
void validateLottieSticker();
|
||||
void validateGoodThumbnail();
|
||||
void setMaybeSupportsStreaming(bool supports);
|
||||
void setLoadedInMediaCacheLocation();
|
||||
|
||||
void destroyLoader() const;
|
||||
|
||||
|
|
|
@ -2504,15 +2504,18 @@ void Session::documentApplyFields(
|
|||
if (!date) {
|
||||
return;
|
||||
}
|
||||
if (dc != 0 && access != 0) {
|
||||
document->setRemoteLocation(dc, access, fileReference);
|
||||
}
|
||||
document->date = date;
|
||||
document->setMimeString(mime);
|
||||
document->updateThumbnails(thumbnailInline, thumbnail);
|
||||
document->size = size;
|
||||
document->recountIsImage();
|
||||
document->setattributes(attributes);
|
||||
|
||||
// Uses 'type' that is computed from attributes.
|
||||
document->recountIsImage();
|
||||
if (dc != 0 && access != 0) {
|
||||
document->setRemoteLocation(dc, access, fileReference);
|
||||
}
|
||||
|
||||
if (document->sticker()
|
||||
&& !document->sticker()->loc.valid()
|
||||
&& thumbLocation.valid()) {
|
||||
|
|
|
@ -274,7 +274,7 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, crl
|
|||
void HistoryVideo::drawCornerStatus(Painter &p, bool selected) const {
|
||||
const auto padding = st::msgDateImgPadding;
|
||||
const auto radial = _animation && _animation->radial.animating();
|
||||
const auto cornerDownload = downloadInCorner() && !_data->loaded();
|
||||
const auto cornerDownload = downloadInCorner() && !_data->loaded() && !_data->loadedInMediaCache();
|
||||
const auto addWidth = cornerDownload ? (st::historyVideoDownloadSize + 2 * padding.y()) : 0;
|
||||
const auto downloadWidth = cornerDownload ? st::normalFont->width(_downloadSize) : 0;
|
||||
const auto statusW = std::max(downloadWidth, st::normalFont->width(_statusText)) + 2 * padding.x() + addWidth;
|
||||
|
|
|
@ -60,6 +60,9 @@ int File::Context::read(bytes::span buffer) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
sendFullInCache();
|
||||
|
||||
_offset += amount;
|
||||
return amount;
|
||||
}
|
||||
|
@ -244,6 +247,9 @@ void File::Context::start(crl::time position) {
|
|||
}
|
||||
|
||||
_reader->headerDone();
|
||||
if (_reader->isRemoteLoader()) {
|
||||
sendFullInCache(true);
|
||||
}
|
||||
if (video.codec || audio.codec) {
|
||||
seekToPosition(format.get(), video.codec ? video : audio, position);
|
||||
}
|
||||
|
@ -258,6 +264,17 @@ void File::Context::start(crl::time position) {
|
|||
_format = std::move(format);
|
||||
}
|
||||
|
||||
void File::Context::sendFullInCache(bool force) {
|
||||
const auto started = _fullInCache.has_value();
|
||||
if (force || started) {
|
||||
const auto nowFullInCache = _reader->fullInCache();
|
||||
if (!started || *_fullInCache != nowFullInCache) {
|
||||
_fullInCache = nowFullInCache;
|
||||
_delegate->fileFullInCache(nowFullInCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void File::Context::readNextPacket() {
|
||||
auto result = readPacket();
|
||||
if (unroll()) {
|
||||
|
|
|
@ -81,6 +81,7 @@ private:
|
|||
[[nodiscard]] base::variant<Packet, AvErrorWrap> readPacket();
|
||||
|
||||
void handleEndOfFile();
|
||||
void sendFullInCache(bool force = false);
|
||||
|
||||
const not_null<FileDelegate*> _delegate;
|
||||
const not_null<Reader*> _reader;
|
||||
|
@ -89,6 +90,7 @@ private:
|
|||
int _size = 0;
|
||||
bool _failed = false;
|
||||
bool _readTillEnd = false;
|
||||
std::optional<bool> _fullInCache;
|
||||
crl::semaphore _semaphore;
|
||||
std::atomic<bool> _interrupted = false;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
Stream &&audio) = 0;
|
||||
virtual void fileError(Error error) = 0;
|
||||
virtual void fileWaitingForData() = 0;
|
||||
virtual void fileFullInCache(bool fullInCache) = 0;
|
||||
|
||||
// Return true if reading and processing more packets is desired.
|
||||
// Return false if sleeping until 'wake()' is called is desired.
|
||||
|
|
|
@ -174,7 +174,7 @@ void Player::trackSendReceivedTill(
|
|||
Expects(state.duration != kTimeUnknown);
|
||||
Expects(state.receivedTill != kTimeUnknown);
|
||||
|
||||
if (!_remoteLoader) {
|
||||
if (!_remoteLoader || _fullInCacheSinceStart.value_or(false)) {
|
||||
return;
|
||||
}
|
||||
const auto receivedTill = std::max(
|
||||
|
@ -302,6 +302,15 @@ void Player::fileError(Error error) {
|
|||
});
|
||||
}
|
||||
|
||||
void Player::fileFullInCache(bool fullInCache) {
|
||||
crl::on_main(&_sessionGuard, [=] {
|
||||
if (!_fullInCacheSinceStart.has_value()) {
|
||||
_fullInCacheSinceStart = fullInCache;
|
||||
}
|
||||
_fullInCache.fire_copy(fullInCache);
|
||||
});
|
||||
}
|
||||
|
||||
void Player::fileWaitingForData() {
|
||||
if (_waitingForData) {
|
||||
return;
|
||||
|
@ -736,6 +745,10 @@ bool Player::finished() const {
|
|||
&& (!_video || _videoFinished);
|
||||
}
|
||||
|
||||
float64 Player::speed() const {
|
||||
return _options.speed;
|
||||
}
|
||||
|
||||
void Player::setSpeed(float64 speed) {
|
||||
Expects(active());
|
||||
Expects(speed >= 0.5 && speed <= 2.);
|
||||
|
@ -767,6 +780,10 @@ rpl::producer<Update, Error> Player::updates() const {
|
|||
return _updates.events();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Player::fullInCache() const {
|
||||
return _fullInCache.events();
|
||||
}
|
||||
|
||||
QSize Player::videoSize() const {
|
||||
return _information.video.size;
|
||||
}
|
||||
|
@ -803,7 +820,8 @@ Media::Player::TrackState Player::prepareLegacyState() const {
|
|||
} else if (_options.loop && result.length > 0) {
|
||||
result.position %= result.length;
|
||||
}
|
||||
result.receivedTill = _remoteLoader
|
||||
result.receivedTill = (_remoteLoader
|
||||
&& !_fullInCacheSinceStart.value_or(false))
|
||||
? getCurrentReceivedTill(result.length)
|
||||
: 0;
|
||||
result.frequency = kMsFrequency;
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
[[nodiscard]] bool finished() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<Update, Error> updates() const;
|
||||
[[nodiscard]] rpl::producer<bool> fullInCache() const;
|
||||
|
||||
[[nodiscard]] QSize videoSize() const;
|
||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||
|
@ -82,6 +83,7 @@ private:
|
|||
bool fileReady(int headerSize, Stream &&video, Stream &&audio) override;
|
||||
void fileError(Error error) override;
|
||||
void fileWaitingForData() override;
|
||||
void fileFullInCache(bool fullInCache) override;
|
||||
bool fileProcessPacket(Packet &&packet) override;
|
||||
bool fileReadMore() override;
|
||||
|
||||
|
@ -176,6 +178,8 @@ private:
|
|||
crl::time _nextFrameTime = kTimeUnknown;
|
||||
base::Timer _renderFrameTimer;
|
||||
rpl::event_stream<Update, Error> _updates;
|
||||
rpl::event_stream<bool> _fullInCache;
|
||||
std::optional<bool> _fullInCacheSinceStart;
|
||||
|
||||
crl::time _totalDuration = kTimeUnknown;
|
||||
crl::time _loopingShift = 0;
|
||||
|
|
|
@ -225,6 +225,7 @@ struct Reader::CacheHelper {
|
|||
|
||||
QMutex mutex;
|
||||
base::flat_map<int, PartsMap> results;
|
||||
std::vector<int> sizes;
|
||||
std::atomic<crl::semaphore*> waiting = nullptr;
|
||||
};
|
||||
|
||||
|
@ -385,6 +386,17 @@ int Reader::Slices::headerSize() const {
|
|||
return _header.parts.size() * kPartSize;
|
||||
}
|
||||
|
||||
bool Reader::Slices::fullInCache() const {
|
||||
return _fullInCache;
|
||||
}
|
||||
|
||||
int Reader::Slices::requestSliceSizesCount() const {
|
||||
if (!headerModeUnknown() || isFullInHeader()) {
|
||||
return 0;
|
||||
}
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
bool Reader::Slices::headerWontBeFilled() const {
|
||||
return headerModeUnknown()
|
||||
&& (_header.parts.size() >= kMaxPartsInHeader);
|
||||
|
@ -438,6 +450,7 @@ void Reader::Slices::processCacheResult(int sliceNumber, PartsMap &&result) {
|
|||
return;
|
||||
}
|
||||
slice.processCacheData(std::move(result));
|
||||
checkSliceFullLoaded(sliceNumber);
|
||||
if (!sliceNumber) {
|
||||
applyHeaderCacheData();
|
||||
if (isGoodHeader()) {
|
||||
|
@ -448,6 +461,66 @@ void Reader::Slices::processCacheResult(int sliceNumber, PartsMap &&result) {
|
|||
}
|
||||
}
|
||||
|
||||
void Reader::Slices::processCachedSizes(const std::vector<int> &sizes) {
|
||||
Expects(sizes.size() == _data.size());
|
||||
|
||||
using Flag = Slice::Flag;
|
||||
const auto count = int(sizes.size());
|
||||
auto loadedCount = 0;
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
const auto sliceNumber = (i + 1);
|
||||
const auto sliceSize = (sliceNumber < _data.size())
|
||||
? kInSlice
|
||||
: (_size - (sliceNumber - 1) * kInSlice);
|
||||
const auto loaded = (sizes[i] == sliceSize);
|
||||
|
||||
if (_data[i].flags & Flag::FullInCache) {
|
||||
++loadedCount;
|
||||
} else if (loaded) {
|
||||
_data[i].flags |= Flag::FullInCache;
|
||||
++loadedCount;
|
||||
}
|
||||
}
|
||||
_fullInCache = (loadedCount == count);
|
||||
}
|
||||
|
||||
void Reader::Slices::checkSliceFullLoaded(int sliceNumber) {
|
||||
if (!sliceNumber && !isFullInHeader()) {
|
||||
return;
|
||||
}
|
||||
const auto partsCount = [&] {
|
||||
if (!sliceNumber) {
|
||||
return (_size + kPartSize - 1) / kPartSize;
|
||||
}
|
||||
return (sliceNumber < _data.size())
|
||||
? kPartsInSlice
|
||||
: ((_size - (sliceNumber - 1) * kInSlice + kPartSize - 1)
|
||||
/ kPartSize);
|
||||
}();
|
||||
auto &slice = (sliceNumber ? _data[sliceNumber - 1] : _header);
|
||||
const auto loaded = (slice.parts.size() == partsCount);
|
||||
|
||||
using Flag = Slice::Flag;
|
||||
if ((slice.flags & Flag::FullInCache) && !loaded) {
|
||||
slice.flags &= ~Flag::FullInCache;
|
||||
_fullInCache = false;
|
||||
} else if (!(slice.flags & Flag::FullInCache) && loaded) {
|
||||
slice.flags |= Flag::FullInCache;
|
||||
_fullInCache = checkFullInCache();
|
||||
}
|
||||
}
|
||||
|
||||
bool Reader::Slices::checkFullInCache() const {
|
||||
using Flag = Slice::Flag;
|
||||
if (isFullInHeader()) {
|
||||
return (_header.flags & Flag::FullInCache);
|
||||
}
|
||||
const auto i = ranges::find_if(_data, [](const Slice &slice) {
|
||||
return !(slice.flags & Flag::FullInCache);
|
||||
});
|
||||
return (i == end(_data));
|
||||
}
|
||||
|
||||
void Reader::Slices::processPart(
|
||||
int offset,
|
||||
QByteArray &&bytes) {
|
||||
|
@ -455,6 +528,7 @@ void Reader::Slices::processPart(
|
|||
|
||||
if (isFullInHeader()) {
|
||||
_header.addPart(offset, bytes);
|
||||
checkSliceFullLoaded(0);
|
||||
return;
|
||||
} else if (_headerMode == HeaderMode::Unknown) {
|
||||
if (_header.parts.contains(offset)) {
|
||||
|
@ -465,6 +539,7 @@ void Reader::Slices::processPart(
|
|||
}
|
||||
const auto index = offset / kInSlice;
|
||||
_data[index].addPart(offset - index * kInSlice, std::move(bytes));
|
||||
checkSliceFullLoaded(index + 1);
|
||||
}
|
||||
|
||||
auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult {
|
||||
|
@ -655,7 +730,7 @@ Reader::SerializedSlice Reader::Slices::serializeAndUnloadUnused() {
|
|||
return false;
|
||||
}();
|
||||
if (noNeedToSaveToCache) {
|
||||
_data[purgeSlice] = Slice();
|
||||
unloadSlice(_data[purgeSlice]);
|
||||
return {};
|
||||
}
|
||||
return serializeAndUnloadSlice(purgeSlice + 1);
|
||||
|
@ -707,13 +782,21 @@ Reader::SerializedSlice Reader::Slices::serializeAndUnloadSlice(
|
|||
// HeaderMode::Good and we unload first slice. We still require
|
||||
// header data to continue working, so don't really unload the header.
|
||||
if (sliceNumber) {
|
||||
slice = Slice();
|
||||
unloadSlice(slice);
|
||||
} else {
|
||||
slice.flags &= ~Slice::Flag::ChangedSinceCache;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Reader::Slices::unloadSlice(Slice &slice) const {
|
||||
const auto full = (slice.flags & Slice::Flag::FullInCache);
|
||||
slice = Slice();
|
||||
if (full) {
|
||||
slice.flags |= Slice::Flag::FullInCache;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray Reader::Slices::serializeComplexSlice(const Slice &slice) const {
|
||||
auto result = QByteArray();
|
||||
const auto count = slice.parts.size();
|
||||
|
@ -742,7 +825,7 @@ QByteArray Reader::Slices::serializeAndUnloadFirstSliceNoHeader() {
|
|||
slice.parts.erase(offset);
|
||||
}
|
||||
auto result = serializeComplexSlice(slice);
|
||||
slice = Slice();
|
||||
unloadSlice(slice);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1022,8 +1105,14 @@ void Reader::readFromCache(int sliceNumber) {
|
|||
const auto key = _cacheHelper->key(sliceNumber);
|
||||
const auto cache = std::weak_ptr<CacheHelper>(_cacheHelper);
|
||||
const auto weak = base::make_weak(this);
|
||||
_owner->cacheBigFile().get(key, [=](QByteArray &&result) {
|
||||
crl::async([=, result = std::move(result)]{
|
||||
const auto ready = [=](
|
||||
QByteArray &&result,
|
||||
std::vector<int> &&sizes = {}) {
|
||||
crl::async([
|
||||
=,
|
||||
result = std::move(result),
|
||||
sizes = std::move(sizes)
|
||||
]() mutable{
|
||||
auto entry = ParseCacheEntry(
|
||||
bytes::make_span(result),
|
||||
sliceNumber,
|
||||
|
@ -1034,6 +1123,7 @@ void Reader::readFromCache(int sliceNumber) {
|
|||
if (!sliceNumber && entry.included) {
|
||||
strong->results.emplace(1, std::move(*entry.included));
|
||||
}
|
||||
strong->sizes = std::move(sizes);
|
||||
if (const auto waiting = strong->waiting.load()) {
|
||||
strong->waiting.store(nullptr, std::memory_order_release);
|
||||
waiting->release();
|
||||
|
@ -1044,7 +1134,13 @@ void Reader::readFromCache(int sliceNumber) {
|
|||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
auto keys = std::vector<Storage::Cache::Key>();
|
||||
const auto count = _slices.requestSliceSizesCount();
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
keys.push_back(_cacheHelper->key(i + 1));
|
||||
}
|
||||
_owner->cacheBigFile().getWithSizes(key, std::move(keys), ready);
|
||||
}
|
||||
|
||||
bool Reader::readFromCacheForDownloader(int sliceNumber) {
|
||||
|
@ -1083,6 +1179,10 @@ int Reader::headerSize() const {
|
|||
return _slices.headerSize();
|
||||
}
|
||||
|
||||
bool Reader::fullInCache() const {
|
||||
return _slices.fullInCache();
|
||||
}
|
||||
|
||||
bool Reader::fill(
|
||||
int offset,
|
||||
bytes::span buffer,
|
||||
|
@ -1184,6 +1284,7 @@ bool Reader::processCacheResults() {
|
|||
|
||||
QMutexLocker lock(&_cacheHelper->mutex);
|
||||
auto loaded = base::take(_cacheHelper->results);
|
||||
auto sizes = base::take(_cacheHelper->sizes);
|
||||
lock.unlock();
|
||||
|
||||
for (auto &[sliceNumber, cachedParts] : _downloaderReadCache) {
|
||||
|
@ -1201,6 +1302,9 @@ bool Reader::processCacheResults() {
|
|||
for (auto &[sliceNumber, result] : loaded) {
|
||||
_slices.processCacheResult(sliceNumber, std::move(result));
|
||||
}
|
||||
if (!sizes.empty()) {
|
||||
_slices.processCachedSizes(sizes);
|
||||
}
|
||||
if (!loaded.empty()
|
||||
&& (loaded.front().first == 0)
|
||||
&& _slices.isGoodHeader()) {
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
[[nodiscard]] std::optional<Error> streamingError() const;
|
||||
void headerDone();
|
||||
[[nodiscard]] int headerSize() const;
|
||||
[[nodiscard]] bool fullInCache() const;
|
||||
|
||||
// Thread safe.
|
||||
void startSleep(not_null<crl::semaphore*> wake);
|
||||
|
@ -104,6 +105,7 @@ private:
|
|||
LoadingFromCache = 0x01,
|
||||
LoadedFromCache = 0x02,
|
||||
ChangedSinceCache = 0x04,
|
||||
FullInCache = 0x08,
|
||||
};
|
||||
friend constexpr inline bool is_flag_type(Flag) { return true; }
|
||||
using Flags = base::flags<Flag>;
|
||||
|
@ -135,13 +137,17 @@ private:
|
|||
|
||||
void headerDone(bool fromCache);
|
||||
[[nodiscard]] int headerSize() const;
|
||||
[[nodiscard]] bool fullInCache() const;
|
||||
[[nodiscard]] bool headerWontBeFilled() const;
|
||||
[[nodiscard]] bool headerModeUnknown() const;
|
||||
[[nodiscard]] bool isFullInHeader() const;
|
||||
[[nodiscard]] bool isGoodHeader() const;
|
||||
[[nodiscard]] bool waitingForHeaderCache() const;
|
||||
|
||||
[[nodiscard]] int requestSliceSizesCount() const;
|
||||
|
||||
void processCacheResult(int sliceNumber, PartsMap &&result);
|
||||
void processCachedSizes(const std::vector<int> &sizes);
|
||||
void processPart(int offset, QByteArray &&bytes);
|
||||
|
||||
[[nodiscard]] FillResult fill(int offset, bytes::span buffer);
|
||||
|
@ -172,12 +178,16 @@ private:
|
|||
[[nodiscard]] FillResult fillFromHeader(
|
||||
int offset,
|
||||
bytes::span buffer);
|
||||
void unloadSlice(Slice &slice) const;
|
||||
void checkSliceFullLoaded(int sliceNumber);
|
||||
[[nodiscard]] bool checkFullInCache() const;
|
||||
|
||||
std::vector<Slice> _data;
|
||||
Slice _header;
|
||||
std::deque<int> _usedSlices;
|
||||
int _size = 0;
|
||||
HeaderMode _headerMode = HeaderMode::Unknown;
|
||||
bool _fullInCache = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1993,6 +1993,11 @@ void OverlayWidget::initStreaming() {
|
|||
handleStreamingError(std::move(error));
|
||||
}, _streamed->player.lifetime());
|
||||
|
||||
_streamed->player.fullInCache(
|
||||
) | rpl::start_with_next([=](bool fullInCache) {
|
||||
_doc->setLoadedInMediaCache(fullInCache);
|
||||
}, _streamed->player.lifetime());
|
||||
|
||||
restartAtSeekPosition(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,19 @@ void Database::getWithTag(
|
|||
});
|
||||
}
|
||||
|
||||
void Database::getWithSizes(
|
||||
const Key &key,
|
||||
std::vector<Key> &&keys,
|
||||
FnMut<void(QByteArray&&, std::vector<int>&&)> &&done) {
|
||||
_wrapped.with([
|
||||
key,
|
||||
keys = std::move(keys),
|
||||
done = std::move(done)
|
||||
](Implementation &unwrapped) mutable {
|
||||
unwrapped.getWithSizes(key, std::move(keys), std::move(done));
|
||||
});
|
||||
}
|
||||
|
||||
auto Database::statsOnMain() const -> rpl::producer<Stats> {
|
||||
return _wrapped.producer_on_main([](const Implementation &unwrapped) {
|
||||
return unwrapped.stats();
|
||||
|
|
|
@ -64,6 +64,11 @@ public:
|
|||
FnMut<void(Error)> &&done = nullptr);
|
||||
void getWithTag(const Key &key, FnMut<void(TaggedValue&&)> &&done);
|
||||
|
||||
void getWithSizes(
|
||||
const Key &key,
|
||||
std::vector<Key> &&keys,
|
||||
FnMut<void(QByteArray&&, std::vector<int>&&)> &&done);
|
||||
|
||||
using Stats = details::Stats;
|
||||
using TaggedSummary = details::TaggedSummary;
|
||||
rpl::producer<Stats> statsOnMain() const;
|
||||
|
|
|
@ -955,7 +955,28 @@ void DatabaseObject::get(
|
|||
}
|
||||
}
|
||||
|
||||
QByteArray DatabaseObject::readValueData(PlaceId place, size_type size) const {
|
||||
void DatabaseObject::getWithSizes(
|
||||
const Key &key,
|
||||
std::vector<Key> &&keys,
|
||||
FnMut<void(QByteArray&&, std::vector<int>&&)> &&done) {
|
||||
get(key, [&](TaggedValue &&value) {
|
||||
if (value.bytes.isEmpty()) {
|
||||
invokeCallback(done, QByteArray(), std::vector<int>());
|
||||
return;
|
||||
}
|
||||
|
||||
auto sizes = keys | ranges::view::transform([&](const Key &sizeKey) {
|
||||
const auto i = _map.find(sizeKey);
|
||||
return (i != end(_map)) ? int(i->second.size) : 0;
|
||||
}) | ranges::to_vector;
|
||||
|
||||
invokeCallback(done, std::move(value.bytes), std::move(sizes));
|
||||
});
|
||||
}
|
||||
|
||||
QByteArray DatabaseObject::readValueData(
|
||||
PlaceId place,
|
||||
size_type size) const {
|
||||
const auto path = placePath(place);
|
||||
File data;
|
||||
const auto result = data.open(path, File::Mode::Read, _key);
|
||||
|
|
|
@ -56,6 +56,11 @@ public:
|
|||
const Key &to,
|
||||
FnMut<void(Error)> &&done);
|
||||
|
||||
void getWithSizes(
|
||||
const Key &key,
|
||||
std::vector<Key> &&keys,
|
||||
FnMut<void(QByteArray&&, std::vector<int>&&)> &&done);
|
||||
|
||||
rpl::producer<Stats> stats() const;
|
||||
|
||||
void clear(FnMut<void(Error)> &&done);
|
||||
|
|
|
@ -810,7 +810,9 @@ void _readLocations() {
|
|||
MediaKey key(first, second);
|
||||
|
||||
_fileLocations.insert(key, loc);
|
||||
_fileLocationPairs.insert(loc.fname, FileLocationPair(key, loc));
|
||||
if (!loc.inMediaCache()) {
|
||||
_fileLocationPairs.insert(loc.fname, FileLocationPair(key, loc));
|
||||
}
|
||||
}
|
||||
|
||||
if (endMarkFound) {
|
||||
|
@ -3133,52 +3135,68 @@ bool hasDraft(const PeerId &peer) {
|
|||
}
|
||||
|
||||
void writeFileLocation(MediaKey location, const FileLocation &local) {
|
||||
if (local.fname.isEmpty()) return;
|
||||
|
||||
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
|
||||
if (aliasIt != _fileLocationAliases.cend()) {
|
||||
location = aliasIt.value();
|
||||
if (local.fname.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileLocationPairs::iterator i = _fileLocationPairs.find(local.fname);
|
||||
if (i != _fileLocationPairs.cend()) {
|
||||
if (i.value().second == local) {
|
||||
if (i.value().first != location) {
|
||||
_fileLocationAliases.insert(location, i.value().first);
|
||||
_writeLocations(WriteMapWhen::Fast);
|
||||
}
|
||||
return;
|
||||
if (!local.inMediaCache()) {
|
||||
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
|
||||
if (aliasIt != _fileLocationAliases.cend()) {
|
||||
location = aliasIt.value();
|
||||
}
|
||||
if (i.value().first != location) {
|
||||
for (FileLocations::iterator j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first);) {
|
||||
if (j.value() == i.value().second) {
|
||||
_fileLocations.erase(j);
|
||||
break;
|
||||
|
||||
FileLocationPairs::iterator i = _fileLocationPairs.find(local.fname);
|
||||
if (i != _fileLocationPairs.cend()) {
|
||||
if (i.value().second == local) {
|
||||
if (i.value().first != location) {
|
||||
_fileLocationAliases.insert(location, i.value().first);
|
||||
_writeLocations(WriteMapWhen::Fast);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_fileLocationPairs.erase(i);
|
||||
if (i.value().first != location) {
|
||||
for (FileLocations::iterator j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first);) {
|
||||
if (j.value() == i.value().second) {
|
||||
_fileLocations.erase(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_fileLocationPairs.erase(i);
|
||||
}
|
||||
}
|
||||
_fileLocationPairs.insert(local.fname, FileLocationPair(location, local));
|
||||
} else {
|
||||
for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
|
||||
if (i.value().inMediaCache() || i.value().check()) {
|
||||
return;
|
||||
}
|
||||
i = _fileLocations.erase(i);
|
||||
}
|
||||
}
|
||||
_fileLocations.insert(location, local);
|
||||
_fileLocationPairs.insert(local.fname, FileLocationPair(location, local));
|
||||
_writeLocations(WriteMapWhen::Fast);
|
||||
}
|
||||
|
||||
FileLocation readFileLocation(MediaKey location, bool check) {
|
||||
void removeFileLocation(MediaKey location) {
|
||||
FileLocations::iterator i = _fileLocations.find(location);
|
||||
if (i == _fileLocations.end()) {
|
||||
return;
|
||||
}
|
||||
while (i != _fileLocations.end() && (i.key() == location)) {
|
||||
i = _fileLocations.erase(i);
|
||||
}
|
||||
_writeLocations(WriteMapWhen::Fast);
|
||||
}
|
||||
|
||||
FileLocation readFileLocation(MediaKey location) {
|
||||
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
|
||||
if (aliasIt != _fileLocationAliases.cend()) {
|
||||
location = aliasIt.value();
|
||||
}
|
||||
|
||||
FileLocations::iterator i = _fileLocations.find(location);
|
||||
for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
|
||||
if (check) {
|
||||
if (!i.value().check()) {
|
||||
_fileLocationPairs.remove(i.value().fname);
|
||||
i = _fileLocations.erase(i);
|
||||
_writeLocations();
|
||||
continue;
|
||||
}
|
||||
if (i != _fileLocations.end()) {
|
||||
if (i.value().inMediaCache()) {
|
||||
int a = 0;
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
|
|
@ -110,7 +110,8 @@ bool hasDraftCursors(const PeerId &peer);
|
|||
bool hasDraft(const PeerId &peer);
|
||||
|
||||
void writeFileLocation(MediaKey location, const FileLocation &local);
|
||||
FileLocation readFileLocation(MediaKey location, bool check = true);
|
||||
FileLocation readFileLocation(MediaKey location);
|
||||
void removeFileLocation(MediaKey location);
|
||||
|
||||
Storage::EncryptionKey cacheKey();
|
||||
QString cachePath();
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace {
|
|||
constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL;
|
||||
constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL;
|
||||
constexpr auto kSerializeTypeShift = quint8(0x08);
|
||||
const auto kInMediaCacheLocation = QString("*media_cache*");
|
||||
|
||||
MTPInputPeer GenerateInputPeer(
|
||||
uint64 id,
|
||||
|
@ -622,7 +623,7 @@ ReadAccessEnabler::~ReadAccessEnabler() {
|
|||
}
|
||||
|
||||
FileLocation::FileLocation(const QString &name) : fname(name) {
|
||||
if (fname.isEmpty()) {
|
||||
if (fname.isEmpty() || fname == kInMediaCacheLocation) {
|
||||
size = 0;
|
||||
} else {
|
||||
setBookmark(psPathBookmark(name));
|
||||
|
@ -646,8 +647,14 @@ FileLocation::FileLocation(const QString &name) : fname(name) {
|
|||
}
|
||||
}
|
||||
|
||||
FileLocation FileLocation::InMediaCacheLocation() {
|
||||
return FileLocation(kInMediaCacheLocation);
|
||||
}
|
||||
|
||||
bool FileLocation::check() const {
|
||||
if (fname.isEmpty()) return false;
|
||||
if (fname.isEmpty() || fname == kInMediaCacheLocation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadAccessEnabler enabler(_bookmark);
|
||||
if (enabler.failed()) {
|
||||
|
@ -683,6 +690,10 @@ QByteArray FileLocation::bookmark() const {
|
|||
return _bookmark ? _bookmark->bookmark() : QByteArray();
|
||||
}
|
||||
|
||||
bool FileLocation::inMediaCache() const {
|
||||
return (fname == kInMediaCacheLocation);
|
||||
}
|
||||
|
||||
void FileLocation::setBookmark(const QByteArray &bm) {
|
||||
_bookmark.reset(bm.isEmpty() ? nullptr : new PsFileBookmark(bm));
|
||||
}
|
||||
|
|
|
@ -434,13 +434,16 @@ public:
|
|||
FileLocation() = default;
|
||||
explicit FileLocation(const QString &name);
|
||||
|
||||
bool check() const;
|
||||
const QString &name() const;
|
||||
static FileLocation InMediaCacheLocation();
|
||||
|
||||
[[nodiscard]] bool check() const;
|
||||
[[nodiscard]] const QString &name() const;
|
||||
void setBookmark(const QByteArray &bookmark);
|
||||
QByteArray bookmark() const;
|
||||
bool isEmpty() const {
|
||||
[[nodiscard]] bool isEmpty() const {
|
||||
return name().isEmpty();
|
||||
}
|
||||
[[nodiscard]] bool inMediaCache() const;
|
||||
|
||||
bool accessEnable() const;
|
||||
void accessDisable() const;
|
||||
|
|
Loading…
Add table
Reference in a new issue