Add query executor
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 14 Aug 2017 21:55:53 +0000 (17:55 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 15 Sep 2017 15:21:13 +0000 (11:21 -0400)
Use a new object, a query executor, to query a component class:

    struct bt_query_executor *query_exec = bt_query_executor_create();
    enum bt_query_status status = bt_query_executor_query(query_exec,
        comp_cls, "object", params, &result);

The user's query method receives this query executor as a parameter so
that some state can be shared between the user who queries (calls
bt_query_executor_query()) and the user's method. Currently, only a
cancellation flag is part of the query executor's state, so that, if you
wish to cancel a query during a signal handler, you can call
bt_query_executor_cancel(): then, when the user's method's current
system call sets the EINTR error (or the equivalent on other supported
platforms), it can check the state of the query executor with
bt_query_executor_is_canceled() to know whether to retry the system call
(debugging mode, query executor is not canceled) or to return an error
(application mode, query executor is canceled).

This is the same mechanism that is used with the graph object and
component objects: bt_graph_cancel() and bt_graph_is_canceled().

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
28 files changed:
bindings/python/bt2/Makefile.am
bindings/python/bt2/bt2/__init__.py.in
bindings/python/bt2/bt2/component.py
bindings/python/bt2/bt2/native_bt.i
bindings/python/bt2/bt2/native_btcomponentclass.i
bindings/python/bt2/bt2/native_btqueryexec.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btversion.i
bindings/python/bt2/bt2/query_executor.py [new file with mode: 0644]
cli/babeltrace.c
include/Makefile.am
include/babeltrace/babeltrace.h
include/babeltrace/graph/component-class.h
include/babeltrace/graph/query-executor-internal.h [new file with mode: 0644]
include/babeltrace/graph/query-executor.h [new file with mode: 0644]
lib/graph/Makefile.am
lib/graph/component-class.c
lib/graph/graph.c
lib/graph/query-executor.c [new file with mode: 0644]
plugins/ctf/fs-src/fs.c
plugins/ctf/fs-src/fs.h
plugins/ctf/fs-src/query.c
plugins/ctf/fs-src/query.h
plugins/ctf/lttng-live/lttng-live-internal.h
plugins/ctf/lttng-live/lttng-live.c
tests/bindings/python/bt2/test_component_class.py
tests/bindings/python/bt2/test_query_executor.py [new file with mode: 0644]
tests/lib/test-plugin-plugins/sfs.c
tests/lib/test_plugin.c

index 2ae93f3f2aad23ac9734bab2f38c804063b3722b..d35a3adbc6363719a00d18b2f5f1ea672e2e8b77 100644 (file)
@@ -26,6 +26,7 @@ STATIC_BINDINGS_DEPS =                        \
        bt2/native_btpacket.i           \
        bt2/native_btplugin.i           \
        bt2/native_btport.i             \
+       bt2/native_btqueryexec.i        \
        bt2/native_btref.i              \
        bt2/native_btstreamclass.i      \
        bt2/native_btstream.i           \
@@ -50,6 +51,7 @@ STATIC_BINDINGS_DEPS =                        \
        bt2/plugin.py                   \
        bt2/port.py                     \
        bt2/py_plugin.py                \
+       bt2/query_executor.py           \
        bt2/stream_class.py             \
        bt2/stream.py                   \
        bt2/trace.py                    \
index ebab24ab780ace043984a0603686f4d3b53a1425..2cc4baaa51f4837cfda3c5ea6e9bd28ccfaa54f4 100644 (file)
@@ -72,6 +72,7 @@ from bt2.port import _PrivateInputPort
 from bt2.port import _PrivateOutputPort
 from bt2.port import _PrivatePort
 from bt2.py_plugin import *
+from bt2.query_executor import *
 from bt2.stream import _Stream
 from bt2.stream_class import *
 from bt2.trace import *
@@ -95,6 +96,14 @@ class NoSuchPlugin(Error):
     pass
 
 
+class InvalidQueryObject(Error):
+    pass
+
+
+class InvalidQueryParams(Error):
+    pass
+
+
 class UnsupportedFeature(Exception):
     pass
 
@@ -123,6 +132,10 @@ class GraphCanceled(Exception):
     pass
 
 
+class QueryExecutorCanceled(Exception):
+    pass
+
+
 class NotificationIteratorCanceled(Exception):
     pass
 
index 927fd061b8aadaea05ce6366af1d3a03fe898a17..9c1786814a1675ebe23ae9553d278a2c967b1fa9 100644 (file)
@@ -54,9 +54,6 @@ class _GenericComponentClass(object._Object):
     def help(self):
         return native_bt.component_class_get_help(self._ptr)
 
-    def query(self, obj, params=None):
-        return _query(self._ptr, obj, params)
-
     def __eq__(self, other):
         if not isinstance(other, _GenericComponentClass):
             try:
@@ -290,24 +287,6 @@ def _trim_docstring(docstring):
     return '\n'.join(trimmed)
 
 
-def _query(comp_cls_ptr, obj, params):
-    utils._check_str(obj)
-
-    if params is None:
-        params_ptr = native_bt.value_null
-    else:
-        params = bt2.create_value(params)
-        params_ptr = params._ptr
-
-    results_ptr = native_bt.component_class_query(comp_cls_ptr, obj,
-                                                  params_ptr)
-
-    if results_ptr is None:
-        raise bt2.Error('cannot query info with object "{}"'.format(obj))
-
-    return bt2.values._create_from_ptr(results_ptr)
-
-
 # Metaclass for component classes defined by Python code.
 #
 # The Python user can create a standard Python class which inherits one
@@ -488,10 +467,7 @@ class _UserComponentType(type):
     def addr(cls):
         return int(cls._cc_ptr)
 
-    def query(cls, obj, params=None):
-        return _query(cls._cc_ptr, obj, params)
-
-    def _query_from_native(cls, obj, params_ptr):
+    def _query_from_native(cls, query_exec_ptr, obj, params_ptr):
         # this can raise, in which case the native call to
         # bt_component_class_query() returns NULL
         if params_ptr is not None:
@@ -500,24 +476,17 @@ class _UserComponentType(type):
         else:
             params = None
 
-        try:
-            results = cls._query(obj, params)
-        except:
-            if not _NO_PRINT_TRACEBACK:
-                traceback.print_exc()
+        native_bt.get(query_exec_ptr)
+        query_exec = bt2.QueryExecutor._create_from_ptr(query_exec_ptr)
 
-            return
+        # this can raise, but the native side checks the exception
+        results = cls._query(query_exec, obj, params)
 
         if results is NotImplemented:
             return results
 
-        try:
-            results = bt2.create_value(results)
-        except:
-            if not _NO_PRINT_TRACEBACK:
-                traceback.print_exc()
-
-            return
+        # this can raise, but the native side checks the exception
+        results = bt2.create_value(results)
 
         if results is None:
             results_addr = int(native_bt.value_null)
@@ -528,8 +497,7 @@ class _UserComponentType(type):
 
         return results_addr
 
-    @classmethod
-    def _query(cls, obj, params):
+    def _query(cls, query_executor, obj, params):
         # BT catches this and returns NULL to the user
         return NotImplemented
 
index c7ae8d63359cc4e36bd5c1b218f81ba856e37e3b..59595a3117965a5bb432d39b2819d7236a8ef614 100644 (file)
@@ -126,6 +126,22 @@ typedef int bt_bool;
        }
 }
 
