PackageFileHeapWriter: Fix update case

* Pull _UnwriteLastPartialChunk() out of Reinit() for reuse.
* _UnwriteLastPartialChunk(): fPendingDataSize wasn't set.
* _PushChunks(): Some simplifications for clarity.
* ChunkBuffer/RemoveDataRanges(): Use data reading and decompression
  methods provided by our base class instead of duplicating the
  implementation.
* RemoveDataRanges():
  - _FlushPendingData() before starting, so we don't ignore the pending
    data and _UnwriteLastPartialChunk() when done, so a partial chunk
    is read back into the pending data buffer.
  - fUncompressedHeapSize wasn't reset before the main processing loop,
    thus resulting in an erroneous size later on.
This commit is contained in:
Ingo Weinhold
2013-05-25 01:12:27 +02:00
parent 520a7a76c7
commit b05413ed78
2 changed files with 68 additions and 69 deletions
@@ -68,6 +68,8 @@ private:
struct ChunkSegment;
struct ChunkBuffer;
friend struct ChunkBuffer;
private:
void _Uninit();
@@ -81,6 +83,7 @@ private:
void _PushChunks(ChunkBuffer& chunkBuffer,
uint64 startOffset, uint64 endOffset);
void _UnwriteLastPartialChunk();
private:
void* fPendingDataBuffer;
+65 -69
View File
@@ -18,8 +18,6 @@
#include <AutoDeleter.h>
#include <package/hpkg/DataReader.h>
#include <package/hpkg/PackageFileHeapReader.h>
#include <package/hpkg/ZlibCompressor.h>
#include <package/hpkg/ZlibDecompressor.h>
#include <RangeArray.h>
@@ -50,12 +48,9 @@ struct PackageFileHeapWriter::ChunkSegment {
struct PackageFileHeapWriter::ChunkBuffer {
ChunkBuffer(BErrorOutput* errorOutput, int fd, off_t heapOffset,
size_t bufferSize)
ChunkBuffer(PackageFileHeapWriter* writer, size_t bufferSize)
:
fErrorOutput(errorOutput),
fFD(fd),
fHeapOffset(heapOffset),
fWriter(writer),
fChunks(),
fCurrentChunkIndex(0),
fNextReadIndex(0),
@@ -100,6 +95,11 @@ struct PackageFileHeapWriter::ChunkBuffer {
return fSegments.Add(segment);
}
bool IsEmpty() const
{
return fSegments.IsEmpty();
}
bool HasMoreSegments() const
{
return fCurrentSegmentIndex < fSegments.Count();
@@ -138,23 +138,10 @@ struct PackageFileHeapWriter::ChunkBuffer {
Chunk& chunk = fChunks[fNextReadIndex++];
chunk.buffer = _GetBuffer();
ssize_t bytesRead = pread(fFD, chunk.buffer, chunk.compressedSize,
fHeapOffset + chunk.offset);
if (bytesRead < 0) {
fErrorOutput->PrintError("PackageFileHeapWriter::ChunkBuffer::"
"ReadNextChunk(offset: %" B_PRIu64 ", size: %" B_PRIu32
") failed to read data: %s\n", chunk.offset,
chunk.compressedSize, strerror(errno));
throw status_t(errno);
}
if ((size_t)bytesRead != chunk.compressedSize) {
fErrorOutput->PrintError("PackageFileHeapWriter::ChunkBuffer::"
"ReadNextChunk(offset: %" B_PRIu64 ", size: %" B_PRIu32
") failed to read all data\n", chunk.offset,
chunk.compressedSize);
throw status_t(B_ERROR);
}
status_t error = fWriter->ReadFileData(chunk.offset, chunk.buffer,
chunk.compressedSize);
if (error != B_OK)
throw error;
}
void CurrentSegmentDone()
@@ -192,20 +179,18 @@ private:
}
private:
BErrorOutput* fErrorOutput;
int fFD;
off_t fHeapOffset;
PackageFileHeapWriter* fWriter;
Array<Chunk> fChunks;
ssize_t fCurrentChunkIndex;
ssize_t fNextReadIndex;
Array<Chunk> fChunks;
ssize_t fCurrentChunkIndex;
ssize_t fNextReadIndex;
Array<ChunkSegment> fSegments;
ssize_t fCurrentSegmentIndex;
Array<ChunkSegment> fSegments;
ssize_t fCurrentSegmentIndex;
BList fBuffers;
BList fUnusedBuffers;
size_t fBufferSize;
BList fBuffers;
BList fUnusedBuffers;
size_t fBufferSize;
};
@@ -257,18 +242,7 @@ PackageFileHeapWriter::Reinit(PackageFileHeapReader* heapReader)
fOffsets[i] = heapReader->Offsets()[i];
}
// If the last chunk is partial, read it in and remove it from the offsets.
size_t lastChunkSize = fUncompressedHeapSize % kChunkSize;
if (lastChunkSize != 0) {
status_t error = heapReader->ReadData(
fUncompressedHeapSize - lastChunkSize, fPendingDataBuffer,
lastChunkSize);
if (error != B_OK)
throw error;
fCompressedHeapSize = fOffsets[fOffsets.Count() - 1];
fOffsets.Remove(fOffsets.Count() - 1);
}
_UnwriteLastPartialChunk();
}
@@ -322,6 +296,10 @@ PackageFileHeapWriter::RemoveDataRanges(
throw status_t(B_BAD_VALUE);
}
// Before we begin flush any pending data, so we don't need any special
// handling and also can use the pending data buffer.
_FlushPendingData();
// We potentially have to recompress all data from the first affected chunk
// to the end (minus the removed ranges, of course). As a basic algorithm we
// can use our usual data writing strategy, i.e. read a chunk, decompress it
@@ -338,7 +316,7 @@ PackageFileHeapWriter::RemoveDataRanges(
// Build a list of (possibly partial) chunks we want to keep.
// the first partial chunk (if any) and all chunks between ranges
ChunkBuffer chunkBuffer(fErrorOutput, fFD, fHeapOffset, kChunkSize);
ChunkBuffer chunkBuffer(this, kChunkSize);
uint64 writeOffset = ranges[0].offset - ranges[0].offset % kChunkSize;
uint64 readOffset = writeOffset;
for (ssize_t i = 0; i < rangeCount; i++) {
@@ -360,9 +338,10 @@ PackageFileHeapWriter::RemoveDataRanges(
// Reset our state to look like all chunks from the first affected one have
// been removed and re-add all data we want to keep.
// truncate the offsets array and reset the heap end offset
// truncate the offsets array and reset the heap sizes
ssize_t firstChunkIndex = ssize_t(writeOffset / kChunkSize);
fCompressedHeapSize = fOffsets[firstChunkIndex];
fUncompressedHeapSize = (uint64)firstChunkIndex * kChunkSize;
fOffsets.Remove(firstChunkIndex, fOffsets.Count() - firstChunkIndex);
// we need a decompression buffer
@@ -409,21 +388,11 @@ PackageFileHeapWriter::RemoveDataRanges(
} else if (decompressedChunk == &chunk) {
uncompressedData = decompressionBuffer;
} else {
size_t uncompressedSize;
status_t error = ZlibDecompressor::DecompressSingleBuffer(
chunk.buffer, chunk.compressedSize,
decompressionBuffer, chunk.uncompressedSize, uncompressedSize);
if (error != B_OK) {
fErrorOutput->PrintError("Failed to decompress data chunk: "
"%s\n", strerror(error));
status_t error = DecompressChunkData(chunk.buffer,
chunk.compressedSize, decompressionBuffer,
chunk.uncompressedSize);
if (error != B_OK)
throw error;
}
if (uncompressedSize != chunk.uncompressedSize) {
fErrorOutput->PrintError("Failed to decompress data chunk: "
"chunk size mismatch\n");
throw status_t(B_ERROR);
}
decompressedChunk = &chunk;
uncompressedData = decompressionBuffer;
@@ -435,6 +404,13 @@ PackageFileHeapWriter::RemoveDataRanges(
chunkBuffer.CurrentSegmentDone();
}
// Make sure a last partial chunk ends up in the pending data buffer. This
// is only necessary when we didn't have to move any chunk segments, since
// the loop would otherwise have read it in and left it in the pending data
// buffer.
if (chunkBuffer.IsEmpty())
_UnwriteLastPartialChunk();
}
@@ -617,14 +593,16 @@ PackageFileHeapWriter::_PushChunks(ChunkBuffer& chunkBuffer, uint64 startOffset,
uint64 uncompressedChunkOffset = (uint64)chunkIndex * kChunkSize;
while (startOffset < endOffset) {
bool isLastChunk = fUncompressedHeapSize - uncompressedChunkOffset
<= kChunkSize;
uint32 inChunkOffset = uint32(startOffset - uncompressedChunkOffset);
uint32 uncompressedChunkSize = chunkIndex + 1 < fOffsets.Count()
? kChunkSize
: fUncompressedHeapSize - uncompressedChunkOffset;
uint32 uncompressedChunkSize = isLastChunk
? fUncompressedHeapSize - uncompressedChunkOffset
: kChunkSize;
uint64 compressedChunkOffset = fOffsets[chunkIndex];
uint32 compressedChunkSize = chunkIndex + 1 < fOffsets.Count()
? fOffsets[chunkIndex + 1] - compressedChunkOffset
: fCompressedHeapSize - compressedChunkOffset;
uint32 compressedChunkSize = isLastChunk
? fCompressedHeapSize - compressedChunkOffset
: fOffsets[chunkIndex + 1] - compressedChunkOffset;
uint32 toKeepSize = uint32(std::min(
(uint64)uncompressedChunkSize - inChunkOffset,
endOffset - startOffset));
@@ -642,6 +620,24 @@ PackageFileHeapWriter::_PushChunks(ChunkBuffer& chunkBuffer, uint64 startOffset,
}
void
PackageFileHeapWriter::_UnwriteLastPartialChunk()
{
// If the last chunk is partial, read it in and remove it from the offsets.
size_t lastChunkSize = fUncompressedHeapSize % kChunkSize;
if (lastChunkSize != 0) {
status_t error = ReadData(fUncompressedHeapSize - lastChunkSize,
fPendingDataBuffer, lastChunkSize);
if (error != B_OK)
throw error;
fPendingDataSize = lastChunkSize;
fCompressedHeapSize = fOffsets[fOffsets.Count() - 1];
fOffsets.Remove(fOffsets.Count() - 1);
}
}
} // namespace BPrivate
} // namespace BHPKG