+
+ is_present = mut->added;
+ }
+
+ return is_present;
+}
+
+
+int
+_GSS_is_element_of_set (struct ElementEntry *ee,
+ struct Set *set)
+{
+ return is_element_of_generation (ee,
+ set->current_generation,
+ set->excluded_generations,
+ set->excluded_generations_size);
+}
+
+
+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)
+{
+ return is_element_of_generation (ee,
+ op->generation_created,
+ op->spec->set->excluded_generations,
+ op->spec->set->excluded_generations_size);
+}
+
+
+/**
+ * Destroy the given operation. Call the implementation-specific
+ * cancel function of the operation. Disconnects from the remote
+ * peer. Does not disconnect the client, as there may be multiple
+ * operations per set.
+ *
+ * @param op operation to destroy
+ * @param gc #GNUNET_YES to perform garbage collection on the set
+ */
+void
+_GSS_operation_destroy (struct Operation *op,
+ int gc)
+{
+ struct Set *set;
+ struct GNUNET_CADET_Channel *channel;
+
+ if (NULL == op->vt)
+ {
+ /* already in #_GSS_operation_destroy() */
+ return;
+ }
+ GNUNET_assert (GNUNET_NO == op->is_incoming);
+ GNUNET_assert (NULL != op->spec);
+ set = op->spec->set;
+ GNUNET_CONTAINER_DLL_remove (set->ops_head,
+ set->ops_tail,
+ op);
+ op->vt->cancel (op);
+ op->vt = NULL;
+ if (NULL != op->spec)
+ {
+ if (NULL != op->spec->context_msg)
+ {
+ GNUNET_free (op->spec->context_msg);
+ op->spec->context_msg = NULL;
+ }
+ GNUNET_free (op->spec);
+ op->spec = NULL;
+ }
+ if (NULL != op->mq)
+ {
+ GNUNET_MQ_destroy (op->mq);
+ op->mq = NULL;
+ }
+ if (NULL != (channel = op->channel))
+ {
+ op->channel = NULL;
+ GNUNET_CADET_channel_destroy (channel);
+ }
+ if (GNUNET_YES == gc)
+ collect_generation_garbage (set);
+ /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL,
+ * there was a channel end handler that will free 'op' on the call stack. */
+}
+
+
+/**
+ * Iterator over hash map entries to free element entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value a `struct ElementEntry *` to be free'd
+ * @return #GNUNET_YES (continue to iterate)
+ */
+static int
+destroy_elements_iterator (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct ElementEntry *ee = value;
+
+ GNUNET_free_non_null (ee->mutations);
+
+ GNUNET_free (ee);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Destroy a set, and free all resources and operations associated with it.
+ *
+ * @param set the set to destroy
+ */
+static void
+set_destroy (struct Set *set)
+{
+ if (NULL != set->client)
+ {
+ /* If the client is not dead yet, destroy it. The client's destroy
+ * callback will call `set_destroy()` again in this case. We do
+ * this so that the channel end handler still has a valid set handle
+ * to destroy. */
+ struct GNUNET_SERVER_Client *client = set->client;
+
+ set->client = NULL;
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+ GNUNET_assert (NULL != set->state);
+ while (NULL != set->ops_head)
+ _GSS_operation_destroy (set->ops_head, GNUNET_NO);
+ set->vt->destroy_set (set->state);
+ set->state = NULL;
+ if (NULL != set->client_mq)
+ {
+ GNUNET_MQ_destroy (set->client_mq);
+ set->client_mq = NULL;
+ }
+ if (NULL != set->iter)
+ {
+ GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
+ set->iter = NULL;
+ set->iteration_id++;
+ }
+ {
+ struct SetContent *content;
+ struct PendingMutation *pm;
+ struct PendingMutation *pm_current;
+
+ content = set->content;
+
+ // discard any pending mutations that reference this set
+ pm = content->pending_mutations_head;
+ while (NULL != pm)
+ {
+ pm_current = pm;
+ pm = pm->next;
+ if (pm_current-> set == set)
+ GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head,
+ content->pending_mutations_tail,
+ pm_current);
+
+ }
+
+ set->content = NULL;
+ GNUNET_assert (0 != content->refcount);
+ content->refcount -= 1;
+ if (0 == content->refcount)
+ {
+ GNUNET_assert (NULL != content->elements);
+ GNUNET_CONTAINER_multihashmap_iterate (content->elements,
+ &destroy_elements_iterator,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (content->elements);
+ content->elements = NULL;
+ GNUNET_free (content);
+ }