/*
This file is part of GNUnet
- Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2013, 2014 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
*/
#include "gnunet-service-set.h"
#include "gnunet-service-set_protocol.h"
+#include "gnunet_statistics_service.h"
/**
* How long do we hold on to an incoming channel if there is
*/
static uint32_t suggest_id = 1;
+/**
+ * Statistics handle.
+ */
+struct GNUNET_STATISTICS_Handle *_GSS_statistics;
+
/**
* Get set that is owned by the given client, if any.
int is_present;
unsigned int i;
- /* If ee->mutations is NULL,
- the element was added in generation 0,
- and there are no removes, thus the element
- is part of any generation we query. */
- if (NULL == ee->mutations)
- return GNUNET_YES;
+ GNUNET_assert (NULL != ee->mutations);
if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size))
{
is_present = mut->added;
}
- return GNUNET_YES;
+ return is_present;
}
}
+static int
+is_element_of_iteration (struct ElementEntry *ee,
+ struct Set *set)
+{
+ return is_element_of_generation (ee,
+ set->iter_generation,
+ set->excluded_generations,
+ set->excluded_generations_size);
+}
+
+
int
_GSS_is_element_of_operation (struct ElementEntry *ee,
struct Operation *op)
NULL);
GNUNET_CONTAINER_multihashmap_destroy (content->elements);
content->elements = NULL;
+ GNUNET_free (content);
}
}
GNUNET_free_non_null (set->excluded_generations);
msg = (const struct GNUNET_SET_ElementMessage *) m;
el.size = ntohs (m->size) - sizeof *msg;
+ el.data = &msg[1];
+ el.element_type = ntohs (msg->element_type);
+ GNUNET_SET_element_hash (&el, &hash);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client inserts element of size %u\n",
+ "Client inserts element %s of size %u\n",
+ GNUNET_h2s (&hash),
el.size);
- el.data = &msg[1];
- GNUNET_CRYPTO_hash (el.data,
- el.size,
- &hash);
ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
&hash);
el.data,
el.size);
ee->element.data = &ee[1];
+ ee->element.element_type = el.element_type;
ee->remote = GNUNET_NO;
ee->mutations = NULL;
ee->mutations_size = 0;
ee->element_hash = hash;
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_put (set->content->elements,
+ &ee->element_hash,
+ ee,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
else if (GNUNET_YES == _GSS_is_element_of_set (ee, set))
{
/* same element inserted twice */
- GNUNET_break (0);
return;
}
- if (0 != set->current_generation)
{
struct MutationEvent mut = {
.generation = set->current_generation,
GNUNET_array_append (ee->mutations, ee->mutations_size, mut);
}
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_put (set->content->elements,
- &ee->element_hash,
- ee,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
set->vt->add (set->state, ee);
}
"Client removes element of size %u\n",
el.size);
el.data = &msg[1];
- GNUNET_CRYPTO_hash (el.data,
- el.size,
- &hash);
+ el.element_type = ntohs (msg->element_type);
+ GNUNET_SET_element_hash (&el, &hash);
ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
&hash);
if (NULL == ee)
{
- /* Client tried to remove non-existing element */
- GNUNET_break (0);
+ /* Client tried to remove non-existing element. */
return;
}
if (GNUNET_NO == _GSS_is_element_of_set (ee, set))
{
/* Client tried to remove element twice */
- GNUNET_break (0);
return;
}
- else if (0 == set->current_generation)
- {
- // If current_generation is 0, then there are no running set operations
- // or lazy copies, thus we can safely remove the element.
- (void) GNUNET_CONTAINER_multihashmap_remove_all (set->content->elements, &hash);
- }
else
{
struct MutationEvent mut = {
struct GNUNET_SET_IterResponseMessage *msg;
GNUNET_assert (NULL != set->iter);
+
+again:
+
ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter,
NULL,
(const void **) &ee);
GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
set->iter = NULL;
set->iteration_id++;
-
+
GNUNET_assert (set->content->iterator_count > 0);
set->content->iterator_count -= 1;
else
{
GNUNET_assert (NULL != ee);
+
+ if (GNUNET_NO == is_element_of_iteration (ee, set))
+ goto again;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending iteration element on %p.\n",
(void *) set);
memcpy (&msg[1],
ee->element.data,
ee->element.size);
- msg->element_type = ee->element.element_type;
+ msg->element_type = htons (ee->element.element_type);
msg->iteration_id = htons (set->iteration_id);
}
GNUNET_MQ_send (set->client_mq, ev);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Iterating set %p with %u elements\n",
+ "Iterating set %p in gen %u with %u content elements\n",
(void *) set,
+ set->current_generation,
GNUNET_CONTAINER_multihashmap_size (set->content->elements));
GNUNET_SERVER_receive_done (client,
GNUNET_OK);
set->content->iterator_count += 1;
set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements);
+ set->iter_generation = set->current_generation;
send_client_element (set);
}
}
set->operation = ntohl (msg->operation);
set->state = set->vt->create ();
+ if (NULL == set->state)
+ {
+ /* initialization failed (i.e. out of memory) */
+ GNUNET_free (set);
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
set->content = GNUNET_new (struct SetContent);
set->content->refcount = 1;
set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
{
found = GNUNET_YES;
break;
- }
+ }
}
if (GNUNET_NO == found)
set->state = set->vt->copy_state (cr->source_set);
set->content = cr->source_set->content;
set->content->refcount += 1;
+
+ set->current_generation = cr->source_set->current_generation;
+ set->excluded_generations_size = cr->source_set->excluded_generations_size;
+ set->excluded_generations = GNUNET_memdup (cr->source_set->excluded_generations,
+ set->excluded_generations_size * sizeof (struct GenerationRange));
+
+ /* Advance the generation of the new set, so that mutations to the
+ of the cloned set and the source set are independent. */
+ advance_generation (set);
+
+
set->client = client;
set->client_mq = GNUNET_MQ_queue_for_server_client (client);
GNUNET_CONTAINER_DLL_insert (sets_head,
* Called to clean up, after a shutdown has been requested.
*
* @param cls closure
- * @param tc context information (why was this task triggered now)
*/
static void
-shutdown_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls)
{
while (NULL != incoming_head)
incoming_destroy (incoming_head);
GNUNET_CADET_disconnect (cadet);
cadet = NULL;
}
+ GNUNET_STATISTICS_destroy (_GSS_statistics, GNUNET_YES);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"handled shutdown request\n");
}
* - we suggested an operation to our listener,
* but did not receive a response in time
* - we got the channel from a peer but no #GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST
- * - shutdown (obviously)
*
* @param cls channel context
* @param tc context information (why was this task triggered now)
*/
static void
-incoming_timeout_cb (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+incoming_timeout_cb (void *cls)
{
struct Operation *incoming = cls;
incoming->timeout_task = NULL;
GNUNET_assert (GNUNET_YES == incoming->is_incoming);
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Remote peer's incoming request timed out\n");
incoming_destroy (incoming);
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 0},
- { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 0},
+ { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, 0},
+ { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, 0},
+ { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENT_REQUESTS, 0},
+ { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, 0},
+ { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, 0},
{ &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, 0},
static const uint32_t cadet_ports[] = {GNUNET_APPLICATION_TYPE_SET, 0};
configuration = cfg;
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &shutdown_task, NULL);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
GNUNET_SERVER_disconnect_notify (server,
&handle_client_disconnect, NULL);
GNUNET_SERVER_add_handlers (server,
server_handlers);
+ _GSS_statistics = GNUNET_STATISTICS_create ("set", cfg);
cadet = GNUNET_CADET_connect (cfg, NULL,
&channel_new_cb,
&channel_end_cb,