aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-10-27 09:08:06 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-10-27 13:18:38 +0000
commit9af8a0a6c48085b7e50627ddb7e68dd69614b0dc (patch)
treeffdc9fa6ba42795cc7cdf23b9c68bcbbaf2e7f3d
parent20f5474fe42c320a3a1711e2ae245dee8c74402b (diff)
downloadpaludis-9af8a0a6c48085b7e50627ddb7e68dd69614b0dc.tar.gz
paludis-9af8a0a6c48085b7e50627ddb7e68dd69614b0dc.tar.xz
Better parallel sync for cave.
-rw-r--r--.gitignore1
-rw-r--r--configure.ac36
-rw-r--r--paludis/environment.cc1
-rw-r--r--paludis/util/Makefile.am.m44
-rw-r--r--paludis/util/condition_variable.cc34
-rw-r--r--paludis/util/condition_variable.hh8
-rw-r--r--paludis/util/files.m44
-rw-r--r--paludis/util/output_deviator.cc58
-rw-r--r--paludis/util/output_deviator.hh9
-rw-r--r--paludis/util/sequence.cc29
-rw-r--r--paludis/util/tail_output_stream-fwd.hh28
-rw-r--r--paludis/util/tail_output_stream.cc119
-rw-r--r--paludis/util/tail_output_stream.hh92
-rw-r--r--paludis/util/tail_output_stream_TEST.cc83
-rw-r--r--paludis/util/tee_output_stream-fwd.hh28
-rw-r--r--paludis/util/tee_output_stream.cc23
-rw-r--r--paludis/util/tee_output_stream.hh94
-rw-r--r--src/clients/cave/cmd_sync.cc63
-rw-r--r--src/clients/cave/formats.cc12
-rw-r--r--src/clients/cave/formats.hh2
20 files changed, 692 insertions, 36 deletions
diff --git a/.gitignore b/.gitignore
index 8e6a4b6..c958429 100644
--- a/.gitignore
+++ b/.gitignore
@@ -367,6 +367,7 @@ paludis-*.*.*.tar.bz2
/paludis/util/stringify_TEST
/paludis/util/strip_TEST
/paludis/util/system_TEST
+/paludis/util/tail_output_stream_TEST
/paludis/util/thread_TEST
/paludis/util/thread_pool_TEST
/paludis/util/tokeniser_TEST
diff --git a/configure.ac b/configure.ac
index a1fdd14..3aa6b52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -554,6 +554,7 @@ fi
AC_MSG_CHECKING([whether to enable threads])
PTHREAD_LIBS=""
+RT_LIBS=""
AC_ARG_ENABLE([threads],
AS_HELP_STRING([--enable-threads], [Enable threads (experimental)]),
[ENABLE_THREADS=$enableval],
@@ -597,11 +598,46 @@ int main(int, char **)
PTHREAD_LIBS="-pthread -lpthread"
PALUDIS_PC_LIBS="${PALUDIS_PC_LIBS} -pthread -lpthread"
PALUDIS_ENABLE_THREADS=1
+
+ AC_MSG_CHECKING([how to get clock_gettime])
+ AC_LINK_IFELSE([
+#include <time.h>
+#include <sys/time.h>
+int main(int, char **)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+}
+],
+ [AC_MSG_RESULT([already have it])],
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="-lrt $LDFLAGS"
+ AC_LINK_IFELSE([
+#include <time.h>
+#include <sys/time.h>
+int main(int, char **)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+}
+],
+ [
+ AC_MSG_RESULT([-lrt])
+ RT_LIBS="-lrt"
+ ],
+ [
+ AC_MSG_RESULT([don't know])
+ AC_MSG_ERROR([enable-threads needs clock_gettime])
+ ])
+ LDFLAGS=$save_LDFLAGS
+ ])
+
else
PALUDIS_ENABLE_THREADS=0
fi
AC_SUBST([PALUDIS_ENABLE_THREADS])
AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([RT_LIBS])
PALUDIS_CXXFLAGS_NO_WOLD_STYLE_CAST=
PALUDIS_CXXFLAGS_NO_WREDUNDANT_DECLS=
diff --git a/paludis/environment.cc b/paludis/environment.cc
index cb482d9..aad5bf4 100644
--- a/paludis/environment.cc
+++ b/paludis/environment.cc
@@ -26,7 +26,6 @@
using namespace paludis;
-template class Sequence<std::string>;
template class WrappedForwardIterator<Sequence<std::string>::ConstIteratorTag, const std::string>;
template class WrappedOutputIterator<Sequence<std::string>::InserterTag, std::string>;
diff --git a/paludis/util/Makefile.am.m4 b/paludis/util/Makefile.am.m4
index 6697248..d1e5d42 100644
--- a/paludis/util/Makefile.am.m4
+++ b/paludis/util/Makefile.am.m4
@@ -79,8 +79,8 @@ EXTRA_DIST = util.hh.m4 Makefile.am.m4 files.m4 srlist srcleanlist selist seclea
SUBDIRS = .
libpaludisutil_@PALUDIS_PC_SLOT@_la_SOURCES = filelist
-libpaludisutil_@PALUDIS_PC_SLOT@_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0 $(PTHREAD_LIBS)
-libpaludisutil_@PALUDIS_PC_SLOT@_la_LIBADD = $(PTHREAD_LIBS)
+libpaludisutil_@PALUDIS_PC_SLOT@_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0 $(PTHREAD_LIBS) $(RT_LIBS)
+libpaludisutil_@PALUDIS_PC_SLOT@_la_LIBADD = $(PTHREAD_LIBS) $(RT_LIBS)
TESTS = testlist
diff --git a/paludis/util/condition_variable.cc b/paludis/util/condition_variable.cc
index bc55da3..a56f780 100644
--- a/paludis/util/condition_variable.cc
+++ b/paludis/util/condition_variable.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2007 Ciaran McCreesh
+ * Copyright (c) 2007, 2008 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -18,6 +18,13 @@
*/
#include <paludis/util/condition_variable.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/log.hh>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <cstring>
using namespace paludis;
@@ -60,6 +67,25 @@ ConditionVariable::wait(Mutex & m)
pthread_cond_wait(_cond, m.posix_mutex());
}
+bool
+ConditionVariable::timed_wait(Mutex & m, const unsigned n)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+ t.tv_sec += n;
+ int r(pthread_cond_timedwait(_cond, m.posix_mutex(), &t));
+
+ if (0 == r)
+ return true;
+ else
+ {
+ if (ETIMEDOUT != r)
+ Log::get_instance()->message("condition_variable.timed_wait_failed", ll_warning, lc_context)
+ << "pthread_cond_timedwait returned " << std::strerror(r) << ", something icky happened";
+ return false;
+ }
+}
+
#else
ConditionVariable::ConditionVariable()
@@ -90,5 +116,11 @@ ConditionVariable::wait(Mutex &)
{
}
+bool
+ConditionVariable::timed_wait(Mutex &, const unsigned)
+{
+ return true;
+}
+
#endif
diff --git a/paludis/util/condition_variable.hh b/paludis/util/condition_variable.hh
index 404f990..4e8c73d 100644
--- a/paludis/util/condition_variable.hh
+++ b/paludis/util/condition_variable.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2007 Ciaran McCreesh
+ * Copyright (c) 2007, 2008 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -86,6 +86,12 @@ namespace paludis
* Wait, using the specified Mutex for synchronisation.
*/
void wait(Mutex &);
+
+ /**
+ * Wait, using the specified Mutex for synchronisation,
+ * but return false if more than n seconds elapse.
+ */
+ bool timed_wait(Mutex &, const unsigned n);
};
}
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index 4472511..192c7e0 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -53,7 +53,7 @@ add(`random', `hh', `cc', `test')
add(`remove_shared_ptr', `hh')
add(`rmd160', `hh', `cc', `test')
add(`save', `hh', `test')
-add(`sequence', `hh', `fwd', `impl')
+add(`sequence', `hh', `fwd', `impl', `cc')
add(`set', `hh', `fwd', `impl')
add(`sha1', `hh', `cc', `test')
add(`sha256', `hh', `cc', `test')
@@ -62,6 +62,8 @@ add(`sr', `hh', `cc')
add(`stringify', `hh', `test')
add(`strip', `hh', `cc', `test')
add(`system', `hh', `cc', `test', `testscript')
+add(`tail_output_stream', `hh', `cc', `fwd', `test')
+add(`tee_output_stream', `hh', `cc', `fwd')
add(`thread', `hh', `cc', `test')
add(`thread_pool', `hh', `cc', `test')
add(`tokeniser', `hh', `cc', `test')
diff --git a/paludis/util/output_deviator.cc b/paludis/util/output_deviator.cc
index 3ba7d9f..ef32d05 100644
--- a/paludis/util/output_deviator.cc
+++ b/paludis/util/output_deviator.cc
@@ -23,13 +23,15 @@
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/log.hh>
-#include <paludis/util/fd_output_stream.hh>
+#include <paludis/util/tee_output_stream.hh>
+#include <paludis/util/tail_output_stream.hh>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctime>
#include <unistd.h>
#include <iostream>
+#include <fstream>
namespace paludis
{
@@ -48,18 +50,25 @@ namespace paludis
struct Implementation<OutputDeviant>
{
const FSEntry file_name;
- int descriptor;
- std::tr1::shared_ptr<FDOutputStream> stream;
+ std::tr1::shared_ptr<TeeOutputStream> tee_stream;
+ std::tr1::shared_ptr<std::ofstream> f_stream;
+ std::tr1::shared_ptr<TailOutputStream> tail_stream;
- Implementation(const FSEntry & f) :
+ Implementation(const FSEntry & f, const unsigned int number_of_tail_lines) :
file_name(f),
- descriptor(open(stringify(f).c_str(), O_CREAT | O_WRONLY, 0644))
+ f_stream(new std::ofstream(stringify(file_name).c_str()))
{
- if (-1 == descriptor)
+ if (! *f_stream)
+ {
Log::get_instance()->message("output_deviator.open_failed", ll_warning, lc_context) << "Cannot open '"
- << f << + "' for write, sending output to stdout and stderr instead";
+ << file_name << + "' for write, sending output to stdout and stderr instead";
+ f_stream.reset();
+ }
else
- stream.reset(new FDOutputStream(descriptor));
+ {
+ tail_stream.reset(new TailOutputStream(number_of_tail_lines));
+ tee_stream.reset(new TeeOutputStream(f_stream.get(), tail_stream.get()));
+ }
}
};
}
@@ -74,31 +83,25 @@ OutputDeviator::~OutputDeviator()
}
const std::tr1::shared_ptr<OutputDeviant>
-OutputDeviator::make_output_deviant(const std::string & n)
+OutputDeviator::make_output_deviant(const std::string & n, const unsigned number_of_tail_lines)
{
- return make_shared_ptr(new OutputDeviant(_imp->log_dir / (n + "." + stringify(std::time(0)) + ".log")));
+ return make_shared_ptr(new OutputDeviant(_imp->log_dir / (n + "." + stringify(std::time(0)) + ".log"), number_of_tail_lines));
}
-OutputDeviant::OutputDeviant(const FSEntry & f) :
- PrivateImplementationPattern<OutputDeviant>(new Implementation<OutputDeviant>(f))
+OutputDeviant::OutputDeviant(const FSEntry & f, const unsigned int n) :
+ PrivateImplementationPattern<OutputDeviant>(new Implementation<OutputDeviant>(f, n))
{
}
OutputDeviant::~OutputDeviant()
{
- if (_imp->descriptor != 1)
- {
- if (0 != ::close(_imp->descriptor))
- Log::get_instance()->message("output_deviant.close_failed", ll_warning, lc_context)
- << "Cannot close '" << _imp->file_name << "'";
- }
}
std::ostream *
OutputDeviant::stdout_stream() const
{
- if (_imp->stream)
- return _imp->stream.get();
+ if (_imp->tee_stream)
+ return _imp->tee_stream.get();
else
return &std::cout;
}
@@ -106,8 +109,8 @@ OutputDeviant::stdout_stream() const
std::ostream *
OutputDeviant::stderr_stream() const
{
- if (_imp->stream)
- return _imp->stream.get();
+ if (_imp->tee_stream)
+ return _imp->tee_stream.get();
else
return &std::cerr;
}
@@ -115,7 +118,7 @@ OutputDeviant::stderr_stream() const
void
OutputDeviant::discard_log()
{
- if (-1 != _imp->descriptor)
+ if (_imp->f_stream)
if (-1 == ::unlink(stringify(_imp->file_name).c_str()))
Log::get_instance()->message("output_deviant.unlink_failed", ll_warning, lc_context)
<< "Cannot unlink '" << _imp->file_name << "'";
@@ -127,6 +130,15 @@ OutputDeviant::log_file_name() const
return _imp->file_name;
}
+const std::tr1::shared_ptr<const Sequence<std::string> >
+OutputDeviant::tail(const bool clear) const
+{
+ if (_imp->tail_stream)
+ return _imp->tail_stream->tail(clear);
+ else
+ return make_null_shared_ptr();
+}
+
template class PrivateImplementationPattern<OutputDeviator>;
template class PrivateImplementationPattern<OutputDeviant>;
diff --git a/paludis/util/output_deviator.hh b/paludis/util/output_deviator.hh
index e1bb168..f572e9c 100644
--- a/paludis/util/output_deviator.hh
+++ b/paludis/util/output_deviator.hh
@@ -23,6 +23,7 @@
#include <paludis/util/output_deviator-fwd.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/fs_entry-fwd.hh>
+#include <paludis/util/sequence-fwd.hh>
#include <tr1/memory>
using namespace paludis;
@@ -36,7 +37,8 @@ namespace paludis
OutputDeviator(const FSEntry & log_dir);
~OutputDeviator();
- const std::tr1::shared_ptr<OutputDeviant> make_output_deviant(const std::string &) PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<OutputDeviant> make_output_deviant(
+ const std::string &, const unsigned int number_of_tail_lines) PALUDIS_ATTRIBUTE((warn_unused_result));
};
class PALUDIS_VISIBLE OutputDeviant :
@@ -45,7 +47,7 @@ namespace paludis
friend class OutputDeviator;
private:
- OutputDeviant(const FSEntry &);
+ OutputDeviant(const FSEntry &, const unsigned int);
public:
~OutputDeviant();
@@ -55,6 +57,9 @@ namespace paludis
void discard_log();
const FSEntry log_file_name() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ const std::tr1::shared_ptr<const Sequence<std::string> > tail(const bool clear) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
};
#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
diff --git a/paludis/util/sequence.cc b/paludis/util/sequence.cc
new file mode 100644
index 0000000..9c8cefd
--- /dev/null
+++ b/paludis/util/sequence.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/sequence-impl.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/util/wrapped_output_iterator-impl.hh>
+
+using namespace paludis;
+
+template class Sequence<std::string>;
+template class WrappedForwardIterator<Sequence<std::string>::ConstIteratorTag, const std::string>;
+template class WrappedOutputIterator<Sequence<std::string>::InserterTag, std::string>;
+
diff --git a/paludis/util/tail_output_stream-fwd.hh b/paludis/util/tail_output_stream-fwd.hh
new file mode 100644
index 0000000..58d9767
--- /dev/null
+++ b/paludis/util/tail_output_stream-fwd.hh
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_TAIL_OUTPUT_STREAM_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_TAIL_OUTPUT_STREAM_FWD_HH 1
+
+namespace paludis
+{
+ class TailOutputStream;
+}
+
+#endif
diff --git a/paludis/util/tail_output_stream.cc b/paludis/util/tail_output_stream.cc
new file mode 100644
index 0000000..4c1cbdd
--- /dev/null
+++ b/paludis/util/tail_output_stream.cc
@@ -0,0 +1,119 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/tail_output_stream.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <tr1/functional>
+#include <algorithm>
+#include <list>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<TailOutputStreamBuf>
+ {
+ unsigned int n;
+ const unsigned int size;
+ std::list<std::string> tail;
+
+ Mutex mutex;
+
+ Implementation(const unsigned int nn) :
+ n(1),
+ size(nn)
+ {
+ tail.push_back("");
+ }
+ };
+}
+
+TailOutputStreamBuf::TailOutputStreamBuf(const unsigned int n) :
+ PrivateImplementationPattern<TailOutputStreamBuf>(new Implementation<TailOutputStreamBuf>(n))
+{
+}
+
+TailOutputStreamBuf::~TailOutputStreamBuf()
+{
+}
+
+TailOutputStreamBuf::int_type
+TailOutputStreamBuf::overflow(int_type c)
+{
+ if (c != EOF)
+ _append(std::string(1, c));
+ return c;
+}
+
+std::streamsize
+TailOutputStreamBuf::xsputn(const char * s, std::streamsize num)
+{
+ _append(std::string(s, num));
+ return num;
+}
+
+void
+TailOutputStreamBuf::_append(const std::string & s)
+{
+ Lock lock(_imp->mutex);
+ for (std::string::size_type p(0), p_end(s.length()) ; p != p_end ; ++p)
+ {
+ if ('\n' == s[p])
+ {
+ if (++_imp->n > _imp->size + 1)
+ {
+ _imp->tail.pop_front();
+ --_imp->n;
+ }
+ _imp->tail.push_back("");
+ }
+ else
+ _imp->tail.back().append(&s[p], 1);
+ }
+}
+
+const std::tr1::shared_ptr<const Sequence<std::string> >
+TailOutputStreamBuf::tail(const bool clear)
+{
+ std::tr1::shared_ptr<Sequence<std::string> > result(new Sequence<std::string>);
+ Lock lock(_imp->mutex);
+ for (std::list<std::string>::const_iterator i(_imp->tail.begin()), i_end(_imp->tail.end()), i_last(previous(_imp->tail.end())) ;
+ i != i_end ; ++i)
+ {
+ if (i == i_last && i->empty())
+ continue;
+ result->push_back(*i);
+ }
+
+ if (clear)
+ {
+ Lock lock(_imp->mutex);
+ _imp->tail.clear();
+ _imp->n = 1;
+ _imp->tail.push_back("");
+ }
+
+ return result;
+}
+
+template class PrivateImplementationPattern<TailOutputStreamBuf>;
+
diff --git a/paludis/util/tail_output_stream.hh b/paludis/util/tail_output_stream.hh
new file mode 100644
index 0000000..ac2767b
--- /dev/null
+++ b/paludis/util/tail_output_stream.hh
@@ -0,0 +1,92 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_TAIL_OUTPUT_STREAM_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_TAIL_OUTPUT_STREAM_HH 1
+
+#include <paludis/util/tail_output_stream-fwd.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/sequence.hh>
+#include <tr1/memory>
+#include <ostream>
+
+namespace paludis
+{
+ class PALUDIS_VISIBLE TailOutputStreamBuf :
+ public std::streambuf,
+ private PrivateImplementationPattern<TailOutputStreamBuf>
+ {
+ private:
+ void _append(const std::string &);
+
+ protected:
+ virtual int_type
+ overflow(int_type c);
+
+ virtual std::streamsize
+ xsputn(const char * s, std::streamsize num);
+
+ public:
+ TailOutputStreamBuf(const unsigned n);
+ ~TailOutputStreamBuf();
+
+ const std::tr1::shared_ptr<const Sequence<std::string> > tail(const bool clear);
+ };
+
+ class PALUDIS_VISIBLE TailOutputStreamBase
+ {
+ protected:
+ TailOutputStreamBuf buf;
+
+ public:
+ TailOutputStreamBase(const unsigned n) :
+ buf(n)
+ {
+ }
+ };
+
+ class PALUDIS_VISIBLE TailOutputStream :
+ protected TailOutputStreamBase,
+ public std::ostream
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ TailOutputStream(const unsigned n) :
+ TailOutputStreamBase(n),
+ std::ostream(&buf)
+ {
+ }
+
+ const std::tr1::shared_ptr<const Sequence<std::string> > tail(const bool clear_after)
+ {
+ return buf.tail(clear_after);
+ }
+
+ ///\}
+ };
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<TailOutputStreamBuf>;
+#endif
+}
+
+#endif
diff --git a/paludis/util/tail_output_stream_TEST.cc b/paludis/util/tail_output_stream_TEST.cc
new file mode 100644
index 0000000..590ee51
--- /dev/null
+++ b/paludis/util/tail_output_stream_TEST.cc
@@ -0,0 +1,83 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/tail_output_stream.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ struct TailOutputStreamTest : TestCase
+ {
+ TailOutputStreamTest() : TestCase("tail output stream") { }
+
+ void run()
+ {
+ TailOutputStream s(5);
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(false));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "");
+ }
+
+ s << "one" << std::endl;
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(false));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "one");
+ }
+
+ s << "two" << std::endl;
+ s << "three" << std::endl;
+ s << "four" << std::endl;
+ s << "five" << std::endl;
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(false));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "one/two/three/four/five");
+ }
+
+ s << "six" << std::endl;
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(true));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "two/three/four/five/six");
+ }
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(false));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "");
+ }
+
+ s << "seven" << std::endl;
+ s << "eight" << std::endl;
+
+ {
+ std::tr1::shared_ptr<const Sequence<std::string> > a(s.tail(false));
+ TEST_CHECK_EQUAL(join(a->begin(), a->end(), "/"), "seven/eight");
+ }
+ }
+ } test_tail_output_stream;
+}
+
diff --git a/paludis/util/tee_output_stream-fwd.hh b/paludis/util/tee_output_stream-fwd.hh
new file mode 100644
index 0000000..976a784
--- /dev/null
+++ b/paludis/util/tee_output_stream-fwd.hh
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_TEE_OUTPUT_STREAM_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_TEE_OUTPUT_STREAM_FWD_HH 1
+
+namespace paludis
+{
+ class TeeOutputStream;
+}
+
+#endif
diff --git a/paludis/util/tee_output_stream.cc b/paludis/util/tee_output_stream.cc
new file mode 100644
index 0000000..b0b74e5
--- /dev/null
+++ b/paludis/util/tee_output_stream.cc
@@ -0,0 +1,23 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/tee_output_stream.hh>
+
+using namespace paludis;
+
diff --git a/paludis/util/tee_output_stream.hh b/paludis/util/tee_output_stream.hh
new file mode 100644
index 0000000..0df44df
--- /dev/null
+++ b/paludis/util/tee_output_stream.hh
@@ -0,0 +1,94 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_TEE_OUTPUT_STREAM_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_TEE_OUTPUT_STREAM_HH 1
+
+#include <paludis/util/tee_output_stream-fwd.hh>
+#include <paludis/util/attributes.hh>
+#include <ostream>
+
+namespace paludis
+{
+ class PALUDIS_VISIBLE TeeOutputStreamBuf :
+ public std::streambuf
+ {
+ private:
+ std::ostream * const s1;
+ std::ostream * const s2;
+
+ protected:
+ virtual int_type
+ overflow(int_type c)
+ {
+ if (c != EOF)
+ {
+ s1->put(c);
+ s2->put(c);
+ }
+ return c;
+ }
+
+ virtual std::streamsize
+ xsputn(const char * s, std::streamsize num)
+ {
+ s1->write(s, num);
+ s2->write(s, num);
+ return num;
+ }
+
+ public:
+ TeeOutputStreamBuf(std::ostream * const b1, std::ostream * const b2) :
+ s1(b1),
+ s2(b2)
+ {
+ }
+ };
+
+ class PALUDIS_VISIBLE TeeOutputStreamBase
+ {
+ protected:
+ TeeOutputStreamBuf buf;
+
+ public:
+ TeeOutputStreamBase(std::ostream * const b1, std::ostream * const b2) :
+ buf(b1, b2)
+ {
+ }
+ };
+
+ class PALUDIS_VISIBLE TeeOutputStream :
+ protected TeeOutputStreamBase,
+ public std::ostream
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ TeeOutputStream(std::ostream * const b1, std::ostream * const b2) :
+ TeeOutputStreamBase(b1, b2),
+ std::ostream(&buf)
+ {
+ }
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/src/clients/cave/cmd_sync.cc b/src/clients/cave/cmd_sync.cc
index 22d4930..6a1e333 100644
--- a/src/clients/cave/cmd_sync.cc
+++ b/src/clients/cave/cmd_sync.cc
@@ -28,6 +28,8 @@
#include <paludis/util/output_deviator.hh>
#include <paludis/util/named_value.hh>
#include <paludis/util/make_named_values.hh>
+#include <paludis/util/condition_variable.hh>
+#include <paludis/util/thread.hh>
#include <paludis/repository.hh>
#include <paludis/environment.hh>
#include <paludis/hook.hh>
@@ -88,6 +90,37 @@ namespace
typedef std::map<std::string, Message> Messages;
+ void do_one_sync_notifier(const RepositoryName & r, Mutex & notifier_mutex,
+ Mutex & count_mutex, ConditionVariable & notifier_condition, int & np, int & na, int & nd,
+ bool & finished, OutputDeviant & output_deviant)
+ {
+ bool first(true);
+ while (true)
+ {
+ {
+ Lock lock(count_mutex);
+ if (finished)
+ return;
+
+ if (! first)
+ {
+ cout << format_general_spad(f::sync_repo_active(), stringify(r), np, na, nd);
+ std::tr1::shared_ptr<const Sequence<std::string> > tail(output_deviant.tail(true));
+ if (tail && tail->begin() != tail->end())
+ {
+ for (Sequence<std::string>::ConstIterator t(tail->begin()), t_end(tail->end()) ;
+ t != t_end ; ++t)
+ cout << format_general_s(f::sync_repo_tail(), *t);
+ }
+ }
+ }
+
+ Lock lock(notifier_mutex);
+ notifier_condition.timed_wait(notifier_mutex, 10);
+ first = false;
+ }
+ }
+
void do_one_sync(const std::tr1::shared_ptr<Environment> & env, const RepositoryName & r, Mutex & mutex,
Messages & messages, int & retcode, int & np, int & na, int & nd,
OutputDeviator & output_deviator)
@@ -96,7 +129,7 @@ namespace
{
Lock lock(mutex);
- output_deviant = output_deviator.make_output_deviant("sync-" + stringify(r));
+ output_deviant = output_deviator.make_output_deviant("sync-" + stringify(r), 10);
}
bool done_decrement(false);
@@ -122,7 +155,26 @@ namespace
if (! repo->syncable_interface())
throw BadRepositoryForCommand(r, "does not support syncing");
- bool result(repo->syncable_interface()->sync(output_deviant));
+ bool result(false);
+ {
+ Mutex notifier_mutex;
+ ConditionVariable notifier_condition;
+ bool finished(false);
+ Thread notifier_thread(std::tr1::bind(&do_one_sync_notifier, r,
+ std::tr1::ref(notifier_mutex), std::tr1::ref(mutex),
+ std::tr1::ref(notifier_condition),
+ std::tr1::ref(np), std::tr1::ref(na), std::tr1::ref(nd),
+ std::tr1::ref(finished), std::tr1::ref(*output_deviant)));
+
+ result = repo->syncable_interface()->sync(output_deviant);
+
+ {
+ Lock lock(mutex);
+ finished = true;
+ }
+
+ notifier_condition.acquire_then_signal(notifier_mutex);
+ }
{
Lock lock(mutex);
@@ -228,13 +280,14 @@ SyncCommand::run(
{
Mutex mutex;
- ActionQueue actions(5);
int active(0), done(0), pending(repos.size());
+
+ ActionQueue actions(5);
for (std::set<RepositoryName, RepositoryNameComparator>::const_iterator r(repos.begin()), r_end(repos.end()) ;
r != r_end ; ++r)
actions.enqueue(std::tr1::bind(&do_one_sync, env, *r, std::tr1::ref(mutex),
- std::tr1::ref(messages), std::tr1::ref(retcode), std::tr1::ref(pending), std::tr1::ref(active), std::tr1::ref(done),
- std::tr1::ref(output_deviator)));
+ std::tr1::ref(messages), std::tr1::ref(retcode), std::tr1::ref(pending),
+ std::tr1::ref(active), std::tr1::ref(done), std::tr1::ref(output_deviator)));
}
if (0 != env->perform_hook(Hook("sync_all_post")
diff --git a/src/clients/cave/formats.cc b/src/clients/cave/formats.cc
index b20114d..11f8f03 100644
--- a/src/clients/cave/formats.cc
+++ b/src/clients/cave/formats.cc
@@ -448,3 +448,15 @@ paludis::cave::f::sync_repo_done_failure()
return "-> " + c::bold_red() + "%s" + c::normal() + "%{column 30}failed%{column 52}%p%{column 60}%a%{column 68}%d\\n";
}
+const std::string
+paludis::cave::f::sync_repo_active()
+{
+ return "-> %s%{column 30}active%{column 52}%p%{column 60}%a%{column 68}%d\\n";
+}
+
+const std::string
+paludis::cave::f::sync_repo_tail()
+{
+ return " ... %s\\n";
+}
+
diff --git a/src/clients/cave/formats.hh b/src/clients/cave/formats.hh
index a3a26cd..31cbbcb 100644
--- a/src/clients/cave/formats.hh
+++ b/src/clients/cave/formats.hh
@@ -125,6 +125,8 @@ namespace paludis
const std::string sync_repo_done_success();
const std::string sync_repo_done_no_syncing_required();
const std::string sync_repo_done_failure();
+ const std::string sync_repo_active();
+ const std::string sync_repo_tail();
}
}
}