dovecot-2.2: iostream-temp: Avoid copying data if IOSTREAM_TEMP_...
dovecot at dovecot.org
dovecot at dovecot.org
Sun Feb 3 21:53:48 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/50d43f04511b
changeset: 15721:50d43f04511b
user: Timo Sirainen <tss at iki.fi>
date: Sun Feb 03 21:53:24 2013 +0200
description:
iostream-temp: Avoid copying data if IOSTREAM_TEMP_FLAG_TRY_FD_DUP is set.
diffstat:
src/lib/iostream-temp.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++-
src/lib/iostream-temp.h | 10 +++-
2 files changed, 114 insertions(+), 5 deletions(-)
diffs (179 lines):
diff -r 42e152c01ace -r 50d43f04511b src/lib/iostream-temp.c
--- a/src/lib/iostream-temp.c Sun Feb 03 21:52:48 2013 +0200
+++ b/src/lib/iostream-temp.c Sun Feb 03 21:53:24 2013 +0200
@@ -5,7 +5,7 @@
#include "str.h"
#include "safe-mkstemp.h"
#include "write-full.h"
-#include "istream.h"
+#include "istream-private.h"
#include "ostream-private.h"
#include "iostream-temp.h"
@@ -15,7 +15,13 @@
struct temp_ostream {
struct ostream_private ostream;
+
char *temp_path_prefix;
+ enum iostream_temp_flags flags;
+
+ struct istream *dupstream;
+ uoff_t dupstream_offset, dupstream_start_offset;
+
buffer_t *buf;
int fd;
bool fd_tried;
@@ -87,6 +93,8 @@
ssize_t ret = 0;
unsigned int i;
+ tstream->flags &= ~IOSTREAM_TEMP_FLAG_TRY_FD_DUP;
+
if (tstream->fd != -1)
return o_stream_temp_fd_sendv(tstream, iov, iov_count);
@@ -105,15 +113,91 @@
return ret;
}
-struct ostream *iostream_temp_create(const char *temp_path_prefix)
+static int o_stream_temp_dup_cancel(struct temp_ostream *tstream)
+{
+ struct istream *input;
+ uoff_t size = tstream->dupstream_offset -
+ tstream->dupstream_start_offset;
+ off_t ret;
+
+ i_stream_seek(tstream->dupstream, tstream->dupstream_start_offset);
+
+ input = i_stream_create_limit(tstream->dupstream, size);
+ do {
+ ret = io_stream_copy(&tstream->ostream.ostream,
+ input, IO_BLOCK_SIZE);
+ } while (input->v_offset < tstream->dupstream_offset && ret > 0);
+ if (ret < 0 && tstream->ostream.ostream.stream_errno == 0) {
+ i_assert(input->stream_errno != 0);
+ tstream->ostream.ostream.stream_errno = input->stream_errno;
+ }
+ i_stream_destroy(&input);
+ i_stream_unref(&tstream->dupstream);
+ return ret < 0 ? -1 : 0;
+}
+
+static int o_stream_temp_dup_istream(struct temp_ostream *outstream,
+ struct istream *instream)
+{
+ uoff_t in_size;
+ off_t ret;
+
+ if (!instream->readable_fd || i_stream_get_fd(instream) == -1)
+ return 0;
+
+ if (i_stream_get_size(instream, TRUE, &in_size) <= 0) {
+ if (outstream->dupstream != NULL)
+ return o_stream_temp_dup_cancel(outstream);
+ return 0;
+ }
+
+ if (outstream->dupstream == NULL) {
+ outstream->dupstream = instream;
+ outstream->dupstream_start_offset = instream->v_offset;
+ i_stream_ref(outstream->dupstream);
+ } else {
+ if (outstream->dupstream != instream ||
+ outstream->dupstream_offset != instream->v_offset ||
+ outstream->dupstream_offset > in_size)
+ return o_stream_temp_dup_cancel(outstream);
+ }
+ ret = in_size - instream->v_offset;
+ i_stream_seek(instream, in_size);
+ outstream->dupstream_offset = instream->v_offset;
+ return ret;
+}
+
+static off_t o_stream_temp_send_istream(struct ostream_private *_outstream,
+ struct istream *instream)
+{
+ struct temp_ostream *outstream = (struct temp_ostream *)_outstream;
+ uoff_t orig_offset;
+ int ret;
+
+ if ((outstream->flags & IOSTREAM_TEMP_FLAG_TRY_FD_DUP) != 0) {
+ orig_offset = outstream->dupstream_offset;
+ if ((ret = o_stream_temp_dup_istream(outstream, instream)) > 0)
+ return outstream->dupstream_offset - orig_offset;
+ if (ret < 0)
+ return -1;
+ outstream->flags &= ~IOSTREAM_TEMP_FLAG_TRY_FD_DUP;
+ }
+ return io_stream_copy(&outstream->ostream.ostream,
+ instream, IO_BLOCK_SIZE);
+}
+
+struct ostream *iostream_temp_create(const char *temp_path_prefix,
+ enum iostream_temp_flags flags)
{
struct temp_ostream *tstream;
struct ostream *output;
tstream = i_new(struct temp_ostream, 1);
tstream->ostream.sendv = o_stream_temp_sendv;
+ tstream->ostream.send_istream = o_stream_temp_send_istream;
tstream->ostream.iostream.close = o_stream_temp_close;
tstream->temp_path_prefix = i_strdup(temp_path_prefix);
+ tstream->flags = flags;
tstream->buf = buffer_create_dynamic(default_pool, 8192);
tstream->fd = -1;
@@ -132,9 +216,26 @@
{
struct temp_ostream *tstream =
(struct temp_ostream *)(*output)->real_stream;
- struct istream *input;
+ struct istream *input, *input2;
+ uoff_t abs_offset, size;
+ int fd;
- if (tstream->fd != -1) {
+ if (tstream->dupstream != NULL) {
+ abs_offset = tstream->dupstream->real_stream->abs_start_offset +
+ tstream->dupstream_start_offset;
+ size = tstream->dupstream_offset -
+ tstream->dupstream_start_offset;
+ fd = dup(i_stream_get_fd(tstream->dupstream));
+ if (fd == -1)
+ input = i_stream_create_error(errno);
+ else {
+ input2 = i_stream_create_fd(fd, max_buffer_size, TRUE);
+ i_stream_seek(input2, abs_offset);
+ input = i_stream_create_limit(input2, size);
+ i_stream_unref(&input2);
+ }
+ i_stream_unref(&tstream->dupstream);
+ } else if (tstream->fd != -1) {
input = i_stream_create_fd(tstream->fd, max_buffer_size, TRUE);
tstream->fd = -1;
} else {
diff -r 42e152c01ace -r 50d43f04511b src/lib/iostream-temp.h
--- a/src/lib/iostream-temp.h Sun Feb 03 21:52:48 2013 +0200
+++ b/src/lib/iostream-temp.h Sun Feb 03 21:53:24 2013 +0200
@@ -1,9 +1,17 @@
#ifndef IOSTREAM_TEMP_H
#define IOSTREAM_TEMP_H
+enum iostream_temp_flags {
+ /* if o_stream_send_istream() is called with a readable fd, don't
+ actually copy the input stream, just have iostream_temp_finish()
+ return a new iostream pointing to the fd dup()ed */
+ IOSTREAM_TEMP_FLAG_TRY_FD_DUP = 0x01
+};
+
/* Start writing to given output stream. The data is initially written to
memory, and later to a temporary file that is immediately unlinked. */
-struct ostream *iostream_temp_create(const char *temp_path_prefix);
+struct ostream *iostream_temp_create(const char *temp_path_prefix,
+ enum iostream_temp_flags flags);
/* Finished writing to stream. Return input stream for it and free the
output stream. */
struct istream *iostream_temp_finish(struct ostream **output,
More information about the dovecot-cvs
mailing list