mirror of
https://review.haiku-os.org/haiku
synced 2025-02-19 20:18:52 +01:00
Zstd wants a ~90 KB scratch buffer to decompress our 64 KB chunks. Rather than let it allocate that itself every time, pass in a 2*64KB "scratch" buffer and statically allocate the working memory from it. Pass it down using iovecs, and pass down the other buffers in the same way, to reduce parameters. Further, rework the object_cache used for heap decompression buffers to contain objects sized as 4x64KB, so we only need to do one allocation and deallocation for the compression/decompression and scratch buffers. Set the minimum reserve to 1 so that the low-memory manager doesn't reclaim this, as we'll need it when reading back data. Improves packagefs I/O performance (and thus boot speeds at least a bit, it appears.) Change-Id: Id51f6f598b33b9d757a283184c533bb97049529f Reviewed-on: https://review.haiku-os.org/c/haiku/+/8717 Reviewed-by: waddlesplash <waddlesplash@gmail.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
204 lines
5.6 KiB
C++
204 lines
5.6 KiB
C++
/*
|
|
* Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
|
|
#define _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
|
|
|
|
|
|
#include <new>
|
|
|
|
#include <Referenceable.h>
|
|
|
|
#include <CompressionAlgorithm.h>
|
|
#include <package/hpkg/DataReader.h>
|
|
|
|
|
|
namespace BPackageKit {
|
|
|
|
namespace BHPKG {
|
|
|
|
|
|
class BErrorOutput;
|
|
|
|
|
|
namespace BPrivate {
|
|
|
|
|
|
template<typename Parameters>
|
|
struct GenericCompressionAlgorithmOwner : BReferenceable {
|
|
BCompressionAlgorithm* algorithm;
|
|
Parameters* parameters;
|
|
|
|
GenericCompressionAlgorithmOwner(BCompressionAlgorithm* algorithm,
|
|
Parameters* parameters)
|
|
:
|
|
algorithm(algorithm),
|
|
parameters(parameters)
|
|
{
|
|
}
|
|
|
|
~GenericCompressionAlgorithmOwner()
|
|
{
|
|
delete algorithm;
|
|
delete parameters;
|
|
}
|
|
|
|
static GenericCompressionAlgorithmOwner* Create(
|
|
BCompressionAlgorithm* algorithm, Parameters* parameters)
|
|
{
|
|
GenericCompressionAlgorithmOwner* owner
|
|
= new(std::nothrow) GenericCompressionAlgorithmOwner(algorithm,
|
|
parameters);
|
|
if (owner == NULL) {
|
|
delete algorithm;
|
|
delete parameters;
|
|
}
|
|
|
|
return owner;
|
|
}
|
|
};
|
|
|
|
typedef GenericCompressionAlgorithmOwner<BCompressionParameters>
|
|
CompressionAlgorithmOwner;
|
|
typedef GenericCompressionAlgorithmOwner<BDecompressionParameters>
|
|
DecompressionAlgorithmOwner;
|
|
|
|
|
|
class PackageFileHeapAccessorBase : public BAbstractBufferedDataReader {
|
|
public:
|
|
class OffsetArray;
|
|
|
|
public:
|
|
PackageFileHeapAccessorBase(
|
|
BErrorOutput* errorOutput,
|
|
BPositionIO* file, off_t heapOffset,
|
|
DecompressionAlgorithmOwner*
|
|
decompressionAlgorithm);
|
|
virtual ~PackageFileHeapAccessorBase();
|
|
|
|
off_t HeapOffset() const
|
|
{ return fHeapOffset; }
|
|
off_t CompressedHeapSize() const
|
|
{ return fCompressedHeapSize; }
|
|
uint64 UncompressedHeapSize() const
|
|
{ return fUncompressedHeapSize; }
|
|
size_t ChunkSize() const
|
|
{ return kChunkSize; }
|
|
|
|
// normally used after cloning a PackageFileHeapReader only
|
|
void SetErrorOutput(BErrorOutput* errorOutput)
|
|
{ fErrorOutput = errorOutput; }
|
|
void SetFile(BPositionIO* file)
|
|
{ fFile = file; }
|
|
|
|
// BAbstractBufferedDataReader
|
|
virtual status_t ReadDataToOutput(off_t offset,
|
|
size_t size, BDataIO* output);
|
|
|
|
public:
|
|
static const size_t kChunkSize = 64 * 1024;
|
|
#if defined(_KERNEL_MODE)
|
|
static void* sQuadChunkCache;
|
|
#endif
|
|
|
|
protected:
|
|
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
|
|
void* compressedDataBuffer,
|
|
void* uncompressedDataBuffer,
|
|
iovec* scratchBuffer = NULL) = 0;
|
|
status_t ReadAndDecompressChunkData(uint64 offset,
|
|
size_t compressedSize,
|
|
size_t uncompressedSize,
|
|
void* compressedDataBuffer,
|
|
void* uncompressedDataBuffer,
|
|
iovec* scratchBuffer = NULL);
|
|
status_t DecompressChunkData(const iovec& compressedBuffer,
|
|
iovec& uncompressedBuffer,
|
|
iovec* scratchBuffer = NULL);
|
|
status_t ReadFileData(uint64 offset, void* buffer,
|
|
size_t size);
|
|
|
|
protected:
|
|
BErrorOutput* fErrorOutput;
|
|
BPositionIO* fFile;
|
|
off_t fHeapOffset;
|
|
uint64 fCompressedHeapSize;
|
|
uint64 fUncompressedHeapSize;
|
|
DecompressionAlgorithmOwner* fDecompressionAlgorithm;
|
|
};
|
|
|
|
|
|
/*! Stores the chunk offsets in a compact way, while still providing quick
|
|
access.
|
|
- The object doesn't store the number of chunks/offsets it contains. During
|
|
initialization the chunk count is provided. Later, when getting an offset,
|
|
the caller is responsible for ensuring a valid index.
|
|
- The first (index 0) chunk offset is omitted, since it is always 0.
|
|
- The chunk offsets that fit in a 32 bit number use only one 32 bit element
|
|
in the offsets array.
|
|
- The chunk offsets that don't fit in a 32 bit number use two elements in
|
|
the offsets array.
|
|
Memory use is one pointer, if the chunk count is <= 1 (uncompressed heap size
|
|
<= 64 KiB). Afterwards it's one pointer plus 32 bit per chunk as long as the
|
|
last offset still fits 32 bit (compressed heap size < 4GiB). For any further
|
|
chunks it is 64 bit per chunk. So, for the common case we use sizeof(void*)
|
|
plus 1 KiB per 16 MiB of uncompressed heap, or about 64 KiB per 1 GiB. Which
|
|
seems reasonable for packagefs to keep in memory.
|
|
*/
|
|
class PackageFileHeapAccessorBase::OffsetArray {
|
|
public:
|
|
OffsetArray();
|
|
~OffsetArray();
|
|
|
|
bool InitUncompressedChunksOffsets(
|
|
size_t totalChunkCount);
|
|
bool InitChunksOffsets(size_t totalChunkCount,
|
|
size_t baseIndex, const uint16* chunkSizes,
|
|
size_t chunkCount);
|
|
|
|
bool Init(size_t totalChunkCount,
|
|
const OffsetArray& other);
|
|
// "copy" init
|
|
|
|
uint64 operator[](size_t index) const;
|
|
|
|
private:
|
|
static uint32* _AllocateOffsetArray(size_t totalChunkCount,
|
|
size_t offset32BitChunkCount);
|
|
|
|
private:
|
|
uint32* fOffsets;
|
|
// - NULL, if chunkCount <= 1
|
|
// - element 0 contains the number of 32 bit
|
|
// offsets that follow, or is 0, when all
|
|
// offsets are 32 bit only
|
|
// - the following offsets use two elements
|
|
// each (lower followed by upper 32 bit)
|
|
// to represent the 64 bit value
|
|
};
|
|
|
|
|
|
inline uint64
|
|
PackageFileHeapAccessorBase::OffsetArray::operator[](size_t index) const
|
|
{
|
|
if (index == 0)
|
|
return 0;
|
|
|
|
if (fOffsets[0] == 0 || index < fOffsets[0])
|
|
return fOffsets[index];
|
|
|
|
index += index - fOffsets[0];
|
|
return fOffsets[index] | ((uint64)fOffsets[index + 1] << 32);
|
|
}
|
|
|
|
|
|
} // namespace BPrivate
|
|
|
|
} // namespace BHPKG
|
|
|
|
} // namespace BPackageKit
|
|
|
|
|
|
#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
|