- set iteration
authorFlorian Dold <florian.dold@gmail.com>
Tue, 23 Jul 2013 17:26:35 +0000 (17:26 +0000)
committerFlorian Dold <florian.dold@gmail.com>
Tue, 23 Jul 2013 17:26:35 +0000 (17:26 +0000)
src/set/gnunet-service-set.c
src/set/gnunet-service-set.h
src/set/gnunet-service-set_union.c
src/set/set.h
src/set/set_api.c

index a55c2188e6f500c6613c8cdc1f836c90fa436cfd..8445b3799fad35237a15c08a3bff4187c1cc3d8c 100644 (file)
@@ -454,6 +454,32 @@ handle_incoming_msg (struct OperationState *op,
 }
 
 
+/**
+ * Called when a client wants to iterate the elements of a set.
+ *
+ * @param cls unused
+ * @param client client that sent the message
+ * @param m message sent by the client
+ */
+static void
+handle_client_iterate (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *m)
+{
+  struct Set *set;
+  
+  set = set_get (client);
+  if (NULL == set)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_client_disconnect (client);
+    return;
+  }
+
+  set->vt->iterate (set);
+}
+
+
 /**
  * Called when a client wants to create a new set.
  *
@@ -939,6 +965,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
     {handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
     {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE,
         sizeof (struct GNUNET_SET_CreateMessage)},
+    {handle_client_iterate, NULL, GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST,
+        sizeof (struct GNUNET_MessageHeader)},
     {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
     {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN,
         sizeof (struct GNUNET_SET_ListenMessage)},
index 6ababe92fe2f05958927c875f1b8d83b2e68eded..c93cc660a9c9feb88d1e1918810622885b76b8f3 100644 (file)
@@ -169,6 +169,15 @@ typedef void (*CancelImpl) (struct SetState *set,
                             uint32_t request_id);
 
 
+/**
+ * Signature of functions that implement sending all the set's
+ * elements to the client.
+ *
+ * @param set set that should be iterated over
+ */
+typedef void (*IterateImpl) (struct Set *set);
+
+
 /**
  * Dispatch table for a specific set operation.
  * Every set operation has to implement the callback
@@ -222,6 +231,11 @@ struct SetVT
    * its ID.
    */
   CancelImpl cancel;
+
+  /**
+   * Callback for iterating over all set elements.
+   */
+  IterateImpl iterate;
 };
 
 
index e512761cc9a23052d84eed3a93a51bba79230a76..87100bf54be24c2fdb199e8233c4dde4c1231334 100644 (file)
@@ -1421,6 +1421,53 @@ union_op_cancel (struct SetState *set_state, uint32_t op_id)
 }
 
 
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ *         iterate,
+ *         GNUNET_NO if not.
+ */
+static int
+send_iter_element_iter (void *cls,
+                        const struct GNUNET_HashCode *key,
+                        void *value)
+{
+  struct ElementEntry *ee = value;
+  struct Set *set = cls;
+  struct GNUNET_SET_IterResponseMessage *m;
+  struct GNUNET_MQ_Envelope *ev;
+
+  ev = GNUNET_MQ_msg_extra (m, ee->element.size,
+                            GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
+
+  m->element_type = ee->element.type;
+  memcpy (&m[1], ee->element.data, ee->element.size);
+  GNUNET_MQ_send (set->client_mq, ev);
+
+  return GNUNET_YES;
+}
+
+
+/**
+ * Send all elements of the union set to the client.
+ *
+ * @param set set to iterate over
+ */
+static void
+union_iterate (struct Set *set)
+{
+  struct GNUNET_MQ_Envelope *ev;
+
+  GNUNET_CONTAINER_multihashmap_iterate (set->state->elements, send_iter_element_iter, set);
+  ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
+  GNUNET_MQ_send (set->client_mq, ev);
+}
+
+
 const struct SetVT *
 _GSS_union_vt ()
 {
@@ -1433,7 +1480,8 @@ _GSS_union_vt ()
     .evaluate = &union_evaluate,
     .accept = &union_accept,
     .peer_disconnect = &union_peer_disconnect,
-    .cancel = &union_op_cancel
+    .cancel = &union_op_cancel,
+    .iterate = &union_iterate
   };
 
   return &union_vt;
index fc29e66967cfaf484456a82266e0b74518b4fcbe..9f6eb3642e6327f4278d4bc1c6f09333d879b80e 100644 (file)
@@ -211,6 +211,21 @@ struct GNUNET_SET_CancelMessage
   uint32_t request_id GNUNET_PACKED;
 };
 
