Cache small files in one value.

This commit is contained in:
John Preston 2019-03-06 18:05:11 +04:00
parent 8399f4189f
commit a59c3da3d0
2 changed files with 60 additions and 36 deletions

View File

@ -190,9 +190,8 @@ auto Reader::Slice::prepareFill(int from, int till) -> PrepareFillResult {
result.ready = false; result.ready = false;
const auto fromOffset = (from / kPartSize) * kPartSize; const auto fromOffset = (from / kPartSize) * kPartSize;
const auto tillPart = (till + kPartSize - 1) / kPartSize; const auto tillPart = (till + kPartSize - 1) / kPartSize;
const auto preloadTillOffset = std::min( const auto preloadTillOffset = (tillPart + kPreloadPartsAhead)
(tillPart + kPreloadPartsAhead) * kPartSize, * kPartSize;
kInSlice);
const auto after = ranges::upper_bound( const auto after = ranges::upper_bound(
parts, parts,
@ -262,23 +261,22 @@ Reader::Slices::Slices(int size, bool useCache)
_header.flags |= Slice::Flag::Header; _header.flags |= Slice::Flag::Header;
if (useCache) { if (useCache) {
_header.flags |= Slice::Flag::LoadingFromCache; _header.flags |= Slice::Flag::LoadingFromCache;
// #TODO streaming HeaderMode::Full.
//if (_size <= kMaxOnlyInHeader) {
// _headerMode = HeaderMode::Full;
//}
} else { } else {
_headerMode = HeaderMode::NoCache; _headerMode = HeaderMode::NoCache;
} }
if (!fullInHeader()) {
_data.resize((_size + kInSlice - 1) / kInSlice);
}
}
const auto count = ((_size + kInSlice - 1) / kInSlice); bool Reader::Slices::fullInHeader() const {
_data.resize(count); return (_size <= kMaxOnlyInHeader);
} }
void Reader::Slices::headerDone(bool fromCache) { void Reader::Slices::headerDone(bool fromCache) {
if (_headerMode != HeaderMode::Unknown) { if (_headerMode != HeaderMode::Unknown) {
return; return;
} }
// #TODO streaming HeaderMode::Full.
_headerMode = HeaderMode::Small; _headerMode = HeaderMode::Small;
if (!fromCache) { if (!fromCache) {
for (auto &slice : _data) { for (auto &slice : _data) {
@ -292,12 +290,15 @@ void Reader::Slices::headerDone(bool fromCache) {
bool Reader::Slices::headerWontBeFilled() const { bool Reader::Slices::headerWontBeFilled() const {
return (_headerMode == HeaderMode::Unknown) return (_headerMode == HeaderMode::Unknown)
&& (_header.parts.size() == kMaxPartsInHeader); && (_header.parts.size() >= kMaxPartsInHeader);
} }
void Reader::Slices::applyHeaderCacheData() { void Reader::Slices::applyHeaderCacheData() {
if (_header.parts.empty()) { if (_header.parts.empty()) {
return; return;
} else if (fullInHeader()) {
headerDone(true);
return;
} }
for (const auto &[offset, part] : _header.parts) { for (const auto &[offset, part] : _header.parts) {
const auto index = offset / kInSlice; const auto index = offset / kInSlice;
@ -308,7 +309,7 @@ void Reader::Slices::applyHeaderCacheData() {
headerDone(true); headerDone(true);
} }
bool Reader::Slices::processCacheResult( void Reader::Slices::processCacheResult(
int sliceNumber, int sliceNumber,
QByteArray &&result) { QByteArray &&result) {
Expects(sliceNumber >= 0 && sliceNumber <= _data.size()); Expects(sliceNumber >= 0 && sliceNumber <= _data.size());
@ -316,7 +317,7 @@ bool Reader::Slices::processCacheResult(
auto &slice = (sliceNumber ? _data[sliceNumber - 1] : _header); auto &slice = (sliceNumber ? _data[sliceNumber - 1] : _header);
if (!(slice.flags &Slice::Flag::LoadingFromCache)) { if (!(slice.flags &Slice::Flag::LoadingFromCache)) {
// We could've already unloaded this slice using LRU _usedSlices. // We could've already unloaded this slice using LRU _usedSlices.
return true; return;
} }
const auto success = slice.processCacheData( const auto success = slice.processCacheData(
std::move(result), std::move(result),
@ -324,24 +325,25 @@ bool Reader::Slices::processCacheResult(
if (!sliceNumber) { if (!sliceNumber) {
applyHeaderCacheData(); applyHeaderCacheData();
} }
return success;
} }
std::optional<Error> Reader::Slices::processPart( void Reader::Slices::processPart(
int offset, int offset,
QByteArray &&bytes) { QByteArray &&bytes) {
Expects(offset / kInSlice < _data.size()); Expects(fullInHeader() || (offset / kInSlice < _data.size()));
const auto index = offset / kInSlice; if (fullInHeader()) {
if (_headerMode == HeaderMode::Unknown) { _header.addPart(offset, bytes);
return;
} else if (_headerMode == HeaderMode::Unknown) {
if (_header.parts.contains(offset)) { if (_header.parts.contains(offset)) {
return {}; return;
} else if (_header.parts.size() < kMaxPartsInHeader) { } else if (_header.parts.size() < kMaxPartsInHeader) {
_header.addPart(offset, bytes); _header.addPart(offset, bytes);
} }
} }
const auto index = offset / kInSlice;
_data[index].addPart(offset - index * kInSlice, std::move(bytes)); _data[index].addPart(offset - index * kInSlice, std::move(bytes));
return {};
} }
auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult { auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult {
@ -356,6 +358,8 @@ auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult {
&& !(_header.flags & Flag::LoadedFromCache)) { && !(_header.flags & Flag::LoadedFromCache)) {
// Waiting for initial cache query. // Waiting for initial cache query.
return {}; return {};
} else if (fullInHeader()) {
return fillFromHeader(offset, buffer);
} }
auto result = FillResult(); auto result = FillResult();
@ -379,7 +383,7 @@ auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult {
} }
for (const auto offset : prepared.offsetsFromLoader.values()) { for (const auto offset : prepared.offsetsFromLoader.values()) {
const auto full = offset + sliceIndex * kInSlice; const auto full = offset + sliceIndex * kInSlice;
if (sliceIndex + 1 != _data.size() || full < _size) { if (offset < kInSlice && full < _size) {
result.offsetsFromLoader.add(full); result.offsetsFromLoader.add(full);
} }
} }
@ -429,6 +433,29 @@ auto Reader::Slices::fill(int offset, bytes::span buffer) -> FillResult {
return result; return result;
} }
auto Reader::Slices::fillFromHeader(int offset, bytes::span buffer)
-> FillResult {
auto result = FillResult();
const auto from = offset;
const auto till = int(offset + buffer.size());
const auto prepared = _header.prepareFill(from, till);
for (const auto full : prepared.offsetsFromLoader.values()) {
if (full < _size) {
result.offsetsFromLoader.add(full);
}
}
if (prepared.ready) {
CopyLoaded(
buffer,
ranges::make_iterator_range(prepared.start, prepared.finish),
from,
till);
result.filled = true;
}
return result;
}
void Reader::Slices::markSliceUsed(int sliceIndex) { void Reader::Slices::markSliceUsed(int sliceIndex) {
const auto i = ranges::find(_usedSlices, sliceIndex); const auto i = ranges::find(_usedSlices, sliceIndex);
const auto end = _usedSlices.end(); const auto end = _usedSlices.end();
@ -443,11 +470,11 @@ void Reader::Slices::markSliceUsed(int sliceIndex) {
} }
int Reader::Slices::maxSliceSize(int sliceNumber) const { int Reader::Slices::maxSliceSize(int sliceNumber) const {
return (sliceNumber == _data.size()) return !sliceNumber
? _size
: (sliceNumber == _data.size())
? (_size - (sliceNumber - 1) * kInSlice) ? (_size - (sliceNumber - 1) * kInSlice)
: (sliceNumber > 0) : kInSlice;
? kInSlice
: _size;
} }
Reader::SerializedSlice Reader::Slices::serializeAndUnloadUnused() { Reader::SerializedSlice Reader::Slices::serializeAndUnloadUnused() {
@ -746,13 +773,9 @@ bool Reader::processLoadedParts() {
} else if (!_loadingOffsets.remove(part.offset)) { } else if (!_loadingOffsets.remove(part.offset)) {
continue; continue;
} }
const auto error = _slices.processPart( _slices.processPart(
part.offset, part.offset,
std::move(part.bytes)); std::move(part.bytes));
if (error) {
_failed = *error;
return false;
}
} }
return !loaded.empty(); return !loaded.empty();
} }

View File

@ -114,19 +114,18 @@ private:
Slices(int size, bool useCache); Slices(int size, bool useCache);
void headerDone(bool fromCache); void headerDone(bool fromCache);
bool headerWontBeFilled() const; [[nodiscard]] bool headerWontBeFilled() const;
bool processCacheResult(int sliceNumber, QByteArray &&result); void processCacheResult(int sliceNumber, QByteArray &&result);
std::optional<Error> processPart(int offset, QByteArray &&bytes); void processPart(int offset, QByteArray &&bytes);
FillResult fill(int offset, bytes::span buffer); [[nodiscard]] FillResult fill(int offset, bytes::span buffer);
SerializedSlice unloadToCache(); [[nodiscard]] SerializedSlice unloadToCache();
private: private:
enum class HeaderMode { enum class HeaderMode {
Unknown, Unknown,
Small, Small,
// Full,
NoCache, NoCache,
}; };
@ -135,6 +134,8 @@ private:
SerializedSlice serializeAndUnloadSlice(int sliceNumber); SerializedSlice serializeAndUnloadSlice(int sliceNumber);
SerializedSlice serializeAndUnloadUnused(); SerializedSlice serializeAndUnloadUnused();
void markSliceUsed(int sliceIndex); void markSliceUsed(int sliceIndex);
bool fullInHeader() const;
FillResult fillFromHeader(int offset, bytes::span buffer);
std::vector<Slice> _data; std::vector<Slice> _data;
Slice _header; Slice _header;