+/* Output argument typemap for value output (always appends) */
+%typemap(in, numinputs=0) struct bt_value **BTOUTVALUE (struct bt_value *temp_value = NULL) {
+       $1 = &temp_value;
+}
+
+%typemap(argout) struct bt_value **BTOUTVALUE {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_bt_value, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
 /* Output argument typemap for initialized uint64_t output parameter (always appends) */
 %typemap(in, numinputs=0) uint64_t *OUTPUTINIT (uint64_t temp = -1ULL) {
        $1 = &temp;
@@ -194,6 +210,7 @@ typedef int bt_bool;
 %include "native_btpacket.i"
 %include "native_btplugin.i"
 %include "native_btport.i"
+%include "native_btqueryexec.i"
 %include "native_btref.i"
 %include "native_btstream.i"
 %include "native_btstreamclass.i"
index da25e3762d51775b3bdf094822580034f6c59815..2fe6ce3469ab9201288f7382d4f76214d90be428 100644 (file)
@@ -40,9 +40,6 @@ const char *bt_component_class_get_description(
                struct bt_component_class *component_class);
 const char *bt_component_class_get_help(
                struct bt_component_class *component_class);
-struct bt_value *bt_component_class_query(
-               struct bt_component_class *component_class,
-               const char *object, struct bt_value *params);
 enum bt_component_class_type bt_component_class_get_type(
                struct bt_component_class *component_class);
 
@@ -108,9 +105,9 @@ static PyObject *py_mod_bt2_exc_unsupported_feature_type = NULL;
 static PyObject *py_mod_bt2_exc_try_again_type = NULL;
 static PyObject *py_mod_bt2_exc_stop_type = NULL;
 static PyObject *py_mod_bt2_exc_port_connection_refused_type = NULL;
-static PyObject *py_mod_bt2_exc_graph_canceled_type = NULL;
 static PyObject *py_mod_bt2_exc_notif_iter_canceled_type = NULL;
-static PyObject *py_mod_bt2_exc_connection_ended_type = NULL;
+static PyObject *py_mod_bt2_exc_invalid_query_object_type = NULL;
+static PyObject *py_mod_bt2_exc_invalid_query_params_type = NULL;
 
 static void bt_py3_cc_init_from_bt2(void)
 {
@@ -129,17 +126,22 @@ static void bt_py3_cc_init_from_bt2(void)
        assert(py_mod_bt2_exc_error_type);
        py_mod_bt2_exc_unsupported_feature_type =
                PyObject_GetAttrString(py_mod_bt2, "UnsupportedFeature");
+       assert(py_mod_bt2_exc_unsupported_feature_type);
        py_mod_bt2_exc_try_again_type =
                PyObject_GetAttrString(py_mod_bt2, "TryAgain");
+       assert(py_mod_bt2_exc_try_again_type);
        py_mod_bt2_exc_stop_type =
                PyObject_GetAttrString(py_mod_bt2, "Stop");
+       assert(py_mod_bt2_exc_stop_type);
        py_mod_bt2_exc_port_connection_refused_type =
                PyObject_GetAttrString(py_mod_bt2, "PortConnectionRefused");
-       py_mod_bt2_exc_graph_canceled_type =
-               PyObject_GetAttrString(py_mod_bt2, "GraphCanceled");
-       py_mod_bt2_exc_connection_ended_type =
-               PyObject_GetAttrString(py_mod_bt2, "ConnectionEnded");
-       assert(py_mod_bt2_exc_stop_type);
+       assert(py_mod_bt2_exc_port_connection_refused_type);
+       py_mod_bt2_exc_invalid_query_object_type =
+               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryObject");
+       assert(py_mod_bt2_exc_invalid_query_object_type);
+       py_mod_bt2_exc_invalid_query_params_type =
+               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryParams");
+       assert(py_mod_bt2_exc_invalid_query_params_type);
 }
 
 static void bt_py3_cc_exit_handler(void)
@@ -163,9 +165,9 @@ static void bt_py3_cc_exit_handler(void)
        Py_XDECREF(py_mod_bt2_exc_try_again_type);
        Py_XDECREF(py_mod_bt2_exc_stop_type);
        Py_XDECREF(py_mod_bt2_exc_port_connection_refused_type);
-       Py_XDECREF(py_mod_bt2_exc_graph_canceled_type);
        Py_XDECREF(py_mod_bt2_exc_notif_iter_canceled_type);
-       Py_XDECREF(py_mod_bt2_exc_connection_ended_type);
+       Py_XDECREF(py_mod_bt2_exc_invalid_query_object_type);
+       Py_XDECREF(py_mod_bt2_exc_invalid_query_params_type);
 }
 
 
@@ -211,6 +213,33 @@ end:
        return status;
 }
 
