[lttng-dev] [PATCH babeltrace] Add a format-agnostic iterator creation mechanism

Jérémie Galarneau jeremie.galarneau at efficios.com
Mon May 27 23:38:47 EDT 2013


Iterators now expose an event providing function so that a user does not
need to know the input trace format to get "bt_ctf_event"s.

A context can now create a specialized iterator depending on its input
trace format.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau at efficios.com>
---
 converter/babeltrace.c                 | 10 +++---
 formats/ctf/ctf.c                      |  3 ++
 formats/ctf/iterator.c                 | 34 +++++++++++++-------
 include/babeltrace/context-internal.h  |  1 +
 include/babeltrace/context.h           | 31 ++++++++++++++++++
 include/babeltrace/ctf/iterator.h      |  6 ++--
 include/babeltrace/format.h            | 14 +++++++++
 include/babeltrace/iterator-internal.h |  1 +
 include/babeltrace/iterator.h          | 11 +++++++
 lib/context.c                          | 57 ++++++++++++++++++++++++++++++++++
 lib/iterator.c                         | 14 +++++++++
 tests/lib/test-seeks.c                 | 42 ++++++++++++-------------
 12 files changed, 183 insertions(+), 41 deletions(-)

diff --git a/converter/babeltrace.c b/converter/babeltrace.c
index 8f09845..c86df93 100644
--- a/converter/babeltrace.c
+++ b/converter/babeltrace.c
@@ -617,19 +617,19 @@ static
 int convert_trace(struct bt_trace_descriptor *td_write,
 		  struct bt_context *ctx)
 {
-	struct bt_ctf_iter *iter;
+	struct bt_iter *iter;
 	struct bt_iter_pos begin_pos;
 	struct bt_ctf_event *ctf_event;
 	int ret;
 	const GPtrArray *out_streams = bt_trace_descriptor_get_stream_pos(td_write);
 
 	begin_pos.type = BT_SEEK_BEGIN;
-	iter = bt_ctf_iter_create(ctx, &begin_pos, NULL);
+	iter = bt_context_create_iterator(ctx, &begin_pos, NULL);
 	if (!iter) {
 		ret = -1;
 		goto error_iter;
 	}
-	while ((ctf_event = bt_ctf_iter_read_event(iter))) {
+	while ((ctf_event = bt_iter_get_event(iter))) {
 		int sout_nr;
 		for (sout_nr = 0; sout_nr < out_streams->len; ++sout_nr) {
 			struct bt_stream_pos *sout =
@@ -643,7 +643,7 @@ int convert_trace(struct bt_trace_descriptor *td_write,
 				goto end;
 			}
 		}
-		ret = bt_iter_next(bt_ctf_get_iter(iter));
+		ret = bt_iter_next(iter);
 		if (ret < 0) {
 			goto end;
 		}
@@ -651,7 +651,7 @@ int convert_trace(struct bt_trace_descriptor *td_write,
 	ret = 0;
 
 end:
-	bt_ctf_iter_destroy(iter);
+	bt_context_destroy_iterator(ctx, iter);
 error_iter:
 	return ret;
 }
diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c
index aee80b1..c029791 100644
--- a/formats/ctf/ctf.c
+++ b/formats/ctf/ctf.c
@@ -29,6 +29,7 @@
 #include <babeltrace/format.h>
 #include <babeltrace/ctf/types.h>
 #include <babeltrace/ctf/metadata.h>
+#include <babeltrace/ctf/iterator.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/ctf/events-internal.h>
 #include <babeltrace/trace-handle-internal.h>
@@ -144,6 +145,8 @@ struct bt_format ctf_format = {
 	.timestamp_begin = ctf_timestamp_begin,
 	.timestamp_end = ctf_timestamp_end,
 	.convert_index_timestamp = ctf_convert_index_timestamp,
+	.iterator_create = bt_ctf_iter_create,
+	.iterator_destroy = bt_ctf_iter_destroy
 };
 
 static
diff --git a/formats/ctf/iterator.c b/formats/ctf/iterator.c
index d2cd914..a294167 100644
--- a/formats/ctf/iterator.c
+++ b/formats/ctf/iterator.c
@@ -30,6 +30,7 @@
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/format.h>
 #include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
 #include <babeltrace/ctf-ir/metadata.h>
 #include <babeltrace/prio_heap.h>
 #include <babeltrace/iterator-internal.h>
@@ -39,7 +40,7 @@
 
 #include "events-private.h"
 
-struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
+struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx,
 		const struct bt_iter_pos *begin_pos,
 		const struct bt_iter_pos *end_pos)
 {
@@ -60,10 +61,11 @@ struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
 	iter->recalculate_dep_graph = 0;
 	iter->main_callbacks.callback = NULL;
 	iter->dep_gc = g_ptr_array_new();
-	return iter;
+	iter->parent.get_event = bt_ctf_iter_read_event;
+	return &iter->parent;
 }
 
-void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
+void bt_ctf_iter_destroy(struct bt_iter *iter)
 {
 	struct bt_stream_callbacks *bt_stream_cb;
 	struct bt_callback_chain *bt_chain;
@@ -71,13 +73,16 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
 
 	assert(iter);
 
+	struct bt_ctf_iter *ctf_iter =
+		container_of(iter, struct bt_ctf_iter, parent);
+
 	/* free all events callbacks */
-	if (iter->main_callbacks.callback)
-		g_array_free(iter->main_callbacks.callback, TRUE);
+	if (ctf_iter->main_callbacks.callback)
+		g_array_free(ctf_iter->main_callbacks.callback, TRUE);
 
 	/* free per-event callbacks */
-	for (i = 0; i < iter->callbacks->len; i++) {
-		bt_stream_cb = &g_array_index(iter->callbacks,
+	for (i = 0; i < ctf_iter->callbacks->len; i++) {
+		bt_stream_cb = &g_array_index(ctf_iter->callbacks,
 				struct bt_stream_callbacks, i);
 		if (!bt_stream_cb || !bt_stream_cb->per_id_callbacks)
 			continue;
@@ -90,10 +95,10 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
 		}
 		g_array_free(bt_stream_cb->per_id_callbacks, TRUE);
 	}
-	g_array_free(iter->callbacks, TRUE);
-	g_ptr_array_free(iter->dep_gc, TRUE);
+	g_array_free(ctf_iter->callbacks, TRUE);
+	g_ptr_array_free(ctf_iter->dep_gc, TRUE);
 
-	bt_iter_fini(&iter->parent);
+	bt_iter_fini(iter);
 	g_free(iter);
 }
 
@@ -158,9 +163,14 @@ stop:
 	return NULL;
 }
 
-struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter)
+struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter)
 {
-	return bt_ctf_iter_read_event_flags(iter, NULL);
+	struct bt_ctf_iter *ctf_iter;
+	if (!iter) {
+		return NULL;
+	}
+	ctf_iter = container_of(iter, struct bt_ctf_iter, parent);
+	return bt_ctf_iter_read_event_flags(ctf_iter, NULL);
 }
 
 uint64_t bt_ctf_get_lost_events_count(struct bt_ctf_iter *iter)
