enh(FileStream): Add FileStreamBuf::resizeBuffer to set larger internal buffers. (#4621)

Larger buffers improve performance significantly when streaming large quantity of data on very fast devices.
This commit is contained in:
Matej Kenda
2024-09-09 17:33:50 +02:00
committed by GitHub
parent 710c2a41f3
commit 91c256095f
8 changed files with 224 additions and 53 deletions

View File

@@ -43,15 +43,15 @@ class BasicBufferedBidirectionalStreamBuf: public std::basic_streambuf<ch, tr>
/// for implementing an iostream.
{
protected:
typedef std::basic_streambuf<ch, tr> Base;
typedef std::basic_ios<ch, tr> IOS;
typedef ch char_type;
typedef tr char_traits;
typedef ba Allocator;
typedef typename Base::int_type int_type;
typedef typename Base::pos_type pos_type;
typedef typename Base::off_type off_type;
typedef typename IOS::openmode openmode;
using Base = std::basic_streambuf<ch, tr>;
using IOS = std::basic_ios<ch, tr>;
using char_type = ch;
using char_traits = tr;
using Allocator = ba;
using int_type = typename Base::int_type;
using pos_type = typename Base::pos_type;
using off_type = typename Base::off_type;
using openmode = typename IOS::openmode;
public:
BasicBufferedBidirectionalStreamBuf(std::streamsize bufferSize, openmode mode):
@@ -69,6 +69,9 @@ public:
Allocator::deallocate(_pWriteBuffer, _bufsize);
}
BasicBufferedBidirectionalStreamBuf(const BasicBufferedBidirectionalStreamBuf&) = delete;
BasicBufferedBidirectionalStreamBuf& operator = (const BasicBufferedBidirectionalStreamBuf&) = delete;
virtual int_type overflow(int_type c)
{
if (!(_mode & IOS::out)) return char_traits::eof();
@@ -130,6 +133,22 @@ protected:
this->setp(_pWriteBuffer, _pWriteBuffer + _bufsize);
}
virtual bool resizeBuffer(std::streamsize bufferSize)
{
if (_bufsize != bufferSize)
{
Allocator::deallocate(_pReadBuffer, _bufsize);
Allocator::deallocate(_pWriteBuffer, _bufsize);
_bufsize = bufferSize;
_pReadBuffer = Allocator::allocate(_bufsize);
_pWriteBuffer = Allocator::allocate(_bufsize);
}
resetBuffers();
return true;
}
private:
virtual int readFromDevice(char_type* /*buffer*/, std::streamsize /*length*/)
{
@@ -152,13 +171,10 @@ private:
return -1;
}
std::streamsize _bufsize;
char_type* _pReadBuffer;
char_type* _pWriteBuffer;
openmode _mode;
BasicBufferedBidirectionalStreamBuf(const BasicBufferedBidirectionalStreamBuf&);
BasicBufferedBidirectionalStreamBuf& operator = (const BasicBufferedBidirectionalStreamBuf&);
std::streamsize _bufsize {0};
char_type* _pReadBuffer {nullptr};
char_type* _pWriteBuffer {nullptr};
openmode _mode {0};
};
@@ -172,8 +188,8 @@ private:
#if defined(_MSC_VER) && defined(POCO_DLL) && !defined(Foundation_EXPORTS)
template class Foundation_API BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char>>;
#endif
typedef BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char>> BufferedBidirectionalStreamBuf;
using BufferedBidirectionalStreamBuf
= BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char>>;
} // namespace Poco

View File

@@ -53,7 +53,7 @@ public:
FileIOS();
/// Creates the basic stream.
~FileIOS();
~FileIOS() override;
/// Destroys the stream.
virtual void open(const std::string& path, std::ios::openmode mode);
@@ -115,7 +115,7 @@ public:
/// Throws a FileNotFoundException (or a similar exception) if the file
/// does not exist or is not accessible for other reasons.
~FileInputStream();
~FileInputStream() override;
/// Destroys the stream.
void open(const std::string& path, std::ios::openmode mode = std::ios::in) override;
@@ -158,7 +158,7 @@ public:
/// for std::ofstream, which is std::ios::out only. This is for backwards compatibility
/// with earlier POCO versions.
~FileOutputStream();
~FileOutputStream() override;
/// Destroys the FileOutputStream.
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::trunc) override;
@@ -203,7 +203,7 @@ public:
/// for std::fstream, which is std::ios::out only. This is for backwards compatibility
/// with earlier POCO versions.
~FileStream();
~FileStream() override;
/// Destroys the FileOutputStream.
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::in) override;

View File

@@ -36,7 +36,7 @@ public:
FileStreamBuf();
/// Creates a FileStreamBuf.
~FileStreamBuf();
~FileStreamBuf() override;
/// Destroys the FileStream.
void open(const std::string& path, std::ios::openmode mode);
@@ -49,10 +49,16 @@ public:
/// Closes the File stream buffer. Returns true if successful,
/// false otherwise.
std::streampos seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode mode = std::ios::in | std::ios::out);
bool resizeBuffer(std::streamsize bufferSize) override;
/// Resizes internal buffer. Minimum size is BUFFER_SIZE.
/// Minimum is used when requested size is smaller.
/// Buffer can be resized only when the file is not open.
/// Returns true if resize succeeded.
std::streampos seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode mode = std::ios::in | std::ios::out) override;
/// Change position by offset, according to way and mode.
std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out);
std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out) override;
/// Change to specified position, according to mode.
void flushToDisk();
@@ -70,13 +76,13 @@ protected:
BUFFER_SIZE = 4096
};
int readFromDevice(char* buffer, std::streamsize length);
int writeToDevice(const char* buffer, std::streamsize length);
int readFromDevice(char* buffer, std::streamsize length) override;
int writeToDevice(const char* buffer, std::streamsize length) override;
private:
std::string _path;
NativeHandle _fd;
std::streamoff _pos;
std::streamoff _pos {0};
};

View File

@@ -25,7 +25,6 @@
namespace Poco {
class Foundation_API FileStreamBuf: public BufferedBidirectionalStreamBuf
/// This stream buffer handles Fileio
{
@@ -48,10 +47,16 @@ public:
/// Closes the File stream buffer. Returns true if successful,
/// false otherwise.
std::streampos seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode mode = std::ios::in | std::ios::out);
bool resizeBuffer(std::streamsize bufferSize) override;
/// Resizes internal buffer. Minimum size is BUFFER_SIZE.
/// Minimum is used when requested size is smaller.
/// Buffer can be resized only when the file is not open.
/// Returns true if resize succeeded.
std::streampos seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode mode = std::ios::in | std::ios::out) override;
/// change position by offset, according to way and mode
std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out);
std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out) override;
/// change to specified position, according to mode
void flushToDisk();
@@ -69,13 +74,13 @@ protected:
BUFFER_SIZE = 4096
};
int readFromDevice(char* buffer, std::streamsize length);
int writeToDevice(const char* buffer, std::streamsize length);
int readFromDevice(char* buffer, std::streamsize length) override;
int writeToDevice(const char* buffer, std::streamsize length) override;
private:
std::string _path;
NativeHandle _handle;
UInt64 _pos;
UInt64 _pos {0};
};