+static enum bt_query_status bt_py3_exc_to_query_status(void)
+{
+       enum bt_query_status status = BT_QUERY_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_invalid_query_object_type)) {
+               status = BT_QUERY_STATUS_INVALID_OBJECT;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_invalid_query_params_type)) {
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_try_again_type)) {
+               status = BT_QUERY_STATUS_AGAIN;
+       } else {
+               status = BT_QUERY_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
 static enum bt_component_status bt_py3_exc_to_component_status(void)
 {
        enum bt_component_status status = BT_COMPONENT_STATUS_OK;
@@ -493,16 +522,21 @@ static void bt_py3_cc_port_disconnected(
        Py_XDECREF(py_method_result);
 }
 
-static struct bt_value *bt_py3_cc_query(
+static struct bt_component_class_query_return bt_py3_cc_query(
                struct bt_component_class *comp_cls,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params)
 {
        PyObject *py_cls = NULL;
        PyObject *py_params_ptr = NULL;
+       PyObject *py_query_exec_ptr = NULL;
        PyObject *py_query_func = NULL;
        PyObject *py_object = NULL;
        PyObject *py_results_addr = NULL;
-       struct bt_value *results = NULL;
+       struct bt_component_class_query_return ret = {
+               .status = BT_QUERY_STATUS_OK,
+               .result = NULL,
+       };
 
        py_cls = lookup_cc_ptr_to_py_cls(comp_cls);
        if (!py_cls) {
@@ -518,6 +552,13 @@ static struct bt_value *bt_py3_cc_query(
                goto error;
        }
 
+       py_query_exec_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(query_exec),
+               SWIGTYPE_p_bt_query_executor, 0);
+       if (!py_query_exec_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
        py_object = SWIG_FromCharPtr(object);
        if (!py_object) {
                BT_LOGE_STR("Failed to create a Python string.");
@@ -525,10 +566,19 @@ static struct bt_value *bt_py3_cc_query(
        }
 
        py_results_addr = PyObject_CallMethod(py_cls,
-               "_query_from_native", "(OO)", py_object, py_params_ptr);
-       if (!py_results_addr || py_results_addr == Py_None) {
-               BT_LOGE_STR("User's _query() method failed.");
-               goto error;
+               "_query_from_native", "(OOO)", py_query_exec_ptr,
+               py_object, py_params_ptr);
+       ret.status = bt_py3_exc_to_query_status();
+       if (!py_results_addr && ret.status == BT_QUERY_STATUS_OK) {
+               /* Pretty sure this should never happen, but just in case */
+               BT_LOGE("_query_from_native() class method failed without raising an exception: "
+                       "status=%d", ret.status);
+               ret.status = BT_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       if (ret.status != BT_QUERY_STATUS_OK) {
+               goto end;
        }
 
        if (py_results_addr == Py_NotImplemented) {
@@ -541,21 +591,24 @@ static struct bt_value *bt_py3_cc_query(
         * (PyLong) containing the address of a BT value object (new
         * reference).
         */
-       results = (void *) PyLong_AsUnsignedLongLong(py_results_addr);
+       ret.result = (void *) PyLong_AsUnsignedLongLong(py_results_addr);
        assert(!PyErr_Occurred());
-       assert(results);
+       assert(ret.result);
        goto end;
 
 error:
-       BT_PUT(results);
+       BT_PUT(ret.result);
        PyErr_Clear();
+       ret.status = BT_QUERY_STATUS_ERROR;
+       BT_PUT(ret.result);
 
 end:
        Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_query_exec_ptr);
        Py_XDECREF(py_query_func);
        Py_XDECREF(py_object);
        Py_XDECREF(py_results_addr);
-       return results;
+       return ret;
 }
 
 static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init(
diff --git a/bindings/python/bt2/bt2/native_btqueryexec.i b/bindings/python/bt2/bt2/native_btqueryexec.i
new file mode 100644 (file)
index 0000000..b6af2a6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Types */
+struct bt_query_executor;
+
+/* Query status */
+enum bt_query_status {
+       BT_QUERY_STATUS_OK = 0,
+       BT_QUERY_STATUS_AGAIN = 11,
+       BT_QUERY_STATUS_EXECUTOR_CANCELED = 125,
+       BT_QUERY_STATUS_ERROR = -1,
+       BT_QUERY_STATUS_INVALID = -22,
+       BT_QUERY_STATUS_INVALID_OBJECT = -23,
+       BT_QUERY_STATUS_INVALID_PARAMS = -24,
+       BT_QUERY_STATUS_NOMEM = -12,
+};
+
+/* Functions */
+struct bt_query_executor *bt_query_executor_create(void);
+enum bt_query_status bt_query_executor_query(
+               struct bt_query_executor *query_executor,
+               struct bt_component_class *component_class,
+               const char *object, struct bt_value *params,
+               struct bt_value **BTOUTVALUE);
+enum bt_query_status bt_query_executor_cancel(
+               struct bt_query_executor *query_executor);
+int bt_query_executor_is_canceled(struct bt_query_executor *query_executor);
index e368b9b337cc7065ef3789f042dcc4d015231c86..3d99e7d2769ed6021b031ad36106948bad627a77 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/version.h>
-%}
-
 /* Version functions */
 int bt_version_get_major(void);
 int bt_version_get_minor(void);
diff --git a/bindings/python/bt2/bt2/query_executor.py b/bindings/python/bt2/bt2/query_executor.py
new file mode 100644 (file)
index 0000000..0064416
--- /dev/null
@@ -0,0 +1,96 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.component
+import bt2
+
+
+class QueryExecutor(object._Object):
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.QUERY_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status == native_bt.QUERY_STATUS_EXECUTOR_CANCELED:
+            raise bt2.QueryExecutorCanceled
+        elif status == native_bt.QUERY_STATUS_INVALID_OBJECT:
+            raise bt2.InvalidQueryObject
+        elif status == native_bt.QUERY_STATUS_INVALID_PARAMS:
+            raise bt2.InvalidQueryParams
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def __init__(self):
+        ptr = native_bt.query_executor_create()
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create query executor object')
+
+        super().__init__(ptr)
+
+    def cancel(self):
+        status = native_bt.query_executor_cancel(self._ptr)
+        self._handle_status(status, 'cannot cancel query executor object')
+
+    @property
+    def is_canceled(self):
+        is_canceled = native_bt.query_executor_is_canceled(self._ptr)
+        assert(is_canceled >= 0)
+        return is_canceled > 0
+
+    def query(self, component_class, object, params=None):
+        if not isinstance(component_class, bt2.component._GenericComponentClass):
+            err = False
+
+            try:
+                if not issubclass(component_class, bt2.component._UserComponent):
+                    err = True
+            except TypeError:
+                err = True
+
+            if err:
+                o = component_class
+                raise TypeError("'{}' is not a component class object".format(o))
+
+        utils._check_str(object)
+
+        if params is None:
+            params_ptr = native_bt.value_null
+        else:
+            params = bt2.create_value(params)
+            params_ptr = params._ptr
+
+        if isinstance(component_class, bt2.component._GenericComponentClass):
+            cc_ptr = component_class._ptr
+        else:
+            cc_ptr = component_class._cc_ptr
+
+        status, result_ptr = native_bt.query_executor_query(self._ptr, cc_ptr,
+                                                            object, params_ptr)
+        self._handle_status(status, 'cannot query component class')
+        assert(result_ptr)
+        return bt2.values._create_from_ptr(result_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        return self.addr == other.addr
index 9eef511dac1d565026ba9f2902301e9ab8a6059a..95b89c81d85b44a02ba49c42da0521514ec72535 100644 (file)
 #include "logging.h"
 
 #include <babeltrace/babeltrace.h>
-#include <babeltrace/plugin/plugin.h>
 #include <babeltrace/common-internal.h>
-#include <babeltrace/graph/component.h>
-#include <babeltrace/graph/component-source.h>
-#include <babeltrace/graph/component-sink.h>
-#include <babeltrace/graph/component-filter.h>
-#include <babeltrace/graph/component-class.h>
-#include <babeltrace/graph/port.h>
-#include <babeltrace/graph/graph.h>
-#include <babeltrace/graph/connection.h>
-#include <babeltrace/graph/notification-iterator.h>
-#include <babeltrace/ref.h>
-#include <babeltrace/values.h>
 #include <babeltrace/values-internal.h>
-#include <babeltrace/logging.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <popt.h>
@@ -85,6 +72,7 @@ static const char* log_level_env_var_names[] = {
 
 /* Application's processing graph (weak) */
 static struct bt_graph *the_graph;
+static struct bt_query_executor *the_query_executor;
 static bool canceled = false;
 
 GPtrArray *loaded_plugins;
@@ -122,6 +110,10 @@ void signal_handler(int signum)
                bt_graph_cancel(the_graph);
        }
 
+       if (the_query_executor) {
+               bt_query_executor_cancel(the_query_executor);
+       }
+
        canceled = true;
 }
 
@@ -153,6 +145,116 @@ void fini_static_data(void)
        g_ptr_array_free(loaded_plugins, TRUE);
 }
 
+static
+int create_the_query_executor(void)
+{
+       int ret = 0;
+
+       the_query_executor = bt_query_executor_create();
+       if (!the_query_executor) {
+               BT_LOGE_STR("Cannot create a query executor.");
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static
+void destroy_the_query_executor(void)
+{
+       BT_PUT(the_query_executor);
+}
+
+static
+int query(struct bt_component_class *comp_cls, const char *obj,
+               struct bt_value *params, struct bt_value **user_result,
+               const char **fail_reason)
+{
+       struct bt_value *result = NULL;
+       enum bt_query_status status;
+       *fail_reason = "unknown error";
+       int ret = 0;
+
+       assert(fail_reason);
+       assert(user_result);
+       ret = create_the_query_executor();
+       if (ret) {
+               /* create_the_query_executor() logs errors */
+               goto end;
+       }
+
+       if (canceled) {
+               BT_LOGI("Canceled by user before executing the query: "
+                       "comp-cls-addr=%p, comp-cls-name=\"%s\", "
+                       "query-obj=\"%s\"", comp_cls,
+                       bt_component_class_get_name(comp_cls), obj);
+               *fail_reason = "canceled by user";
+               goto error;
+       }
+
+       while (true) {
+               status = bt_query_executor_query(the_query_executor, comp_cls,
+                       obj, params, &result);
+               switch (status) {
+               case BT_QUERY_STATUS_OK:
+                       goto ok;
+               case BT_QUERY_STATUS_AGAIN:
+               {
+                       const uint64_t sleep_time_us = 100000;
+
+                       /* Wait 100 ms and retry */
+                       BT_LOGV("Got BT_QUERY_STATUS_AGAIN: sleeping: "
+                               "time-us=%" PRIu64, sleep_time_us);
+
+                       if (usleep(sleep_time_us)) {
+                               if (bt_query_executor_is_canceled(the_query_executor)) {
+                                       BT_LOGI("Query was canceled by user: "
+                                               "comp-cls-addr=%p, comp-cls-name=\"%s\", "
+                                               "query-obj=\"%s\"", comp_cls,
+                                               bt_component_class_get_name(comp_cls),
+                                               obj);
+                                       *fail_reason = "canceled by user";
+                                       goto error;
+                               }
+                       }
+
+                       continue;
+               }
+               case BT_QUERY_STATUS_EXECUTOR_CANCELED:
+                       *fail_reason = "canceled by user";
+                       goto error;
+               case BT_QUERY_STATUS_ERROR:
+               case BT_QUERY_STATUS_INVALID:
+                       goto error;
+               case BT_QUERY_STATUS_INVALID_OBJECT:
+                       *fail_reason = "invalid or unknown query object";
+                       goto error;
+               case BT_QUERY_STATUS_INVALID_PARAMS:
+                       *fail_reason = "invalid query parameters";
+                       goto error;
+               case BT_QUERY_STATUS_NOMEM:
+                       *fail_reason = "not enough memory";
+                       goto error;
+               default:
+                       BT_LOGF("Unknown query status: status=%d", status);
+                       abort();
+               }
+       }
+
+ok:
+       *user_result = result;
+       result = NULL;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       destroy_the_query_executor();
+       bt_put(result);
+       return ret;
+}
+
 static
 struct bt_plugin *find_plugin(const char *name)
 {
@@ -792,6 +894,7 @@ int cmd_query(struct bt_config *cfg)
        int ret = 0;
        struct bt_component_class *comp_cls = NULL;
        struct bt_value *results = NULL;
+       const char *fail_reason = NULL;
 
        comp_cls = find_component_class(cfg->cmd_data.query.cfg_component->plugin_name->str,
                cfg->cmd_data.query.cfg_component->comp_cls_name->str,
@@ -815,35 +918,39 @@ int cmd_query(struct bt_config *cfg)
                goto end;
        }
 
-       results = bt_component_class_query(comp_cls,
-               cfg->cmd_data.query.object->str,
-               cfg->cmd_data.query.cfg_component->params);
-       if (!results) {
-               BT_LOGE("Failed to query component class: plugin-name=\"%s\", "
-                       "comp-cls-name=\"%s\", comp-cls-type=%d "
-                       "object=\"%s\"",
-                       cfg->cmd_data.query.cfg_component->plugin_name->str,
-                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.query.cfg_component->type,
-                       cfg->cmd_data.query.object->str);
-               fprintf(stderr, "%s%sFailed to query info to %s",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               print_plugin_comp_cls_opt(stderr,
-                       cfg->cmd_data.query.cfg_component->plugin_name->str,
-                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.query.cfg_component->type);
-               fprintf(stderr, "%s%s with object `%s`%s\n",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       cfg->cmd_data.query.object->str,
-                       bt_common_color_reset());
-               ret = -1;
-               goto end;
+       ret = query(comp_cls, cfg->cmd_data.query.object->str,
+               cfg->cmd_data.query.cfg_component->params, &results,
+               &fail_reason);
+       if (ret) {
+               goto failed;
        }
 
        print_value(stdout, results, 0);
+       goto end;
+
+failed:
+       BT_LOGE("Failed to query component class: %s: plugin-name=\"%s\", "
+               "comp-cls-name=\"%s\", comp-cls-type=%d "
+               "object=\"%s\"", fail_reason,
+               cfg->cmd_data.query.cfg_component->plugin_name->str,
+               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.query.cfg_component->type,
+               cfg->cmd_data.query.object->str);
+       fprintf(stderr, "%s%sFailed to query info to %s",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               bt_common_color_reset());
+       print_plugin_comp_cls_opt(stderr,
+               cfg->cmd_data.query.cfg_component->plugin_name->str,
+               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.query.cfg_component->type);
+       fprintf(stderr, "%s%s with object `%s`: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               cfg->cmd_data.query.object->str,
+               fail_reason,
+               bt_common_color_reset());
+       ret = -1;
 
 end:
        bt_put(comp_cls);
@@ -1046,6 +1153,7 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg)
        static const enum bt_component_class_type comp_cls_type =
                BT_COMPONENT_CLASS_TYPE_SOURCE;
        int64_t array_size, i;
+       const char *fail_reason = NULL;
 
        assert(cfg->cmd_data.print_lttng_live_sessions.url);
        comp_cls = find_component_class(plugin_name, comp_cls_name,
@@ -1076,15 +1184,9 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg)
                goto error;
        }
 
-       results = bt_component_class_query(comp_cls, "sessions",
-               params);
-       if (!results) {
-               BT_LOGE_STR("Failed to query for sessions.");
-               fprintf(stderr, "%s%sFailed to request sessions%s\n",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               goto error;
+       ret = query(comp_cls, "sessions", params, &results, &fail_reason);
+       if (ret) {
+               goto failed;
        }
 
        if (!bt_value_is_array(results)) {
@@ -1153,6 +1255,20 @@ int cmd_print_lttng_live_sessions(struct bt_config *cfg)
 
                BT_PUT(map);
        }
+
+       goto end;
+
+failed:
+       BT_LOGE("Failed to query for sessions: %s", fail_reason);
+       fprintf(stderr, "%s%sFailed to request sessions: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               fail_reason,
+               bt_common_color_reset());
+
+error:
+       ret = -1;
+
 end:
        bt_put(v);
        bt_put(map);
@@ -1160,10 +1276,6 @@ end:
        bt_put(params);
        bt_put(comp_cls);
        return 0;
-
-error:
-       ret = -1;
-       goto end;
 }
 
 static
@@ -1179,6 +1291,7 @@ int cmd_print_ctf_metadata(struct bt_config *cfg)
        static const char * const comp_cls_name = "fs";
        static const enum bt_component_class_type comp_cls_type =
                BT_COMPONENT_CLASS_TYPE_SOURCE;
+       const char *fail_reason = NULL;
 
        assert(cfg->cmd_data.print_ctf_metadata.path);
        comp_cls = find_component_class(plugin_name, comp_cls_name,
@@ -1212,16 +1325,9 @@ int cmd_print_ctf_metadata(struct bt_config *cfg)
                goto end;
        }
 
-       results = bt_component_class_query(comp_cls, "metadata-info",
-               params);
-       if (!results) {
-               ret = -1;
-               BT_LOGE_STR("Failed to query for metadata info.");
-               fprintf(stderr, "%s%sFailed to request metadata info%s\n",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               goto end;
+       ret = query(comp_cls, "metadata-info", params, &results, &fail_reason);
+       if (ret) {
+               goto failed;
        }
 
        metadata_text_value = bt_value_map_get(results, "text");
@@ -1234,8 +1340,19 @@ int cmd_print_ctf_metadata(struct bt_config *cfg)
        ret = bt_value_string_get(metadata_text_value, &metadata_text);
        assert(ret == 0);
        printf("%s\n", metadata_text);
+       goto end;
+
+failed:
+       ret = -1;
+       BT_LOGE("Failed to query for metadata info: %s", fail_reason);
+       fprintf(stderr, "%s%sFailed to request metadata info: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               fail_reason,
+               bt_common_color_reset());
 
 end:
+       destroy_the_query_executor();
        bt_put(results);
        bt_put(params);
        bt_put(metadata_text_value);
@@ -1943,6 +2060,7 @@ int set_stream_intersections(struct cmd_run_ctx *ctx,
        struct bt_value *stream_info = NULL;
        struct port_id *port_id = NULL;
        struct trace_range *trace_range = NULL;
+       const char *fail_reason = NULL;
 
        component_path_value = bt_value_map_get(cfg_comp->params, "path");
        if (!bt_value_is_string(component_path_value)) {
@@ -1974,10 +2092,11 @@ int set_stream_intersections(struct cmd_run_ctx *ctx,
                goto error;
        }
 
-       query_result = bt_component_class_query(comp_cls, "trace-info",
-               query_params);
-       if (!query_result) {
-               BT_LOGD("Component class \'%s\' does not support the \'trace-info\' query.",
+       ret = query(comp_cls, "trace-info", query_params, &query_result,
+               &fail_reason);
+       if (ret) {
+               BT_LOGD("Component class does not support the `trace-info` query: %s: "
+                       "comp-class-name=\"%s\"", fail_reason,
                        bt_component_class_get_name(comp_cls));
                ret = -1;
                goto error;
index a0dd70802c8fae0fe01e5720f1f262e396506357..e115d36b4e8a727971c010866e883c89963b1d42 100644 (file)
@@ -72,6 +72,7 @@ babeltracegraphinclude_HEADERS = \
        babeltrace/graph/notification-packet.h \
        babeltrace/graph/notification-stream.h \
        babeltrace/graph/port.h \
+       babeltrace/graph/query-executor.h \
        babeltrace/graph/private-component-filter.h \
        babeltrace/graph/private-component-sink.h \
        babeltrace/graph/private-component-source.h \
@@ -135,6 +136,7 @@ noinst_HEADERS = \
        babeltrace/graph/notification-packet-internal.h \
        babeltrace/graph/notification-stream-internal.h \
        babeltrace/graph/port-internal.h \
+       babeltrace/graph/query-executor-internal.h \
        babeltrace/lib-logging-internal.h \
        babeltrace/list-internal.h \
        babeltrace/logging-internal.h \
index 31fcb9aae78db61a5d54c195897ccd42d1d0ea05..02c83dc13820eeda22882e72d7b3859b350adc6d 100644 (file)
@@ -93,5 +93,6 @@
 #include <babeltrace/graph/private-connection.h>
 #include <babeltrace/graph/private-notification-iterator.h>
 #include <babeltrace/graph/private-port.h>
+#include <babeltrace/graph/query-executor.h>
 
 #endif /* BABELTRACE_BABELTRACE_H */
index a4d1e7a26569878f0964632e1cc6ee9601e9c234..466bd549f90f2b7ac628bc852a8233a9ade5a81b 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdint.h>
 #include <babeltrace/graph/component-status.h>
 #include <babeltrace/graph/notification-iterator.h>
+#include <babeltrace/graph/query-executor.h>
 #include <babeltrace/types.h>
 
 #ifdef __cplusplus
@@ -41,6 +42,7 @@ struct bt_private_port;
 struct bt_port;
 struct bt_value;
 struct bt_private_notification_iterator;
+struct bt_query_executor;
 
 /**
  * Component class type.
@@ -63,6 +65,11 @@ struct bt_notification_iterator_next_return {
        enum bt_notification_iterator_status status;
 };
 
+struct bt_component_class_query_return {
+       struct bt_value *result;
+       enum bt_query_status status;
+};
+
 typedef enum bt_component_status (*bt_component_class_init_method)(
                struct bt_private_component *private_component,
                struct bt_value *params, void *init_method_data);
@@ -86,8 +93,9 @@ typedef enum bt_notification_iterator_status
                struct bt_private_notification_iterator *private_notification_iterator,
                int64_t time);
 
-typedef struct bt_value *(*bt_component_class_query_method)(
+typedef struct bt_component_class_query_return (*bt_component_class_query_method)(
                struct bt_component_class *component_class,
+               struct bt_query_executor *query_executor,
                const char *object, struct bt_value *params);
 
 typedef enum bt_component_status (*bt_component_class_accept_port_connection_method)(
@@ -163,10 +171,6 @@ extern const char *bt_component_class_get_description(
 extern const char *bt_component_class_get_help(
                struct bt_component_class *component_class);
 
-extern struct bt_value *bt_component_class_query(
-               struct bt_component_class *component_class,
-               const char *object, struct bt_value *params);
-
 /**
  * Get a component class' type.
  *
diff --git a/include/babeltrace/graph/query-executor-internal.h b/include/babeltrace/graph/query-executor-internal.h
new file mode 100644 (file)
index 0000000..055f7a3
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
+#define BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/types.h>
+#include <babeltrace/object-internal.h>
+
+struct bt_query_executor {
+       struct bt_object base;
+       bt_bool canceled;
+};
+
+static inline const char *bt_query_status_string(enum bt_query_status status)
+{
+       switch (status) {
+       case BT_QUERY_STATUS_OK:
+               return "BT_QUERY_STATUS_OK";
+       case BT_QUERY_STATUS_AGAIN:
+               return "BT_QUERY_STATUS_AGAIN";
+       case BT_QUERY_STATUS_EXECUTOR_CANCELED:
+               return "BT_QUERY_STATUS_EXECUTOR_CANCELED";
+       case BT_QUERY_STATUS_ERROR:
+               return "BT_QUERY_STATUS_ERROR";
+       case BT_QUERY_STATUS_INVALID:
+               return "BT_QUERY_STATUS_INVALID";
+       case BT_QUERY_STATUS_INVALID_OBJECT:
+               return "BT_QUERY_STATUS_INVALID_OBJECT";
+       case BT_QUERY_STATUS_INVALID_PARAMS:
+               return "BT_QUERY_STATUS_INVALID_PARAMS";
+       case BT_QUERY_STATUS_NOMEM:
+               return "BT_QUERY_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+};
+
+#endif /* BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H */
diff --git a/include/babeltrace/graph/query-executor.h b/include/babeltrace/graph/query-executor.h
new file mode 100644 (file)
index 0000000..f2187dd
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef BABELTRACE_GRAPH_QUERY_EXECUTOR_H
+#define BABELTRACE_GRAPH_QUERY_EXECUTOR_H
+
+/*
+ * BabelTrace - Babeltrace Component Connection Interface
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_value;
+struct bt_query_executor;
+struct bt_component_class;
+
+enum bt_query_status {
+       BT_QUERY_STATUS_OK                      = 0,
+       BT_QUERY_STATUS_AGAIN                   = 11,
+       BT_QUERY_STATUS_EXECUTOR_CANCELED       = 125,
+       BT_QUERY_STATUS_ERROR                   = -1,
+       BT_QUERY_STATUS_INVALID                 = -22,
+       BT_QUERY_STATUS_INVALID_OBJECT          = -23,
+       BT_QUERY_STATUS_INVALID_PARAMS          = -24,
+       BT_QUERY_STATUS_NOMEM                   = -12,
+};
+
+extern
+struct bt_query_executor *bt_query_executor_create(void);
+
+extern
+enum bt_query_status bt_query_executor_query(
+               struct bt_query_executor *query_executor,
+               struct bt_component_class *component_class,
+               const char *object, struct bt_value *params,
+               struct bt_value **result);
+
+extern
+enum bt_query_status bt_query_executor_cancel(
+               struct bt_query_executor *query_executor);
+
+extern
+bt_bool bt_query_executor_is_canceled(struct bt_query_executor *query_executor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_GRAPH_QUERY_EXECUTOR_H */
index 6999094398bc452644bd8348192c388ae8f8309d..4e6085692cd61ed31cbac16d4ae25242a0ec20e3 100644 (file)
@@ -14,7 +14,8 @@ libgraph_la_SOURCES = \
        sink.c \
        filter.c \
        iterator.c \
-       component-class-sink-colander.c
+       component-class-sink-colander.c \
+       query-executor.c
 
 libgraph_la_LIBADD = \
        notification/libgraph-notification.la
index a899416dd2e4afab9ec11228dfb572fcfc5ec1fd..5343575066e5e3c8bd61114e5a8a8ba437062971 100644 (file)
@@ -969,49 +969,3 @@ int bt_component_class_freeze(
 end:
        return ret;
 }
-
-struct bt_value *bt_component_class_query(
-               struct bt_component_class *component_class,
-               const char *object, struct bt_value *params)
-{
-       struct bt_value *results = NULL;
-
-       if (!component_class) {
-               BT_LOGW_STR("Invalid parameter: component class is NULL.");
-               goto end;
-       }
-
-       if (!object) {
-               BT_LOGW_STR("Invalid parameter: object string is NULL.");
-               goto end;
-       }
-
-       if (!params) {
-               BT_LOGW_STR("Invalid parameter: parameters value is NULL.");
-               goto end;
-       }
-
-       if (!component_class->methods.query) {
-               /* Not an error: nothing to query */
-               BT_LOGD("Component class has no registered query method: "
-                       "addr=%p, name=\"%s\", type=%s",
-                       component_class,
-                       bt_component_class_get_name(component_class),
-                       bt_component_class_type_string(component_class->type));
-               goto end;
-       }
-
-       BT_LOGD("Calling user's query method: "
-               "comp-class-addr=%p, comp-class-name=\"%s\", comp-class-type=%s"
-               "object=\"%s\", params-addr=%p",
-               component_class,
-               bt_component_class_get_name(component_class),
-               bt_component_class_type_string(component_class->type),
-               object, params);
-       results = component_class->methods.query(component_class,
-               object, params);
-       BT_LOGD("User method returned: results-addr=%p", results);
-
-end:
-       return results;
-}
index 7b013d358b9d2d03223ea5cdf848aa2ca4153111..0c18ef62bf7dbbfe42a9b5164845473bb0353265 100644 (file)
@@ -808,7 +808,7 @@ void bt_graph_notify_ports_disconnected(struct bt_graph *graph,
        }
 }
 
-extern enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
+enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
 {
        enum bt_graph_status ret = BT_GRAPH_STATUS_OK;
 
@@ -825,9 +825,19 @@ end:
        return ret;
 }
 
-extern bt_bool bt_graph_is_canceled(struct bt_graph *graph)
+bt_bool bt_graph_is_canceled(struct bt_graph *graph)
 {
-       return graph ? graph->canceled : BT_FALSE;
+       bt_bool canceled = BT_FALSE;
+
+       if (!graph) {
+               BT_LOGW_STR("Invalid parameter: graph is NULL.");
+               goto end;
+       }
+
+       canceled = graph->canceled;
+
+end:
+       return canceled;
 }
 
 BT_HIDDEN
diff --git a/lib/graph/query-executor.c b/lib/graph/query-executor.c
new file mode 100644 (file)
index 0000000..f1cd95b
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "QUERY-EXECUTOR"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/graph/query-executor.h>
+#include <babeltrace/graph/query-executor-internal.h>
+#include <babeltrace/graph/component-class.h>
+#include <babeltrace/graph/component-class-internal.h>
+#include <babeltrace/values.h>
+#include <babeltrace/object-internal.h>
+#include <babeltrace/compiler-internal.h>
+
+static
+void bt_query_executor_destroy(struct bt_object *obj)
+{
+       struct bt_query_executor *query_exec =
+               container_of(obj, struct bt_query_executor, base);
+
+       BT_LOGD("Destroying port: addr=%p", query_exec);
+       g_free(query_exec);
+}
+
+struct bt_query_executor *bt_query_executor_create(void)
+{
+       struct bt_query_executor *query_exec;
+
+       BT_LOGD_STR("Creating query executor.");
+       query_exec = g_new0(struct bt_query_executor, 1);
+       if (!query_exec) {
+               BT_LOGE_STR("Failed to allocate one query executor.");
+               goto end;
+       }
+
+       bt_object_init(query_exec, bt_query_executor_destroy);
+       BT_LOGD("Created query executor: addr=%p", query_exec);
+
+end:
+       return query_exec;
+}
+
+enum bt_query_status bt_query_executor_query(
+               struct bt_query_executor *query_exec,
+               struct bt_component_class *component_class,
+               const char *object, struct bt_value *params,
+               struct bt_value **user_result)
+{
+       struct bt_component_class_query_return ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
+
+       if (!query_exec) {
+               BT_LOGW_STR("Invalid parameter: query executor is NULL.");
+               ret.status = BT_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (query_exec->canceled) {
+               BT_LOGW_STR("Invalid parameter: query executor is canceled.");
+               ret.status = BT_QUERY_STATUS_EXECUTOR_CANCELED;
+               goto end;
+       }
+
+       if (!component_class) {
+               BT_LOGW_STR("Invalid parameter: component class is NULL.");
+               ret.status = BT_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!object) {
+               BT_LOGW_STR("Invalid parameter: object string is NULL.");
+               ret.status = BT_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!params) {
+               params = bt_value_null;
+       }
+
+       if (!component_class->methods.query) {
+               /* Not an error: nothing to query */
+               BT_LOGD("Component class has no registered query method: "
+                       "addr=%p, name=\"%s\", type=%s",
+                       component_class,
+                       bt_component_class_get_name(component_class),
+                       bt_component_class_type_string(component_class->type));
+               ret.status = BT_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_LOGD("Calling user's query method: "
+               "query-exec-addr=%p, comp-class-addr=%p, "
+               "comp-class-name=\"%s\", comp-class-type=%s, "
+               "object=\"%s\", params-addr=%p",
+               query_exec, component_class,
+               bt_component_class_get_name(component_class),
+               bt_component_class_type_string(component_class->type),
+               object, params);
+       ret = component_class->methods.query(component_class, query_exec,
+               object, params);
+       BT_LOGD("User method returned: status=%s, result-addr=%p",
+               bt_query_status_string(ret.status), ret.result);
+       if (query_exec->canceled) {
+               BT_PUT(ret.result);
+               ret.status = BT_QUERY_STATUS_EXECUTOR_CANCELED;
+               goto end;
+       } else {
+               if (ret.status == BT_QUERY_STATUS_EXECUTOR_CANCELED) {
+                       /*
+                        * The user cannot decide that the executor is
+                        * canceled if it's not.
+                        */
+                       BT_PUT(ret.result);
+                       ret.status = BT_QUERY_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       switch (ret.status) {
+       case BT_QUERY_STATUS_INVALID:
+               /*
+                * This is reserved for invalid parameters passed to
+                * this function.
+                */
+               BT_PUT(ret.result);
+               ret.status = BT_QUERY_STATUS_ERROR;
+               break;
+       case BT_QUERY_STATUS_OK:
+               if (!ret.result) {
+                       ret.result = bt_value_null;
+               }
+               break;
+       default:
+               if (ret.result) {
+                       BT_LOGW("User method did not return BT_QUERY_STATUS_OK, but result is not NULL: "
+                               "status=%s, result-addr=%p",
+                               bt_query_status_string(ret.status), ret.result);
+                       BT_PUT(ret.result);
+               }
+       }
+
+end:
+       if (user_result) {
+               *user_result = ret.result;
+               ret.result = NULL;
+       }
+
+       bt_put(ret.result);
+       return ret.status;
+}
+
+enum bt_query_status bt_query_executor_cancel(
+               struct bt_query_executor *query_exec)
+{
+       enum bt_query_status ret = BT_QUERY_STATUS_OK;
+
+       if (!query_exec) {
+               BT_LOGW_STR("Invalid parameter: query executor is NULL.");
+               ret = BT_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       query_exec->canceled = BT_TRUE;
+       BT_LOGV("Canceled query executor: addr=%p", query_exec);
+
+end:
+       return ret;
+}
+
+bt_bool bt_query_executor_is_canceled(struct bt_query_executor *query_exec)
+{
+       bt_bool canceled = BT_FALSE;
+
+       if (!query_exec) {
+               BT_LOGW_STR("Invalid parameter: query executor is NULL.");
+               goto end;
+       }
+
+       canceled = query_exec->canceled;
+
+end:
+       return canceled;
+}
index d2c0ede31ba4202301fee7149545e61a2ee90b2b..e36a70c4a7fe8fcfa9a543b6568d269d97d35962 100644 (file)
@@ -1365,19 +1365,25 @@ enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp,
 }
 
 BT_HIDDEN
-struct bt_value *ctf_fs_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return ctf_fs_query(
+               struct bt_component_class *comp_class,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params)
 {
-       struct bt_value *result = NULL;
+       struct bt_component_class_query_return ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
 
        if (!strcmp(object, "metadata-info")) {
-               result = metadata_info_query(comp_class, params);
+               ret = metadata_info_query(comp_class, params);
        } else if (!strcmp(object, "trace-info")) {
-               result = trace_info_query(comp_class, params);
+               ret = trace_info_query(comp_class, params);
        } else {
                BT_LOGE("Unknown query object `%s`", object);
+               ret.status = BT_QUERY_STATUS_INVALID_OBJECT;
                goto end;
        }
 end:
-       return result;
+       return ret;
 }
index d832495d9212a1ccf52bd47108f042c762a3f6f5..46fa9d8c5c44c319489a7c3f821276ddb249b553 100644 (file)
@@ -142,7 +142,9 @@ BT_HIDDEN
 void ctf_fs_finalize(struct bt_private_component *component);
 
 BT_HIDDEN
-struct bt_value *ctf_fs_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return ctf_fs_query(
+               struct bt_component_class *comp_class,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params);
 
 BT_HIDDEN
index b037f609b7c57c6371e14e77d08697dd0a38744e..696d3d43e297b4c2f6eeb31ff18577c103972760 100644 (file)
@@ -46,10 +46,15 @@ struct range {
 };
 
 BT_HIDDEN
-struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return metadata_info_query(
+               struct bt_component_class *comp_class,
                struct bt_value *params)
 {
-       struct bt_value *result = NULL;
+       struct bt_component_class_query_return query_ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
+
        struct bt_value *path_value = NULL;
        char *metadata_text = NULL;
        FILE *metadata_fp = NULL;
@@ -59,13 +64,15 @@ struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
        const char *path;
        bool is_packetized;
 
-       result = bt_value_map_create();
-       if (!result) {
+       query_ret.result = bt_value_map_create();
+       if (!query_ret.result) {
+               query_ret.status = BT_QUERY_STATUS_NOMEM;
                goto error;
        }
 
        if (!bt_value_is_map(params)) {
                BT_LOGE_STR("Query parameters is not a map value object.");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
@@ -73,6 +80,7 @@ struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
        ret = bt_value_string_get(path_value, &path);
        if (ret) {
                BT_LOGE_STR("Cannot get `path` string parameter.");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
@@ -138,14 +146,14 @@ struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
 
        g_string_append(g_metadata_text, metadata_text);
 
-       ret = bt_value_map_insert_string(result, "text",
+       ret = bt_value_map_insert_string(query_ret.result, "text",
                g_metadata_text->str);
        if (ret) {
                BT_LOGE_STR("Cannot insert metadata text into query result.");
                goto error;
        }
 
-       ret = bt_value_map_insert_bool(result, "is-packetized",
+       ret = bt_value_map_insert_bool(query_ret.result, "is-packetized",
                is_packetized);
        if (ret) {
                BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
@@ -155,7 +163,11 @@ struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
        goto end;
 
 error:
-       BT_PUT(result);
+       BT_PUT(query_ret.result);
+
+       if (query_ret.status >= 0) {
+               query_ret.status = BT_QUERY_STATUS_ERROR;
+       }
 
 end:
        bt_put(path_value);
@@ -168,7 +180,8 @@ end:
        if (metadata_fp) {
                fclose(metadata_fp);
        }
-       return result;
+
+       return query_ret;
 }
 
 static
@@ -445,10 +458,15 @@ end:
 }
 
 BT_HIDDEN
-struct bt_value *trace_info_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return trace_info_query(
+               struct bt_component_class *comp_class,
                struct bt_value *params)
 {
-       struct bt_value *trace_infos = NULL;
+       struct bt_component_class_query_return query_ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
+
        struct bt_value *path_value = NULL;
        int ret = 0;
        const char *path = NULL;
@@ -460,6 +478,7 @@ struct bt_value *trace_info_query(struct bt_component_class *comp_class,
 
        if (!bt_value_is_map(params)) {
                BT_LOGE("Query parameters is not a map value object.");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
@@ -467,6 +486,7 @@ struct bt_value *trace_info_query(struct bt_component_class *comp_class,
        ret = bt_value_string_get(path_value, &path);
        if (ret) {
                BT_LOGE("Cannot get `path` string parameter.");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
@@ -489,8 +509,9 @@ struct bt_value *trace_info_query(struct bt_component_class *comp_class,
                goto error;
        }
 
-       trace_infos = bt_value_array_create();
-       if (!trace_infos) {
+       query_ret.result = bt_value_array_create();
+       if (!query_ret.result) {
+               query_ret.status = BT_QUERY_STATUS_NOMEM;
                goto error;
        }
 
@@ -516,7 +537,7 @@ struct bt_value *trace_info_query(struct bt_component_class *comp_class,
                        goto error;
                }
 
-               status = bt_value_array_append(trace_infos, trace_info);
+               status = bt_value_array_append(query_ret.result, trace_info);
                bt_put(trace_info);
                if (status != BT_VALUE_STATUS_OK) {
                        goto error;
@@ -526,7 +547,12 @@ struct bt_value *trace_info_query(struct bt_component_class *comp_class,
        goto end;
 
 error:
-       BT_PUT(trace_infos);
+       BT_PUT(query_ret.result);
+
+       if (query_ret.status >= 0) {
+               query_ret.status = BT_QUERY_STATUS_ERROR;
+       }
+
 end:
        if (normalized_path) {
                g_string_free(normalized_path, TRUE);
@@ -549,5 +575,5 @@ end:
        }
        /* "path" becomes invalid with the release of path_value. */
        bt_put(path_value);
-       return trace_infos;
+       return query_ret;
 }
index 996a0f1a8e47d5cdbbeb1eb5c235d821bd26877f..fff036c63403d1ada27ef6739f3b1191174a75ef 100644 (file)
 #include <babeltrace/graph/component-class.h>
 
 BT_HIDDEN
-struct bt_value *metadata_info_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return metadata_info_query(
+               struct bt_component_class *comp_class,
                struct bt_value *params);
 
 BT_HIDDEN
-struct bt_value *trace_info_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return trace_info_query(
+               struct bt_component_class *comp_class,
                struct bt_value *params);
 
 #endif /* BABELTRACE_PLUGIN_CTF_FS_QUERY_H */
index 8b0af2d04161d8d239a650749c8448e1354feb9a..bf94314e6dfcd63be84d1d26e0c3f1286a56836d 100644 (file)
@@ -215,7 +215,9 @@ enum bt_ctf_lttng_live_iterator_status {
 enum bt_component_status lttng_live_component_init(struct bt_private_component *source,
                struct bt_value *params, void *init_method_data);
 
-struct bt_value *lttng_live_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return lttng_live_query(
+               struct bt_component_class *comp_class,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params);
 
 void lttng_live_component_finalize(struct bt_private_component *component);
index d89f3723b405fe3adcb2e6495895fe62dc16eb1f..c3e7b641c4a52311644e5d09738d91226607c9d4 100644 (file)
@@ -961,22 +961,30 @@ error:
 }
 
 static
-struct bt_value *lttng_live_query_list_sessions(struct bt_component_class *comp_class,
+struct bt_component_class_query_return lttng_live_query_list_sessions(
+               struct bt_component_class *comp_class,
+               struct bt_query_executor *query_exec,
                struct bt_value *params)
 {
+       struct bt_component_class_query_return query_ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
+
        struct bt_value *url_value = NULL;
-       struct bt_value *results = NULL;
        const char *url;
        struct bt_live_viewer_connection *viewer_connection = NULL;
 
        url_value = bt_value_map_get(params, "url");
        if (!url_value || bt_value_is_null(url_value) || !bt_value_is_string(url_value)) {
                BT_LOGW("Mandatory \"url\" parameter missing");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
        if (bt_value_string_get(url_value, &url) != BT_VALUE_STATUS_OK) {
                BT_LOGW("\"url\" parameter is required to be a string value");
+               query_ret.status = BT_QUERY_STATUS_INVALID_PARAMS;
                goto error;
        }
 
@@ -985,28 +993,47 @@ struct bt_value *lttng_live_query_list_sessions(struct bt_component_class *comp_
                goto error;
        }
 
-       results = bt_live_viewer_connection_list_sessions(viewer_connection);
+       query_ret.result =
+               bt_live_viewer_connection_list_sessions(viewer_connection);
+       if (!query_ret.result) {
+               goto error;
+       }
+
        goto end;
+
 error:
-       BT_PUT(results);
+       BT_PUT(query_ret.result);
+
+       if (query_ret.status >= 0) {
+               query_ret.status = BT_QUERY_STATUS_ERROR;
+       }
+
 end:
        if (viewer_connection) {
                bt_live_viewer_connection_destroy(viewer_connection);
        }
        BT_PUT(url_value);
-       return results;
+       return query_ret;
 }
 
 BT_HIDDEN
-struct bt_value *lttng_live_query(struct bt_component_class *comp_class,
+struct bt_component_class_query_return lttng_live_query(
+               struct bt_component_class *comp_class,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params)
 {
+       struct bt_component_class_query_return ret = {
+               .result = NULL,
+               .status = BT_QUERY_STATUS_OK,
+       };
+
        if (strcmp(object, "sessions") == 0) {
                return lttng_live_query_list_sessions(comp_class,
-                       params);
+                       query_exec, params);
        }
        BT_LOGW("Unknown query object `%s`", object);
-       return NULL;
+       ret.status = BT_QUERY_STATUS_INVALID_OBJECT;
+       return ret;
 }
 
 static
index a8160c338c241f25299b89bb37757322915f2d5a..d29f22f7e0b927830d5cce52c7734c0bec69676e 100644 (file)
@@ -168,7 +168,7 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
         with self.assertRaises(bt2.Error):
-            MySink.query('obj', 23)
+            bt2.QueryExecutor().query(MySink, 'obj', 23)
 
     def test_query_raises(self):
         class MySink(bt2._UserSinkComponent):
@@ -176,11 +176,11 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 raise ValueError
 
         with self.assertRaises(bt2.Error):
-            MySink.query('obj', 23)
+            bt2.QueryExecutor().query(MySink, 'obj', 23)
 
     def test_query_wrong_return_type(self):
         class MySink(bt2._UserSinkComponent):
@@ -188,11 +188,11 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 return ...
 
         with self.assertRaises(bt2.Error):
-            MySink.query('obj', 23)
+            bt2.QueryExecutor().query(MySink, 'obj', 23)
 
     def test_query_params_none(self):
         class MySink(bt2._UserSinkComponent):
@@ -200,14 +200,14 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 nonlocal query_params
                 query_params = params
                 return None
 
         query_params = None
         params = None
-        res = MySink.query('obj', params)
+        res = bt2.QueryExecutor().query(MySink, 'obj', params)
         self.assertEqual(query_params, params)
         self.assertIsNone(res)
         del query_params
@@ -218,14 +218,14 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 nonlocal query_params
                 query_params = params
                 return 17.5
 
         query_params = None
         params = ['coucou', 23, None]
-        res = MySink.query('obj', params)
+        res = bt2.QueryExecutor().query(MySink, 'obj', params)
         self.assertEqual(query_params, params)
         self.assertEqual(res, 17.5)
         del query_params
@@ -236,7 +236,7 @@ class UserComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 nonlocal query_params
                 query_params = params
                 return {
@@ -255,7 +255,7 @@ class UserComponentClassTestCase(unittest.TestCase):
             'null': None,
         }
 
-        res = MySink.query('obj', params)
+        res = bt2.QueryExecutor().query(MySink, 'obj', params)
         self.assertEqual(query_params, params)
         self.assertEqual(res, {
             'null': None,
@@ -283,7 +283,7 @@ class GenericComponentClassTestCase(unittest.TestCase):
                 pass
 
             @classmethod
-            def _query(cls, obj, params):
+            def _query(cls, query_exec, obj, params):
                 return [obj, params, 23]
 
         self._py_comp_cls = MySink
@@ -318,6 +318,7 @@ class GenericComponentClassTestCase(unittest.TestCase):
         self.assertEqual(self._py_comp_cls, self._comp_cls)
 
     def test_query(self):
-        res = self._comp_cls.query('an object', {'yes': 'no', 'book': -17})
+        res = bt2.QueryExecutor().query(self._comp_cls, 'an object',
+                                        {'yes': 'no', 'book': -17})
         expected = ['an object', {'yes': 'no', 'book': -17}, 23]
         self.assertEqual(res, expected)
diff --git a/tests/bindings/python/bt2/test_query_executor.py b/tests/bindings/python/bt2/test_query_executor.py
new file mode 100644 (file)
index 0000000..f0ee9d4
--- /dev/null
@@ -0,0 +1,131 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class QueryExecutorTestCase(unittest.TestCase):
+    def test_query(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                nonlocal query_params
+                query_params = params
+                return {
+                    'null': None,
+                    'bt2': 'BT2',
+                }
+
+        query_params = None
+        params = {
+            'array': ['coucou', 23, None],
+            'other_map': {
+                'yes': 'yeah',
+                '19': 19,
+                'minus 1.5': -1.5,
+            },
+            'null': None,
+        }
+
+        res = bt2.QueryExecutor().query(MySink, 'obj', params)
+        self.assertEqual(query_params, params)
+        self.assertEqual(res, {
+            'null': None,
+            'bt2': 'BT2',
+        })
+        del query_params
+
+    def test_query_params_none(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                nonlocal query_params
+                query_params = params
+
+        query_params = 23
+        res = bt2.QueryExecutor().query(MySink, 'obj', None)
+        self.assertEqual(query_params, None)
+        del query_params
+
+    def test_query_gen_error(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                raise ValueError
+
+        with self.assertRaises(bt2.Error):
+            res = bt2.QueryExecutor().query(MySink, 'obj', [17, 23])
+
+    def test_query_invalid_object(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                raise bt2.InvalidQueryObject
+
+        with self.assertRaises(bt2.InvalidQueryObject):
+            res = bt2.QueryExecutor().query(MySink, 'obj', [17, 23])
+
+    def test_query_invalid_params(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                raise bt2.InvalidQueryParams
+
+        with self.assertRaises(bt2.InvalidQueryParams):
+            res = bt2.QueryExecutor().query(MySink, 'obj', [17, 23])
+
+    def test_query_try_again(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                raise bt2.TryAgain
+
+        with self.assertRaises(bt2.TryAgain):
+            res = bt2.QueryExecutor().query(MySink, 'obj', [17, 23])
+
+    def test_cancel_no_query(self):
+        query_exec = bt2.QueryExecutor()
+        self.assertFalse(query_exec.is_canceled)
+        query_exec.cancel()
+        self.assertTrue(query_exec.is_canceled)
+
+    def test_query_canceled(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, query_exec, obj, params):
+                raise bt2.TryAgain
+
+        query_exec = bt2.QueryExecutor()
+        query_exec.cancel()
+
+        with self.assertRaises(bt2.QueryExecutorCanceled):
+            res = query_exec.query(MySink, 'obj', [17, 23])
+
+    def test_eq(self):
+        query_exec = bt2.QueryExecutor()
+        self.assertEqual(query_exec, query_exec)
+
+    def test_eq_invalid(self):
+        query_exec = bt2.QueryExecutor()
+        self.assertNotEqual(query_exec, 23)
index c17f078b8fd172494e9aa0bb143cdf0bb8a1c5f8..b66baead25c196ccdc39b9b181261380802dc683 100644 (file)
@@ -57,19 +57,23 @@ static enum bt_notification_iterator_status dummy_iterator_seek_time_method(
        return BT_NOTIFICATION_ITERATOR_STATUS_OK;
 }
 
-static struct bt_value *query_method(
+static struct bt_component_class_query_return query_method(
                struct bt_component_class *component_class,
+               struct bt_query_executor *query_exec,
                const char *object, struct bt_value *params)
 {
-       int ret;
-       struct bt_value *results = bt_value_array_create();
+       struct bt_component_class_query_return ret = {
+               .status = BT_QUERY_STATUS_OK,
+               .result = bt_value_array_create(),
+       };
+       int iret;
 
-       assert(results);
-       ret = bt_value_array_append_string(results, object);
-       assert(ret == 0);
-       ret = bt_value_array_append(results, params);
-       assert(ret == 0);
-       return results;
+       assert(ret.result);
+       iret = bt_value_array_append_string(ret.result, object);
+       assert(iret == 0);
+       iret = bt_value_array_append(ret.result, params);
+       assert(iret == 0);
+       return ret;
 }
 
 BT_PLUGIN_MODULE();
index 2a6e7fd87dd49b4844ad30a4326a11e6ee8d23f5..c367b90d7b8e139a604442f8417d1a7a38b21861 100644 (file)
@@ -24,6 +24,7 @@
 #include <babeltrace/values.h>
 #include <babeltrace/graph/component.h>
 #include <babeltrace/graph/graph.h>
+#include <babeltrace/graph/query-executor.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -168,7 +169,10 @@ static void test_sfs(const char *plugin_dir)
        const char *object_str;
        enum bt_value_status value_ret;
        enum bt_graph_status graph_ret;
+       struct bt_query_executor *query_exec = bt_query_executor_create();
+       int ret;
 
+       assert(query_exec);
        assert(sfs_path);
        diag("sfs plugin test below");
 
@@ -214,15 +218,18 @@ static void test_sfs(const char *plugin_dir)
                "bt_plugin_get_component_class_by_name_and_type() does not find a component class given the wrong type");
        params = bt_value_integer_create_init(23);
        assert(params);
-       ok (!bt_component_class_query(NULL, "get-something", params),
-               "bt_component_class_query() handles NULL (component class)");
-       ok (!bt_component_class_query(filter_comp_class, NULL, params),
-               "bt_component_class_query() handles NULL (object)");
-       ok (!bt_component_class_query(filter_comp_class, "get-something", NULL),
-               "bt_component_class_query() handles NULL (parameters)");
-       results = bt_component_class_query(filter_comp_class,
-               "get-something", params);
-       ok(results, "bt_component_class_query() succeeds");
+       ret = bt_query_executor_query(NULL, filter_comp_class, "object",
+               params, &results);
+       ok (ret, "bt_query_executor_query() handles NULL (query executor)");
+       ret = bt_query_executor_query(query_exec, NULL, "object",
+               params, &results);
+       ok (ret, "bt_query_executor_query() handles NULL (component class)");
+       ret = bt_query_executor_query(query_exec, filter_comp_class, NULL,
+               params, &results);
+       ok (ret, "bt_query_executor_query() handles NULL (object)");
+       ret = bt_query_executor_query(query_exec, filter_comp_class,
+               "get-something", params, &results);
+       ok(ret == 0 && results, "bt_query_executor_query() succeeds");
        assert(bt_value_is_array(results) && bt_value_array_size(results) == 2);
        object = bt_value_array_get(results, 0);
        assert(object && bt_value_is_string(object));
@@ -270,6 +277,7 @@ static void test_sfs(const char *plugin_dir)
        bt_put(res_params);
        bt_put(results);
        bt_put(params);
+       bt_put(query_exec);
 }
 
 static void test_create_all_from_dir(const char *plugin_dir)
This page took 0.053308 seconds and 4 git commands to generate.