diff --git a/include/babeltrace/context-internal.h b/include/babeltrace/context-internal.h
index 17d6202..7600d8d 100644
--- a/include/babeltrace/context-internal.h
+++ b/include/babeltrace/context-internal.h
@@ -51,6 +51,7 @@ struct bt_context {
 	int refcount;
 	int last_trace_handle_id;
 	struct bt_iter *current_iterator;
+	struct bt_format *input_trace_format;
 };
 
 #endif /* _BABELTRACE_CONTEXT_INTERNAL_H */
diff --git a/include/babeltrace/context.h b/include/babeltrace/context.h
index b28df09..6455b65 100644
--- a/include/babeltrace/context.h
+++ b/include/babeltrace/context.h
@@ -32,6 +32,7 @@
  */
 
 #include <unistd.h>
+#include <stdio.h>
 #include <babeltrace/format.h>
 
 #ifdef __cplusplus
@@ -96,6 +97,36 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
 int bt_context_remove_trace(struct bt_context *ctx, int trace_id);
 
 /*
+ * bt_context_create_iterator: Allocate an iterator on the current trace
+ * collection's events.
+ *
+ * begin_pos and end_pos are optional parameters to specify the position
+ * at which the trace collection should be seeked upon iterator
+ * creation, and the position at which iteration will start returning
+ * "EOF".
+ *
+ * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at
+ * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of
+ * trace) is the EOF criterion.
+ *
+ * Return a pointer to the newly allocated iterator.
+ *
+ * Only one iterator can be created against a context. If more than one
+ * iterator is being created for the same context, the second creation
+ * will return NULL. The previous iterator must be destroyed before
+ * creation of the new iterator for this function to succeed.
+ */
+struct bt_iter *bt_context_create_iterator(struct bt_context *ctx,
+	const struct bt_iter_pos *position_begin,
+	const struct bt_iter_pos *position_end);
+
+/*
+ * bt_context_destroy_iterator: Free a trace collection iterator.
+ */
+void bt_context_destroy_iterator(struct bt_context *ctx,
+		 struct bt_iter *iterator);
+
+/*
  * bt_context_get and bt_context_put : increments and decrement the
  * refcount of the context
  *
diff --git a/include/babeltrace/ctf/iterator.h b/include/babeltrace/ctf/iterator.h
index ec6aac7..159e4a4 100644
--- a/include/babeltrace/ctf/iterator.h
+++ b/include/babeltrace/ctf/iterator.h
@@ -59,7 +59,7 @@ struct bt_ctf_event;
  * will return NULL. The previous iterator must be destroyed before
  * creation of the new iterator for this function to succeed.
  */
-struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
+struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx,
 		const struct bt_iter_pos *begin_pos,
 		const struct bt_iter_pos *end_pos);
 
@@ -71,7 +71,7 @@ struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter);
 /*
  * bt_ctf_iter_destroy - Free a CTF trace collection iterator.
  */
-void bt_ctf_iter_destroy(struct bt_ctf_iter *iter);
+void bt_ctf_iter_destroy(struct bt_iter *iter);
 
 /*
  * bt_ctf_iter_read_event: Read the iterator's current event data.
@@ -80,7 +80,7 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter);
  *
  * Return current event on success, NULL on end of trace.
  */
-struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter);
+struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter);
 
 /*
  * bt_ctf_iter_read_event_flags: Read the iterator's current event data.
diff --git a/include/babeltrace/format.h b/include/babeltrace/format.h
index 9f3d1c8..c170d83 100644
--- a/include/babeltrace/format.h
+++ b/include/babeltrace/format.h
@@ -45,6 +45,9 @@ typedef int bt_intern_str;
 struct bt_stream_pos;
 struct bt_context;
 struct bt_trace_handle;
+struct bt_trace_descriptor;
+struct bt_iter;
+struct bt_iter_pos;
 
 struct bt_mmap_stream {
 	int fd;
@@ -77,6 +80,17 @@ struct bt_format {
 	uint64_t (*timestamp_end)(struct bt_trace_descriptor *descriptor,
 			struct bt_trace_handle *handle, enum bt_clock_type type);
 	int (*convert_index_timestamp)(struct bt_trace_descriptor *descriptor);
+
+	/*
+	 * Only one iterator can be created against a context. If more than one
+	 * iterator is being created for the same context, the second creation
+	 * will return NULL. The previous iterator must be destroyed before
+	 * creation of the new iterator for this function to succeed.
+	 */
+	struct bt_iter *(*iterator_create)(struct bt_context *ctx,
+			const struct bt_iter_pos *begin_pos,
+			const struct bt_iter_pos *end_pos);
+	void (*iterator_destroy)(struct bt_iter *iterator);
 };
 
 extern struct bt_format *bt_lookup_format(bt_intern_str qname);
diff --git a/include/babeltrace/iterator-internal.h b/include/babeltrace/iterator-internal.h
index 2b0b2f2..2008d76 100644
--- a/include/babeltrace/iterator-internal.h
+++ b/include/babeltrace/iterator-internal.h
@@ -39,6 +39,7 @@ struct bt_iter {
 	struct ptr_heap *stream_heap;
 	struct bt_context *ctx;
 	const struct bt_iter_pos *end_pos;
+	struct bt_ctf_event *(*get_event)(struct bt_iter *iter);
 };
 
 /*
diff --git a/include/babeltrace/iterator.h b/include/babeltrace/iterator.h
index 360a9c7..aa189a8 100644
--- a/include/babeltrace/iterator.h
+++ b/include/babeltrace/iterator.h
@@ -27,6 +27,7 @@
 
 #include <babeltrace/format.h>
 #include <babeltrace/context.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -40,6 +41,7 @@ enum {
 /* Forward declarations */
 struct bt_iter;
 struct bt_saved_pos;
