* BBufferIO did not implement Seek() and Position() correctly; it just passed

it to the stream. This caused Read()/Write() to need two syscalls for nothing
  (this only caused the actual stream to share the same position with the
  BBufferIO, something you just cannot rely on when using buffered I/O).
* Anyway, this reduces the time VirtualBox needs to open some RAW test images
  from over 4 minutes to less than 15 seconds...


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28662 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-11-16 21:23:45 +00:00
parent 5d029ca0bd
commit 1b21be7091
2 changed files with 59 additions and 39 deletions
+3 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2007, Haiku, Inc. All Rights Reserved. * Copyright 2007-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _BUFFER_IO_H #ifndef _BUFFER_IO_H
@@ -40,7 +40,8 @@ class BBufferIO : public BPositionIO {
char* fBuffer; char* fBuffer;
size_t fBufferSize; size_t fBufferSize;
size_t fBufferUsed; size_t fBufferUsed;
uint32 _reserved_ints[6]; off_t fPosition;
uint32 _reserved_ints[4];
bool fBufferIsDirty; bool fBufferIsDirty;
bool fOwnsStream; bool fOwnsStream;
bool _reserved_bools[6]; bool _reserved_bools[6];
+56 -37
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2007, Haiku * Copyright (c) 2001-2008, Haiku
* Distributed under the terms of the MIT license * Distributed under the terms of the MIT license
* *
* Authors: * Authors:
@@ -14,7 +14,7 @@
#include <string.h> #include <string.h>
BBufferIO::BBufferIO(BPositionIO *stream, size_t bufferSize, bool ownsStream) BBufferIO::BBufferIO(BPositionIO* stream, size_t bufferSize, bool ownsStream)
: :
fBufferStart(0), fBufferStart(0),
fStream(stream), fStream(stream),
@@ -22,18 +22,16 @@ BBufferIO::BBufferIO(BPositionIO *stream, size_t bufferSize, bool ownsStream)
fBufferUsed(0), fBufferUsed(0),
fBufferIsDirty(false), fBufferIsDirty(false),
fOwnsStream(ownsStream) fOwnsStream(ownsStream)
{ {
if (bufferSize < 512) fBufferSize = max_c(bufferSize, 512);
bufferSize = 512; fPosition = stream->Position();
fBufferSize = bufferSize;
// What can we do if this malloc fails ? // What can we do if this malloc fails ?
// I think R5 uses new, but doesn't catch the thrown exception // I think R5 uses new, but doesn't catch the thrown exception
// (if you specify a very big buffer, the application just // (if you specify a very big buffer, the application just
// terminates with abort). // terminates with abort).
fBuffer = (char *)malloc(fBufferSize); fBuffer = (char*)malloc(fBufferSize);
} }
@@ -52,27 +50,26 @@ BBufferIO::~BBufferIO()
ssize_t ssize_t
BBufferIO::ReadAt(off_t pos, void *buffer, size_t size) BBufferIO::ReadAt(off_t pos, void* buffer, size_t size)
{ {
// We refuse to crash, even if // We refuse to crash, even if
// you were lazy and didn't give a valid // you were lazy and didn't give a valid
// stream on construction. // stream on construction.
if (fStream == NULL) if (fStream == NULL)
return B_NO_INIT; return B_NO_INIT;
if (buffer == NULL) if (buffer == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
// If the amount of data we want doesn't fit in the buffer, just // If the amount of data we want doesn't fit in the buffer, just
// read it directly from the disk (and don't touch the buffer). // read it directly from the disk (and don't touch the buffer).
if (size > fBufferSize) { if (size > fBufferSize || fBuffer == NULL) {
if (fBufferIsDirty) if (fBufferIsDirty)
Flush(); Flush();
return fStream->ReadAt(pos, buffer, size); return fStream->ReadAt(pos, buffer, size);
} }
// If the data we are looking for is not in the buffer... // If the data we are looking for is not in the buffer...
if (size > fBufferUsed if (size > fBufferUsed
|| pos < fBufferStart || pos < fBufferStart
|| pos > fBufferStart + fBufferUsed || pos > fBufferStart + fBufferUsed
|| pos + size > fBufferStart + fBufferUsed) { || pos + size > fBufferStart + fBufferUsed) {
@@ -86,7 +83,7 @@ BBufferIO::ReadAt(off_t pos, void *buffer, size_t size)
fBufferStart = pos; // The data is buffered starting from this offset fBufferStart = pos; // The data is buffered starting from this offset
} }
size = min_c(size, fBufferUsed); size = min_c(size, fBufferUsed);
// copy data from the cache to the given buffer // copy data from the cache to the given buffer
memcpy(buffer, fBuffer + pos - fBufferStart, size); memcpy(buffer, fBuffer + pos - fBufferStart, size);
@@ -96,16 +93,15 @@ BBufferIO::ReadAt(off_t pos, void *buffer, size_t size)
ssize_t ssize_t
BBufferIO::WriteAt(off_t pos, const void *buffer, size_t size) BBufferIO::WriteAt(off_t pos, const void* buffer, size_t size)
{ {
if (fStream == NULL) if (fStream == NULL)
return B_NO_INIT; return B_NO_INIT;
if (buffer == NULL) if (buffer == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
// If data doesn't fit into the buffer, write it directly to the stream // If data doesn't fit into the buffer, write it directly to the stream
if (size > fBufferSize) if (size > fBufferSize || fBuffer == NULL)
return fStream->WriteAt(pos, buffer, size); return fStream->WriteAt(pos, buffer, size);
// If we have cached data in the buffer, whose offset into the stream // If we have cached data in the buffer, whose offset into the stream
@@ -113,7 +109,7 @@ BBufferIO::WriteAt(off_t pos, const void *buffer, size_t size)
if (!fBufferIsDirty && fBufferStart > pos) { if (!fBufferIsDirty && fBufferStart > pos) {
fBufferStart = 0; fBufferStart = 0;
fBufferUsed = 0; fBufferUsed = 0;
} }
// If we want to write beyond the cached data... // If we want to write beyond the cached data...
if (pos > fBufferStart + fBufferUsed if (pos > fBufferStart + fBufferUsed
@@ -132,7 +128,7 @@ BBufferIO::WriteAt(off_t pos, const void *buffer, size_t size)
} }
} }
memcpy(fBuffer + pos - fBufferStart, buffer, size); memcpy(fBuffer + pos - fBufferStart, buffer, size);
fBufferIsDirty = true; fBufferIsDirty = true;
fBufferUsed = max_c((size + pos), fBufferUsed); fBufferUsed = max_c((size + pos), fBufferUsed);
@@ -147,17 +143,40 @@ BBufferIO::Seek(off_t position, uint32 seekMode)
if (fStream == NULL) if (fStream == NULL)
return B_NO_INIT; return B_NO_INIT;
return fStream->Seek(position, seekMode); switch (seekMode) {
case SEEK_CUR:
fPosition += position;
if (fPosition < 0)
fPosition = 0;
break;
case SEEK_SET:
if (position < 0)
return B_BAD_VALUE;
fPosition = position;
break;
case SEEK_END:
{
off_t size;
status_t status = fStream->GetSize(&size);
if (status != B_OK)
return status;
fPosition = size - position;
if (fPosition < 0)
fPosition = 0;
break;
}
}
return fPosition;
} }
off_t off_t
BBufferIO::Position() const BBufferIO::Position() const
{ {
if (fStream == NULL) return fPosition;
return B_NO_INIT;
return fStream->Position();
} }
@@ -186,7 +205,7 @@ BBufferIO::Flush()
} }
BPositionIO * BPositionIO*
BBufferIO::Stream() const BBufferIO::Stream() const
{ {
return fStream; return fStream;
@@ -208,9 +227,9 @@ BBufferIO::OwnsStream() const
void void
BBufferIO::SetOwnsStream(bool owns_stream) BBufferIO::SetOwnsStream(bool ownsStream)
{ {
fOwnsStream = owns_stream; fOwnsStream = ownsStream;
} }
@@ -231,9 +250,9 @@ BBufferIO::PrintToStream() const
// These functions are here to maintain future binary // These functions are here to maintain future binary
// compatibility. // compatibility.
status_t BBufferIO::_Reserved_BufferIO_0(void *) { return B_ERROR; } status_t BBufferIO::_Reserved_BufferIO_0(void*) { return B_ERROR; }
status_t BBufferIO::_Reserved_BufferIO_1(void *) { return B_ERROR; } status_t BBufferIO::_Reserved_BufferIO_1(void*) { return B_ERROR; }
status_t BBufferIO::_Reserved_BufferIO_2(void *) { return B_ERROR; } status_t BBufferIO::_Reserved_BufferIO_2(void*) { return B_ERROR; }
status_t BBufferIO::_Reserved_BufferIO_3(void *) { return B_ERROR; } status_t BBufferIO::_Reserved_BufferIO_3(void*) { return B_ERROR; }
status_t BBufferIO::_Reserved_BufferIO_4(void *) { return B_ERROR; } status_t BBufferIO::_Reserved_BufferIO_4(void*) { return B_ERROR; }