diff options
-rw-r--r-- | src/set/gnunet-service-set.c | 54 | ||||
-rw-r--r-- | src/set/gnunet-service-set.h | 8 | ||||
-rw-r--r-- | src/set/test_set.conf | 2 | ||||
-rw-r--r-- | src/set/test_set_union_copy.c | 17 |
4 files changed, 58 insertions, 23 deletions
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c index 754bc96e0..2f1578514 100644 --- a/src/set/gnunet-service-set.c +++ b/src/set/gnunet-service-set.c | |||
@@ -341,12 +341,7 @@ is_element_of_generation (struct ElementEntry *ee, | |||
341 | int is_present; | 341 | int is_present; |
342 | unsigned int i; | 342 | unsigned int i; |
343 | 343 | ||
344 | /* If ee->mutations is NULL, | 344 | GNUNET_assert (NULL != ee->mutations); |
345 | the element was added in generation 0, | ||
346 | and there are no removes, thus the element | ||
347 | is part of any generation we query. */ | ||
348 | if (NULL == ee->mutations) | ||
349 | return GNUNET_YES; | ||
350 | 345 | ||
351 | if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size)) | 346 | if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size)) |
352 | { | 347 | { |
@@ -389,7 +384,7 @@ is_element_of_generation (struct ElementEntry *ee, | |||
389 | is_present = mut->added; | 384 | is_present = mut->added; |
390 | } | 385 | } |
391 | 386 | ||
392 | return GNUNET_YES; | 387 | return is_present; |
393 | } | 388 | } |
394 | 389 | ||
395 | 390 | ||
@@ -404,6 +399,17 @@ _GSS_is_element_of_set (struct ElementEntry *ee, | |||
404 | } | 399 | } |
405 | 400 | ||
406 | 401 | ||
402 | static int | ||
403 | is_element_of_iteration (struct ElementEntry *ee, | ||
404 | struct Set *set) | ||
405 | { | ||
406 | return is_element_of_generation (ee, | ||
407 | set->iter_generation, | ||
408 | set->excluded_generations, | ||
409 | set->excluded_generations_size); | ||
410 | } | ||
411 | |||
412 | |||
407 | int | 413 | int |
408 | _GSS_is_element_of_operation (struct ElementEntry *ee, | 414 | _GSS_is_element_of_operation (struct ElementEntry *ee, |
409 | struct Operation *op) | 415 | struct Operation *op) |
@@ -842,11 +848,9 @@ execute_add (struct Set *set, | |||
842 | else if (GNUNET_YES == _GSS_is_element_of_set (ee, set)) | 848 | else if (GNUNET_YES == _GSS_is_element_of_set (ee, set)) |
843 | { | 849 | { |
844 | /* same element inserted twice */ | 850 | /* same element inserted twice */ |
845 | GNUNET_break (0); | ||
846 | return; | 851 | return; |
847 | } | 852 | } |
848 | 853 | ||
849 | if (0 != set->current_generation) | ||
850 | { | 854 | { |
851 | struct MutationEvent mut = { | 855 | struct MutationEvent mut = { |
852 | .generation = set->current_generation, | 856 | .generation = set->current_generation, |
@@ -888,22 +892,14 @@ execute_remove (struct Set *set, | |||
888 | &hash); | 892 | &hash); |
889 | if (NULL == ee) | 893 | if (NULL == ee) |
890 | { | 894 | { |
891 | /* Client tried to remove non-existing element */ | 895 | /* Client tried to remove non-existing element. */ |
892 | GNUNET_break (0); | ||
893 | return; | 896 | return; |
894 | } | 897 | } |
895 | if (GNUNET_NO == _GSS_is_element_of_set (ee, set)) | 898 | if (GNUNET_NO == _GSS_is_element_of_set (ee, set)) |
896 | { | 899 | { |
897 | /* Client tried to remove element twice */ | 900 | /* Client tried to remove element twice */ |
898 | GNUNET_break (0); | ||
899 | return; | 901 | return; |
900 | } | 902 | } |
901 | else if (0 == set->current_generation) | ||
902 | { | ||
903 | // If current_generation is 0, then there are no running set operations | ||
904 | // or lazy copies, thus we can safely remove the element. | ||
905 | (void) GNUNET_CONTAINER_multihashmap_remove_all (set->content->elements, &hash); | ||
906 | } | ||
907 | else | 903 | else |
908 | { | 904 | { |
909 | struct MutationEvent mut = { | 905 | struct MutationEvent mut = { |
@@ -958,6 +954,9 @@ send_client_element (struct Set *set) | |||
958 | struct GNUNET_SET_IterResponseMessage *msg; | 954 | struct GNUNET_SET_IterResponseMessage *msg; |
959 | 955 | ||
960 | GNUNET_assert (NULL != set->iter); | 956 | GNUNET_assert (NULL != set->iter); |
957 | |||
958 | again: | ||
959 | |||
961 | ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, | 960 | ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, |
962 | NULL, | 961 | NULL, |
963 | (const void **) &ee); | 962 | (const void **) &ee); |
@@ -997,6 +996,10 @@ send_client_element (struct Set *set) | |||
997 | else | 996 | else |
998 | { | 997 | { |
999 | GNUNET_assert (NULL != ee); | 998 | GNUNET_assert (NULL != ee); |
999 | |||
1000 | if (GNUNET_NO == is_element_of_iteration (ee, set)) | ||
1001 | goto again; | ||
1002 | |||
1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1003 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1001 | "Sending iteration element on %p.\n", | 1004 | "Sending iteration element on %p.\n", |
1002 | (void *) set); | 1005 | (void *) set); |
@@ -1046,13 +1049,15 @@ handle_client_iterate (void *cls, | |||
1046 | return; | 1049 | return; |
1047 | } | 1050 | } |
1048 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1051 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1049 | "Iterating set %p with %u elements\n", | 1052 | "Iterating set %p in gen %u with %u content elements\n", |
1050 | (void *) set, | 1053 | (void *) set, |
1054 | set->current_generation, | ||
1051 | GNUNET_CONTAINER_multihashmap_size (set->content->elements)); | 1055 | GNUNET_CONTAINER_multihashmap_size (set->content->elements)); |
1052 | GNUNET_SERVER_receive_done (client, | 1056 | GNUNET_SERVER_receive_done (client, |
1053 | GNUNET_OK); | 1057 | GNUNET_OK); |
1054 | set->content->iterator_count += 1; | 1058 | set->content->iterator_count += 1; |
1055 | set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); | 1059 | set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); |
1060 | set->iter_generation = set->current_generation; | ||
1056 | send_client_element (set); | 1061 | send_client_element (set); |
1057 | } | 1062 | } |
1058 | 1063 | ||
@@ -1529,6 +1534,17 @@ handle_client_copy_lazy_connect (void *cls, | |||
1529 | set->state = set->vt->copy_state (cr->source_set); | 1534 | set->state = set->vt->copy_state (cr->source_set); |
1530 | set->content = cr->source_set->content; | 1535 | set->content = cr->source_set->content; |
1531 | set->content->refcount += 1; | 1536 | set->content->refcount += 1; |
1537 | |||
1538 | set->current_generation = cr->source_set->current_generation; | ||
1539 | set->excluded_generations_size = cr->source_set->excluded_generations_size; | ||
1540 | set->excluded_generations = GNUNET_memdup (cr->source_set->excluded_generations, | ||
1541 | set->excluded_generations_size * sizeof (struct GenerationRange)); | ||
1542 | |||
1543 | /* Advance the generation of the new set, so that mutations to the | ||
1544 | of the cloned set and the source set are independent. */ | ||
1545 | advance_generation (set); | ||
1546 | |||
1547 | |||
1532 | set->client = client; | 1548 | set->client = client; |
1533 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); | 1549 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); |
1534 | GNUNET_CONTAINER_DLL_insert (sets_head, | 1550 | GNUNET_CONTAINER_DLL_insert (sets_head, |
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h index c3650aa9b..bc3052f02 100644 --- a/src/set/gnunet-service-set.h +++ b/src/set/gnunet-service-set.h | |||
@@ -560,6 +560,9 @@ struct Set | |||
560 | */ | 560 | */ |
561 | struct GenerationRange *excluded_generations; | 561 | struct GenerationRange *excluded_generations; |
562 | 562 | ||
563 | /** | ||
564 | * Number of elements in array @a excluded_generations. | ||
565 | */ | ||
563 | unsigned int excluded_generations_size; | 566 | unsigned int excluded_generations_size; |
564 | 567 | ||
565 | /** | 568 | /** |
@@ -574,6 +577,11 @@ struct Set | |||
574 | uint16_t iteration_id; | 577 | uint16_t iteration_id; |
575 | 578 | ||
576 | /** | 579 | /** |
580 | * Generation we're currently iteration over. | ||
581 | */ | ||
582 | unsigned int iter_generation; | ||
583 | |||
584 | /** | ||
577 | * Content, possibly shared by multiple sets, | 585 | * Content, possibly shared by multiple sets, |
578 | * and thus reference counted. | 586 | * and thus reference counted. |
579 | */ | 587 | */ |
diff --git a/src/set/test_set.conf b/src/set/test_set.conf index 4f32b8854..ae7708c2d 100644 --- a/src/set/test_set.conf +++ b/src/set/test_set.conf | |||
@@ -6,7 +6,7 @@ GNUNET_TEST_HOME = /tmp/test-gnunet-set/ | |||
6 | [set] | 6 | [set] |
7 | AUTOSTART = YES | 7 | AUTOSTART = YES |
8 | #PREFIX = valgrind | 8 | #PREFIX = valgrind |
9 | PREFIX = valgrind --leak-check=full | 9 | #PREFIX = valgrind --leak-check=full |
10 | #PREFIX = gdbserver :1234 | 10 | #PREFIX = gdbserver :1234 |
11 | OPTIONS = -L INFO | 11 | OPTIONS = -L INFO |
12 | 12 | ||
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c index bb8d57631..47520588a 100644 --- a/src/set/test_set_union_copy.c +++ b/src/set/test_set_union_copy.c | |||
@@ -157,7 +157,7 @@ void test_done (void *cls) | |||
157 | 157 | ||
158 | void check_new_set_count (void *cls) | 158 | void check_new_set_count (void *cls) |
159 | { | 159 | { |
160 | check_count (set2, "new set", 2, &test_done, NULL); | 160 | check_count (set2, "new set", 4, &test_done, NULL); |
161 | } | 161 | } |
162 | 162 | ||
163 | 163 | ||
@@ -166,8 +166,13 @@ void copy_done (void *cls, struct GNUNET_SET_Handle *new_set) | |||
166 | printf ("copy done\n"); | 166 | printf ("copy done\n"); |
167 | set2 = new_set; | 167 | set2 = new_set; |
168 | remove_element_str (set2, "spam"); | 168 | remove_element_str (set2, "spam"); |
169 | add_element_str (set2, "new1"); | ||
170 | add_element_str (set2, "new2"); | ||
171 | remove_element_str (set2, "new2"); | ||
172 | remove_element_str (set2, "new3"); | ||
169 | // Check that set1 didn't change. | 173 | // Check that set1 didn't change. |
170 | check_count (set1, "old set", 3, &check_new_set_count, NULL); | 174 | check_count (set1, "old set", 3, |
175 | &check_new_set_count, NULL); | ||
171 | } | 176 | } |
172 | 177 | ||
173 | 178 | ||
@@ -203,8 +208,14 @@ run (void *cls, | |||
203 | set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); | 208 | set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); |
204 | add_element_str (set1, "foo"); | 209 | add_element_str (set1, "foo"); |
205 | add_element_str (set1, "bar"); | 210 | add_element_str (set1, "bar"); |
211 | /* duplicate -- ignored */ | ||
212 | add_element_str (set1, "bar"); | ||
206 | remove_element_str (set1, "foo"); | 213 | remove_element_str (set1, "foo"); |
214 | /* non-existent -- ignored */ | ||
215 | remove_element_str (set1, "nonexist1"); | ||
207 | add_element_str (set1, "spam"); | 216 | add_element_str (set1, "spam"); |
217 | /* duplicate -- ignored */ | ||
218 | remove_element_str (set1, "foo"); | ||
208 | add_element_str (set1, "eggs"); | 219 | add_element_str (set1, "eggs"); |
209 | 220 | ||
210 | check_count (set1, "initial test", 3, &test_copy, NULL); | 221 | check_count (set1, "initial test", 3, &test_copy, NULL); |
@@ -214,7 +225,7 @@ run (void *cls, | |||
214 | int | 225 | int |
215 | main (int argc, char **argv) | 226 | main (int argc, char **argv) |
216 | { | 227 | { |
217 | if (0 != GNUNET_TESTING_peer_run ("test_set_api", | 228 | if (0 != GNUNET_TESTING_peer_run ("test_set_union_copy", |
218 | "test_set.conf", | 229 | "test_set.conf", |
219 | &run, NULL)) | 230 | &run, NULL)) |
220 | { | 231 | { |