Some libvirt functions use streams, this patch add compress stream support. So VolumeDownload/VolumeUpload can greatly speedup by using compressed streams to save network bandtwidth and don't transfer zero bytes (in case of raw disk format) Signed-off-by: Vasiliy Tolstov <v.tolstov@xxxxxxxxx> --- configure.ac | 2 ++ daemon/Makefile.am | 3 +++ include/libvirt/libvirt-stream.h | 3 +++ m4/virt-archive.m4 | 29 ++++++++++++++++++++++++++ src/Makefile.am | 17 +++++++++++----- src/datatypes.h | 7 +++++++ src/fdstream.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/libvirt-stream.c | 15 ++++++++++++++ tools/Makefile.am | 17 ++++++++++++++-- 9 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 m4/virt-archive.m4 diff --git a/configure.ac b/configure.ac index 03463b0..58a15bb 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,7 @@ LIBVIRT_CHECK_SANLOCK LIBVIRT_CHECK_SASL LIBVIRT_CHECK_SELINUX LIBVIRT_CHECK_SSH2 +LIBVIRT_CHECK_LIBARCHIVE LIBVIRT_CHECK_SYSTEMD_DAEMON LIBVIRT_CHECK_UDEV LIBVIRT_CHECK_WIRESHARK @@ -2892,6 +2893,7 @@ LIBVIRT_RESULT_SANLOCK LIBVIRT_RESULT_SASL LIBVIRT_RESULT_SELINUX LIBVIRT_RESULT_SSH2 +LIBVIRT_RESULT_LIBARCHIVE LIBVIRT_RESULT_SYSTEMD_DAEMON LIBVIRT_RESULT_UDEV LIBVIRT_RESULT_WIRESHARK diff --git a/daemon/Makefile.am b/daemon/Makefile.am index be1b5a9..a4d63eb 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -177,17 +177,20 @@ libvirtd_CFLAGS = \ $(XDR_CFLAGS) $(DBUS_CFLAGS) $(LIBNL_CFLAGS) \ $(WARN_CFLAGS) $(PIE_CFLAGS) \ $(COVERAGE_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ -DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\"" libvirtd_LDFLAGS = \ $(RELRO_LDFLAGS) \ $(PIE_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ $(NULL) libvirtd_LDADD = \ $(LIBXML_LIBS) \ + $(LIBARCHIVE_LIBS) \ $(GNUTLS_LIBS) \ $(SASL_LIBS) \ $(DBUS_LIBS) \ diff --git a/include/libvirt/libvirt-stream.h b/include/libvirt/libvirt-stream.h index 831640d..c75f03e 100644 --- a/include/libvirt/libvirt-stream.h +++ b/include/libvirt/libvirt-stream.h @@ -31,10 +31,13 @@ typedef enum { VIR_STREAM_NONBLOCK = (1 << 0), + VIR_STREAM_COMPRESS_GZIP = (1 << 1), + VIR_STREAM_COMPRESS_XZ = (1 << 2), } virStreamFlags; virStreamPtr virStreamNew(virConnectPtr conn, unsigned int flags); + int virStreamRef(virStreamPtr st); int virStreamSend(virStreamPtr st, diff --git a/m4/virt-archive.m4 b/m4/virt-archive.m4 new file mode 100644 index 0000000..9770732 --- /dev/null +++ b/m4/virt-archive.m4 @@ -0,0 +1,29 @@ +dnl The libarchive.so library +dnl +dnl Copyright (C) 2012-2013 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_CHECK_LIBARCHIVE],[ + LIBVIRT_CHECK_PKG([LIBARCHIVE], [libarchive], [3.1.2]) + AC_SUBST(LIBARCHIVE_CFLAGS) + AC_SUBST(LIBARCHIVE_LIBS) + AC_SUBST(LIBARCHIVE_LDFLAGS) +]) + +AC_DEFUN([LIBVIRT_RESULT_LIBARCHIVE],[ + LIBVIRT_RESULT_LIB([LIBARCHIVE]) +]) diff --git a/src/Makefile.am b/src/Makefile.am index 060abe8..429c2c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,11 +25,11 @@ abs_topsrcdir = $(shell cd $(top_srcdir) && pwd) # No libraries with the exception of LIBXML should be listed # here. List them against the individual XXX_la_CFLAGS targets # that actually use them. Also keep GETTEXT_CPPFLAGS at the end. -INCLUDES = -I../gnulib/lib \ +INCLUDES = -I../gnulib/lib \ -I$(top_srcdir)/gnulib/lib \ - -I$(top_srcdir) \ + -I$(top_srcdir) \ -I../include \ - -I$(top_srcdir)/include \ + -I$(top_srcdir)/include \ -I$(srcdir)/util \ -DIN_LIBVIRT \ -Dabs_topbuilddir="\"$(abs_topbuilddir)\"" \ @@ -37,14 +37,16 @@ INCLUDES = -I../gnulib/lib \ $(GETTEXT_CPPFLAGS) AM_CFLAGS = $(LIBXML_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ $(WARN_CFLAGS) \ - $(LOCK_CHECKING_CFLAGS) \ + $(LOCK_CHECKING_CFLAGS) \ $(WIN32_EXTRA_CFLAGS) \ $(COVERAGE_CFLAGS) AM_LDFLAGS = $(DRIVER_MODULE_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ $(RELRO_LDFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) EXTRA_DIST = $(conf_DATA) util/keymaps.csv @@ -1051,11 +1053,13 @@ libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \ $(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \ $(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS) \ $(SYSTEMD_DAEMON_CFLAGS) $(POLKIT_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ -I$(srcdir)/conf libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \ $(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \ $(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \ $(SECDRIVER_LIBS) $(NUMACTL_LIBS) $(SYSTEMD_DAEMON_LIBS) \ + $(LIBARCHIVE_LIBS) \ $(POLKIT_LIBS) @@ -2214,6 +2218,7 @@ libvirt_lxc_la_LDFLAGS = \ $(AM_LDFLAGS) \ $(CYGWIN_EXTRA_LDFLAGS) \ $(MINGW_EXTRA_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) libvirt_lxc_la_CFLAGS = $(AM_CFLAGS) libvirt_lxc_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD) @@ -2292,13 +2297,15 @@ libvirt_setuid_rpc_client_la_SOURCES = \ libvirt_setuid_rpc_client_la_LDFLAGS = \ $(AM_LDFLAGS) \ $(LIBXML_LIBS) \ + $(LIBARCHIVE_LIBS) \ $(SECDRIVER_LIBS) \ $(NULL) libvirt_setuid_rpc_client_la_CFLAGS = \ -DLIBVIRT_SETUID_RPC_CLIENT \ -I$(srcdir)/conf \ - -I$(srcdir)/rpc \ + -I$(srcdir)/rpc \ $(AM_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ $(SECDRIVER_CFLAGS) \ $(XDR_CFLAGS) \ $(NULL) diff --git a/src/datatypes.h b/src/datatypes.h index be108fe..4c0c10d 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -29,6 +29,10 @@ # include "virobject.h" # include "viruuid.h" +#ifdef WITH_LIBARCHIVE +# include <archive.h> +#endif + extern virClassPtr virConnectClass; extern virClassPtr virDomainClass; extern virClassPtr virDomainSnapshotClass; @@ -520,6 +524,9 @@ struct _virStream { virStreamDriverPtr driver; void *privateData; +#ifdef WITH_LIBARCHIVE + struct archive *archive; +#endif }; /** diff --git a/src/fdstream.c b/src/fdstream.c index b8ea86e..9a71a9f 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -33,6 +33,10 @@ #include <netinet/in.h> #include <termios.h> +#ifdef WITH_LIBARCHIVE +# include <archive.h> +#endif + #include "fdstream.h" #include "virerror.h" #include "datatypes.h" @@ -319,6 +323,12 @@ virFDStreamCloseInt(virStreamPtr st, bool streamAbort) if (VIR_CLOSE(fdst->errfd) < 0) VIR_DEBUG("ignoring failed close on fd %d", fdst->errfd); +#ifdef WITH_LIBARCHIVE + if (st->archive != NULL) { + archive_write_free(st->archive); + archive_read_free(st->archive); + } +#endif st->privateData = NULL; /* call the internal stream closing callback */ @@ -385,7 +395,16 @@ static int virFDStreamWrite(virStreamPtr st, const char *bytes, size_t nbytes) } retry: +#ifdef WITH_LIBARCHIVE + if (st->archive != NULL) { + archive_write_open_fd(st->archive, fdst->fd); + ret = archive_write_data(st->archive, bytes, nbytes); + } else { + ret = write(fdst->fd, bytes, nbytes); + } +#else ret = write(fdst->fd, bytes, nbytes); +#endif if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { ret = -2; @@ -397,7 +416,15 @@ static int virFDStreamWrite(virStreamPtr st, const char *bytes, size_t nbytes) _("cannot write to stream")); } } else if (fdst->length) { +#ifdef WITH_LIBARCHIVE + if (st->archive != NULL) { + fdst->offset += nbytes; + } else { + fdst->offset += ret; + } +#else fdst->offset += ret; +#endif } virMutexUnlock(&fdst->lock); @@ -435,7 +462,16 @@ static int virFDStreamRead(virStreamPtr st, char *bytes, size_t nbytes) } retry: +#ifdef WITH_LIBARCHIVE + if (st->archive != NULL) { + archive_read_open_fd(st->archive, fdst->fd, 4096); + ret = archive_read_data(st->archive, bytes, nbytes); + } else { + ret = read(fdst->fd, bytes, nbytes); + } +#else ret = read(fdst->fd, bytes, nbytes); +#endif if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { ret = -2; @@ -447,7 +483,15 @@ static int virFDStreamRead(virStreamPtr st, char *bytes, size_t nbytes) _("cannot read from stream")); } } else if (fdst->length) { +#ifdef WITH_LIBARCHIVE + if (st->archive != NULL) { + fdst->offset += nbytes; + } else { + fdst->offset += ret; + } +#else fdst->offset += ret; +#endif } virMutexUnlock(&fdst->lock); diff --git a/src/libvirt-stream.c b/src/libvirt-stream.c index c16f586..0f09d9d 100644 --- a/src/libvirt-stream.c +++ b/src/libvirt-stream.c @@ -24,6 +24,10 @@ #include "viralloc.h" #include "virlog.h" +#ifdef WITH_LIBARCHIVE +# include <archive.h> +#endif + VIR_LOG_INIT("libvirt.stream"); #define VIR_FROM_THIS VIR_FROM_STREAMS @@ -45,6 +49,7 @@ VIR_LOG_INIT("libvirt.stream"); * * If a non-blocking data stream is required passed * VIR_STREAM_NONBLOCK for flags, otherwise pass 0. + * VIR_STREAM_COMPRESS_GZIP or VIR_STREAM_COMPRESS_XZ * * Returns the new stream, or NULL upon error */ @@ -66,6 +71,16 @@ virStreamNew(virConnectPtr conn, else virDispatchError(conn); + if ((flags & VIR_STREAM_COMPRESS_GZIP) || (flags & VIR_STREAM_COMPRESS_XZ)) { + st->archive = archive_write_new(); + + if (flags & VIR_STREAM_COMPRESS_GZIP) + archive_write_add_filter(st->archive, ARCHIVE_FILTER_GZIP); + + if (flags & VIR_STREAM_COMPRESS_XZ) + archive_write_add_filter(st->archive, ARCHIVE_FILTER_XZ); + } + return st; } diff --git a/tools/Makefile.am b/tools/Makefile.am index 03e9339..fa19a20 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -25,8 +25,12 @@ INCLUDES = \ AM_LDFLAGS = \ $(RELRO_LDFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) +AM_CFLAGS = \ + $(LIBARCHIVE_CFLAGS) + POD2MAN = pod2man -c "Virtualization Support" -r "$(PACKAGE)-$(VERSION)" ICON_FILES = \ @@ -140,15 +144,18 @@ virt_host_validate_LDFLAGS = \ $(AM_LDFLAGS) \ $(PIE_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) virt_host_validate_LDADD = \ ../src/libvirt.la \ - ../gnulib/lib/libgnu.la \ + ../gnulib/lib/libgnu.la \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) virt_host_validate_CFLAGS = \ $(LIBXML_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ $(WARN_CFLAGS) \ $(PIE_CFLAGS) \ $(COVERAGE_CFLAGS) \ @@ -165,15 +172,18 @@ virt_login_shell_SOURCES = \ virt_login_shell_LDFLAGS = \ $(AM_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ + $(LIBARHCIVE_LDFLAGS) \ $(NULL) virt_login_shell_LDADD = \ $(STATIC_BINARIES) \ $(PIE_LDFLAGS) \ ../src/libvirt-setuid-rpc-client.la \ + $(LIBARCHIVE_LDFLAGS) \ ../gnulib/lib/libgnu.la virt_login_shell_CFLAGS = \ -DLIBVIRT_SETUID_RPC_CLIENT \ + $(LIBARCHIVE_CFLAGS) \ $(LIBXML_CFLAGS) \ $(WARN_CFLAGS) \ $(PIE_CFLAGS) \ @@ -202,6 +212,7 @@ virsh_SOURCES = \ virsh_LDFLAGS = \ $(AM_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(NULL) virsh_LDADD = \ $(STATIC_BINARIES) \ @@ -209,14 +220,16 @@ virsh_LDADD = \ ../src/libvirt.la \ ../src/libvirt-lxc.la \ ../src/libvirt-qemu.la \ - ../gnulib/lib/libgnu.la \ + ../gnulib/lib/libgnu.la \ $(LIBXML_LIBS) \ + $(LIBARCHIVE_LIBS) \ $(VIRSH_LIBS) virsh_CFLAGS = \ $(WARN_CFLAGS) \ $(PIE_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(LIBXML_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ $(READLINE_CFLAGS) BUILT_SOURCES = -- 2.5.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list