[tracker/dbus-fd-experiment: 2/3] libtracker-client: Add Steroids support



commit 7eadb6584e1cd8b09aee2d38ea3b4a85b1405fcf
Author: Adrien Bustany <abustany gnome org>
Date:   Mon May 24 08:52:02 2010 -0400

    libtracker-client: Add Steroids support

 src/libtracker-client/tracker.c |  348 +++++++++++++++++++++++++++++++++++++++
 src/libtracker-client/tracker.h |   12 ++
 2 files changed, 360 insertions(+), 0 deletions(-)
---
diff --git a/src/libtracker-client/tracker.c b/src/libtracker-client/tracker.c
index 455fb86..9921ae4 100644
--- a/src/libtracker-client/tracker.c
+++ b/src/libtracker-client/tracker.c
@@ -27,6 +27,10 @@
 #include <dbus/dbus-glib-bindings.h>
 
 #include <libtracker-common/tracker-dbus.h>
+#include <tracker-store/tracker-steroids.h>
+
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "tracker.h"
 
@@ -92,6 +96,7 @@
  **/
 
 typedef struct {
+	DBusGConnection *connection;
 	DBusGProxy *proxy_statistics;
 	DBusGProxy *proxy_resources;
 
@@ -141,6 +146,19 @@ typedef struct {
 	guint id;
 } CallbackArray;
 
+struct TrackerResultIterator {
+	int fd;
+	DBusPendingCall *call;
+	int rc;
+	char buffer[STEROIDS_BUFFER_SIZE];
+	int buffer_index;
+	char *large_row_buf;
+
+	guint  n_columns;
+	int   *offsets;
+	char  *data;
+};
+
 #endif /* TRACKER_DISABLE_DEPRECATED */
 
 static gboolean is_service_available (void);
@@ -360,6 +378,8 @@ client_constructed (GObject *object)
 		return;
 	}
 
