aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-11-03 11:37:04 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-11-03 11:37:04 +0000
commit5b096137be44c5354713cfc02b30767c7b9da0f6 (patch)
treebb5e94c6ddf113628c4b6fba91352a0ed59ebfa4
parentd871dc2994417f4aeee9199d23b7e5d66e03bc63 (diff)
downloadpaludis-5b096137be44c5354713cfc02b30767c7b9da0f6.tar.gz
paludis-5b096137be44c5354713cfc02b30767c7b9da0f6.tar.xz
Parallel sync support
-rw-r--r--paludis/sync_task.cc147
-rw-r--r--paludis/sync_task.hh4
-rw-r--r--src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.cc7
-rw-r--r--src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.hh1
-rw-r--r--src/clients/paludis/command_line.cc6
-rw-r--r--src/clients/paludis/command_line.hh3
-rw-r--r--src/clients/paludis/sync.cc22
7 files changed, 146 insertions, 44 deletions
diff --git a/paludis/sync_task.cc b/paludis/sync_task.cc
index 33a76f3..4fe8daf 100644
--- a/paludis/sync_task.cc
+++ b/paludis/sync_task.cc
@@ -22,6 +22,9 @@
#include <paludis/syncer.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/util/action_queue.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/tr1_functional.hh>
#include <paludis/package_database.hh>
#include <paludis/hook.hh>
#include <list>
@@ -37,16 +40,18 @@ namespace paludis
{
Environment * const env;
std::list<RepositoryName> targets;
+ const bool parallel;
- Implementation(Environment * const e) :
- env(e)
+ Implementation(Environment * const e, const bool p) :
+ env(e),
+ parallel(p)
{
}
};
}
-SyncTask::SyncTask(Environment * const env) :
- PrivateImplementationPattern<SyncTask>(new Implementation<SyncTask>(env))
+SyncTask::SyncTask(Environment * const env, const bool p) :
+ PrivateImplementationPattern<SyncTask>(new Implementation<SyncTask>(env, p))
{
}
@@ -61,6 +66,93 @@ SyncTask::add_target(const std::string & t)
_imp->targets.push_back(RepositoryName(t));
}
+namespace
+{
+ struct ItemSyncer
+ {
+ typedef void result;
+
+ Mutex mutex;
+ int x, y, a;
+ Environment * const env;
+ SyncTask * const task;
+
+ ItemSyncer(int yy, Environment * const e, SyncTask * const t) :
+ x(0),
+ y(yy),
+ a(0),
+ env(e),
+ task(t)
+ {
+ }
+
+ void sync(const RepositoryName & r)
+ {
+ Context context_local("When syncing repository '" + stringify(r) + "':");
+
+ {
+ Lock l(mutex);
+ ++x;
+ ++a;
+ task->on_sync_status(x, y, a);
+ }
+
+ try
+ {
+ if (0 !=
+ env->perform_hook(Hook("sync_pre")("TARGET", stringify(r))
+ ("X_OF_Y", stringify(x) + " of " + stringify(y) + " (" + stringify(a) + " active)")
+ ).max_exit_status)
+ throw SyncFailedError("Sync of '" + stringify(r) + "' aborted by hook");
+
+ {
+ Lock l(mutex);
+ task->on_sync_pre(r);
+ }
+
+ tr1::shared_ptr<const Repository> rr(env->package_database()->fetch_repository(r));
+ if (rr->syncable_interface && rr->syncable_interface->sync())
+ {
+ Lock l(mutex);
+ task->on_sync_succeed(r);
+ }
+ else
+ {
+ Lock l(mutex);
+ task->on_sync_skip(r);
+ }
+
+ {
+ Lock l(mutex);
+ task->on_sync_post(r);
+ }
+
+ if (0 !=
+ env->perform_hook(Hook("sync_post")("TARGET", stringify(r))
+ ("X_OF_Y", stringify(x) + " of " + stringify(y) + " (" + stringify(a) + " active)")
+ ).max_exit_status)
+ throw SyncFailedError("Sync of '" + stringify(r) + "' aborted by hook");
+
+ {
+ Lock l(mutex);
+ --a;
+ task->on_sync_status(x, y, a);
+ }
+ }
+ catch (const SyncFailedError & e)
+ {
+ HookResult PALUDIS_ATTRIBUTE((unused)) dummy(env->perform_hook(Hook("sync_fail")("TARGET", stringify(r))
+ ("X_OF_Y", stringify(x) + " of " + stringify(y) + " (" + stringify(a) + " active)")
+ ));
+ Lock l(mutex);
+ task->on_sync_fail(r, e);
+ --a;
+ task->on_sync_status(x, y, a);
+ }
+ }
+ };
+}
+
void
SyncTask::execute()
{
@@ -77,41 +169,22 @@ SyncTask::execute()
throw SyncFailedError("Sync aborted by hook");
on_sync_all_pre();
- int x(0), y(std::distance(_imp->targets.begin(), _imp->targets.end()));
- for (std::list<RepositoryName>::const_iterator r(_imp->targets.begin()), r_end(_imp->targets.end()) ;
- r != r_end ; ++r)
- {
- Context context_local("When syncing repository '" + stringify(*r) + "':");
- ++x;
+ ItemSyncer s(std::distance(_imp->targets.begin(), _imp->targets.end()), _imp->env, this);
- try
- {
- if (0 !=
- _imp->env->perform_hook(Hook("sync_pre")("TARGET", stringify(*r))
- ("X_OF_Y", stringify(x) + " of " + stringify(y))).max_exit_status)
- throw SyncFailedError("Sync of '" + stringify(*r) + "' aborted by hook");
- on_sync_pre(*r);
-
- tr1::shared_ptr<const Repository> rr(_imp->env->package_database()->fetch_repository(*r));
-
- if (rr->syncable_interface && rr->syncable_interface->sync())
- on_sync_succeed(*r);
- else
- on_sync_skip(*r);
-
- on_sync_post(*r);
- if (0 !=
- _imp->env->perform_hook(Hook("sync_post")("TARGET", stringify(*r))
- ("X_OF_Y", stringify(x) + " of " + stringify(y))).max_exit_status)
- throw SyncFailedError("Sync of '" + stringify(*r) + "' aborted by hook");
- }
- catch (const SyncFailedError & e)
- {
- HookResult PALUDIS_ATTRIBUTE((unused)) dummy(_imp->env->perform_hook(Hook("sync_fail")("TARGET", stringify(*r))
- ("X_OF_Y", stringify(x) + " of " + stringify(y))));
- on_sync_fail(*r, e);
- }
+ using namespace tr1::placeholders;
+#ifdef PALUDIS_ENABLE_THREADS
+ if (_imp->parallel)
+ {
+ ActionQueue actions(5);
+ for (std::list<RepositoryName>::const_iterator t(_imp->targets.begin()), t_end(_imp->targets.end()) ;
+ t != t_end ; ++t)
+ actions.enqueue(tr1::bind(&ItemSyncer::sync, &s, *t));
}
+ else
+ std::for_each(_imp->targets.begin(), _imp->targets.end(), tr1::bind(&ItemSyncer::sync, &s, _1));
+#else
+ std::for_each(_imp->targets.begin(), _imp->targets.end(), tr1::bind(&ItemSyncer::sync, &s, _1));
+#endif
on_sync_all_post();
if (0 !=
diff --git a/paludis/sync_task.hh b/paludis/sync_task.hh
index fb7d0cb..20ce9d1 100644
--- a/paludis/sync_task.hh
+++ b/paludis/sync_task.hh
@@ -54,7 +54,7 @@ namespace paludis
///\name Basic operations
///\{
- SyncTask(Environment * const env);
+ SyncTask(Environment * const env, const bool parallel);
///\}
@@ -84,6 +84,8 @@ namespace paludis
virtual void on_sync_succeed(const RepositoryName &) = 0;
virtual void on_sync_all_post() = 0;
+ virtual void on_sync_status(const int x, const int y, const int a) = 0;
+
///\}
///\name Target iteration
diff --git a/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.cc b/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.cc
index f09e091..334c25f 100644
--- a/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.cc
+++ b/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.cc
@@ -28,7 +28,7 @@ namespace paludis
}
GuiSyncTask::GuiSyncTask(MainWindow * const m) :
- SyncTask(m->environment()),
+ SyncTask(m->environment(), false),
PrivateImplementationPattern<GuiSyncTask>(new Implementation<GuiSyncTask>(m, this)),
_imp(PrivateImplementationPattern<GuiSyncTask>::_imp)
{
@@ -102,3 +102,8 @@ GuiSyncTask::paludis_thread_execute()
execute();
}
+void
+GuiSyncTask::on_sync_status(const int, const int, const int)
+{
+}
+
diff --git a/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.hh b/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.hh
index 9952284..c37bc01 100644
--- a/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.hh
+++ b/src/clients/gtkpaludis/libgtkpaludis/gui_sync_task.hh
@@ -27,6 +27,7 @@ namespace gtkpaludis
virtual void on_sync_fail(const paludis::RepositoryName &, const paludis::SyncFailedError &);
virtual void on_sync_succeed(const paludis::RepositoryName &);
virtual void on_sync_all_post();
+ virtual void on_sync_status(const int x, const int y, const int a);
public:
GuiSyncTask(MainWindow * const);
diff --git a/src/clients/paludis/command_line.cc b/src/clients/paludis/command_line.cc
index 47f371a..dd23f99 100644
--- a/src/clients/paludis/command_line.cc
+++ b/src/clients/paludis/command_line.cc
@@ -73,6 +73,12 @@ CommandLine::CommandLine() :
a_environment(&general_args, "environment", 'E', "Environment specification (class:suffix, both parts optional)"),
a_resume_command_template(&general_args, "resume-command-template", '\0',
"Save the resume command to a file. If the filename contains 'XXXXXX', use mkstemp(3) to generate the filename"),
+#ifdef PALUDIS_ENABLE_THREADS
+ a_parallel(&general_args, "parallel", 'P', "Perform tasks in parallel, where supported (currently --sync only)"),
+#else
+ a_parallel(&general_args, "parallel", 'P', "Does nothing. (For compatibility with Paludis when built with thread "
+ "support, which you shouldn't be using.)"),
+#endif
query_args(this, "Query options",
"Options which are relevant for --query."),
diff --git a/src/clients/paludis/command_line.hh b/src/clients/paludis/command_line.hh
index f998999..40918cd 100644
--- a/src/clients/paludis/command_line.hh
+++ b/src/clients/paludis/command_line.hh
@@ -166,6 +166,9 @@ class CommandLine :
/// --resume-command-template
paludis::args::StringArg a_resume_command_template;
+ /// --parallel
+ paludis::args::SwitchArg a_parallel;
+
///}
/// \name Query arguments
diff --git a/src/clients/paludis/sync.cc b/src/clients/paludis/sync.cc
index 4ae0390..3a8b4cb 100644
--- a/src/clients/paludis/sync.cc
+++ b/src/clients/paludis/sync.cc
@@ -43,8 +43,8 @@ namespace
int _return_code;
public:
- OurSyncTask(tr1::shared_ptr<Environment> env) :
- SyncTask(env.get()),
+ OurSyncTask(tr1::shared_ptr<Environment> env, const bool p) :
+ SyncTask(env.get(), p),
_return_code(0)
{
}
@@ -57,6 +57,8 @@ namespace
virtual void on_sync_succeed(const RepositoryName &);
virtual void on_sync_all_post();
+ virtual void on_sync_status(const int x, const int y, const int a);
+
int return_code() const
{
return _return_code;
@@ -72,7 +74,6 @@ namespace
OurSyncTask::on_sync_pre(const RepositoryName & r)
{
cout << colour(cl_heading, "Sync " + stringify(r)) << endl;
- cerr << xterm_title("Syncing " + stringify(r));
}
void
@@ -108,13 +109,25 @@ namespace
{
cout << endl;
}
+
+ void
+ OurSyncTask::on_sync_status(const int x, const int y, const int a)
+ {
+ cerr << xterm_title("Syncing " + stringify(x) + " of " + stringify(y) + ", "
+ + stringify(a) + " active");
+ }
}
int do_sync(tr1::shared_ptr<Environment> env)
{
Context context("When performing sync action from command line:");
- OurSyncTask task(env);
+ bool parallel(false);
+#ifdef PALUDIS_ENABLE_THREADS
+ parallel = CommandLine::get_instance()->a_parallel.specified();
+#endif
+
+ OurSyncTask task(env, parallel);
for (CommandLine::ParametersConstIterator q(CommandLine::get_instance()->begin_parameters()),
q_end(CommandLine::get_instance()->end_parameters()) ; q != q_end ; ++q)
@@ -126,4 +139,3 @@ int do_sync(tr1::shared_ptr<Environment> env)
return task.return_code();
}
-