+struct bt_ctf_event;
 
 /*
  * bt_iter is an abstract class, each format has to implement its own
@@ -123,6 +125,15 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos);
 struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter,
 		uint64_t timestamp);
 
+/*
+ * bt_iter_get_event: Get the iterator's current event data
+ *
+ * @iter trace collection iterator (input). Should not be NULL.
+ *
+ * Return current event on success, NULL on end of trace.
+ */
+struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/context.c b/lib/context.c
index dc77366..61215a3 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -87,6 +87,12 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
 		ret = -1;
 		goto end;
 	}
+	if (ctx->input_trace_format && ctx->input_trace_format != fmt) {
+		fprintf(stderr, "[error] [Context] Opening traces of different formats in the same context is not supported.\n");
+		ret = -1;
+		goto end;
+	}
+	ctx->input_trace_format = fmt;
 	if (path) {
 		td = fmt->open_trace(path, O_RDONLY, packet_seek, NULL);
 		if (!td) {
@@ -211,3 +217,54 @@ void bt_context_put(struct bt_context *ctx)
 	if (ctx->refcount == 0)
 		bt_context_destroy(ctx);
 }
+
+struct bt_iter *bt_context_create_iterator(struct bt_context *ctx,
+			const struct bt_iter_pos *position_begin,
+			const struct bt_iter_pos *position_end)
+{
+	struct bt_iter *iter = NULL;
+	struct bt_format *fmt;
+	assert(ctx);
+
+	if (!ctx->input_trace_format) {
+		fprintf(stderr, "[error] No trace opened in context.\n");
+		goto end;
+	}
+	fmt = ctx->input_trace_format;
+	if (!fmt->iterator_create) {
+		fprintf(stderr, "[error] The %s format plug-in did not register an iterator creation function.\n", g_quark_to_string(fmt->name));
+		goto end;
+	}
+	iter = fmt->iterator_create(ctx, position_begin, position_end);
+
+	if (!ctx->current_iterator) {
+		fprintf(stderr, "[error] The %s format plug-in did not call bt_iter_init in its iterator creation function.\n",
+			g_quark_to_string(fmt->name));
+	}
+
+end:
+	return iter;
+}
+
+void bt_context_destroy_iterator(struct bt_context *ctx,
+			struct bt_iter *iter)
+{
+	struct bt_format *fmt;
+	assert(ctx);
+
+	if (!ctx->input_trace_format) {
+		fprintf(stderr, "[error] No trace opened in context.\n");
+		return;
+	}
+	fmt = ctx->input_trace_format;
+	if (!fmt->iterator_destroy) {
+		fprintf(stderr, "[error] The %s format plug-in did not register an iterator destruction function.\n",
+			g_quark_to_string(fmt->name));
+		return;
+	}
+	fmt->iterator_destroy(iter);
+	if (ctx->current_iterator) {
+		fprintf(stderr, "[warn] The %s format plug-in did not call bt_iter_fini in its iterator destruction function.\n",
+			g_quark_to_string(fmt->name));
+	}
+}
diff --git a/lib/iterator.c b/lib/iterator.c
index 4190e65..b838000 100644
--- a/lib/iterator.c
+++ b/lib/iterator.c
@@ -805,3 +805,17 @@ int bt_iter_next(struct bt_iter *iter)
 end:
 	return ret;
 }
+
+struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter)
+{
+	struct bt_ctf_event *event;
+	if (!iter->get_event) {
+		event = NULL;
+		fprintf(stderr, "[error] No get_event callback registered by the output plug-in.\n");
+		goto end;
+	}
+	event = iter->get_event(iter);
+
+end:
+	return event;
+}
diff --git a/tests/lib/test-seeks.c b/tests/lib/test-seeks.c
index 47bb42e..69e4d4b 100644
--- a/tests/lib/test-seeks.c
+++ b/tests/lib/test-seeks.c
@@ -37,7 +37,7 @@
 void run_seek_begin(char *path, uint64_t expected_begin)
 {
 	struct bt_context *ctx;
-	struct bt_ctf_iter *iter;
+	struct bt_iter *iter;
 	struct bt_ctf_event *event;
 	struct bt_iter_pos newpos;
 	int ret;
@@ -51,12 +51,12 @@ void run_seek_begin(char *path, uint64_t expected_begin)
 	}
 
 	/* Create iterator with null begin and end */
-	iter = bt_ctf_iter_create(ctx, NULL, NULL);
+	iter = bt_context_create_iterator(ctx, NULL, NULL);
 	if (!iter) {
 		plan_skip_all("Cannot create valid iterator");
 	}
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid");
 
@@ -67,7 +67,7 @@ void run_seek_begin(char *path, uint64_t expected_begin)
 
 	/* Validate that we get the same value after a seek begin */
 	newpos.type = BT_SEEK_BEGIN;
-	ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+	ret = bt_iter_set_pos(iter, &newpos);
 
 	ok(ret == 0, "Seek begin retval %d", ret);
 
@@ -86,7 +86,7 @@ void run_seek_begin(char *path, uint64_t expected_begin)
 void run_seek_last(char *path, uint64_t expected_last)
 {
 	struct bt_context *ctx;
-	struct bt_ctf_iter *iter;
+	struct bt_iter *iter;
 	struct bt_ctf_event *event;
 	struct bt_iter_pos newpos;
 	int ret;
@@ -99,18 +99,18 @@ void run_seek_last(char *path, uint64_t expected_last)
 	}
 
 	/* Create iterator with null last and end */
-	iter = bt_ctf_iter_create(ctx, NULL, NULL);
+	iter = bt_context_create_iterator(ctx, NULL, NULL);
 	if (!iter) {
 		plan_skip_all("Cannot create valid iterator");
 	}
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid at beginning");
 
 	/* Seek to last */
 	newpos.type = BT_SEEK_LAST;
-	ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+	ret = bt_iter_set_pos(iter, &newpos);
 
 	ok(ret == 0, "Seek last retval %d", ret);
 
@@ -123,11 +123,11 @@ void run_seek_last(char *path, uint64_t expected_last)
 	ok1(timestamp_last == expected_last);
 
 	/* Try to read next event */
-	ret = bt_iter_next(bt_ctf_get_iter(iter));
+	ret = bt_iter_next(iter);
 
 	ok(ret == 0, "iter next should return an error");
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event == 0, "Event after last should be invalid");
 
@@ -139,7 +139,7 @@ void run_seek_cycles(char *path,
 		uint64_t expected_last)
 {
 	struct bt_context *ctx;
-	struct bt_ctf_iter *iter;
+	struct bt_iter *iter;
 	struct bt_ctf_event *event;
 	struct bt_iter_pos newpos;
 	int ret;
@@ -152,22 +152,22 @@ void run_seek_cycles(char *path,
 	}
 
 	/* Create iterator with null last and end */
-	iter = bt_ctf_iter_create(ctx, NULL, NULL);
+	iter = bt_context_create_iterator(ctx, NULL, NULL);
 	if (!iter) {
 		plan_skip_all("Cannot create valid iterator");
 	}
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid at beginning");
 
 	/* Seek to last */
 	newpos.type = BT_SEEK_LAST;
-	ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+	ret = bt_iter_set_pos(iter, &newpos);
 
 	ok(ret == 0, "Seek last retval %d", ret);
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid at last position");
 
@@ -176,21 +176,21 @@ void run_seek_cycles(char *path,
 	ok1(timestamp == expected_last);
 
 	/* Try to read next event */
-	ret = bt_iter_next(bt_ctf_get_iter(iter));
+	ret = bt_iter_next(iter);
 
 	ok(ret == 0, "iter next should return an error");
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event == 0, "Event after last should be invalid");
 
 	/* Seek to BEGIN */
 	newpos.type = BT_SEEK_BEGIN;
-	ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+	ret = bt_iter_set_pos(iter, &newpos);
 
 	ok(ret == 0, "Seek begin retval %d", ret);
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid at first position");
 
@@ -200,11 +200,11 @@ void run_seek_cycles(char *path,
 
 	/* Seek last again */
 	newpos.type = BT_SEEK_LAST;
-	ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+	ret = bt_iter_set_pos(iter, &newpos);
 
 	ok(ret == 0, "Seek last retval %d", ret);
 
-	event = bt_ctf_iter_read_event(iter);
+	event = bt_iter_get_event(iter);
 
 	ok(event, "Event valid at last position");
 
-- 
1.8.2.3




More information about the lttng-dev mailing list