+struct GNUNET_SET_IterResponseMessage
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SET_ITER_RESPONSE
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Type of the element attachted to the message,
+   * if any.
+   */
+  uint16_t element_type GNUNET_PACKED;
+
+  /* rest: element */
+};
 
 GNUNET_NETWORK_STRUCT_END
 
index 88f334cbcf2eef5eae9f1c0ebbd7bc67ed6a35a7..c2e88e65f614e8756b5cf36695058aacf70c714e 100644 (file)
@@ -67,6 +67,17 @@ struct GNUNET_SET_Handle
    * Has the set become invalid (e.g. service died)?
    */
   int invalid;
+
+  /**
+   * Callback for the current iteration over the set,
+   * NULL if no iterator is active.
+   */
+  GNUNET_SET_ElementIterator iterator;
+
+  /**
+   * Closure for 'iterator'
+   */
+  void *iterator_cls;
 };
 
 
@@ -170,6 +181,47 @@ struct GNUNET_SET_ListenHandle
 };
 
 
+/**
+ * Handle element for iteration over the set.
+ *
+ * @param cls the set
+ * @param mh the message
+ */
+static void
+handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh)
+{
+  struct GNUNET_SET_Handle *set = cls;
+  struct GNUNET_SET_Element element;
+  const struct GNUNET_SET_IterResponseMessage *msg =
+    (const struct GNUNET_SET_IterResponseMessage *) mh;
+
+  if (NULL == set->iterator)
+    return;
+
+  element.type = htons (mh->type);
+  element.data = &msg[1];
+  set->iterator (set->iterator_cls, &element);
+}
+
+
+/**
+ * Handle element for iteration over the set.
+ *
+ * @param cls the set
+ * @param mh the message
+ */
+static void
+handle_iter_done (void *cls, const struct GNUNET_MessageHeader *mh)
+{
+  struct GNUNET_SET_Handle *set = cls;
+
+  if (NULL == set->iterator)
+    return;
+
+  set->iterator (set->iterator_cls, NULL);
+}
+
+
 /**
  * Handle result message for a set operation.
  *
@@ -302,6 +354,8 @@ GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
   struct GNUNET_SET_CreateMessage *msg;
   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
     {handle_result, GNUNET_MESSAGE_TYPE_SET_RESULT, 0},
+    {handle_iter_element, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT, 0},
+    {handle_iter_done, GNUNET_MESSAGE_TYPE_SET_ITER_DONE, 0},
     GNUNET_MQ_HANDLERS_END
   };
 
@@ -623,3 +677,36 @@ GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
   return GNUNET_OK;
 }
 
+
+
+/**
+ * Iterate over all elements in the given set.
+ * Note that this operation involves transferring every element of the set
+ * from the service to the client, and is thus costly.
+ *
+ * @param set the set to iterate over
+ * @param iter the iterator to call for each element
+ * @param cls closure for 'iter'
+ * @return GNUNET_YES if the iteration started successfuly,
+ *         GNUNET_NO if another iteration is active
+ *         GNUNET_SYSERR if the set is invalid (e.g. the server crashed, disconnected)
+ */
+int
+GNUNET_SET_iterate (struct GNUNET_SET_Handle *set, GNUNET_SET_ElementIterator iter, void *cls)
+{
+  struct GNUNET_MQ_Envelope *ev;
+
+  GNUNET_assert (NULL != iter);
+
+  if (GNUNET_YES == set->invalid)
+    return GNUNET_SYSERR;
+  if (NULL != set->iterator)
+    return GNUNET_NO;
+
+  set->iterator = iter;
+  set->iterator_cls = cls;
+  ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST);
+  GNUNET_MQ_send (set->mq, ev);
+  return GNUNET_YES;
+}
+