[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r29623 - gnunet/src/testbed
From: |
gnunet |
Subject: |
[GNUnet-SVN] r29623 - gnunet/src/testbed |
Date: |
Thu, 26 Sep 2013 17:03:13 +0200 |
Author: harsha
Date: 2013-09-26 17:03:13 +0200 (Thu, 26 Sep 2013)
New Revision: 29623
Added:
gnunet/src/testbed/gnunet-service-testbed_connectionpool.c
gnunet/src/testbed/gnunet-service-testbed_connectionpool.h
Modified:
gnunet/src/testbed/Makefile.am
gnunet/src/testbed/gnunet-daemon-testbed-blacklist.c
gnunet/src/testbed/gnunet-service-test-barriers.c
gnunet/src/testbed/gnunet-service-testbed.c
Log:
- towards seperating connection pooling from cache
Modified: gnunet/src/testbed/Makefile.am
===================================================================
--- gnunet/src/testbed/Makefile.am 2013-09-26 14:54:54 UTC (rev 29622)
+++ gnunet/src/testbed/Makefile.am 2013-09-26 15:03:13 UTC (rev 29623)
@@ -42,7 +42,9 @@
gnunet-service-testbed_meminfo.c \
gnunet-service-testbed_meminfo.h \
gnunet-service-testbed_barriers.c \
- gnunet-service-testbed_barriers.h
+ gnunet-service-testbed_barriers.h \
+ gnunet-service-testbed_connectionpool.c \
+ gnunet-service-testbed_connectionpool.h
gnunet_service_testbed_LDADD = $(XLIB) \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/core/libgnunetcore.la \
Modified: gnunet/src/testbed/gnunet-daemon-testbed-blacklist.c
===================================================================
--- gnunet/src/testbed/gnunet-daemon-testbed-blacklist.c 2013-09-26
14:54:54 UTC (rev 29622)
+++ gnunet/src/testbed/gnunet-daemon-testbed-blacklist.c 2013-09-26
15:03:13 UTC (rev 29623)
@@ -20,7 +20,7 @@
/**
- * @file testbed/gnunet-daemon-testbed-blacklist
+ * @file testbed/gnunet-daemon-testbed-blacklist.c
* @brief daemon to restrict incoming connections from other peers at the
* transport layer of a peer
* @author Sree Harsha Totakura <address@hidden>
Modified: gnunet/src/testbed/gnunet-service-test-barriers.c
===================================================================
--- gnunet/src/testbed/gnunet-service-test-barriers.c 2013-09-26 14:54:54 UTC
(rev 29622)
+++ gnunet/src/testbed/gnunet-service-test-barriers.c 2013-09-26 15:03:13 UTC
(rev 29623)
@@ -99,7 +99,7 @@
* @param cls NULL
* @param args arguments passed to GNUNET_PROGRAM_run
* @param cfgfile the path to configuration file
- * @param cfg the configuration file handle
+ * @param config the configuration file handle
*/
static void
run (void *cls, char *const *args, const char *cfgfile,
Modified: gnunet/src/testbed/gnunet-service-testbed.c
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed.c 2013-09-26 14:54:54 UTC (rev
29622)
+++ gnunet/src/testbed/gnunet-service-testbed.c 2013-09-26 15:03:13 UTC (rev
29623)
@@ -26,6 +26,7 @@
#include "gnunet-service-testbed.h"
#include "gnunet-service-testbed_barriers.h"
+#include "gnunet-service-testbed_connectionpool.h"
/***********/
/* Globals */
@@ -826,6 +827,7 @@
GNUNET_free_non_null (hostname);
/* Free hello cache */
GST_cache_clear ();
+ GST_connection_pool_destroy ();
GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
GST_opq_openfds = NULL;
GST_stats_destroy ();
@@ -922,6 +924,7 @@
GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
"CACHE_SIZE", &num));
GST_cache_init ((unsigned int) num);
+ GST_connection_pool_init ((unsigned int) num);
GNUNET_assert (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
"MAX_OPEN_FDS", &num));
Added: gnunet/src/testbed/gnunet-service-testbed_connectionpool.c
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed_connectionpool.c
(rev 0)
+++ gnunet/src/testbed/gnunet-service-testbed_connectionpool.c 2013-09-26
15:03:13 UTC (rev 29623)
@@ -0,0 +1,891 @@
+/*
+ This file is part of GNUnet.
+ (C) 2008--2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet 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 3, or (at your
+ option) any later version.
+
+ GNUnet 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 GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file testbed/gnunet-service-testbed_connectionpool.c
+ * @brief connection pooling for connections to peers' services
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+#include "gnunet-service-testbed.h"
+#include "gnunet-service-testbed_connectionpool.h"
+#include "testbed_api_operations.h"
+
+/**
+ * Redefine LOG with a changed log component string
+ */
+#ifdef LOG
+#undef LOG
+#endif
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-connectionpool", __VA_ARGS__)
+
+
+/**
+ * Time to expire a cache entry
+ */
+#define CACHE_EXPIRY \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * The request handle for obtaining a pooled connection
+ */
+struct GST_ConnectionPool_GetHandle;
+
+
+/**
+ * A pooled connection
+ */
+struct PooledConnection
+{
+ /**
+ * Next ptr for placing this object in the DLL of least recently used pooled
+ * connections
+ */
+ struct PooledConnection *next;
+
+ /**
+ * Prev ptr for placing this object in the DLL of the least recently used
+ * pooled connections
+ */
+ struct PooledConnection *prev;
+
+ /**
+ * The transport handle to the peer corresponding to this entry; can be NULL
+ */
+ struct GNUNET_TRANSPORT_Handle *handle_transport;
+
+ /**
+ * The core handle to the peer corresponding to this entry; can be NULL
+ */
+ struct GNUNET_CORE_Handle *handle_core;
+
+ /**
+ * The operation handle for transport handle
+ */
+ struct GNUNET_TESTBED_Operation *op_transport;
+
+ /**
+ * The operation handle for core handle
+ */
+ struct GNUNET_TESTBED_Operation *op_core;
+
+ /**
+ * The peer identity of this peer. Will be set upon opening a connection to
+ * the peers CORE service. Will be NULL until then and after the CORE
+ * connection is closed
+ */
+ struct GNUNET_PeerIdentity *peer_identity;
+
+ /**
+ * The configuration of the peer. Should be not NULL as long as the
core_handle
+ * or transport_handle are valid
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * DLL head for the queue to serve notifications when a peer is connected
+ */
+ struct GST_ConnectionPool_GetHandle *head_notify;
+
+ /**
+ * DLL tail for the queue to serve notifications when a peer is connected
+ */
+ struct GST_ConnectionPool_GetHandle *tail_notify;
+
+ /**
+ * DLL head for the queue of #GST_ConnectionPool_GetHandle requests that are
+ * waiting for this connection to be opened
+ */
+ struct GST_ConnectionPool_GetHandle *head_waiting;
+
+ /**
+ * DLL tail for the queue of #GST_ConnectionPool_GetHandle requests that are
+ * waiting for this connection to be opened
+ */
+ struct GST_ConnectionPool_GetHandle *tail_waiting;
+
+ /**
+ * The task to expire this connection from the connection pool
+ */
+ GNUNET_SCHEDULER_TaskIdentifier expire_task;
+
+ /**
+ * The task to notify a waiting #GST_ConnectionPool_GetHandle object
+ */
+ GNUNET_SCHEDULER_TaskIdentifier notify_task;
+
+ /**
+ * Number of active requests using this pooled connection
+ */
+ unsigned int demand;
+
+ /**
+ * Is this entry in LRU
+ */
+ int in_lru;
+
+ /**
+ * Is this entry present in the connection pool
+ */
+ int in_pool;
+
+ /**
+ * The index of this peer
+ */
+ uint32_t index;
+};
+
+
+/**
+ * The request handle for obtaining a pooled connection
+ */
+struct GST_ConnectionPool_GetHandle
+{
+ /**
+ * The next ptr for inclusion in the notification DLLs. At first the object
+ * is placed in the waiting DLL of the corresponding #PooledConnection
+ * object. After the handle is opened it is moved to the notification DLL if
+ * @p connect_notify_cb and @p target are not NULL
+ */
+ struct GST_ConnectionPool_GetHandle *next;
+
+ /**
+ * The prev ptr for inclusion in the notification DLLs
+ */
+ struct GST_ConnectionPool_GetHandle *prev;
+
+ /**
+ * The pooled connection object this handle corresponds to
+ */
+ struct PooledConnection *entry;
+
+ /**
+ * The cache callback to call when a handle is available
+ */
+ GST_connection_pool_connection_ready_cb cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cb_cls;
+
+ /**
+ * The peer identity of the target peer. When this target peer is connected,
+ * call the notify callback
+ */
+ const struct GNUNET_PeerIdentity *target;
+
+ /**
+ * The callback to be called for serving notification that the target peer is
+ * connected
+ */
+ GST_connection_pool_peer_connect_notify connect_notify_cb;
+
+ /**
+ * The closure for the notify callback
+ */
+ void *connect_notify_cb_cls;
+
+ /**
+ * The service we want to connect to
+ */
+ enum GST_ConnectionPool_Service service;
+
+ /**
+ * Did we call the pool_connection_ready_cb already?
+ */
+ int connection_ready_called;
+};
+
+
+/**
+ * A hashmap for quickly finding connections in the connection pool
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *map;
+
+/**
+ * DLL head for maitaining the least recently used #PooledConnection objects.
+ * The head is the least recently used object.
+ */
+static struct PooledConnection *head_lru;
+
+/**
+ * DLL tail for maitaining the least recently used #PooledConnection objects
+ */
+static struct PooledConnection *tail_lru;
+
+/**
+ * DLL head for maintaining #PooledConnection objects that are not added into
+ * the connection pool as it was full at the time the object's creation
+ * FIXME
+ */
+static struct PooledConnection *head_not_pooled;
+
+/**
+ * DLL tail for maintaining #PooledConnection objects that are not added into
+ * the connection pool as it was full at the time the object's creation
+ */
+static struct PooledConnection *tail_not_pooled;
+
+/**
+ * The maximum number of entries that can be present in the connection pool
+ */
+static unsigned int max_size;
+
+
+/**
+ * Destroy a #PooledConnection object
+ *
+ * @param entry the #PooledConnection object
+ */
+static void
+destroy_pooled_connection (struct PooledConnection *entry)
+{
+ GNUNET_assert ((NULL == entry->head_notify) && (NULL == entry->tail_notify));
+ GNUNET_assert ((NULL == entry->head_waiting) && (NULL ==
+ entry->tail_waiting));
+ GNUNET_assert (0 == entry->demand);
+ GNUNET_free_non_null (entry->peer_identity);
+ if (entry->in_lru)
+ GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
+ if (entry->in_pool)
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_remove (map,
+ entry->index,
+ entry));
+ LOG_DEBUG ("Cleaning up handles of a pooled connection\n");
+ if (NULL != entry->handle_transport)
+ GNUNET_assert (NULL != entry->op_transport);
+ if (NULL != entry->op_transport)
+ {
+ GNUNET_TESTBED_operation_done (entry->op_transport);
+ entry->op_transport = NULL;
+ }
+ if (NULL != entry->op_core)
+ {
+ GNUNET_TESTBED_operation_done (entry->op_core);
+ entry->op_core = NULL;
+ }
+ GNUNET_assert (NULL == entry->handle_core);
+ GNUNET_assert (NULL == entry->handle_transport);
+ GNUNET_CONFIGURATION_destroy (entry->cfg);
+ GNUNET_free (entry);
+}
+
+
+/**
+ * Expire a #PooledConnection object
+ *
+ * @param cls the #PooledConnection object
+ * @param tc scheduler task context
+ */
+static void
+expire (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PooledConnection *entry = cls;
+
+ entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+ destroy_pooled_connection (entry);
+}
+
+
+static void
+expire_task_cancel (struct PooledConnection *entry)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
+ {
+ GNUNET_SCHEDULER_cancel (entry->expire_task);
+ entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+}
+
+
+/**
+ * Function to add a #PooledConnection object into LRU and begin the expiry
task
+ *
+ * @param entry the #PooledConnection object
+ */
+static void
+add_to_lru (struct PooledConnection *entry)
+{
+ GNUNET_assert (0 == entry->demand);
+ GNUNET_assert (!entry->in_lru);
+ GNUNET_CONTAINER_DLL_insert_tail (head_lru, tail_lru, entry);
+ entry->in_lru = GNUNET_YES;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == entry->expire_task);
+ entry->expire_task = GNUNET_SCHEDULER_add_delayed (CACHE_EXPIRY,
+ &expire, entry);
+}
+
+
+/**
+ * Function to find a #GST_ConnectionPool_GetHandle which is waiting for one of
+ * the handles in given entry which are now available.
+ *
+ * @param entry the pooled connection whose active list has to be searched
+ * @param head the starting list element in the GSTCacheGetHandle where the
+ * search has to be begin
+ * @return a suitable GSTCacheGetHandle whose handle ready notify callback
+ * hasn't been called yet. NULL if no such suitable GSTCacheGetHandle
+ * is found
+ */
+static struct GST_ConnectionPool_GetHandle *
+search_waiting (const struct PooledConnection *entry,
+ struct GST_ConnectionPool_GetHandle *head)
+{
+ struct GST_ConnectionPool_GetHandle *gh;
+
+ for (gh = head; NULL != gh; gh = gh->next)
+ {
+ switch (gh->service)
+ {
+ case GST_CONNECTIONPOOL_SERVICE_CORE:
+ if (NULL == entry->handle_core)
+ continue;
+ if (NULL == entry->peer_identity)
+ continue; /* CORE connection isn't ready yet */
+ break;
+ case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
+ if (NULL == entry->handle_transport)
+ continue;
+ break;
+ }
+ break;
+ }
+ return gh;
+}
+
+
+/**
+ * A handle in the #PooledConnection object pointed by @a cls is ready and
there
+ * is a #GST_ConnectionPool_GetHandle object waiting in the waiting list. This
+ * function retrieves that object and calls the handle ready callback. It
+ * further schedules itself if there are similar waiting objects which can be
notified.
+ *
+ * @param cls the #PooledConnection object
+ * @param tc the task context from scheduler
+ */
+static void
+connection_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PooledConnection *entry = cls;
+ struct GST_ConnectionPool_GetHandle *gh;
+ struct GST_ConnectionPool_GetHandle *gh_next;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->notify_task);
+ entry->notify_task = GNUNET_SCHEDULER_NO_TASK;
+ gh = search_waiting (entry, entry->head_waiting);
+ GNUNET_assert (NULL != gh);
+ gh_next = NULL;
+ if (NULL != gh->next)
+ gh_next = search_waiting (entry, gh->next);
+ GNUNET_CONTAINER_DLL_remove (entry->head_waiting, entry->tail_waiting, gh);
+ gh->connection_ready_called = GNUNET_YES;
+ if (NULL != gh_next)
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
+ if ( (NULL != gh->target) && (NULL != gh->connect_notify_cb) )
+ GNUNET_CONTAINER_DLL_insert_tail (entry->head_notify, entry->tail_notify,
gh);
+ LOG_DEBUG ("Calling notify for handle type %u\n", gh->service);
+ gh->cb (gh->cb_cls, entry->handle_core, entry->handle_transport,
+ entry->peer_identity);
+}
+
+
+/**
+ * Function called from peer connect notify callbacks from CORE and TRANSPORT
+ * connections. This function calls the pendning peer connect notify callbacks
+ * which are queued in an entry.
+ *
+ * @param cls the #PooledConnection object
+ * @param peer the peer that connected
+ * @param service the service where this notification has originated
+ */
+static void
+peer_connect_notify_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const enum GST_ConnectionPool_Service service)
+{
+ struct PooledConnection *entry = cls;
+ struct GST_ConnectionPool_GetHandle *gh;
+ struct GST_ConnectionPool_GetHandle *gh_next;
+ GST_connection_pool_peer_connect_notify cb;
+ void *cb_cls;
+
+ for (gh = entry->head_notify; NULL != gh;)
+ {
+ GNUNET_assert (NULL != gh->target);
+ GNUNET_assert (NULL != gh->connect_notify_cb);
+ GNUNET_assert (gh->connection_ready_called);
+ if (service != gh->service)
+ {
+ gh = gh->next;
+ continue;
+ }
+ if (0 != memcmp (gh->target, peer, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ gh = gh->next;
+ continue;
+ }
+ cb = gh->connect_notify_cb;
+ cb_cls = gh->connect_notify_cb_cls;
+ gh_next = gh->next;
+ GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->tail_notify, gh);
+ gh = gh_next;
+ cb (cb_cls, peer);
+ }
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls the #PooledConnection object
+ * @param peer the peer that connected
+ */
+static void
+transport_peer_connect_notify_cb (void *cls,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct PooledConnection *entry = cls;
+
+ peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_TRANSPORT);
+}
+
+
+/**
+ * Function called when resources for opening a connection to TRANSPORT are
+ * available.
+ *
+ * @param cls the #PooledConnection object
+ */
+static void
+opstart_get_handle_transport (void *cls)
+{
+ struct PooledConnection *entry = cls;
+
+ GNUNET_assert (NULL != entry);
+ LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->index);
+ entry->handle_transport =
+ GNUNET_TRANSPORT_connect (entry->cfg, NULL, entry, NULL,
+ &transport_peer_connect_notify_cb, NULL);
+ if (NULL == entry->handle_transport)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (0 == entry->demand)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
+ return;
+ if (NULL != search_waiting (entry, entry->head_waiting))
+ {
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
+ return;
+ }
+}
+
+
+/**
+ * Function called when the operation responsible for opening a TRANSPORT
+ * connection is marked as done.
+ *
+ * @param cls the cache entry
+ */
+static void
+oprelease_get_handle_transport (void *cls)
+{
+ struct PooledConnection *entry = cls;
+
+ if (NULL == entry->handle_transport)
+ return;
+ GNUNET_TRANSPORT_disconnect (entry->handle_transport);
+ entry->handle_transport = NULL;
+}
+
+
+/**
+ * Method called whenever a given peer connects at CORE level
+ *
+ * @param cls the #PooledConnection object
+ * @param peer peer identity this notification is about
+ */
+static void
+core_peer_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PooledConnection *entry = cls;
+
+ peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_CORE);
+}
+
+
+/**
+ * Function called after GNUNET_CORE_connect has succeeded (or failed
+ * for good). Note that the private key of the peer is intentionally
+ * not exposed here; if you need it, your process should try to read
+ * the private key file directly (which should work if you are
+ * authorized...). Implementations of this function must not call
+ * GNUNET_CORE_disconnect (other than by scheduling a new task to
+ * do this later).
+ *
+ * @param cls the #PooledConnection object
+ * @param my_identity ID of this peer, NULL if we failed
+ */
+static void
+core_startup_cb (void *cls,
+ const struct GNUNET_PeerIdentity *my_identity)
+{
+ struct PooledConnection *entry = cls;
+
+ if (NULL == my_identity)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_assert (NULL == entry->peer_identity);
+ entry->peer_identity = GNUNET_new (struct GNUNET_PeerIdentity);
+ memcpy (entry->peer_identity,
+ my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ if (0 == entry->demand)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
+ return;
+ if (NULL != search_waiting (entry, entry->head_waiting))
+ {
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
+ return;
+ }
+}
+
+
+/**
+ * Function called when resources for opening a connection to CORE are
+ * available.
+ *
+ * @param cls the #PooledConnection object
+ */
+static void
+opstart_get_handle_core (void *cls)
+{
+ struct PooledConnection *entry = cls;
+ const struct GNUNET_CORE_MessageHandler no_handlers[] = {
+ {NULL, 0, 0}
+ };
+
+ GNUNET_assert (NULL != entry);
+ LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->index);
+ entry->handle_core =
+ GNUNET_CORE_connect (entry->cfg, entry, /* closure */
+ &core_startup_cb, /* core startup notify */
+ &core_peer_connect_cb, /* peer connect notify */
+ NULL, /* peer disconnect notify */
+ NULL, /* inbound notify */
+ GNUNET_NO, /* inbound header only? */
+ NULL, /* outbound notify */
+ GNUNET_NO, /* outbound header only? */
+ no_handlers);
+}
+
+
+/**
+ * Function called when the operation responsible for opening a TRANSPORT
+ * connection is marked as done.
+ *
+ * @param cls the #PooledConnection object
+ */
+static void
+oprelease_get_handle_core (void *cls)
+{
+ struct PooledConnection *entry = cls;
+
+ if (NULL == entry->handle_core)
+ return;
+ GNUNET_CORE_disconnect (entry->handle_core);
+ entry->handle_core = NULL;
+ GNUNET_free_non_null (entry->peer_identity);
+ entry->peer_identity = NULL;
+}
+
+
+/**
+ * This function will be called for every #PooledConnection object in @p map
+ *
+ * @param cls NULL
+ * @param key current key code
+ * @param value the #PooledConnection object
+ * @return #GNUNET_YES if we should continue to
+ * iterate,
+ * #GNUNET_NO if not.
+ */
+static int
+cleanup_iterator (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct PooledConnection *entry = value;
+
+ GNUNET_assert (NULL != entry);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_remove (map, key, entry));
+ if (entry->in_lru)
+ GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
+ destroy_pooled_connection (entry);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Initialise the connection pool.
+ *
+ * @param size the size of the connection pool. Each entry in the connection
+ * pool can handle a connection to each of the services enumerated in
+ * #GST_ConnectionPool_Service
+ */
+void
+GST_connection_pool_init (unsigned int size)
+{
+ max_size = size;
+ if (0 == max_size)
+ return;
+ GNUNET_assert (NULL == map);
+ map = GNUNET_CONTAINER_multihashmap32_create (((size * 3) / 4) + 1);
+}
+
+
+/**
+ * Cleanup the connection pool
+ */
+void
+GST_connection_pool_destroy ()
+{
+ struct PooledConnection *entry;
+
+ if (NULL != map)
+ {
+ GNUNET_assert (GNUNET_SYSERR !=
+ GNUNET_CONTAINER_multihashmap32_iterate (map,
+ &cleanup_iterator,
+ NULL));
+ GNUNET_CONTAINER_multihashmap32_destroy (map);
+ map = NULL;
+ }
+ while (NULL != (entry = head_lru))
+ {
+ GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
+ destroy_pooled_connection (entry);
+ }
+}
+
+
+/**
+ * Get a connection handle to @a service. If the connection is opened before
+ * and the connection handle is present in the connection pool, it is returned
+ * through @a cb. @a peer_id is used for the lookup in the connection pool.
If
+ * the connection handle is not present in the connection pool, a new
connection
+ * handle is opened for the @a service using @a cfg. Additionally, @a target,
+ * @a connect_notify_cb can be specified to get notified when @a target is
+ * connected at @a service.
+ *
+ * @note @a connect_notify_cb will not be called if @a target is
+ * already connected @a service level. Use
+ * GNUNET_TRANSPORT_check_neighbour_connected() or a similar function from the
+ * respective @a service's API to check if the target peer is already
connected or
+ * not. @a connect_notify_cb will be called only once or never (in case @a
target
+ * cannot be connected or is already connected).
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param service the service of interest
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for @a cb
+ * @param target the peer identify of the peer whose connection to our
TRANSPORT
+ * subsystem will be notified through the @a connect_notify_cb. Can
be NULL
+ * @param connect_notify_cb the callback to call when the @a target peer is
+ * connected. This callback will only be called once or never again
(in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for @a connect_notify_cb
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GST_ConnectionPool_GetHandle *
+GST_connection_pool_get_handle (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ enum GST_ConnectionPool_Service service,
+ GST_connection_pool_connection_ready_cb cb,
+ void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_connection_pool_peer_connect_notify
connect_notify_cb,
+ void *connect_notify_cb_cls)
+{
+ struct GST_ConnectionPool_GetHandle *gh;
+ struct PooledConnection *entry;
+ struct GNUNET_TESTBED_Operation *op;
+ void *handle;
+ uint32_t peer_id32;
+
+ peer_id32 = (uint32_t) peer_id;
+ entry = NULL;
+ if (NULL != map)
+ entry = GNUNET_CONTAINER_multihashmap32_get (map, peer_id32);
+ if (NULL != entry)
+ {
+ if (entry->in_lru)
+ {
+ GNUNET_assert (0 == entry->demand);
+ expire_task_cancel (entry);
+ GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
+ entry->in_lru = GNUNET_NO;
+ }
+ switch (service)
+ {
+ case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
+ handle = entry->handle_transport;
+ if (NULL != handle)
+ LOG_DEBUG ("Found TRANSPORT handle for peer %u\n",
+ entry->index);
+ break;
+ case GST_CONNECTIONPOOL_SERVICE_CORE:
+ handle = entry->handle_core;
+ if (NULL != handle)
+ LOG_DEBUG ("Found CORE handle for peer %u\n",
+ entry->index);
+ break;
+ }
+ }
+ else
+ {
+ entry = GNUNET_new (struct PooledConnection);
+ entry->index = peer_id32;
+ if ((NULL != map)
+ && (GNUNET_CONTAINER_multihashmap32_size (map) < max_size))
+ {
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_put (map,
+ entry->index,
+ entry,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ entry->in_pool = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_insert_tail (head_not_pooled, tail_not_pooled,
entry);
+ }
+ entry->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ }
+ entry->demand++;
+ gh = GNUNET_new (struct GST_ConnectionPool_GetHandle);
+ gh->entry = entry;
+ gh->cb = cb;
+ gh->cb_cls = cb_cls;
+ gh->target = target;
+ gh->connect_notify_cb = connect_notify_cb;
+ gh->connect_notify_cb_cls = connect_notify_cb_cls;
+ gh->service = service;
+ GNUNET_CONTAINER_DLL_insert (entry->head_waiting, entry->tail_waiting, gh);
+ if (NULL != handle)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK == entry->notify_task)
+ {
+ if (NULL != search_waiting (entry, entry->head_waiting))
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready,
entry);
+ }
+ return gh;
+ }
+ op = NULL;
+ switch (gh->service)
+ {
+ case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
+ if (NULL != entry->op_transport)
+ return gh; /* Operation pending */
+ op = GNUNET_TESTBED_operation_create_ (entry,
&opstart_get_handle_transport,
+ &oprelease_get_handle_transport);
+ entry->op_transport = op;
+ break;
+ case GST_CONNECTIONPOOL_SERVICE_CORE:
+ if (NULL != entry->op_core)
+ return gh; /* Operation pending */
+ op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_core,
+ &oprelease_get_handle_core);
+ entry->op_core = op;
+ break;
+ }
+ GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, op);
+ GNUNET_TESTBED_operation_begin_wait_ (op);
+ return gh;
+}
+
+
+/**
+ * Relinquish a #GST_ConnectionPool_GetHandle object. If the connection
+ * associated with the object is currently being used by other
+ * #GST_ConnectionPool_GetHandle objects, it is left in the connection pool.
If
+ * no other objects are using the connection and the connection pool is not
full
+ * then it is placed in a LRU queue. If the connection pool is full, then
+ * connections from the LRU queue are evicted and closed to create place for
this
+ * connection. If the connection pool if full and the LRU queue is empty, then
+ * the connection is closed.
+ *
+ * @param gh the handle
+ */
+void
+GST_connection_pool_get_handle_done (struct GST_ConnectionPool_GetHandle *gh)
+{
+ struct PooledConnection *entry;
+
+ entry = gh->entry;
+ if (!gh->connection_ready_called)
+ GNUNET_CONTAINER_DLL_remove (entry->head_waiting, entry->tail_waiting, gh);
+ else if ((NULL != gh->next) || (NULL != gh->prev))
+ GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->head_notify, gh);
+ GNUNET_free (gh);
+ gh = NULL;
+ GNUNET_assert (!entry->in_lru);
+ if ( (!entry->in_pool) && (NULL != map) )
+ {
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap32_contains (map,
+ entry->index))
+ goto unallocate;
+ if ((GNUNET_CONTAINER_multihashmap32_size (map) == max_size)
+ && (NULL == head_lru))
+ goto unallocate;
+ destroy_pooled_connection (head_lru);
+ GNUNET_CONTAINER_DLL_remove (head_not_pooled, tail_not_pooled, entry);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_put (map,
+ entry->index,
+ entry,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ entry->in_pool = GNUNET_YES;
+ }
+ unallocate:
+ GNUNET_assert (0 < entry->demand);
+ entry->demand--;
+ if (0 != entry->demand)
+ return;
+ if (entry->in_pool)
+ {
+ add_to_lru (entry);
+ return;
+ }
+ destroy_pooled_connection (entry);
+}
Added: gnunet/src/testbed/gnunet-service-testbed_connectionpool.h
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed_connectionpool.h
(rev 0)
+++ gnunet/src/testbed/gnunet-service-testbed_connectionpool.h 2013-09-26
15:03:13 UTC (rev 29623)
@@ -0,0 +1,161 @@
+/*
+ This file is part of GNUnet.
+ (C) 2008--2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet 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 3, or (at your
+ option) any later version.
+
+ GNUnet 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 GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file testbed/gnunet-service-testbed_connectionpool.h
+ * @brief Interface for connection pooling subroutines
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+
+/**
+ * The request handle for obtaining a pooled connection
+ */
+struct GST_ConnectionPool_GetHandle;
+
+
+/**
+ * The type of service
+ */
+enum GST_ConnectionPool_Service
+{
+ /**
+ * Transport service
+ */
+ GST_CONNECTIONPOOL_SERVICE_TRANSPORT = 1,
+
+ /**
+ * Core service
+ */
+ GST_CONNECTIONPOOL_SERVICE_CORE
+};
+
+
+/**
+ * Initialise the connection pool.
+ *
+ * @param size the size of the connection pool. Each entry in the connection
+ * pool can handle a connection to each of the services enumerated in
+ * #GST_ConnectionPool_Service
+ */
+void
+GST_connection_pool_init (unsigned int size);
+
+
+/**
+ * Cleanup the connection pool
+ */
+void
+GST_connection_pool_destroy ();
+
+/**
+ * Functions of this type are called when the needed handle is available for
+ * usage. These functions are to be registered with the function
+ * GST_connection_pool_get_handle(). The corresponding handles will be set upon
+ * success. If they are not set, then it signals an error while opening the
+ * handles.
+ *
+ * @param cls the closure passed to GST_connection_pool_get_handle()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param peer_id the identity of the peer. Will be NULL if ch is NULL. In
other
+ * cases, its value being NULL means that CORE connection has failed.
+ */
+typedef void
+(*GST_connection_pool_connection_ready_cb) (void *cls,
+ struct GNUNET_CORE_Handle * ch,
+ struct GNUNET_TRANSPORT_Handle *
th,
+ const struct GNUNET_PeerIdentity *
+ peer_id);
+
+
+/**
+ * Callback to notify when the target peer given to
+ * GST_connection_pool_get_handle() is connected.
+ *
+ * @param cls the closure given to GST_connection_pool_get_handle() for this
+ * callback
+ * @param target the peer identity of the target peer
+ */
+typedef void
+(*GST_connection_pool_peer_connect_notify) (void *cls,
+ const struct GNUNET_PeerIdentity
+ *target);
+
+
+/**
+ * Get a connection handle to @a service. If the connection is opened before
+ * and the connection handle is present in the connection pool, it is returned
+ * through @a cb. @a peer_id is used for the lookup in the connection pool.
If
+ * the connection handle is not present in the connection pool, a new
connection
+ * handle is opened for the @a service using @a cfg. Additionally, @a target,
+ * @a connect_notify_cb can be specified to get notified when @a target is
+ * connected at @a service.
+ *
+ * @note @a connect_notify_cb will not be called if @a target is
+ * already connected @a service level. Use
+ * GNUNET_TRANSPORT_check_neighbour_connected() or a similar function from the
+ * respective @a service's API to check if the target peer is already
connected or
+ * not. @a connect_notify_cb will be called only once or never (in case @a
target
+ * cannot be connected or is already connected).
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param service the service of interest
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for @a cb
+ * @param target the peer identify of the peer whose connection to our
TRANSPORT
+ * subsystem will be notified through the @a connect_notify_cb. Can
be NULL
+ * @param connect_notify_cb the callback to call when the @a target peer is
+ * connected. This callback will only be called once or never again
(in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for @a connect_notify_cb
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GST_ConnectionPool_GetHandle *
+GST_connection_pool_get_handle (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ enum GST_ConnectionPool_Service service,
+ GST_connection_pool_connection_ready_cb cb,
+ void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_connection_pool_peer_connect_notify
connect_notify_cb,
+ void *connect_notify_cb_cls);
+
+
+/**
+ * Relinquish a #GST_ConnectionPool_GetHandle object. If the connection
+ * associated with the object is currently being used by other
+ * #GST_ConnectionPool_GetHandle objects, it is left in the connection pool.
If
+ * no other objects are using the connection and the connection pool is not
full
+ * then it is placed in a LRU queue. If the connection pool is full, then
+ * connections from the LRU queue are evicted and closed to create place for
this
+ * connection. If the connection pool if full and the LRU queue is empty, then
+ * the connection is closed.
+ *
+ * @param gh the handle
+ */
+void
+GST_connection_pool_get_handle_done (struct GST_ConnectionPool_GetHandle *gh);
+
+
+/* End of gnunet-service-testbed_connectionpool.h */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r29623 - gnunet/src/testbed,
gnunet <=