+	private->connection = connection;
+
 	private->proxy_statistics =
 		dbus_g_proxy_new_for_name (connection,
 		                           TRACKER_DBUS_SERVICE,
@@ -677,6 +697,151 @@ find_conversion (const char  *format,
 	return start;
 }
 
+static int
+iterator_buffer_read_int (TrackerResultIterator *iterator)
+{
+	int result = 0;
+	char *dst = iterator->buffer + iterator->buffer_index;
+
+	result += (((unsigned char)*(dst++)));
+	result += (((unsigned char)*(dst++)) <<  8);
+	result += (((unsigned char)*(dst++)) << 16);
+	result += (((unsigned char)*(dst++)) << 24);
+	iterator->buffer_index += sizeof (int);
+
+	return result;
+}
+
+static void
+pipe_read (int fd, char *dst, int size)
+{
+	ssize_t readsofar = 0;
+
+	while (readsofar < size) {
+		readsofar += read (fd,
+		                   dst + readsofar,
+		                   size - readsofar);
+	}
+}
+
+/* Copied from dbus-gobject.c, in DBus-GLib */
+static gint
+dbus_error_to_gerror_code (const char *derr)
+{
+	if (0) ;
+	else if (!strcmp (derr, DBUS_ERROR_FAILED))
+		return DBUS_GERROR_FAILED ;
+	else if (!strcmp (derr, DBUS_ERROR_NO_MEMORY))
+		return DBUS_GERROR_NO_MEMORY ;
+	else if (!strcmp (derr, DBUS_ERROR_SERVICE_UNKNOWN))
+		return DBUS_GERROR_SERVICE_UNKNOWN ;
+	else if (!strcmp (derr, DBUS_ERROR_NAME_HAS_NO_OWNER))
+		return DBUS_GERROR_NAME_HAS_NO_OWNER ;
+	else if (!strcmp (derr, DBUS_ERROR_NO_REPLY))
+		return DBUS_GERROR_NO_REPLY ;
+	else if (!strcmp (derr, DBUS_ERROR_IO_ERROR))
+		return DBUS_GERROR_IO_ERROR ;
+	else if (!strcmp (derr, DBUS_ERROR_BAD_ADDRESS))
+		return DBUS_GERROR_BAD_ADDRESS ;
+	else if (!strcmp (derr, DBUS_ERROR_NOT_SUPPORTED))
+		return DBUS_GERROR_NOT_SUPPORTED ;
+	else if (!strcmp (derr, DBUS_ERROR_LIMITS_EXCEEDED))
+		return DBUS_GERROR_LIMITS_EXCEEDED ;
+	else if (!strcmp (derr, DBUS_ERROR_ACCESS_DENIED))
+		return DBUS_GERROR_ACCESS_DENIED ;
+	else if (!strcmp (derr, DBUS_ERROR_AUTH_FAILED))
+		return DBUS_GERROR_AUTH_FAILED ;
+	else if (!strcmp (derr, DBUS_ERROR_NO_SERVER))
+		return DBUS_GERROR_NO_SERVER ;
+	else if (!strcmp (derr, DBUS_ERROR_TIMEOUT))
+		return DBUS_GERROR_TIMEOUT ;
+	else if (!strcmp (derr, DBUS_ERROR_NO_NETWORK))
+		return DBUS_GERROR_NO_NETWORK ;
+	else if (!strcmp (derr, DBUS_ERROR_ADDRESS_IN_USE))
+		return DBUS_GERROR_ADDRESS_IN_USE ;
+	else if (!strcmp (derr, DBUS_ERROR_DISCONNECTED))
+		return DBUS_GERROR_DISCONNECTED ;
+	else if (!strcmp (derr, DBUS_ERROR_INVALID_ARGS))
+		return DBUS_GERROR_INVALID_ARGS ;
+	else if (!strcmp (derr, DBUS_ERROR_FILE_NOT_FOUND))
+		return DBUS_GERROR_FILE_NOT_FOUND ;
+	else if (!strcmp (derr, DBUS_ERROR_FILE_EXISTS))
+		return DBUS_GERROR_FILE_EXISTS ;
+	else if (!strcmp (derr, DBUS_ERROR_UNKNOWN_METHOD))
+		return DBUS_GERROR_UNKNOWN_METHOD ;
+	else if (!strcmp (derr, DBUS_ERROR_TIMED_OUT))
+		return DBUS_GERROR_TIMED_OUT ;
+	else if (!strcmp (derr, DBUS_ERROR_MATCH_RULE_NOT_FOUND))
+		return DBUS_GERROR_MATCH_RULE_NOT_FOUND ;
+	else if (!strcmp (derr, DBUS_ERROR_MATCH_RULE_INVALID))
+		return DBUS_GERROR_MATCH_RULE_INVALID ;
+	else if (!strcmp (derr, DBUS_ERROR_SPAWN_EXEC_FAILED))
+		return DBUS_GERROR_SPAWN_EXEC_FAILED ;
+	else if (!strcmp (derr, DBUS_ERROR_SPAWN_FORK_FAILED))
+		return DBUS_GERROR_SPAWN_FORK_FAILED ;
+	else if (!strcmp (derr, DBUS_ERROR_SPAWN_CHILD_EXITED))
+		return DBUS_GERROR_SPAWN_CHILD_EXITED ;
+	else if (!strcmp (derr, DBUS_ERROR_SPAWN_CHILD_SIGNALED))
+		return DBUS_GERROR_SPAWN_CHILD_SIGNALED ;
+	else if (!strcmp (derr, DBUS_ERROR_SPAWN_FAILED))
+		return DBUS_GERROR_SPAWN_FAILED ;
+	else if (!strcmp (derr, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN))
+		return DBUS_GERROR_UNIX_PROCESS_ID_UNKNOWN ;
+	else if (!strcmp (derr, DBUS_ERROR_INVALID_SIGNATURE))
+		return DBUS_GERROR_INVALID_SIGNATURE ;
+	else if (!strcmp (derr, DBUS_ERROR_INVALID_FILE_CONTENT))
+		return DBUS_GERROR_INVALID_FILE_CONTENT ;
+	else if (!strcmp (derr, DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN))
+		return DBUS_GERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN ;
+	else
+		return DBUS_GERROR_REMOTE_EXCEPTION;
+}
+
+/**
+ * dbus_set_g_error:
+ * @gerror: an error
+ * @error: a #DBusError
+ *
+ * Store the information from a DBus method error return into a
+ * GError.  For the normal case of an arbitrary remote process,
+ * the error code will be DBUS_GERROR_REMOTE_EXCEPTION.  Now,
+ * DBus errors have two components; a message and a "name".
+ * The former is an arbitrary (normally American English) string.
+ * The second is a string like com.example.FooFailure which
+ * programs can use as a conditional source.  Because a GError
+ * only has one string, we use a hack to encode both values:
+ *
+ * &lt;human readable string&gt;&lt;null&gt;&lt;error name&gt;&lt;null&gt;
+ *
+ * You can use the following code to retrieve both values:
+ *
+ * |[const char *msg = error->message;
+ * size_t len = strlen(msg);
+ * const char *error_name = msg+len+1;]|
+ *
+ * Copied from dbus-gobject.c, DBus-GLib
+ */
+void
+dbus_set_g_error (GError    **gerror,
+                  DBusError  *error)
+{
+	int code;
+
+	code = dbus_error_to_gerror_code (error->name);
+	if (code != DBUS_GERROR_REMOTE_EXCEPTION)
+		g_set_error (gerror, DBUS_GERROR,
+		             code,
+		             "%s",
+		             error->message);
+	else
+		g_set_error (gerror, DBUS_GERROR,
+		             code,
+		             "%s%c%s",
+		             error->message ? error->message : "",
+		             '\0',
+		             error->name);
+}
+
 /**
  * tracker_uri_vprintf_escaped:
  * @format: a standard printf() format string, but notice
@@ -1045,6 +1210,189 @@ tracker_resources_sparql_query (TrackerClient  *client,
 	return table;
 }
 
+TrackerResultIterator*
+tracker_resources_sparql_query_steroids (TrackerClient  *client,
+                                         const gchar    *query,
+                                         GError        **error)
+{
+	TrackerClientPrivate *private;
+	DBusConnection *connection;
+	DBusMessage *message;
+	DBusMessage *reply;
+	guint query_id;
+	DBusError dbus_error;
+	TrackerResultIterator *iterator;
+
+	g_return_val_if_fail (TRACKER_IS_CLIENT (client), NULL);
+	g_return_val_if_fail (query, NULL);
+
+	private = TRACKER_CLIENT_GET_PRIVATE (client);
+
+	connection = dbus_g_connection_get_connection (private->connection);
+
+	dbus_error_init (&dbus_error);
+
+	message = dbus_message_new_method_call (TRACKER_STEROIDS_SERVICE,
+	                                        TRACKER_STEROIDS_PATH,
+	                                        TRACKER_STEROIDS_INTERFACE,
+	                                        "PrepareQuery");
+	dbus_message_append_args (message,
+	                          DBUS_TYPE_STRING, &query,
+	                          DBUS_TYPE_INVALID);
+	reply = dbus_connection_send_with_reply_and_block (connection,
+	                                                   message,
+	                                                   -1,
+	                                                   &dbus_error);
+	dbus_message_unref (message);
+
+	if (!reply) {
+		dbus_set_g_error (error, &dbus_error);
+		return NULL;
+	}
+
+	iterator = g_slice_new0 (TrackerResultIterator);
+
+	dbus_message_get_args (reply,
+	                       &dbus_error,
+	                       DBUS_TYPE_UNIX_FD, &iterator->fd,
+	                       DBUS_TYPE_UINT32,  &query_id,
+	                       DBUS_TYPE_INVALID);
+	dbus_message_unref (reply);
+
+	message = dbus_message_new_method_call (TRACKER_STEROIDS_SERVICE,
+	                                        TRACKER_STEROIDS_PATH,
+	                                        TRACKER_STEROIDS_INTERFACE,
+	                                        "Fetch");
+	dbus_message_append_args (message,
+	                          DBUS_TYPE_UINT32, &query_id,
+	                          DBUS_TYPE_INVALID);
+	reply = dbus_connection_send_with_reply_and_block (connection,
+	                                                   message,
+	                                                   -1,
+	                                                   &dbus_error);
+	dbus_message_unref (message);
+
+	if (!reply) {
+		dbus_set_g_error (error, &dbus_error);
+		tracker_result_iterator_free (iterator);
+		return NULL;
+	}
+
+	dbus_message_unref (reply);
+
+	/* Pre fetch the first buffer to initialize the iterator */
+	pipe_read (iterator->fd, iterator->buffer, STEROIDS_BUFFER_SIZE);
+
+	iterator->rc = iterator_buffer_read_int (iterator);
+
+	switch (iterator->rc) {
+	case STEROIDS_RC_ROW:
+	case STEROIDS_RC_LARGEROW:
+		iterator->n_columns = iterator_buffer_read_int (iterator);
+		break;
+	case STEROIDS_RC_DONE:
+		break;
+	case STEROIDS_RC_ERROR:
+		tracker_result_iterator_free (iterator);
+		iterator = NULL;
+		break;
+	}
+
+	/* Reset the iterator internal state */
+	iterator->buffer_index = 0;
+
+	return iterator;
+}
+
+void
+tracker_result_iterator_free (TrackerResultIterator *iterator)
+{
+	g_slice_free (TrackerResultIterator, iterator);
+}
+
+guint
+tracker_result_iterator_n_columns (TrackerResultIterator *iterator)
+{
+	g_return_val_if_fail (iterator, 0);
+
+	return iterator->n_columns;
+}
+
+gboolean
+tracker_result_iterator_has_next (TrackerResultIterator *iterator)
+{
+	g_return_val_if_fail (iterator, FALSE);
+
+	return (iterator->rc == STEROIDS_RC_ROW || iterator->rc == STEROIDS_RC_LARGEROW);
+}
+
+void
+tracker_result_iterator_next (TrackerResultIterator  *iterator)
+{
+	int row_size;
+
+	g_return_if_fail (iterator);
+
+	if (iterator->large_row_buf) {
+		g_free (iterator->large_row_buf);
+		iterator->large_row_buf = NULL;
+	}
+
+	if ((unsigned char)(*(iterator->buffer + iterator->buffer_index)) == STEROIDS_EOP ||
+	    iterator->buffer_index == STEROIDS_BUFFER_SIZE) {
+		pipe_read (iterator->fd, iterator->buffer, STEROIDS_BUFFER_SIZE);
+		iterator->buffer_index = 0;
+	}
+
+	iterator->rc = iterator_buffer_read_int (iterator);
+
+	switch (iterator->rc) {
+		case STEROIDS_RC_ROW:
+			iterator->n_columns = iterator_buffer_read_int (iterator);
+			iterator->offsets = (int *)(iterator->buffer + iterator->buffer_index);
+			iterator->buffer_index += iterator->n_columns * sizeof (int);
+			iterator->data = iterator->buffer + iterator->buffer_index;
+			iterator->buffer_index += iterator->offsets[iterator->n_columns - 1] + 1;
+			break;
+		case STEROIDS_RC_LARGEROW:
+			row_size = iterator_buffer_read_int (iterator);
+			iterator->large_row_buf = malloc (sizeof (char) * row_size);
+			memcpy (iterator->large_row_buf, iterator->buffer, STEROIDS_BUFFER_SIZE);
+			pipe_read (iterator->fd,
+			           iterator->large_row_buf + STEROIDS_BUFFER_SIZE,
+			           row_size - STEROIDS_BUFFER_SIZE);
+			/* The number of columns will always fit into the iterator read buffer,
+			 * since it's an int */
+			iterator->n_columns = iterator_buffer_read_int (iterator);
+			/* For subsequent reads we need additional steps so that we can treat
+			 * iterator->read_buffer and large_row_buf as a single large buffer */
+			iterator->offsets = (int *)(iterator->large_row_buf + 3 * sizeof (int));
+			iterator->data = (char *)iterator->offsets + sizeof (int) * iterator->n_columns;
+			iterator->buffer_index = STEROIDS_BUFFER_SIZE;
+			break;
+		case STEROIDS_RC_DONE:
+			break;
+		default:
+			/* If an error happened, it has been reported by
+			 * tracker_resources_sparql_query_steroids */
+			break;
+	}
+}
+
+const gchar *
+tracker_result_iterator_value (TrackerResultIterator *iterator,
+                               guint                  column)
+{
+	g_return_val_if_fail (iterator, NULL);
+	g_return_val_if_fail (column < iterator->n_columns, NULL);
+
+	if (column == 0) {
+		return iterator->data;
+	} else {
+		return iterator->data + iterator->offsets[column-1] + 1;
+	}
+}
+
 /**
  * tracker_resources_sparql_update:
  * @client: a #TrackerClient.
diff --git a/src/libtracker-client/tracker.h b/src/libtracker-client/tracker.h
index 0069907..34d3153 100644
--- a/src/libtracker-client/tracker.h
+++ b/src/libtracker-client/tracker.h
@@ -49,6 +49,8 @@ typedef struct {
 	GObjectClass parent;
 } TrackerClientClass;
 
+typedef struct TrackerResultIterator TrackerResultIterator;
+
 /**
  * TrackerClientFlags:
  * @TRACKER_CLIENT_ENABLE_WARNINGS: If supplied warnings will be
@@ -122,6 +124,16 @@ void           tracker_resources_load                      (TrackerClient
 GPtrArray *    tracker_resources_sparql_query              (TrackerClient          *client,
                                                             const gchar            *query,
                                                             GError                **error);
+TrackerResultIterator *
+               tracker_resources_sparql_query_steroids     (TrackerClient          *client,
+                                                            const gchar            *query,
+                                                            GError                **error);
+void           tracker_result_iterator_free                (TrackerResultIterator  *iterator);
+guint          tracker_result_iterator_n_columns           (TrackerResultIterator  *iterator);
+gboolean       tracker_result_iterator_has_next            (TrackerResultIterator  *iterator);
+void           tracker_result_iterator_next                (TrackerResultIterator  *iterator);
+const gchar *  tracker_result_iterator_value               (TrackerResultIterator  *iterator,
+                                                            guint                   column);
 void           tracker_resources_sparql_update             (TrackerClient          *client,
                                                             const gchar            *query,
                                                             GError                **error);



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