diff options
author | Florian Dold <florian.dold@gmail.com> | 2013-08-12 18:00:43 +0000 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2013-08-12 18:00:43 +0000 |
commit | 566dfe32be22ed1f071b974be3c4dd8bc5721151 (patch) | |
tree | dc4e89e80aab53e1cb69604c2960eaaf5043bb17 /src | |
parent | d734cfd6677de174aa51a07437b0e0cae4c870be (diff) | |
download | gnunet-566dfe32be22ed1f071b974be3c4dd8bc5721151.tar.gz gnunet-566dfe32be22ed1f071b974be3c4dd8bc5721151.zip |
- correct iteraion in multihashmap
- iterate over elements with client ack in set
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_protocols.h | 4 | ||||
-rw-r--r-- | src/set/gnunet-service-set.c | 141 | ||||
-rw-r--r-- | src/set/gnunet-service-set.h | 70 | ||||
-rw-r--r-- | src/set/gnunet-service-set_union.c | 216 | ||||
-rw-r--r-- | src/set/set.h | 13 | ||||
-rw-r--r-- | src/set/set_api.c | 5 | ||||
-rw-r--r-- | src/set/test_set.conf | 2 | ||||
-rw-r--r-- | src/set/test_set_api.c | 47 | ||||
-rw-r--r-- | src/util/container_multihashmap.c | 4 |
9 files changed, 291 insertions, 211 deletions
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index ba34af814..06703abe9 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h | |||
@@ -1690,9 +1690,9 @@ extern "C" | |||
1690 | #define GNUNET_MESSAGE_TYPE_SET_CANCEL 570 | 1690 | #define GNUNET_MESSAGE_TYPE_SET_CANCEL 570 |
1691 | 1691 | ||
1692 | /** | 1692 | /** |
1693 | * Acknowledge results | 1693 | * Acknowledge result from iteration |
1694 | */ | 1694 | */ |
1695 | #define GNUNET_MESSAGE_TYPE_SET_ACK 571 | 1695 | #define GNUNET_MESSAGE_TYPE_SET_ITER_ACK 571 |
1696 | 1696 | ||
1697 | /** | 1697 | /** |
1698 | * Create an empty set | 1698 | * Create an empty set |
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c index cfa0ab711..9210e1ea8 100644 --- a/src/set/gnunet-service-set.c +++ b/src/set/gnunet-service-set.c | |||
@@ -261,6 +261,28 @@ listener_destroy (struct Listener *listener) | |||
261 | 261 | ||
262 | 262 | ||
263 | /** | 263 | /** |
264 | * Iterator over hash map entries. | ||
265 | * | ||
266 | * @param cls closure | ||
267 | * @param key current key code | ||
268 | * @param value value in the hash map | ||
269 | * @return GNUNET_YES if we should continue to | ||
270 | * iterate, | ||
271 | * GNUNET_NO if not. | ||
272 | */ | ||
273 | static int | ||
274 | destroy_elements_iterator (void *cls, | ||
275 | const struct GNUNET_HashCode * key, | ||
276 | void *value) | ||
277 | { | ||
278 | struct ElementEntry *ee = value; | ||
279 | |||
280 | GNUNET_free (ee); | ||
281 | return GNUNET_YES; | ||
282 | } | ||
283 | |||
284 | |||
285 | /** | ||
264 | * Destroy a set, and free all resources associated with it. | 286 | * Destroy a set, and free all resources associated with it. |
265 | * | 287 | * |
266 | * @param set the set to destroy | 288 | * @param set the set to destroy |
@@ -282,6 +304,18 @@ set_destroy (struct Set *set) | |||
282 | GNUNET_MQ_destroy (set->client_mq); | 304 | GNUNET_MQ_destroy (set->client_mq); |
283 | set->client_mq = NULL; | 305 | set->client_mq = NULL; |
284 | } | 306 | } |
307 | if (NULL != set->elements) | ||
308 | { | ||
309 | GNUNET_CONTAINER_multihashmap_iterate (set->elements, | ||
310 | destroy_elements_iterator, NULL); | ||
311 | GNUNET_CONTAINER_multihashmap_destroy (set->elements); | ||
312 | set->elements = NULL; | ||
313 | } | ||
314 | if (NULL != set->iter) | ||
315 | { | ||
316 | GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter); | ||
317 | set->iter = NULL; | ||
318 | } | ||
285 | GNUNET_assert (NULL != set->state); | 319 | GNUNET_assert (NULL != set->state); |
286 | set->vt->destroy_set (set->state); | 320 | set->vt->destroy_set (set->state); |
287 | set->state = NULL; | 321 | set->state = NULL; |
@@ -455,6 +489,32 @@ handle_incoming_msg (struct OperationState *op, | |||
455 | } | 489 | } |
456 | 490 | ||
457 | 491 | ||
492 | static void | ||
493 | send_client_element (struct Set *set) | ||
494 | { | ||
495 | int ret; | ||
496 | struct ElementEntry *ee; | ||
497 | struct GNUNET_MQ_Envelope *ev; | ||
498 | |||
499 | GNUNET_assert (NULL != set->iter); | ||
500 | ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, NULL, (const void **) &ee); | ||
501 | if (GNUNET_NO == ret) | ||
502 | { | ||
503 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE); | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | struct GNUNET_SET_IterResponseMessage *msg; | ||
508 | |||
509 | GNUNET_assert (NULL != ee); | ||
510 | ev = GNUNET_MQ_msg_extra (msg, ee->element.size, GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT); | ||
511 | memcpy (&msg[1], ee->element.data, ee->element.size); | ||
512 | msg->element_type = ee->element.type; | ||
513 | } | ||
514 | GNUNET_MQ_send (set->client_mq, ev); | ||
515 | } | ||
516 | |||
517 | |||
458 | /** | 518 | /** |
459 | * Called when a client wants to iterate the elements of a set. | 519 | * Called when a client wants to iterate the elements of a set. |
460 | * | 520 | * |
@@ -477,8 +537,17 @@ handle_client_iterate (void *cls, | |||
477 | return; | 537 | return; |
478 | } | 538 | } |
479 | 539 | ||
540 | if (NULL != set->iter) | ||
541 | { | ||
542 | GNUNET_break (0); | ||
543 | GNUNET_SERVER_client_disconnect (client); | ||
544 | return; | ||
545 | } | ||
546 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "iterating union set with %u elements\n", | ||
547 | GNUNET_CONTAINER_multihashmap_size (set->elements)); | ||
480 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 548 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
481 | set->vt->iterate (set); | 549 | set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->elements); |
550 | send_client_element (set); | ||
482 | } | 551 | } |
483 | 552 | ||
484 | 553 | ||
@@ -525,6 +594,7 @@ handle_client_create (void *cls, | |||
525 | } | 594 | } |
526 | 595 | ||
527 | set->state = set->vt->create (); | 596 | set->state = set->vt->create (); |
597 | set->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
528 | set->client = client; | 598 | set->client = client; |
529 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); | 599 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); |
530 | GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set); | 600 | GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set); |
@@ -633,6 +703,7 @@ handle_client_add_remove (void *cls, | |||
633 | struct Set *set; | 703 | struct Set *set; |
634 | const struct GNUNET_SET_ElementMessage *msg; | 704 | const struct GNUNET_SET_ElementMessage *msg; |
635 | struct GNUNET_SET_Element el; | 705 | struct GNUNET_SET_Element el; |
706 | struct ElementEntry *ee; | ||
636 | 707 | ||
637 | set = set_get (client); | 708 | set = set_get (client); |
638 | if (NULL == set) | 709 | if (NULL == set) |
@@ -641,16 +712,55 @@ handle_client_add_remove (void *cls, | |||
641 | GNUNET_SERVER_client_disconnect (client); | 712 | GNUNET_SERVER_client_disconnect (client); |
642 | return; | 713 | return; |
643 | } | 714 | } |
715 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
644 | msg = (const struct GNUNET_SET_ElementMessage *) m; | 716 | msg = (const struct GNUNET_SET_ElementMessage *) m; |
645 | el.size = ntohs (m->size) - sizeof *msg; | 717 | el.size = ntohs (m->size) - sizeof *msg; |
646 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 718 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
647 | "client ins/rem element of size %u\n", el.size); | 719 | "client ins/rem element of size %u\n", el.size); |
648 | el.data = &msg[1]; | 720 | el.data = &msg[1]; |
649 | if (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type)) | 721 | if (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type)) |
650 | set->vt->remove (set->state, &el); | 722 | { |
723 | struct GNUNET_HashCode hash; | ||
724 | |||
725 | GNUNET_CRYPTO_hash (el.data, el.size, &hash); | ||
726 | ee = GNUNET_CONTAINER_multihashmap_get (set->elements, &hash); | ||
727 | if (NULL == ee) | ||
728 | { | ||
729 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove non-existing element\n"); | ||
730 | return; | ||
731 | } | ||
732 | if (GNUNET_YES == ee->removed) | ||
733 | { | ||
734 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove element twice\n"); | ||
735 | return; | ||
736 | } | ||
737 | ee->removed = GNUNET_YES; | ||
738 | ee->generation_removed = set->current_generation; | ||
739 | set->vt->remove (set->state, ee); | ||
740 | } | ||
651 | else | 741 | else |
652 | set->vt->add (set->state, &el); | 742 | { |
653 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 743 | struct ElementEntry *ee_dup; |
744 | |||
745 | ee = GNUNET_malloc (el.size + sizeof *ee); | ||
746 | ee->element.size = el.size; | ||
747 | memcpy (&ee[1], el.data, el.size); | ||
748 | ee->element.data = &ee[1]; | ||
749 | ee->generation_added = set->current_generation; | ||
750 | ee->remote = GNUNET_NO; | ||
751 | GNUNET_CRYPTO_hash (ee->element.data, el.size, &ee->element_hash); | ||
752 | ee_dup = GNUNET_CONTAINER_multihashmap_get (set->elements, | ||
753 | &ee->element_hash); | ||
754 | if (NULL != ee_dup) | ||
755 | { | ||
756 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element inserted twice, ignoring\n"); | ||
757 | GNUNET_free (ee); | ||
758 | return; | ||
759 | } | ||
760 | GNUNET_CONTAINER_multihashmap_put (set->elements, &ee->element_hash, ee, | ||
761 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
762 | set->vt->add (set->state, ee); | ||
763 | } | ||
654 | } | 764 | } |
655 | 765 | ||
656 | 766 | ||
@@ -712,12 +822,29 @@ handle_client_evaluate (void *cls, | |||
712 | * @param m the message | 822 | * @param m the message |
713 | */ | 823 | */ |
714 | static void | 824 | static void |
715 | handle_client_ack (void *cls, | 825 | handle_client_iter_ack (void *cls, |
716 | struct GNUNET_SERVER_Client *client, | 826 | struct GNUNET_SERVER_Client *client, |
717 | const struct GNUNET_MessageHeader *m) | 827 | const struct GNUNET_MessageHeader *m) |
718 | { | 828 | { |
719 | /* FIXME: implement */ | 829 | struct Set *set; |
830 | |||
831 | set = set_get (client); | ||
832 | if (NULL == set) | ||
833 | { | ||
834 | GNUNET_break (0); | ||
835 | GNUNET_SERVER_client_disconnect (client); | ||
836 | return; | ||
837 | } | ||
838 | |||
839 | if (NULL == set->iter) | ||
840 | { | ||
841 | GNUNET_break (0); | ||
842 | GNUNET_SERVER_client_disconnect (client); | ||
843 | return; | ||
844 | } | ||
845 | |||
720 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 846 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
847 | send_client_element (set); | ||
721 | } | 848 | } |
722 | 849 | ||
723 | 850 | ||
@@ -976,7 +1103,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
976 | static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { | 1103 | static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { |
977 | {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, | 1104 | {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, |
978 | sizeof (struct GNUNET_SET_AcceptRejectMessage)}, | 1105 | sizeof (struct GNUNET_SET_AcceptRejectMessage)}, |
979 | {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0}, | 1106 | {handle_client_iter_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ITER_ACK, 0}, |
980 | {handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0}, | 1107 | {handle_client_add_remove, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0}, |
981 | {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, | 1108 | {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, |
982 | sizeof (struct GNUNET_SET_CreateMessage)}, | 1109 | sizeof (struct GNUNET_SET_CreateMessage)}, |
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h index c93cc660a..ae28b24c2 100644 --- a/src/set/gnunet-service-set.h +++ b/src/set/gnunet-service-set.h | |||
@@ -57,6 +57,7 @@ struct OperationState; | |||
57 | /* forward declarations */ | 57 | /* forward declarations */ |
58 | struct Set; | 58 | struct Set; |
59 | struct TunnelContext; | 59 | struct TunnelContext; |
60 | struct ElementEntry; | ||
60 | 61 | ||
61 | 62 | ||
62 | /** | 63 | /** |
@@ -103,6 +104,8 @@ struct OperationSpecification | |||
103 | }; | 104 | }; |
104 | 105 | ||
105 | 106 | ||
107 | |||
108 | |||
106 | /** | 109 | /** |
107 | * Signature of functions that create the implementation-specific | 110 | * Signature of functions that create the implementation-specific |
108 | * state for a set supporting a specific operation. | 111 | * state for a set supporting a specific operation. |
@@ -119,7 +122,7 @@ typedef struct SetState *(*CreateImpl) (void); | |||
119 | * @param set implementation-specific set state | 122 | * @param set implementation-specific set state |
120 | * @param msg element message from the client | 123 | * @param msg element message from the client |
121 | */ | 124 | */ |
122 | typedef void (*AddRemoveImpl) (struct SetState *state, const struct GNUNET_SET_Element *element); | 125 | typedef void (*AddRemoveImpl) (struct SetState *state, struct ElementEntry *ee); |
123 | 126 | ||
124 | 127 | ||
125 | /** | 128 | /** |
@@ -240,6 +243,54 @@ struct SetVT | |||
240 | 243 | ||
241 | 244 | ||
242 | /** | 245 | /** |
246 | * Information about an element element in the set. | ||
247 | * All elements are stored in a hash-table | ||
248 | * from their hash-code to their 'struct Element', | ||
249 | * so that the remove and add operations are reasonably | ||
250 | * fast. | ||
251 | */ | ||
252 | struct ElementEntry | ||
253 | { | ||
254 | /** | ||
255 | * The actual element. The data for the element | ||
256 | * should be allocated at the end of this struct. | ||
257 | */ | ||
258 | struct GNUNET_SET_Element element; | ||
259 | |||
260 | /** | ||
261 | * Hash of the element. | ||
262 | * Will be used to derive the different IBF keys | ||
263 | * for different salts. | ||
264 | */ | ||
265 | struct GNUNET_HashCode element_hash; | ||
266 | |||
267 | /** | ||
268 | * Generation the element was added by the client. | ||
269 | * Operations of earlier generations will not consider the element. | ||
270 | */ | ||
271 | unsigned int generation_added; | ||
272 | |||
273 | /** | ||
274 | * GNUNET_YES if the element has been removed in some generation. | ||
275 | */ | ||
276 | int removed; | ||
277 | |||
278 | /** | ||
279 | * Generation the element was removed by the client. | ||
280 | * Operations of later generations will not consider the element. | ||
281 | * Only valid if is_removed is GNUNET_YES. | ||
282 | */ | ||
283 | unsigned int generation_removed; | ||
284 | |||
285 | /** | ||
286 | * GNUNET_YES if the element is a remote element, and does not belong | ||
287 | * to the operation's set. | ||
288 | */ | ||
289 | int remote; | ||
290 | }; | ||
291 | |||
292 | |||
293 | /** | ||
243 | * A set that supports a specific operation | 294 | * A set that supports a specific operation |
244 | * with other peers. | 295 | * with other peers. |
245 | */ | 296 | */ |
@@ -281,6 +332,23 @@ struct Set | |||
281 | * Implementation-specific state. | 332 | * Implementation-specific state. |
282 | */ | 333 | */ |
283 | struct SetState *state; | 334 | struct SetState *state; |
335 | |||
336 | /** | ||
337 | * Current state of iterating elements for the client. | ||
338 | * NULL if we are not currently iterating. | ||
339 | */ | ||
340 | struct GNUNET_CONTAINER_MultiHashMapIterator *iter; | ||
341 | |||
342 | /** | ||
343 | * Maps 'struct GNUNET_HashCode' to 'struct ElementEntry'. | ||
344 | */ | ||
345 | struct GNUNET_CONTAINER_MultiHashMap *elements; | ||
346 | |||
347 | /** | ||
348 | * Current generation, that is, number of | ||
349 | * previously executed operations on this set | ||
350 | */ | ||
351 | unsigned int current_generation; | ||
284 | }; | 352 | }; |
285 | 353 | ||
286 | 354 | ||
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c index 1980cdacb..e48386492 100644 --- a/src/set/gnunet-service-set_union.c +++ b/src/set/gnunet-service-set_union.c | |||
@@ -167,7 +167,7 @@ struct OperationState | |||
167 | * Set state of the set that this operation | 167 | * Set state of the set that this operation |
168 | * belongs to. | 168 | * belongs to. |
169 | */ | 169 | */ |
170 | struct SetState *set_state; | 170 | struct Set *set; |
171 | 171 | ||
172 | /** | 172 | /** |
173 | * Evaluate operations are held in | 173 | * Evaluate operations are held in |
@@ -184,54 +184,6 @@ struct OperationState | |||
184 | 184 | ||
185 | 185 | ||
186 | /** | 186 | /** |
187 | * Information about an element element in the set. | ||
188 | * All elements are stored in a hash-table | ||
189 | * from their hash-code to their 'struct Element', | ||
190 | * so that the remove and add operations are reasonably | ||
191 | * fast. | ||
192 | */ | ||
193 | struct ElementEntry | ||
194 | { | ||
195 | /** | ||
196 | * The actual element. The data for the element | ||
197 | * should be allocated at the end of this struct. | ||
198 | */ | ||
199 | struct GNUNET_SET_Element element; | ||
200 | |||
201 | /** | ||
202 | * Hash of the element. | ||
203 | * Will be used to derive the different IBF keys | ||
204 | * for different salts. | ||
205 | */ | ||
206 | struct GNUNET_HashCode element_hash; | ||
207 | |||
208 | /** | ||
209 | * Generation the element was added by the client. | ||
210 | * Operations of earlier generations will not consider the element. | ||
211 | */ | ||
212 | unsigned int generation_added; | ||
213 | |||
214 | /** | ||
215 | * GNUNET_YES if the element has been removed in some generation. | ||
216 | */ | ||
217 | int removed; | ||
218 | |||
219 | /** | ||
220 | * Generation the element was removed by the client. | ||
221 | * Operations of later generations will not consider the element. | ||
222 | * Only valid if is_removed is GNUNET_YES. | ||
223 | */ | ||
224 | unsigned int generation_removed; | ||
225 | |||
226 | /** | ||
227 | * GNUNET_YES if the element is a remote element, and does not belong | ||
228 | * to the operation's set. | ||
229 | */ | ||
230 | int remote; | ||
231 | }; | ||
232 | |||
233 | |||
234 | /** | ||
235 | * The key entry is used to associate an ibf key with | 187 | * The key entry is used to associate an ibf key with |
236 | * an element. | 188 | * an element. |
237 | */ | 189 | */ |
@@ -289,11 +241,6 @@ struct SetState | |||
289 | struct StrataEstimator *se; | 241 | struct StrataEstimator *se; |
290 | 242 | ||
291 | /** | 243 | /** |
292 | * Maps 'struct GNUNET_HashCode' to 'struct ElementEntry'. | ||
293 | */ | ||
294 | struct GNUNET_CONTAINER_MultiHashMap *elements; | ||
295 | |||
296 | /** | ||
297 | * Evaluate operations are held in | 244 | * Evaluate operations are held in |
298 | * a linked list. | 245 | * a linked list. |
299 | */ | 246 | */ |
@@ -304,38 +251,9 @@ struct SetState | |||
304 | * a linked list. | 251 | * a linked list. |
305 | */ | 252 | */ |
306 | struct OperationState *ops_tail; | 253 | struct OperationState *ops_tail; |
307 | |||
308 | /** | ||
309 | * Current generation, that is, number of | ||
310 | * previously executed operations on this set | ||
311 | */ | ||
312 | unsigned int current_generation; | ||
313 | }; | 254 | }; |
314 | 255 | ||
315 | 256 | ||
316 | |||
317 | /** | ||
318 | * Iterator over hash map entries. | ||
319 | * | ||
320 | * @param cls closure | ||
321 | * @param key current key code | ||
322 | * @param value value in the hash map | ||
323 | * @return GNUNET_YES if we should continue to | ||
324 | * iterate, | ||
325 | * GNUNET_NO if not. | ||
326 | */ | ||
327 | static int | ||
328 | destroy_elements_iterator (void *cls, | ||
329 | const struct GNUNET_HashCode * key, | ||
330 | void *value) | ||
331 | { | ||
332 | struct ElementEntry *ee = value; | ||
333 | |||
334 | GNUNET_free (ee); | ||
335 | return GNUNET_YES; | ||
336 | } | ||
337 | |||
338 | |||
339 | /** | 257 | /** |
340 | * Iterator over hash map entries. | 258 | * Iterator over hash map entries. |
341 | * | 259 | * |
@@ -378,8 +296,8 @@ static void | |||
378 | union_operation_destroy (struct OperationState *eo) | 296 | union_operation_destroy (struct OperationState *eo) |
379 | { | 297 | { |
380 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying union op\n"); | 298 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying union op\n"); |
381 | GNUNET_CONTAINER_DLL_remove (eo->set_state->ops_head, | 299 | GNUNET_CONTAINER_DLL_remove (eo->set->state->ops_head, |
382 | eo->set_state->ops_tail, | 300 | eo->set->state->ops_tail, |
383 | eo); | 301 | eo); |
384 | if (NULL != eo->mq) | 302 | if (NULL != eo->mq) |
385 | { | 303 | { |
@@ -647,9 +565,9 @@ prepare_ibf (struct OperationState *eo, uint16_t size) | |||
647 | if (NULL == eo->key_to_element) | 565 | if (NULL == eo->key_to_element) |
648 | { | 566 | { |
649 | unsigned int len; | 567 | unsigned int len; |
650 | len = GNUNET_CONTAINER_multihashmap_size (eo->set_state->elements); | 568 | len = GNUNET_CONTAINER_multihashmap_size (eo->set->elements); |
651 | eo->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); | 569 | eo->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); |
652 | GNUNET_CONTAINER_multihashmap_iterate (eo->set_state->elements, | 570 | GNUNET_CONTAINER_multihashmap_iterate (eo->set->elements, |
653 | init_key_to_element_iterator, eo); | 571 | init_key_to_element_iterator, eo); |
654 | } | 572 | } |
655 | if (NULL != eo->local_ibf) | 573 | if (NULL != eo->local_ibf) |
@@ -720,7 +638,7 @@ send_strata_estimator (struct OperationState *eo) | |||
720 | ev = GNUNET_MQ_msg_header_extra (strata_msg, | 638 | ev = GNUNET_MQ_msg_header_extra (strata_msg, |
721 | SE_STRATA_COUNT * IBF_BUCKET_SIZE * SE_IBF_SIZE, | 639 | SE_STRATA_COUNT * IBF_BUCKET_SIZE * SE_IBF_SIZE, |
722 | GNUNET_MESSAGE_TYPE_SET_P2P_SE); | 640 | GNUNET_MESSAGE_TYPE_SET_P2P_SE); |
723 | strata_estimator_write (eo->set_state->se, &strata_msg[1]); | 641 | strata_estimator_write (eo->set->state->se, &strata_msg[1]); |
724 | GNUNET_MQ_send (eo->mq, ev); | 642 | GNUNET_MQ_send (eo->mq, ev); |
725 | eo->phase = PHASE_EXPECT_IBF; | 643 | eo->phase = PHASE_EXPECT_IBF; |
726 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent SE, expecting IBF\n"); | 644 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent SE, expecting IBF\n"); |
@@ -1218,7 +1136,7 @@ union_evaluate (struct OperationSpecification *spec, | |||
1218 | tc->vt = _GSS_union_vt (); | 1136 | tc->vt = _GSS_union_vt (); |
1219 | tc->op = eo; | 1137 | tc->op = eo; |
1220 | eo->se = strata_estimator_dup (spec->set->state->se); | 1138 | eo->se = strata_estimator_dup (spec->set->state->se); |
1221 | eo->set_state = spec->set->state; | 1139 | eo->set = spec->set; |
1222 | eo->spec = spec; | 1140 | eo->spec = spec; |
1223 | eo->tunnel = tunnel; | 1141 | eo->tunnel = tunnel; |
1224 | eo->mq = GNUNET_MESH_mq_create (tunnel); | 1142 | eo->mq = GNUNET_MESH_mq_create (tunnel); |
@@ -1230,8 +1148,8 @@ union_evaluate (struct OperationSpecification *spec, | |||
1230 | /* we started the operation, thus we have to send the operation request */ | 1148 | /* we started the operation, thus we have to send the operation request */ |
1231 | eo->phase = PHASE_EXPECT_SE; | 1149 | eo->phase = PHASE_EXPECT_SE; |
1232 | 1150 | ||
1233 | GNUNET_CONTAINER_DLL_insert (eo->set_state->ops_head, | 1151 | GNUNET_CONTAINER_DLL_insert (eo->set->state->ops_head, |
1234 | eo->set_state->ops_tail, | 1152 | eo->set->state->ops_tail, |
1235 | eo); | 1153 | eo); |
1236 | 1154 | ||
1237 | send_operation_request (eo); | 1155 | send_operation_request (eo); |
@@ -1259,15 +1177,15 @@ union_accept (struct OperationSpecification *spec, | |||
1259 | eo = GNUNET_new (struct OperationState); | 1177 | eo = GNUNET_new (struct OperationState); |
1260 | tc->vt = _GSS_union_vt (); | 1178 | tc->vt = _GSS_union_vt (); |
1261 | tc->op = eo; | 1179 | tc->op = eo; |
1262 | eo->set_state = spec->set->state; | 1180 | eo->set = spec->set; |
1263 | eo->generation_created = eo->set_state->current_generation++; | 1181 | eo->generation_created = eo->set->current_generation++; |
1264 | eo->spec = spec; | 1182 | eo->spec = spec; |
1265 | eo->tunnel = tunnel; | 1183 | eo->tunnel = tunnel; |
1266 | eo->mq = GNUNET_MESH_mq_create (tunnel); | 1184 | eo->mq = GNUNET_MESH_mq_create (tunnel); |
1267 | eo->se = strata_estimator_dup (eo->set_state->se); | 1185 | eo->se = strata_estimator_dup (eo->set->state->se); |
1268 | /* transfer ownership of mq and socket from incoming to eo */ | 1186 | /* transfer ownership of mq and socket from incoming to eo */ |
1269 | GNUNET_CONTAINER_DLL_insert (eo->set_state->ops_head, | 1187 | GNUNET_CONTAINER_DLL_insert (eo->set->state->ops_head, |
1270 | eo->set_state->ops_tail, | 1188 | eo->set->state->ops_tail, |
1271 | eo); | 1189 | eo); |
1272 | /* kick off the operation */ | 1190 | /* kick off the operation */ |
1273 | send_strata_estimator (eo); | 1191 | send_strata_estimator (eo); |
@@ -1287,9 +1205,6 @@ union_set_create (void) | |||
1287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "union set created\n"); | 1205 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "union set created\n"); |
1288 | 1206 | ||
1289 | set_state = GNUNET_new (struct SetState); | 1207 | set_state = GNUNET_new (struct SetState); |
1290 | /* keys of the hash map are stored in the element entrys, thus we do not | ||
1291 | * want the hash map to copy them */ | ||
1292 | set_state->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
1293 | set_state->se = strata_estimator_create (SE_STRATA_COUNT, | 1208 | set_state->se = strata_estimator_create (SE_STRATA_COUNT, |
1294 | SE_IBF_SIZE, SE_IBF_HASH_NUM); | 1209 | SE_IBF_SIZE, SE_IBF_HASH_NUM); |
1295 | return set_state; | 1210 | return set_state; |
@@ -1303,30 +1218,8 @@ union_set_create (void) | |||
1303 | * @param element the element to add to the set | 1218 | * @param element the element to add to the set |
1304 | */ | 1219 | */ |
1305 | static void | 1220 | static void |
1306 | union_add (struct SetState *set_state, const struct GNUNET_SET_Element *element) | 1221 | union_add (struct SetState *set_state, struct ElementEntry *ee) |
1307 | { | 1222 | { |
1308 | struct ElementEntry *ee; | ||
1309 | struct ElementEntry *ee_dup; | ||
1310 | |||
1311 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "adding union element of size %u\n", element->size); | ||
1312 | |||
1313 | ee = GNUNET_malloc (element->size + sizeof *ee); | ||
1314 | ee->element.size = element->size; | ||
1315 | memcpy (&ee[1], element->data, element->size); | ||
1316 | ee->element.data = &ee[1]; | ||
1317 | ee->generation_added = set_state->current_generation; | ||
1318 | ee->remote = GNUNET_NO; | ||
1319 | GNUNET_CRYPTO_hash (ee->element.data, element->size, &ee->element_hash); | ||
1320 | ee_dup = GNUNET_CONTAINER_multihashmap_get (set_state->elements, | ||
1321 | &ee->element_hash); | ||
1322 | if (NULL != ee_dup) | ||
1323 | { | ||
1324 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "element inserted twice, ignoring\n"); | ||
1325 | GNUNET_free (ee); | ||
1326 | return; | ||
1327 | } | ||
1328 | GNUNET_CONTAINER_multihashmap_put (set_state->elements, &ee->element_hash, ee, | ||
1329 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1330 | strata_estimator_insert (set_state->se, get_ibf_key (&ee->element_hash, 0)); | 1223 | strata_estimator_insert (set_state->se, get_ibf_key (&ee->element_hash, 0)); |
1331 | } | 1224 | } |
1332 | 1225 | ||
@@ -1348,17 +1241,10 @@ union_set_destroy (struct SetState *set_state) | |||
1348 | strata_estimator_destroy (set_state->se); | 1241 | strata_estimator_destroy (set_state->se); |
1349 | set_state->se = NULL; | 1242 | set_state->se = NULL; |
1350 | } | 1243 | } |
1351 | if (NULL != set_state->elements) | ||
1352 | { | ||
1353 | GNUNET_CONTAINER_multihashmap_iterate (set_state->elements, | ||
1354 | destroy_elements_iterator, NULL); | ||
1355 | GNUNET_CONTAINER_multihashmap_destroy (set_state->elements); | ||
1356 | set_state->elements = NULL; | ||
1357 | } | ||
1358 | |||
1359 | GNUNET_free (set_state); | 1244 | GNUNET_free (set_state); |
1360 | } | 1245 | } |
1361 | 1246 | ||
1247 | |||
1362 | /** | 1248 | /** |
1363 | * Remove the element given in the element message from the set. | 1249 | * Remove the element given in the element message from the set. |
1364 | * Only marks the element as removed, so that older set operations can still exchange it. | 1250 | * Only marks the element as removed, so that older set operations can still exchange it. |
@@ -1367,25 +1253,9 @@ union_set_destroy (struct SetState *set_state) | |||
1367 | * @param element set element to remove | 1253 | * @param element set element to remove |
1368 | */ | 1254 | */ |
1369 | static void | 1255 | static void |
1370 | union_remove (struct SetState *set_state, const struct GNUNET_SET_Element *element) | 1256 | union_remove (struct SetState *set_state, struct ElementEntry *element) |
1371 | { | 1257 | { |
1372 | struct GNUNET_HashCode hash; | 1258 | /* FIXME: remove from strata estimator */ |
1373 | struct ElementEntry *ee; | ||
1374 | |||
1375 | GNUNET_CRYPTO_hash (element->data, element->size, &hash); | ||
1376 | ee = GNUNET_CONTAINER_multihashmap_get (set_state->elements, &hash); | ||
1377 | if (NULL == ee) | ||
1378 | { | ||
1379 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove non-existing element\n"); | ||
1380 | return; | ||
1381 | } | ||
1382 | if (GNUNET_YES == ee->removed) | ||
1383 | { | ||
1384 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to remove element twice\n"); | ||
1385 | return; | ||
1386 | } | ||
1387 | ee->removed = GNUNET_YES; | ||
1388 | ee->generation_removed = set_state->current_generation; | ||
1389 | } | 1259 | } |
1390 | 1260 | ||
1391 | 1261 | ||
@@ -1466,55 +1336,6 @@ union_op_cancel (struct SetState *set_state, uint32_t op_id) | |||
1466 | } | 1336 | } |
1467 | 1337 | ||
1468 | 1338 | ||
1469 | /** | ||
1470 | * Iterator over hash map entries. | ||
1471 | * | ||
1472 | * @param cls closure | ||
1473 | * @param key current key code | ||
1474 | * @param value value in the hash map | ||
1475 | * @return GNUNET_YES if we should continue to | ||
1476 | * iterate, | ||
1477 | * GNUNET_NO if not. | ||
1478 | */ | ||
1479 | static int | ||
1480 | send_iter_element_iter (void *cls, | ||
1481 | const struct GNUNET_HashCode *key, | ||
1482 | void *value) | ||
1483 | { | ||
1484 | struct ElementEntry *ee = value; | ||
1485 | struct Set *set = cls; | ||
1486 | struct GNUNET_SET_IterResponseMessage *m; | ||
1487 | struct GNUNET_MQ_Envelope *ev; | ||
1488 | |||
1489 | ev = GNUNET_MQ_msg_extra (m, ee->element.size, | ||
1490 | GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT); | ||
1491 | |||
1492 | m->element_type = ee->element.type; | ||
1493 | memcpy (&m[1], ee->element.data, ee->element.size); | ||
1494 | GNUNET_MQ_send (set->client_mq, ev); | ||
1495 | |||
1496 | return GNUNET_YES; | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | /** | ||
1501 | * Send all elements of the union set to the client. | ||
1502 | * | ||
1503 | * @param set set to iterate over | ||
1504 | */ | ||
1505 | static void | ||
1506 | union_iterate (struct Set *set) | ||
1507 | { | ||
1508 | struct GNUNET_MQ_Envelope *ev; | ||
1509 | |||
1510 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "iterating union set with %u elements\n", | ||
1511 | GNUNET_CONTAINER_multihashmap_size (set->state->elements)); | ||
1512 | GNUNET_CONTAINER_multihashmap_iterate (set->state->elements, send_iter_element_iter, set); | ||
1513 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE); | ||
1514 | GNUNET_MQ_send (set->client_mq, ev); | ||
1515 | } | ||
1516 | |||
1517 | |||
1518 | const struct SetVT * | 1339 | const struct SetVT * |
1519 | _GSS_union_vt () | 1340 | _GSS_union_vt () |
1520 | { | 1341 | { |
@@ -1528,7 +1349,6 @@ _GSS_union_vt () | |||
1528 | .accept = &union_accept, | 1349 | .accept = &union_accept, |
1529 | .peer_disconnect = &union_peer_disconnect, | 1350 | .peer_disconnect = &union_peer_disconnect, |
1530 | .cancel = &union_op_cancel, | 1351 | .cancel = &union_op_cancel, |
1531 | .iterate = &union_iterate | ||
1532 | }; | 1352 | }; |
1533 | 1353 | ||
1534 | return &union_vt; | 1354 | return &union_vt; |
diff --git a/src/set/set.h b/src/set/set.h index ec8390448..8527b6abb 100644 --- a/src/set/set.h +++ b/src/set/set.h | |||
@@ -227,6 +227,19 @@ struct GNUNET_SET_IterResponseMessage | |||
227 | /* rest: element */ | 227 | /* rest: element */ |
228 | }; | 228 | }; |
229 | 229 | ||
230 | struct GNUNET_SET_IterAckMessage | ||
231 | { | ||
232 | /** | ||
233 | * Type: GNUNET_MESSAGE_TYPE_SET_ITER_ACK | ||
234 | */ | ||
235 | struct GNUNET_MessageHeader header; | ||
236 | |||
237 | /** | ||
238 | * Non-zero if the service should continue sending elements. | ||
239 | */ | ||
240 | uint32_t send_more; | ||
241 | }; | ||
242 | |||
230 | GNUNET_NETWORK_STRUCT_END | 243 | GNUNET_NETWORK_STRUCT_END |
231 | 244 | ||
232 | #endif | 245 | #endif |
diff --git a/src/set/set_api.c b/src/set/set_api.c index 7f52fb0a9..3b287d5a4 100644 --- a/src/set/set_api.c +++ b/src/set/set_api.c | |||
@@ -222,6 +222,8 @@ handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh) | |||
222 | struct GNUNET_SET_Element element; | 222 | struct GNUNET_SET_Element element; |
223 | const struct GNUNET_SET_IterResponseMessage *msg = | 223 | const struct GNUNET_SET_IterResponseMessage *msg = |
224 | (const struct GNUNET_SET_IterResponseMessage *) mh; | 224 | (const struct GNUNET_SET_IterResponseMessage *) mh; |
225 | struct GNUNET_SET_IterAckMessage *ack_msg; | ||
226 | struct GNUNET_MQ_Envelope *ev; | ||
225 | 227 | ||
226 | if (NULL == set->iterator) | 228 | if (NULL == set->iterator) |
227 | return; | 229 | return; |
@@ -230,6 +232,9 @@ handle_iter_element (void *cls, const struct GNUNET_MessageHeader *mh) | |||
230 | element.type = htons (msg->element_type); | 232 | element.type = htons (msg->element_type); |
231 | element.data = &msg[1]; | 233 | element.data = &msg[1]; |
232 | set->iterator (set->iterator_cls, &element); | 234 | set->iterator (set->iterator_cls, &element); |
235 | ev = GNUNET_MQ_msg (ack_msg, GNUNET_MESSAGE_TYPE_SET_ITER_ACK); | ||
236 | ack_msg->send_more = htonl (1); | ||
237 | GNUNET_MQ_send (set->mq, ev); | ||
233 | } | 238 | } |
234 | 239 | ||
235 | 240 | ||
diff --git a/src/set/test_set.conf b/src/set/test_set.conf index 7bc26ed7e..22df91a40 100644 --- a/src/set/test_set.conf +++ b/src/set/test_set.conf | |||
@@ -8,7 +8,7 @@ PORT = 2106 | |||
8 | HOSTNAME = localhost | 8 | HOSTNAME = localhost |
9 | HOME = $SERVICEHOME | 9 | HOME = $SERVICEHOME |
10 | BINARY = gnunet-service-set | 10 | BINARY = gnunet-service-set |
11 | #PREFIX = valgrind --leak-check=full | 11 | PREFIX = valgrind |
12 | #PREFIX = gdbserver :1234 | 12 | #PREFIX = gdbserver :1234 |
13 | ACCEPT_FROM = 127.0.0.1; | 13 | ACCEPT_FROM = 127.0.0.1; |
14 | ACCEPT_FROM6 = ::1; | 14 | ACCEPT_FROM6 = ::1; |
diff --git a/src/set/test_set_api.c b/src/set/test_set_api.c index 59c79ee38..6085c59f3 100644 --- a/src/set/test_set_api.c +++ b/src/set/test_set_api.c | |||
@@ -36,7 +36,7 @@ static struct GNUNET_SET_Handle *set2; | |||
36 | static struct GNUNET_SET_ListenHandle *listen_handle; | 36 | static struct GNUNET_SET_ListenHandle *listen_handle; |
37 | const static struct GNUNET_CONFIGURATION_Handle *config; | 37 | const static struct GNUNET_CONFIGURATION_Handle *config; |
38 | 38 | ||
39 | int num_done; | 39 | static int iter_count; |
40 | 40 | ||
41 | 41 | ||
42 | static void | 42 | static void |
@@ -144,6 +144,9 @@ init_set2 (void *cls) | |||
144 | GNUNET_SET_add_element (set2, &element, NULL, NULL); | 144 | GNUNET_SET_add_element (set2, &element, NULL, NULL); |
145 | element.data = "quux"; | 145 | element.data = "quux"; |
146 | element.size = strlen(element.data); | 146 | element.size = strlen(element.data); |
147 | GNUNET_SET_add_element (set2, &element, NULL, NULL); | ||
148 | element.data = "baz"; | ||
149 | element.size = strlen(element.data); | ||
147 | GNUNET_SET_add_element (set2, &element, start, NULL); | 150 | GNUNET_SET_add_element (set2, &element, start, NULL); |
148 | } | 151 | } |
149 | 152 | ||
@@ -167,6 +170,44 @@ init_set1 (void) | |||
167 | } | 170 | } |
168 | 171 | ||
169 | 172 | ||
173 | static int | ||
174 | iter_cb (void *cls, | ||
175 | const struct GNUNET_SET_Element *element) | ||
176 | { | ||
177 | if (NULL == element) | ||
178 | { | ||
179 | GNUNET_assert (iter_count == 3); | ||
180 | GNUNET_SET_destroy (cls); | ||
181 | return GNUNET_YES; | ||
182 | } | ||
183 | printf ("iter: got element\n"); | ||
184 | iter_count++; | ||
185 | return GNUNET_YES; | ||
186 | } | ||
187 | |||
188 | |||
189 | static void | ||
190 | test_iter () | ||
191 | { | ||
192 | struct GNUNET_SET_Element element; | ||
193 | struct GNUNET_SET_Handle *iter_set; | ||
194 | |||
195 | iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION); | ||
196 | |||
197 | element.data = "hello"; | ||
198 | element.size = strlen(element.data); | ||
199 | GNUNET_SET_add_element (iter_set, &element, NULL, NULL); | ||
200 | element.data = "bar"; | ||
201 | element.size = strlen(element.data); | ||
202 | GNUNET_SET_add_element (iter_set, &element, NULL, NULL); | ||
203 | element.data = "quux"; | ||
204 | element.size = strlen(element.data); | ||
205 | GNUNET_SET_add_element (iter_set, &element, NULL, NULL); | ||
206 | |||
207 | GNUNET_SET_iterate (iter_set, iter_cb, iter_set); | ||
208 | } | ||
209 | |||
210 | |||
170 | /** | 211 | /** |
171 | * Signature of the 'main' function for a (single-peer) testcase that | 212 | * Signature of the 'main' function for a (single-peer) testcase that |
172 | * is run using 'GNUNET_TESTING_peer_run'. | 213 | * is run using 'GNUNET_TESTING_peer_run'. |
@@ -188,6 +229,10 @@ run (void *cls, | |||
188 | printf ("my id (from CRYPTO): %s\n", GNUNET_h2s (&local_id.hashPubKey)); | 229 | printf ("my id (from CRYPTO): %s\n", GNUNET_h2s (&local_id.hashPubKey)); |
189 | GNUNET_TESTING_peer_get_identity (peer, &local_id); | 230 | GNUNET_TESTING_peer_get_identity (peer, &local_id); |
190 | printf ("my id (from TESTING): %s\n", GNUNET_h2s (&local_id.hashPubKey)); | 231 | printf ("my id (from TESTING): %s\n", GNUNET_h2s (&local_id.hashPubKey)); |
232 | |||
233 | test_iter (); | ||
234 | |||
235 | return; | ||
191 | set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); | 236 | set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); |
192 | set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); | 237 | set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); |
193 | GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id); | 238 | GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id); |
diff --git a/src/util/container_multihashmap.c b/src/util/container_multihashmap.c index 9ef8f74a4..a365e81d9 100644 --- a/src/util/container_multihashmap.c +++ b/src/util/container_multihashmap.c | |||
@@ -872,7 +872,9 @@ GNUNET_CONTAINER_multihashmap_iterator_next (struct GNUNET_CONTAINER_MultiHashMa | |||
872 | return GNUNET_YES; | 872 | return GNUNET_YES; |
873 | } | 873 | } |
874 | } | 874 | } |
875 | iter->idx++; | 875 | iter->idx += 1; |
876 | if (iter->idx < iter->map->map_length) | ||
877 | iter->me = iter->map->map[iter->idx]; | ||
876 | } | 878 | } |
877 | } | 879 | } |
878 | 880 | ||