diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2023-04-03 09:34:54 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2023-05-05 18:47:03 +0200 |
commit | 0f2581204a70038ed7ca78089a9bd96d158e02c0 (patch) | |
tree | 7708448554efc524a2cf88d184e762fb22deb803 /vcl/source/graphic | |
parent | d1999f23caf47a36786182adbe071619fd60f999 (diff) |
BinaryDataContainer swap out implementation.
We can easily accumulate a large number of in-memory graphic
objects, and swapping these as well as the un-compressed
images can become important.
For now we swap out the container when the image is swapped
out, however it seems unlikely it will ever need to be swapped
in again.
Despite the shared pImpl, we retained the reference counting
on the underling vector to keep this immutable while we hand
out a MemoryStream reference to it.
Change-Id: Ib7ca45afb8499460b1852461f7c11afca3f3cdfa
Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151359
Tested-by: Jenkins
Diffstat (limited to 'vcl/source/graphic')
-rw-r--r-- | vcl/source/graphic/BinaryDataContainer.cxx | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/vcl/source/graphic/BinaryDataContainer.cxx b/vcl/source/graphic/BinaryDataContainer.cxx index b35195b7d27e..f395497f9449 100644 --- a/vcl/source/graphic/BinaryDataContainer.cxx +++ b/vcl/source/graphic/BinaryDataContainer.cxx @@ -10,21 +10,76 @@ #include <vcl/BinaryDataContainer.hxx> #include <o3tl/hash_combine.hxx> +#include <unotools/tempfile.hxx> +#include <comphelper/lok.hxx> +#include <sal/log.hxx> + +struct BinaryDataContainer::Impl +{ + // temp file to store the data out of RAM if necessary + std::unique_ptr<utl::TempFileNamed> mpFile; + // the binary data + std::shared_ptr<std::vector<sal_uInt8>> mpData; + + Impl(SvStream& stream, size_t size) { readData(stream, size); } + + /// Populate mpData from the stream + void readData(SvStream& stream, size_t size) + { + auto pData = std::make_shared<std::vector<sal_uInt8>>(size); + if (stream.ReadBytes(pData->data(), pData->size()) == size) + mpData = std::move(pData); + } + + /// ensure the data is in-RAM + void ensureSwappedIn() + { + if (mpData || !mpFile) + return; + + auto pStream = mpFile->GetStream(StreamMode::READ); + pStream->Seek(0); + readData(*pStream, pStream->remainingSize()); + + // Horrifying data loss ... + SAL_WARN_IF(pStream->GetError(), "vcl", + "Inconsistent system - failed to swap image back in"); + SAL_DEBUG("Swap in: " << pStream->GetError()); + } + + void swapOut() + { + if (mpFile) + { + // we already have it swapped out. + mpData.reset(); + return; + } + + if (!mpData || mpData->empty()) + return; + + mpFile.reset(new utl::TempFileNamed()); + auto pStream = mpFile->GetStream(StreamMode::READWRITE); + + pStream->WriteBytes(mpData->data(), mpData->size()); + + mpData.reset(); + } +}; BinaryDataContainer::BinaryDataContainer(SvStream& stream, size_t size) + : mpImpl(new Impl(stream, size)) { - auto pBuffer = std::make_shared<std::vector<sal_uInt8>>(size); - if (stream.ReadBytes(pBuffer->data(), pBuffer->size()) == size) - mpData = std::move(pBuffer); } size_t BinaryDataContainer::calculateHash() const { size_t nSeed = 0; - if (mpData) + if (mpImpl && mpImpl->mpData && !mpImpl->mpData->empty()) { o3tl::hash_combine(nSeed, getSize()); - for (sal_uInt8 const& rByte : *mpData) + for (sal_uInt8 const& rByte : *mpImpl->mpData) o3tl::hash_combine(nSeed, rByte); } return nSeed; @@ -34,10 +89,11 @@ css::uno::Sequence<sal_Int8> BinaryDataContainer::getCopyAsByteSequence() const { if (isEmpty()) return css::uno::Sequence<sal_Int8>(); + assert(mpImpl); css::uno::Sequence<sal_Int8> aData(getSize()); - std::copy(mpData->cbegin(), mpData->cend(), aData.getArray()); + std::copy(mpImpl->mpData->cbegin(), mpImpl->mpData->cend(), aData.getArray()); return aData; } @@ -53,10 +109,9 @@ class ReferencedMemoryStream : public SvMemoryStream std::shared_ptr<std::vector<sal_uInt8>> mpData; public: - ReferencedMemoryStream(const std::shared_ptr<std::vector<sal_uInt8>>& rData) - : SvMemoryStream(rData ? rData->data() : nullptr, rData ? rData->size() : 0, - StreamMode::READ) - , mpData(rData) + ReferencedMemoryStream(const std::shared_ptr<std::vector<sal_uInt8>>& pData) + : SvMemoryStream(pData->data(), pData->size(), StreamMode::READ) + , mpData(pData) { } }; @@ -64,18 +119,52 @@ public: std::shared_ptr<SvStream> BinaryDataContainer::getAsStream() { - return std::make_shared<ReferencedMemoryStream>(mpData); + ensureSwappedIn(); // TODO: transfer in streamed chunks + return std::make_shared<ReferencedMemoryStream>(mpImpl->mpData); } std::size_t BinaryDataContainer::writeToStream(SvStream& rStream) const { + ensureSwappedIn(); // TODO: transfer in streamed chunks return rStream.WriteBytes(getData(), getSize()); } -size_t BinaryDataContainer::getSize() const { return mpData ? mpData->size() : 0; } +size_t BinaryDataContainer::getSize() const +{ + ensureSwappedIn(); + return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0; +} + +size_t BinaryDataContainer::getSizeBytes() const +{ + return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0; +} + +bool BinaryDataContainer::isEmpty() const +{ + ensureSwappedIn(); + return !mpImpl || !mpImpl->mpData || mpImpl->mpData->empty(); +} + +const sal_uInt8* BinaryDataContainer::getData() const +{ + ensureSwappedIn(); + return mpImpl && mpImpl->mpData ? mpImpl->mpData->data() : nullptr; +} -bool BinaryDataContainer::isEmpty() const { return !mpData || mpData->empty(); } +void BinaryDataContainer::ensureSwappedIn() const +{ + if (mpImpl) + mpImpl->ensureSwappedIn(); +} + +void BinaryDataContainer::swapOut() const +{ + // Only bother reducing memory footprint in kit mode - for mobile/online etc. + if (!mpImpl || !comphelper::LibreOfficeKit::isActive()) + return; -const sal_uInt8* BinaryDataContainer::getData() const { return mpData ? mpData->data() : nullptr; } + mpImpl->swapOut(); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |