[tracker/tracker-store-ipc: 5/5] Added libtracker-socket-ipc



commit 1ccde0fb45c7c8c5e1a48ae79fd321db03de469d
Author: Philip Van Hoof <philip codeminded be>
Date:   Sun May 31 20:36:41 2009 +0200

    Added libtracker-socket-ipc
    
    This is an experimental API for clients to perform rapid SPARQL UPDATE calls
---
 configure.ac                                       |   31 +++
 src/Makefile.am                                    |    8 +-
 src/libtracker-socket-ipc/Makefile.am              |   41 ++++
 .../tracker-socket-ipc-test.c                      |   61 ++++++
 src/libtracker-socket-ipc/tracker-socket-ipc.c     |  225 ++++++++++++++++++++
 src/libtracker-socket-ipc/tracker-socket-ipc.h     |   43 ++++
 src/tracker-store/tracker-socket-listener.c        |   12 +-
 7 files changed, 416 insertions(+), 5 deletions(-)

diff --git a/configure.ac b/configure.ac
index 81d998c..63b9230 100644
--- a/configure.ac
+++ b/configure.ac
@@ -725,6 +725,36 @@ fi
 AM_CONDITIONAL(HAVE_LIBTRACKERGTK, test "$have_libtrackergtk" = "yes")
 
 ##################################################################
+# Enable building libtracker-socket-ipc?
+##################################################################
+
+AC_ARG_ENABLE([libtrackersocketipc], 
+              AS_HELP_STRING([--enable-libtrackersocketipc], 
+	      		     [enable libtrackersocketipc [[default=auto]]]),,
+	      [enable_libtrackersocketipc=auto])
+
+if test "x$enable_libtrackersocketipc" != "xno" ; then
+   PKG_CHECK_MODULES(LIBTRACKERSOCKETIPC, [
+		     glib-2.0    >= $GLIB_REQUIRED
+        	     gvariant],
+		     [have_libtrackersocketipc=yes], 
+   		     [have_libtrackersocketipc=no])
+
+   AC_SUBST([LIBTRACKERSOCKETIPC_CFLAGS])
+   AC_SUBST([LIBTRACKERSOCKETIPC_LIBS])
+else
+   have_libtrackersocketipc="no  (disabled)"
+fi
+
+if test "x$enable_libtrackersocketipc" = "xyes"; then
+   if test "x$have_libtrackersocketipc" != "xyes"; then
+      AC_MSG_ERROR([Couldn't find libtracker_socket_ipc dependencies (glib-2.0 >= $GLIB_REQUIRED, gvariant).])
+   fi
+fi
+
+AM_CONDITIONAL(HAVE_LIBTRACKERSOCKETIPC, test "$have_libtrackersocketipc" = "yes")
+
+##################################################################
 # Enable building tracker-applet notification icon?
 ##################################################################
 
@@ -1358,6 +1388,7 @@ AC_CONFIG_FILES([
 	src/libtracker-data/Makefile
 	src/libtracker-db/Makefile
 	src/libtracker-gtk/Makefile
+	src/libtracker-socket-ipc/Makefile
 	src/libtracker/Makefile
 	src/Makefile
 	src/rasqal/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 79678cc..9865bc3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,10 @@ if HAVE_TRACKER_SEARCH_TOOL
 build_tracker_search_tool = tracker-search-tool
 endif
 
+if HAVE_LIBTRACKERSOCKETIPC
+build_libtracker_socket_ipc = libtracker-socket-ipc
+endif
+
 SUBDIRS = 					\
 	libstemmer				\
 	$(build_libinotify)			\
@@ -37,7 +41,8 @@ SUBDIRS = 					\
 	$(build_libtrackergtk)			\
 	$(build_tracker_applet)			\
 	$(build_tracker_search_tool)		\
-	$(build_tracker_preferences)
+	$(build_tracker_preferences)		\
+	$(build_libtracker_socket_ipc)
 
 DIST_SUBDIRS = 					\
 	libstemmer				\
@@ -56,4 +61,5 @@ DIST_SUBDIRS = 					\
 	tracker-applet	 			\
 	tracker-search-tool			\
 	tracker-preferences			\
+	libtracker-socket-ipc			\
 	plugins
diff --git a/src/libtracker-socket-ipc/Makefile.am b/src/libtracker-socket-ipc/Makefile.am
new file mode 100644
index 0000000..883a0ba
--- /dev/null
+++ b/src/libtracker-socket-ipc/Makefile.am
@@ -0,0 +1,41 @@
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES =						\
+	-DSHAREDIR=\""$(datadir)"\"			\
+	-DG_LOG_DOMAIN=\"Tracker\"			\
+	-DTRACKER_COMPILATION				\
+	-I$(top_srcdir)/src				\
+	$(WARN_CFLAGS)					\
+	$(GLIB2_CFLAGS)					\
+	$(GOBJECT_CFLAGS)				\
+	$(GCOV_CFLAGS)					\
+	$(LIBTRACKERSOCKETIPC_CFLAGS)			\
+	$(UNAC_CFLAGS)
+
+noinst_PROGRAMS = tracker-socket-ipc-test
+
+libtracker_socket_ipcdir = $(libdir)/tracker-$(TRACKER_API_VERSION)
+libtracker_socket_ipcincludedir=$(includedir)/tracker-$(TRACKER_API_VERSION)/libtracker-socket-ipc/
+libtracker_socket_ipc_LTLIBRARIES = libtracker-socket-ipc.la
+
+libtracker_socket_ipc_la_SOURCES =	 			\
+	tracker-socket-ipc.c					
+
+libtracker_socket_ipcinclude_HEADERS =				\
+	tracker-socket-ipc.h
+
+libtracker_socket_ipc_la_LDFLAGS = 				\
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+libtracker_socket_ipc_la_LIBADD = 				\
+	$(UNAC_LIBS)						\
+	$(GCOV_LIBS)						\
+	$(GLIB2_LIBS)						\
+	$(LIBTRACKERSOCKETIPC_LIBS)
+
+tracker_socket_ipc_test_SOURCES = tracker-socket-ipc-test.c
+
+tracker_socket_ipc_test_LDADD = $(LIBTRACKERSOCKETIPC_LIBS) 	\
+	$(GLIB2_LIBS) $(GOBJECT_LIBS) \
+	$(top_builddir)/src/libtracker-socket-ipc/libtracker-socket-ipc.la
+
diff --git a/src/libtracker-socket-ipc/tracker-socket-ipc-test.c b/src/libtracker-socket-ipc/tracker-socket-ipc-test.c
new file mode 100644
index 0000000..ff0abd7
--- /dev/null
+++ b/src/libtracker-socket-ipc/tracker-socket-ipc-test.c
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Philip Van Hoof <philip codeminded be>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors: Philip Van Hoof <philip codeminded be>
+ */
+
+#include <glib.h>
+
+#include "tracker-socket-ipc.h"
+
+static void
+on_received (GError *error, gpointer user_data)
+{
+	guint i = (guint) user_data;
+
+	g_print ("Received %u (%s)\n", i,
+	         error ? error->message : "OK");
+}
+
+static gboolean
+run_program (gpointer user_data)
+{
+	guint i;
+
+	for (i = 0; i < 1000; i++) {
+		tracker_socket_ipc_queue_sparql_update ("INSERT { <test> a nfo:Document }",
+		                                        on_received, (gpointer) i, NULL);
+	}
+
+	return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+	GMainLoop *loop;
+
+	g_type_init ();
+	tracker_socket_ipc_init ();
+
+	loop = g_main_loop_new (NULL, FALSE);
+
+	g_timeout_add_seconds (1, run_program, NULL);
+
+	g_main_loop_run (loop);
+}
diff --git a/src/libtracker-socket-ipc/tracker-socket-ipc.c b/src/libtracker-socket-ipc/tracker-socket-ipc.c
new file mode 100644
index 0000000..825306a
--- /dev/null
+++ b/src/libtracker-socket-ipc/tracker-socket-ipc.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Philip Van Hoof <philip codeminded be>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors: Philip Van Hoof <philip codeminded be>
+ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+#include "tracker-socket-ipc.h"
+
+#define IPC_ERROR_DOMAIN      "TrackerSocketIpcDomain"
+#define IPC_DOMAIN             g_quark_from_static_string (IPC_ERROR_DOMAIN)
+
+static int sockfd = -1;
+static GHashTable *queued = NULL;
+static gchar standard_buffer[4028];
+
+typedef struct {
+	TrackerSocketIpcSparqlUpdateCallback callback;
+	GDestroyNotify destroy;
+	gpointer user_data;
+} QueuedTask;
+
+static void
+queued_task_free (QueuedTask *queued_task)
+{
+	if (queued_task->destroy) {
+		queued_task->destroy (queued_task->user_data);
+	}
+	g_slice_free (QueuedTask, queued_task);
+}
+
+static gboolean
+data_to_handle_received (GIOChannel *source,
+                         GIOCondition cond,
+                         gpointer data)
+{
+	gint clientfd = (int) data;
+
+	if (cond & G_IO_IN) {
+		gchar status[40];
+		gsize len;
+
+		len = recv (clientfd, status, sizeof (status), 0);
+
+		if (len == sizeof (status) && status[14] == '{' && status[25] == '}' &&
+		    status[27] == '{' && status[38] == '}') {
+
+			QueuedTask *queued_task;
+			gchar *ptr = status + 15;
+			const gchar *key = status + 3;
+			guint data_length;
+			gchar *free_data = NULL, *error_msg;
+			guint error_code;
+
+			status[2] = '\0';
+			status[25] = '\0';
+			status[38] = '\0';
+			status[13] = '\0';
+
+			error_code = atol (ptr);
+
+			ptr = status + 28;
+			data_length = atol (ptr);
+
+			if (data_length > sizeof (standard_buffer)) {
+				free_data = error_msg = (gchar *) malloc (data_length);
+			} else {
+				standard_buffer[data_length] = '\0';
+				error_msg = standard_buffer;
+			}
+
+			len = recv (clientfd, error_msg, data_length, 0);
+
+			queued_task = g_hash_table_lookup (queued, key);
+
+			if (queued_task && len == data_length) {
+				GError *new_error = NULL;
+
+				if (g_strcmp0 (status, "ER") == 0) {
+					g_set_error (&new_error,
+					             IPC_DOMAIN,
+					             error_code,
+					             "%s", error_msg);
+				}
+
+				if (queued_task->callback) {
+					queued_task->callback (new_error, 
+					                       queued_task->user_data);
+				}
+
+				g_hash_table_remove (queued, key);
+
+				g_free (free_data);
+			} else {
+				g_free (free_data);
+				goto failed;
+			}
+
+		} else {
+			goto failed;
+		}
+	}
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		g_io_channel_close (source);
+		goto failed;
+	}
+
+	return TRUE;
+
+failed:
+
+	return FALSE;
+
+}
+
+void
+tracker_socket_ipc_init (void)
+{
+	GIOChannel *io;
+	gchar *path, *tmp;
+	struct sockaddr_un addr;
+	int len;
+
+	tmp = g_strdup_printf ("tracker-%s", g_get_user_name ());
+	path = g_build_filename (g_get_tmp_dir (), tmp, "socket", NULL);
+
+	addr.sun_family = AF_UNIX;
+	strcpy (addr.sun_path, path);
+
+	g_free (tmp);
+	g_free (path);
+
+	sockfd = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (!sockfd) {
+		perror ("socket");
+	}
+
+	len = strlen(addr.sun_path) + sizeof(addr.sun_family);
+
+	if (connect(sockfd, (struct sockaddr *)&addr, len) == -1) {
+		perror("connect");
+		close (sockfd);
+	} else {
+
+		//listen (sockfd, 1);
+
+		io = g_io_channel_unix_new (sockfd);
+		signal(SIGPIPE, SIG_IGN);
+
+		queued = g_hash_table_new_full (g_str_hash, g_str_equal,
+		                                (GDestroyNotify) g_free,
+		                                (GDestroyNotify) queued_task_free);
+
+		g_io_add_watch (io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+		                data_to_handle_received, (gpointer) sockfd);
+	
+		g_io_channel_unref (io);
+	}
+}
+
+void
+tracker_socket_ipc_shutdown (void)
+{
+	close (sockfd);
+	g_hash_table_unref (queued);
+}
+
+void
+tracker_socket_ipc_queue_sparql_update   (const gchar   *sparql,
+                                          TrackerSocketIpcSparqlUpdateCallback callback,
+                                          gpointer       user_data,
+                                          GDestroyNotify destroy)
+{
+	static guint key_counter = 0;
+	QueuedTask *queued_task;
+	gchar *query, *key;
+
+	g_return_if_fail (queued != NULL);
+
+	queued_task = g_slice_new (QueuedTask);
+	queued_task->callback = callback;
+	queued_task->destroy = destroy;
+	queued_task->user_data = user_data;
+
+	key = g_strdup_printf ("%010u", key_counter++);
+
+	query = g_strdup_printf ("UPDATE {%s} {%010u}\n%s",
+	                         key,
+	                         strlen (sparql),
+	                         sparql);
+
+	if (send (sockfd, query, strlen (query), 0) == -1) {
+		perror("send");
+	}
+
+	g_hash_table_insert (queued, key, queued_task);
+
+	g_free (query);
+}
+
diff --git a/src/libtracker-socket-ipc/tracker-socket-ipc.h b/src/libtracker-socket-ipc/tracker-socket-ipc.h
new file mode 100644
index 0000000..5a14bb7
--- /dev/null
+++ b/src/libtracker-socket-ipc/tracker-socket-ipc.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Philip Van Hoof <philip codeminded be>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors: Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __LIBTRACKER_SOCKET_IPC_H__
+#define __LIBTRACKER_SOCKET_IPC_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef void (* TrackerSocketIpcSparqlUpdateCallback)  (GError          *error,
+                                                        gpointer         user_data);
+
+void          tracker_socket_ipc_init                  (void);
+void          tracker_socket_ipc_shutdown              (void);
+
+void          tracker_socket_ipc_queue_sparql_update   (const gchar   *sparql,
+                                                        TrackerSocketIpcSparqlUpdateCallback callback,
+                                                        gpointer       user_data,
+                                                        GDestroyNotify destroy);
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_SOCKET_IPC_H__ */
diff --git a/src/tracker-store/tracker-socket-listener.c b/src/tracker-store/tracker-socket-listener.c
index ac783ae..4c704b0 100644
--- a/src/tracker-store/tracker-socket-listener.c
+++ b/src/tracker-store/tracker-socket-listener.c
@@ -77,9 +77,13 @@ on_update_fin (GError   *error,
 	}
 
 	if (error) {
-		message = g_strdup_printf ("ER:%s:%s", info->key, error->message);
+		message = g_strdup_printf ("ER:%s:{%010u}:{%010u}:%s", info->key,
+		                           error->code,
+		                           strlen (error->message),
+		                           error->message);
 	} else {
-		message = g_strdup_printf ("OK:%s", info->key);
+		message = g_strdup_printf ("OK:%s:{%010u}:{%010u}:none", info->key,
+		                           0, 4);
 	}
 
 	send (info->clientfd, message, strlen (message), 0);
@@ -102,8 +106,8 @@ data_to_handle_received (GIOChannel *source,
 		if (len == sizeof (command) && command[7] == '{' && command[18] == '}' &&
 		    command[20] == '{' && command[31] == '}') {
 
-			gchar *ptr = command + 8;
-			const gchar *key = command + 21;
+			gchar *ptr = command + 21;
+			const gchar *key = command + 8;
 			guint data_length;
 			gchar *free_data = NULL, *query_data;
 



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