From 88749b5dc18eb5708af20185e4339e76bda6fb72 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 27 Dec 2015 14:29:01 +0100 Subject: 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. --- apt-pkg/contrib/fileutl.cc | 152 +++++++++++++++++++++++++++++++++++++++++++++ apt-pkg/contrib/fileutl.h | 1 + 2 files changed, 153 insertions(+) (limited to 'apt-pkg') 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(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, -- cgit v1.2.3