[gnome-builder] pipeline: short-circuit when pipeline is past requested phase



commit d42b55a8840aa59bec321ab2434f7aac0379a678
Author: Christian Hergert <chergert redhat com>
Date:   Mon Oct 16 14:35:07 2017 -0700

    pipeline: short-circuit when pipeline is past requested phase
    
    If the build pipeline has already past the requested phase, we
    can short circuit. This should help in situations where we end
    up queuing the request because a build is in progress (which is
    beyond the phase we need to complete).
    
    There is still an issue with this where queued items are stuck
    behind an higher-requested phase and they will not be flushed
    until that build has completed. To fix this issue, we need to
    scan forward and flush items with lower requested phases.

 src/libide/buildsystem/ide-build-manager.c  |    9 +-
 src/libide/buildsystem/ide-build-pipeline.c |  129 ++++++++++++++++++++++-----
 src/libide/buildsystem/ide-build-pipeline.h |    8 ++
 src/tests/test-ide-build-pipeline.c         |   11 +--
 4 files changed, 125 insertions(+), 32 deletions(-)
---
diff --git a/src/libide/buildsystem/ide-build-manager.c b/src/libide/buildsystem/ide-build-manager.c
index 344baab..50a4517 100644
--- a/src/libide/buildsystem/ide-build-manager.c
+++ b/src/libide/buildsystem/ide-build-manager.c
@@ -1156,10 +1156,11 @@ ide_build_manager_execute_async (IdeBuildManager     *self,
       IDE_EXIT;
     }
 
-  ide_build_pipeline_execute_async (self->pipeline,
-                                    cancellable,
-                                    ide_build_manager_execute_cb,
-                                    g_steal_pointer (&task));
+  ide_build_pipeline_build_async (self->pipeline,
+                                  phase,
+                                  cancellable,
+                                  ide_build_manager_execute_cb,
+                                  g_steal_pointer (&task));
 
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ERROR_COUNT]);
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
diff --git a/src/libide/buildsystem/ide-build-pipeline.c b/src/libide/buildsystem/ide-build-pipeline.c
index b1e0725..d66dc2c 100644
--- a/src/libide/buildsystem/ide-build-pipeline.c
+++ b/src/libide/buildsystem/ide-build-pipeline.c
@@ -1413,59 +1413,144 @@ ide_build_pipeline_task_notify_completed (IdeBuildPipeline *self,
 }
 
 /**
- * ide_build_pipeline_execute_async:
+ * ide_build_pipeline_build_async:
  * @self: A @IdeBuildPipeline
+ * @phase: the requested build phase
  * @cancellable: (nullable): A #GCancellable or %NULL
  * @callback: a callback to execute upon completion
  * @user_data: data for @callback
  *
  * Asynchronously starts the build pipeline.
  *
- * Any phase that has been invalidated up to the requested phase
- * will be executed until a stage has failed.
+ * The @phase parameter should contain the #IdeBuildPhase that is
+ * necessary to complete. If you simply want to trigger a generic
+ * build, you probably want %IDE_BUILD_PHASE_BUILD. If you only
+ * need to configure the project (and necessarily the dependencies
+ * up to that phase) you might want %IDE_BUILD_PHASE_CONFIGURE.
+ *
+ * You may not specify %IDE_BUILD_PHASE_AFTER or
+ * %IDE_BUILD_PHASE_BEFORE flags as those must always be processed
+ * with the underlying phase they are attached to.
  *
  * Upon completion, @callback will be executed and should call
  * ide_build_pipeline_execute_finish() to get the status of the
  * operation.
+ *
+ * Since: 3.28
  */
 void
-ide_build_pipeline_execute_async (IdeBuildPipeline    *self,
-                                  GCancellable        *cancellable,
-                                  GAsyncReadyCallback  callback,
-                                  gpointer             user_data)
+ide_build_pipeline_build_async (IdeBuildPipeline    *self,
+                                IdeBuildPhase        phase,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
-  g_autoptr(GFile) builddir = NULL;
-  g_autoptr(GError) error = NULL;
   TaskData *task_data;
 
   IDE_ENTRY;
 
-  g_return_if_fail (IDE_IS_BUILD_PIPELINE (self));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
   task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_build_pipeline_execute_async);
+  g_task_set_source_tag (task, ide_build_pipeline_build_async);
   g_task_set_priority (task, G_PRIORITY_LOW);
 
-  if (self->requested_mask == IDE_BUILD_PHASE_NONE)
-    {
-      g_task_return_boolean (task, TRUE);
-      IDE_EXIT;
-    }
-
   /*
-   * XXX: Maybe we should allow a phase to be provided with execute
-   *      now for symmetry with the others. Also, rename to build_async()?
+   * If the requested phase has already been met (by a previous build
+   * or by an active build who has already surpassed this build phase,
+   * we can return a result immediately.
    */
