summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2015-12-27 14:29:01 +0100
committerJulian Andres Klode <jak@debian.org>2015-12-27 16:23:32 +0100
commit88749b5dc18eb5708af20185e4339e76bda6fb72 (patch)
treead65ee47d4e4277461a6e4cc83637b1fc746be0d
parent766761fd836d9e247daea924809965c21cc65dc7 (diff)
FileFd: Add a buffered writing mode
This is somewhat experimental right now, and might not work for everyone, so it is on an opt-in basis.
-rw-r--r--apt-pkg/contrib/fileutl.cc152
-rw-r--r--apt-pkg/contrib/fileutl.h1
2 files changed, 153 insertions, 0 deletions
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index ecc8c83fd..71dfc83a2 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -955,6 +955,7 @@ struct APT_HIDDEN simple_buffer { /*{{{*/
/*}}}*/
class APT_HIDDEN FileFdPrivate { /*{{{*/
+ friend class BufferedWriteFileFdPrivate;
protected:
FileFd * const filefd;
simple_buffer buffer;
@@ -1149,6 +1150,154 @@ public:
virtual ~FileFdPrivate() {}
};
/*}}}*/
+class APT_HIDDEN BufferedWriteFileFdPrivate : public FileFdPrivate { /*{{{*/
+protected:
+ FileFdPrivate *wrapped;
+ simple_buffer writebuffer;
+
+public:
+
+ explicit BufferedWriteFileFdPrivate(FileFdPrivate *Priv) :
+ FileFdPrivate(Priv->filefd), wrapped(Priv) {};
+
+ virtual APT::Configuration::Compressor get_compressor() const override
+ {
+ return wrapped->get_compressor();
+ }
+ virtual void set_compressor(APT::Configuration::Compressor const &compressor) override
+ {
+ return wrapped->set_compressor(compressor);
+ }
+ virtual unsigned int get_openmode() const override
+ {
+ return wrapped->get_openmode();
+ }
+ virtual void set_openmode(unsigned int openmode) override
+ {
+ return wrapped->set_openmode(openmode);
+ }
+ virtual bool get_is_pipe() const override
+ {
+ return wrapped->get_is_pipe();
+ }
+ virtual void set_is_pipe(bool is_pipe) override
+ {
+ FileFdPrivate::set_is_pipe(is_pipe);
+ wrapped->set_is_pipe(is_pipe);
+ }
+ virtual unsigned long long get_seekpos() const override
+ {
+ return wrapped->get_seekpos();
+ }
+ virtual void set_seekpos(unsigned long long seekpos) override
+ {
+ return wrapped->set_seekpos(seekpos);
+ }
+ virtual bool InternalOpen(int const iFd, unsigned int const Mode) override
+ {
+ if (InternalFlush() == false)
+ return false;
+ return wrapped->InternalOpen(iFd, Mode);
+ }
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
+ {
+ if (InternalFlush() == false)
+ return -1;
+ return wrapped->InternalUnbufferedRead(To, Size);
+
+ }
+ virtual bool InternalReadError() override
+ {
+ return wrapped->InternalReadError();
+ }
+ virtual char * InternalReadLine(char * To, unsigned long long Size) override
+ {
+ if (InternalFlush() == false)
+ return nullptr;
+ return wrapped->InternalReadLine(To, Size);
+ }
+ virtual bool InternalFlush() override
+ {
+ size_t written = 0;
+ char *data = writebuffer.get();
+ auto size = writebuffer.size();
+
+ while (written <= size) {
+ auto written_this_time = wrapped->InternalWrite(data + written, size - written);
+ if (written_this_time < 0)
+ return false;
+ if (written_this_time == 0)
+ break;
+
+ written += written_this_time;
+ }
+
+ writebuffer.reset();
+ return true;
+ }
+ virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) override
+ {
+ size_t written = 0;
+
+ while (written < Size) {
+ auto buffered = writebuffer.write(static_cast<char const*>(From) + written, Size - written);
+
+ written += buffered;
+
+ if (writebuffer.full() && InternalFlush() == false)
+ return -1;
+ }
+
+ return written;
+ }
+ virtual bool InternalWriteError()
+ {
+ return wrapped->InternalWriteError();
+ }
+ virtual bool InternalSeek(unsigned long long const To)
+ {
+ if (InternalFlush() == false)
+ return false;
+ return wrapped->InternalSeek(To);
+ }
+ virtual bool InternalSkip(unsigned long long Over)
+ {
+ if (InternalFlush() == false)
+ return false;
+ return wrapped->InternalSkip(Over);
+ }
+ virtual bool InternalTruncate(unsigned long long const Size)
+ {
+ if (InternalFlush() == false)
+ return false;
+ return wrapped->InternalTruncate(Size);
+ }
+ virtual unsigned long long InternalTell()
+ {
+ if (InternalFlush() == false)
+ return -1;
+ return wrapped->InternalTell();
+ }
+ virtual unsigned long long InternalSize()
+ {
+ if (InternalFlush() == false)
+ return -1;
+ return wrapped->InternalSize();
+ }
+ virtual bool InternalClose(std::string const &FileName)
+ {
+ return wrapped->InternalClose(FileName);
+ }
+ virtual bool InternalAlwaysAutoClose() const
+ {
+ return wrapped->InternalAlwaysAutoClose();
+ }
+ virtual ~BufferedWriteFileFdPrivate()
+ {
+ delete wrapped;
+ }
+};
+ /*}}}*/
class APT_HIDDEN GzipFileFdPrivate: public FileFdPrivate { /*{{{*/
#ifdef HAVE_ZLIB
public:
@@ -1985,6 +2134,9 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C
else
d = new PipedFileFdPrivate(this);
+ if (Mode & BufferedWrite)
+ d = new BufferedWriteFileFdPrivate(d);
+
d->set_openmode(Mode);
d->set_compressor(compressor);
if ((Flags & AutoClose) != AutoClose && d->InternalAlwaysAutoClose())
diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h
index 8cfb2e989..8619047a0 100644
--- a/apt-pkg/contrib/fileutl.h
+++ b/apt-pkg/contrib/fileutl.h
@@ -66,6 +66,7 @@ class FileFd
Exclusive = (1 << 3),
Atomic = Exclusive | (1 << 4),
Empty = (1 << 5),
+ BufferedWrite = (1 << 6),
WriteEmpty = ReadWrite | Create | Empty,
WriteExists = ReadWrite,