+  if (self->position >= self->pipeline->len)
+    goto short_circuit;
+  else if (self->position >= 0)
+    {
+      const PipelineEntry *entry = &g_array_index (self->pipeline, PipelineEntry, self->position);
+
+      /* This phase is past the requested phase, we can complete the
+       * task immediately.
+       */
+      if (entry->phase > phase)
+        goto short_circuit;
+    }
 
   task_data = task_data_new (task, TASK_BUILD);
-  task_data->phase = 1 << g_bit_nth_msf (self->requested_mask, -1);
+  task_data->phase = 1 << g_bit_nth_msf (phase, -1);
   g_task_set_task_data (task, task_data, task_data_free);
 
   g_queue_push_tail (&self->task_queue, g_steal_pointer (&task));
 
   ide_build_pipeline_queue_flush (self);
+
+  IDE_EXIT;
+
+short_circuit:
+  g_task_return_boolean (task, TRUE);
+  IDE_EXIT;
+}
+
+/**
+ * ide_build_pipeline_build_finish:
+ * @self: An #IdeBuildPipeline
+ * @result: A #GAsyncResult provided to callback
+ * @error: A location for a #GError, or %NULL
+ *
+ * This function completes the asynchronous request to build
+ * up to a particular phase of the build pipeline.
+ *
+ * Returns: %TRUE if the build stages were executed successfully
+ *   up to the requested build phase provided to
+ *   ide_build_pipeline_build_async().
+ *
+ * Since: 3.28
+ */
+gboolean
+ide_build_pipeline_build_finish (IdeBuildPipeline  *self,
+                                 GAsyncResult      *result,
+                                 GError           **error)
+{
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  ret = g_task_propagate_boolean (G_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+/**
+ * ide_build_pipeline_execute_async:
+ * @self: A @IdeBuildPipeline
+ * @cancellable: (nullable): A #GCancellable or %NULL
+ * @callback: a callback to execute upon completion
+ * @user_data: data for @callback
+ *
+ * Asynchronously starts the build pipeline.
+ *
+ * Any phase that has been invalidated up to the requested phase
+ * will be executed until a stage has failed.
+ *
+ * Upon completion, @callback will be executed and should call
+ * ide_build_pipeline_execute_finish() to get the status of the
+ * operation.
+ *
+ * Since: 3.24
+ */
+void
+ide_build_pipeline_execute_async (IdeBuildPipeline    *self,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
+{
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_BUILD_PIPELINE (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ide_build_pipeline_build_async (self, self->requested_mask, cancellable, callback, user_data);
+
+  IDE_EXIT;
 }
 
 static gboolean
diff --git a/src/libide/buildsystem/ide-build-pipeline.h b/src/libide/buildsystem/ide-build-pipeline.h
index f77e42a..a59092a 100644
--- a/src/libide/buildsystem/ide-build-pipeline.h
+++ b/src/libide/buildsystem/ide-build-pipeline.h
@@ -99,6 +99,14 @@ guint                  ide_build_pipeline_add_error_format    (IdeBuildPipeline
                                                                GRegexCompileFlags      flags);
 gboolean               ide_build_pipeline_remove_error_format (IdeBuildPipeline       *self,
                                                                guint                   error_format_id);
+void                   ide_build_pipeline_build_async         (IdeBuildPipeline       *self,
+                                                               IdeBuildPhase           phase,
+                                                               GCancellable           *cancellable,
+                                                               GAsyncReadyCallback     callback,
+                                                               gpointer                user_data);
+gboolean               ide_build_pipeline_build_finish        (IdeBuildPipeline       *self,
+                                                               GAsyncResult           *result,
+                                                               GError                **error);
 void                   ide_build_pipeline_execute_async       (IdeBuildPipeline       *self,
                                                                GCancellable           *cancellable,
                                                                GAsyncReadyCallback     callback,
diff --git a/src/tests/test-ide-build-pipeline.c b/src/tests/test-ide-build-pipeline.c
index 4791d1e..c136fa4 100644
--- a/src/tests/test-ide-build-pipeline.c
+++ b/src/tests/test-ide-build-pipeline.c
@@ -72,14 +72,13 @@ context_loaded (GObject      *object,
                            "configuration", config,
                            NULL);
 
-  ide_build_pipeline_request_phase (pipeline, IDE_BUILD_PHASE_BUILD);
-
   g_debug ("Executing pipeline");
 
-  ide_build_pipeline_execute_async (pipeline,
-                                    NULL,
-                                    execute_cb,
-                                    g_steal_pointer (&task));
+  ide_build_pipeline_build_async (pipeline,
+                                  IDE_BUILD_PHASE_BUILD,
+                                  NULL,
+                                  execute_cb,
+                                  g_steal_pointer (&task));
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]