aboutsummaryrefslogtreecommitdiff
path: root/src/set
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2015-08-30 20:54:44 +0000
committerFlorian Dold <florian.dold@gmail.com>2015-08-30 20:54:44 +0000
commit2e25d8c868521f318381a8b87c9f8c1c7c402b7c (patch)
treea5d9b8fca78e55da9d8c62ff8fe6d1d480a459e0 /src/set
parentc92948f72526fe599680c06cbe80d0ffdc11f597 (diff)
downloadgnunet-2e25d8c868521f318381a8b87c9f8c1c7c402b7c.tar.gz
gnunet-2e25d8c868521f318381a8b87c9f8c1c7c402b7c.zip
add test case for 'GNUNET_SET_copy_lazy', fix bugs
Diffstat (limited to 'src/set')
-rw-r--r--src/set/Makefile.am10
-rw-r--r--src/set/gnunet-service-set.c363
-rw-r--r--src/set/gnunet-service-set.h36
-rw-r--r--src/set/gnunet-service-set_union.c12
-rw-r--r--src/set/set_api.c12
-rw-r--r--src/set/test_set.conf48
-rw-r--r--src/set/test_set_union_copy.c225
7 files changed, 570 insertions, 136 deletions
diff --git a/src/set/Makefile.am b/src/set/Makefile.am
index b91a54683..669a28658 100644
--- a/src/set/Makefile.am
+++ b/src/set/Makefile.am
@@ -67,7 +67,8 @@ if HAVE_TESTING
67check_PROGRAMS = \ 67check_PROGRAMS = \
68 test_set_api \ 68 test_set_api \
69 test_set_union_result_full \ 69 test_set_union_result_full \
70 test_set_intersection_result_full 70 test_set_intersection_result_full \
71 test_set_union_copy
71endif 72endif
72 73
73if ENABLE_TEST_RUN 74if ENABLE_TEST_RUN
@@ -96,5 +97,12 @@ test_set_intersection_result_full_LDADD = \
96 $(top_builddir)/src/testing/libgnunettesting.la \ 97 $(top_builddir)/src/testing/libgnunettesting.la \
97 libgnunetset.la 98 libgnunetset.la
98 99
100test_set_union_copy_SOURCES = \
101 test_set_union_copy.c
102test_set_union_copy_LDADD = \
103 $(top_builddir)/src/util/libgnunetutil.la \
104 $(top_builddir)/src/testing/libgnunettesting.la \
105 libgnunetset.la
106
99EXTRA_DIST = \ 107EXTRA_DIST = \
100 test_set.conf 108 test_set.conf
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c
index b2ad01d1b..75b33536d 100644
--- a/src/set/gnunet-service-set.c
+++ b/src/set/gnunet-service-set.c
@@ -510,8 +510,24 @@ set_destroy (struct Set *set)
510 } 510 }
511 { 511 {
512 struct SetContent *content; 512 struct SetContent *content;
513 struct PendingMutation *pm;
514 struct PendingMutation *pm_current;
513 515
514 content = set->content; 516 content = set->content;
517
518 // discard any pending mutations that reference this set
519 pm = content->pending_mutations_head;
520 while (NULL != pm)
521 {
522 pm_current = pm;
523 pm = pm->next;
524 if (pm_current-> set == set)
525 GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head,
526 content->pending_mutations_tail,
527 pm_current);
528
529 }
530
515 set->content = NULL; 531 set->content = NULL;
516 GNUNET_assert (0 != content->refcount); 532 GNUNET_assert (0 != content->refcount);
517 content->refcount -= 1; 533 content->refcount -= 1;
@@ -531,7 +547,21 @@ set_destroy (struct Set *set)
531 sets_tail, 547 sets_tail,
532 set); 548 set);
533 549
534 // FIXME: remove from lazy copy requests 550 // remove set from pending copy requests
551 {
552 struct LazyCopyRequest *lcr;
553 lcr = lazy_copy_head;
554 while (NULL != lcr)
555 {
556 struct LazyCopyRequest *lcr_current;
557 lcr_current = lcr;
558 lcr = lcr->next;
559 if (lcr_current->source_set == set)
560 GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
561 lazy_copy_tail,
562 lcr_current);
563 }
564 }
535 565
536 GNUNET_free (set); 566 GNUNET_free (set);
537} 567}
@@ -750,6 +780,140 @@ handle_incoming_msg (struct Operation *op,
750} 780}
751 781
752 782
783static void
784execute_add (struct Set *set,
785 const struct GNUNET_MessageHeader *m)
786{
787 const struct GNUNET_SET_ElementMessage *msg;
788 struct GNUNET_SET_Element el;
789 struct ElementEntry *ee;
790 struct GNUNET_HashCode hash;
791
792 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (m->type));
793
794 msg = (const struct GNUNET_SET_ElementMessage *) m;
795 el.size = ntohs (m->size) - sizeof *msg;
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797 "Client inserts element of size %u\n",
798 el.size);
799 el.data = &msg[1];
800 GNUNET_CRYPTO_hash (el.data,
801 el.size,
802 &hash);
803
804 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
805 &hash);
806
807 if (NULL == ee)
808 {
809 ee = GNUNET_malloc (el.size + sizeof *ee);
810 ee->element.size = el.size;
811 memcpy (&ee[1],
812 el.data,
813 el.size);
814 ee->element.data = &ee[1];
815 ee->remote = GNUNET_NO;
816 ee->mutations = NULL;
817 ee->mutations_size = 0;
818 ee->element_hash = hash;
819 } else if (GNUNET_YES == _GSS_is_element_of_set (ee, set)) {
820 /* same element inserted twice */
821 GNUNET_break (0);
822 return;
823 }
824
825 if (0 != set->current_generation)
826 {
827 struct MutationEvent mut = {
828 .generation = set->current_generation,
829 .added = GNUNET_YES
830 };
831 GNUNET_array_append (ee->mutations, ee->mutations_size, mut);
832 ee->mutations_size += 1;
833 }
834
835 GNUNET_break (GNUNET_YES ==
836 GNUNET_CONTAINER_multihashmap_put (set->content->elements,
837 &ee->element_hash,
838 ee,
839 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
840 set->vt->add (set->state, ee);
841}
842
843
844static void
845execute_remove (struct Set *set,
846 const struct GNUNET_MessageHeader *m)
847{
848 const struct GNUNET_SET_ElementMessage *msg;
849 struct GNUNET_SET_Element el;
850 struct ElementEntry *ee;
851 struct GNUNET_HashCode hash;
852
853 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type));
854
855 msg = (const struct GNUNET_SET_ElementMessage *) m;
856 el.size = ntohs (m->size) - sizeof *msg;
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 "Client removes element of size %u\n",
859 el.size);
860 el.data = &msg[1];
861 GNUNET_CRYPTO_hash (el.data,
862 el.size,
863 &hash);
864 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
865 &hash);
866 if (NULL == ee)
867 {
868 /* Client tried to remove non-existing element */
869 GNUNET_break (0);
870 return;
871 }
872 if (GNUNET_NO == _GSS_is_element_of_set (ee, set))
873 {
874 /* Client tried to remove element twice */
875 GNUNET_break (0);
876 return;
877 }
878 else if (0 == set->current_generation)
879 {
880 // If current_generation is 0, then there are no running set operations
881 // or lazy copies, thus we can safely remove the element.
882 (void) GNUNET_CONTAINER_multihashmap_remove_all (set->content->elements, &hash);
883 }
884 else
885 {
886 struct MutationEvent mut = {
887 .generation = set->current_generation,
888 .added = GNUNET_NO
889 };
890 GNUNET_array_append (ee->mutations, ee->mutations_size, mut);
891 ee->mutations_size += 1;
892 }
893 set->vt->remove (set->state, ee);
894}
895
896
897
898static void
899execute_mutation (struct Set *set,
900 const struct GNUNET_MessageHeader *m)
901{
902 switch (ntohs (m->type))
903 {
904 case GNUNET_MESSAGE_TYPE_SET_ADD:
905 execute_add (set, m);
906 break;
907 case GNUNET_MESSAGE_TYPE_SET_REMOVE:
908 execute_remove (set, m);
909 break;
910 default:
911 GNUNET_break (0);
912 }
913}
914
915
916
753/** 917/**
754 * Send the next element of a set to the set's client. The next element is given by 918 * Send the next element of a set to the set's client. The next element is given by
755 * the set's current hashmap iterator. The set's iterator will be set to NULL if there 919 * the set's current hashmap iterator. The set's iterator will be set to NULL if there
@@ -777,14 +941,43 @@ send_client_element (struct Set *set)
777 (const void **) &ee); 941 (const void **) &ee);
778 if (GNUNET_NO == ret) 942 if (GNUNET_NO == ret)
779 { 943 {
944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
945 "Iteration on %p done.\n",
946 (void *) set);
780 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE); 947 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
781 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter); 948 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
782 set->iter = NULL; 949 set->iter = NULL;
783 set->iteration_id++; 950 set->iteration_id++;
951
952 GNUNET_assert (set->content->iterator_count > 0);
953 set->content->iterator_count -= 1;
954
955 if (0 == set->content->iterator_count)
956 {
957 while (NULL != set->content->pending_mutations_head)
958 {
959 struct PendingMutation *pm;
960
961 pm = set->content->pending_mutations_head;
962 GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head,
963 set->content->pending_mutations_tail,
964 pm);
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Executing pending mutation on %p.\n",
967 (void *) pm->set);
968 execute_mutation (pm->set, pm->mutation_message);
969 GNUNET_free (pm->mutation_message);
970 GNUNET_free (pm);
971 }
972 }
973
784 } 974 }
785 else 975 else
786 { 976 {
787 GNUNET_assert (NULL != ee); 977 GNUNET_assert (NULL != ee);
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "Sending iteration element on %p.\n",
980 (void *) set);
788 ev = GNUNET_MQ_msg_extra (msg, 981 ev = GNUNET_MQ_msg_extra (msg,
789 ee->element.size, 982 ee->element.size,
790 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT); 983 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
@@ -831,10 +1024,12 @@ handle_client_iterate (void *cls,
831 return; 1024 return;
832 } 1025 }
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834 "Iterating set with %u elements\n", 1027 "Iterating set %p with %u elements\n",
1028 (void *) set,
835 GNUNET_CONTAINER_multihashmap_size (set->content->elements)); 1029 GNUNET_CONTAINER_multihashmap_size (set->content->elements));
836 GNUNET_SERVER_receive_done (client, 1030 GNUNET_SERVER_receive_done (client,
837 GNUNET_OK); 1031 GNUNET_OK);
1032 set->content->iterator_count += 1;
838 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); 1033 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements);
839 send_client_element (set); 1034 send_client_element (set);
840} 1035}
@@ -992,23 +1187,20 @@ handle_client_reject (void *cls,
992} 1187}
993 1188
994 1189
1190
995/** 1191/**
996 * Called when a client wants to add an element to a set it inhabits. 1192 * Called when a client wants to add or remove an element to a set it inhabits.
997 * 1193 *
998 * @param cls unused 1194 * @param cls unused
999 * @param client client that sent the message 1195 * @param client client that sent the message
1000 * @param m message sent by the client 1196 * @param m message sent by the client
1001 */ 1197 */
1002static void 1198static void
1003handle_client_add (void *cls, 1199handle_client_mutation (void *cls,
1004 struct GNUNET_SERVER_Client *client, 1200 struct GNUNET_SERVER_Client *client,
1005 const struct GNUNET_MessageHeader *m) 1201 const struct GNUNET_MessageHeader *m)
1006{ 1202{
1007 struct Set *set; 1203 struct Set *set;
1008 const struct GNUNET_SET_ElementMessage *msg;
1009 struct GNUNET_SET_Element el;
1010 struct ElementEntry *ee;
1011 struct GNUNET_HashCode hash;
1012 1204
1013 set = set_get (client); 1205 set = set_get (client);
1014 if (NULL == set) 1206 if (NULL == set)
@@ -1018,128 +1210,28 @@ handle_client_add (void *cls,
1018 GNUNET_SERVER_client_disconnect (client); 1210 GNUNET_SERVER_client_disconnect (client);
1019 return; 1211 return;
1020 } 1212 }
1213
1021 GNUNET_SERVER_receive_done (client, 1214 GNUNET_SERVER_receive_done (client,
1022 GNUNET_OK); 1215 GNUNET_OK);
1023 msg = (const struct GNUNET_SET_ElementMessage *) m;
1024 el.size = ntohs (m->size) - sizeof *msg;
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026 "Client inserts element of size %u\n",
1027 el.size);
1028 el.data = &msg[1];
1029 GNUNET_CRYPTO_hash (el.data,
1030 el.size,
1031 &hash);
1032 1216
1033 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, 1217 if (0 != set->content->iterator_count)
1034 &hash);
1035
1036 if (NULL == ee)
1037 { 1218 {
1038 ee = GNUNET_malloc (el.size + sizeof *ee); 1219 struct PendingMutation *pm;
1039 ee->element.size = el.size;
1040 memcpy (&ee[1],
1041 el.data,
1042 el.size);
1043 ee->element.data = &ee[1];
1044 ee->remote = GNUNET_NO;
1045 ee->mutations = NULL;
1046 ee->mutations_size = 0;
1047 ee->element_hash = hash;
1048 } else if (GNUNET_YES == _GSS_is_element_of_set (ee, set)) {
1049 /* same element inserted twice */
1050 GNUNET_break (0);
1051 return;
1052 }
1053 1220
1054 if (0 != set->current_generation) 1221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 { 1222 "Scheduling mutation on set\n");
1056 struct MutationEvent mut = { 1223
1057 .generation = set->current_generation, 1224 pm = GNUNET_new (struct PendingMutation);
1058 .added = GNUNET_YES 1225 pm->mutation_message = GNUNET_copy_message (m);
1059 }; 1226 pm->set = set;
1060 GNUNET_array_append (ee->mutations, ee->mutations_size, mut); 1227 GNUNET_CONTAINER_DLL_insert (set->content->pending_mutations_head,
1061 ee->mutations_size += 1; 1228 set->content->pending_mutations_tail,
1062 } 1229 pm);
1063
1064 GNUNET_break (GNUNET_YES ==
1065 GNUNET_CONTAINER_multihashmap_put (set->content->elements,
1066 &ee->element_hash,
1067 ee,
1068 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1069 set->vt->add (set->state, ee);
1070}
1071
1072
1073/**
1074 * Called when a client wants to remove an element from a set it
1075 * inhabits.
1076 *
1077 * @param cls unused
1078 * @param client client that sent the message
1079 * @param m message sent by the client
1080 */
1081static void
1082handle_client_remove (void *cls,
1083 struct GNUNET_SERVER_Client *client,
1084 const struct GNUNET_MessageHeader *m)
1085{
1086 struct Set *set;
1087 const struct GNUNET_SET_ElementMessage *msg;
1088 struct GNUNET_SET_Element el;
1089 struct ElementEntry *ee;
1090 struct GNUNET_HashCode hash;
1091
1092 set = set_get (client);
1093 if (NULL == set)
1094 {
1095 /* client without a set requested an operation */
1096 GNUNET_break (0);
1097 GNUNET_SERVER_client_disconnect (client);
1098 return;
1099 }
1100 GNUNET_SERVER_receive_done (client,
1101 GNUNET_OK);
1102 msg = (const struct GNUNET_SET_ElementMessage *) m;
1103 el.size = ntohs (m->size) - sizeof *msg;
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "Client removes element of size %u\n",
1106 el.size);
1107 el.data = &msg[1];
1108 GNUNET_CRYPTO_hash (el.data,
1109 el.size,
1110 &hash);
1111 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
1112 &hash);
1113 if (NULL == ee)
1114 {
1115 /* Client tried to remove non-existing element */
1116 GNUNET_break (0);
1117 return;
1118 }
1119 if (GNUNET_NO == _GSS_is_element_of_set (ee, set))
1120 {
1121 /* Client tried to remove element twice */
1122 GNUNET_break (0);
1123 return; 1230 return;
1124 } 1231 }
1125 else if (0 == set->current_generation)
1126 {
1127 // If current_generation is 0, then there are no running set operations
1128 // or lazy copies, thus we can safely remove the element.
1129 (void) GNUNET_CONTAINER_multihashmap_remove_all (set->content->elements, &hash);
1130 }
1131 else
1132 {
1133 struct MutationEvent mut = {
1134 .generation = set->current_generation,
1135 .added = GNUNET_NO
1136 };
1137 GNUNET_array_append (ee->mutations, ee->mutations_size, mut);
1138 ee->mutations_size += 1;
1139 }
1140 set->vt->remove (set->state, ee);
1141}
1142 1232
1233 execute_mutation (set, m);
1234}
1143 1235
1144 1236
1145/** 1237/**
@@ -1302,6 +1394,8 @@ handle_client_copy_lazy_prepare (void *cls,
1302{ 1394{
1303 struct Set *set; 1395 struct Set *set;
1304 struct LazyCopyRequest *cr; 1396 struct LazyCopyRequest *cr;
1397 struct GNUNET_MQ_Envelope *ev;
1398 struct GNUNET_SET_CopyLazyResponseMessage *resp_msg;
1305 1399
1306 set = set_get (client); 1400 set = set_get (client);
1307 if (NULL == set) 1401 if (NULL == set)
@@ -1321,8 +1415,19 @@ handle_client_copy_lazy_prepare (void *cls,
1321 GNUNET_CONTAINER_DLL_insert (lazy_copy_head, 1415 GNUNET_CONTAINER_DLL_insert (lazy_copy_head,
1322 lazy_copy_tail, 1416 lazy_copy_tail,
1323 cr); 1417 cr);
1418
1419
1420 ev = GNUNET_MQ_msg (resp_msg,
1421 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE);
1422 resp_msg->cookie = cr->cookie;
1423 GNUNET_MQ_send (set->client_mq, ev);
1424
1425
1324 GNUNET_SERVER_receive_done (client, 1426 GNUNET_SERVER_receive_done (client,
1325 GNUNET_OK); 1427 GNUNET_OK);
1428
1429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1430 "Client requested lazy copy\n");
1326} 1431}
1327 1432
1328 1433
@@ -1396,11 +1501,12 @@ handle_client_copy_lazy_connect (void *cls,
1396 GNUNET_break (0); 1501 GNUNET_break (0);
1397 GNUNET_free (set); 1502 GNUNET_free (set);
1398 GNUNET_free (cr); 1503 GNUNET_free (cr);
1504 GNUNET_SERVER_client_disconnect (client);
1399 return; 1505 return;
1400 } 1506 }
1401 1507
1402 set->operation = cr->source_set->operation; 1508 set->operation = cr->source_set->operation;
1403 set->state = set->vt->copy_state (set); 1509 set->state = set->vt->copy_state (cr->source_set);
1404 set->content = cr->source_set->content; 1510 set->content = cr->source_set->content;
1405 set->content->refcount += 1; 1511 set->content->refcount += 1;
1406 set->client = client; 1512 set->client = client;
@@ -1413,6 +1519,9 @@ handle_client_copy_lazy_connect (void *cls,
1413 1519
1414 GNUNET_SERVER_receive_done (client, 1520 GNUNET_SERVER_receive_done (client,
1415 GNUNET_OK); 1521 GNUNET_OK);
1522
1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524 "Client connected to lazy set\n");
1416} 1525}
1417 1526
1418 1527
@@ -1787,7 +1896,7 @@ run (void *cls,
1787 { &handle_client_iter_ack, NULL, 1896 { &handle_client_iter_ack, NULL,
1788 GNUNET_MESSAGE_TYPE_SET_ITER_ACK, 1897 GNUNET_MESSAGE_TYPE_SET_ITER_ACK,
1789 sizeof (struct GNUNET_SET_IterAckMessage) }, 1898 sizeof (struct GNUNET_SET_IterAckMessage) },
1790 { &handle_client_add, NULL, 1899 { &handle_client_mutation, NULL,
1791 GNUNET_MESSAGE_TYPE_SET_ADD, 1900 GNUNET_MESSAGE_TYPE_SET_ADD,
1792 0}, 1901 0},
1793 { &handle_client_create_set, NULL, 1902 { &handle_client_create_set, NULL,
@@ -1805,7 +1914,7 @@ run (void *cls,
1805 { &handle_client_reject, NULL, 1914 { &handle_client_reject, NULL,
1806 GNUNET_MESSAGE_TYPE_SET_REJECT, 1915 GNUNET_MESSAGE_TYPE_SET_REJECT,
1807 sizeof (struct GNUNET_SET_RejectMessage)}, 1916 sizeof (struct GNUNET_SET_RejectMessage)},
1808 { &handle_client_remove, NULL, 1917 { &handle_client_mutation, NULL,
1809 GNUNET_MESSAGE_TYPE_SET_REMOVE, 1918 GNUNET_MESSAGE_TYPE_SET_REMOVE,
1810 0}, 1919 0},
1811 { &handle_client_cancel, NULL, 1920 { &handle_client_cancel, NULL,
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h
index d23291c82..fb079d03f 100644
--- a/src/set/gnunet-service-set.h
+++ b/src/set/gnunet-service-set.h
@@ -437,6 +437,25 @@ struct SetContent
437 struct GNUNET_CONTAINER_MultiHashMap *elements; 437 struct GNUNET_CONTAINER_MultiHashMap *elements;
438 438
439 unsigned int latest_generation; 439 unsigned int latest_generation;
440
441 /**
442 * Mutations requested by the client that we're
443 * unable to execute right now because we're iterating
444 * over the underlying hash map of elements.
445 */
446 struct PendingMutation *pending_mutations_head;
447
448 /**
449 * Mutations requested by the client that we're
450 * unable to execute right now because we're iterating
451 * over the underlying hash map of elements.
452 */
453 struct PendingMutation *pending_mutations_tail;
454
455 /**
456 * Number of concurrently active iterators.
457 */
458 int iterator_count;
440}; 459};
441 460
442 461
@@ -454,6 +473,22 @@ struct GenerationRange
454}; 473};
455 474
456 475
476struct PendingMutation
477{
478 struct PendingMutation *prev;
479 struct PendingMutation *next;
480
481 struct Set *set;
482
483 /**
484 * Message that describes the desired mutation.
485 * May only be a GNUNET_MESSAGE_TYPE_SET_ADD or
486 * GNUNET_MESSAGE_TYPE_SET_REMOVE.
487 */
488 struct GNUNET_MessageHeader *mutation_message;
489};
490
491
457/** 492/**
458 * A set that supports a specific operation with other peers. 493 * A set that supports a specific operation with other peers.
459 */ 494 */
@@ -540,7 +575,6 @@ struct Set
540 * and thus reference counted. 575 * and thus reference counted.
541 */ 576 */
542 struct SetContent *content; 577 struct SetContent *content;
543
544}; 578};
545 579
546 580
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c
index b09e9d2a6..5975ef19f 100644
--- a/src/set/gnunet-service-set_union.c
+++ b/src/set/gnunet-service-set_union.c
@@ -1452,6 +1452,17 @@ union_peer_disconnect (struct Operation *op)
1452 finish_and_destroy (op); 1452 finish_and_destroy (op);
1453} 1453}
1454 1454
1455static struct SetState *
1456union_copy_state (struct Set *set)
1457{
1458 struct SetState *new_state;
1459
1460 new_state = GNUNET_new (struct SetState);
1461 GNUNET_assert ( (NULL != set->state) && (NULL != set->state->se) );
1462 new_state->se = strata_estimator_dup (set->state->se);
1463
1464 return new_state;
1465}
1455 1466
1456/** 1467/**
1457 * Get the table with implementing functions for 1468 * Get the table with implementing functions for
@@ -1472,6 +1483,7 @@ _GSS_union_vt ()
1472 .accept = &union_accept, 1483 .accept = &union_accept,
1473 .peer_disconnect = &union_peer_disconnect, 1484 .peer_disconnect = &union_peer_disconnect,
1474 .cancel = &union_op_cancel, 1485 .cancel = &union_op_cancel,
1486 .copy_state = &union_copy_state,
1475 }; 1487 };
1476 1488
1477 return &union_vt; 1489 return &union_vt;
diff --git a/src/set/set_api.c b/src/set/set_api.c
index aadc93678..920571a01 100644
--- a/src/set/set_api.c
+++ b/src/set/set_api.c
@@ -272,6 +272,9 @@ handle_copy_lazy (void *cls,
272 GNUNET_break (0); 272 GNUNET_break (0);
273 return; 273 return;
274 } 274 }
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "Handling response to lazy copy\n");
275 278
276 GNUNET_CONTAINER_DLL_remove (set->copy_req_head, 279 GNUNET_CONTAINER_DLL_remove (set->copy_req_head,
277 set->copy_req_tail, 280 set->copy_req_tail,
@@ -555,9 +558,6 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
555 struct GNUNET_SET_CreateMessage *create_msg; 558 struct GNUNET_SET_CreateMessage *create_msg;
556 struct GNUNET_SET_CopyLazyConnectMessage *copy_msg; 559 struct GNUNET_SET_CopyLazyConnectMessage *copy_msg;
557 560
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
559 "Creating new set (operation %u)\n",
560 op);
561 set = GNUNET_new (struct GNUNET_SET_Handle); 561 set = GNUNET_new (struct GNUNET_SET_Handle);
562 set->client = GNUNET_CLIENT_connect ("set", cfg); 562 set->client = GNUNET_CLIENT_connect ("set", cfg);
563 set->cfg = cfg; 563 set->cfg = cfg;
@@ -574,12 +574,18 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
574 574
575 if (NULL == cookie) 575 if (NULL == cookie)
576 { 576 {
577 LOG (GNUNET_ERROR_TYPE_DEBUG,
578 "Creating new set (operation %u)\n",
579 op);
577 mqm = GNUNET_MQ_msg (create_msg, 580 mqm = GNUNET_MQ_msg (create_msg,
578 GNUNET_MESSAGE_TYPE_SET_CREATE); 581 GNUNET_MESSAGE_TYPE_SET_CREATE);
579 create_msg->operation = htonl (op); 582 create_msg->operation = htonl (op);
580 } 583 }
581 else 584 else
582 { 585 {
586 LOG (GNUNET_ERROR_TYPE_DEBUG,
587 "Creating new set (lazy copy)\n",
588 op);
583 mqm = GNUNET_MQ_msg (copy_msg, 589 mqm = GNUNET_MQ_msg (copy_msg,
584 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT); 590 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT);
585 copy_msg->cookie = *cookie; 591 copy_msg->cookie = *cookie;
diff --git a/src/set/test_set.conf b/src/set/test_set.conf
index 011a5ed4b..f3c0770fe 100644
--- a/src/set/test_set.conf
+++ b/src/set/test_set.conf
@@ -1,4 +1,3 @@
1# @INLINE@ test_set_defaults.conf
2[PATHS] 1[PATHS]
3GNUNET_TEST_HOME = /tmp/test-gnunet-set/ 2GNUNET_TEST_HOME = /tmp/test-gnunet-set/
4 3
@@ -8,11 +7,52 @@ AUTOSTART = YES
8#PREFIX = valgrind 7#PREFIX = valgrind
9#PREFIX = valgrind -v --leak-check=full 8#PREFIX = valgrind -v --leak-check=full
10#PREFIX = gdbserver :1234 9#PREFIX = gdbserver :1234
11#OPTIONS = -L INFO 10OPTIONS = -L INFO
12 11
13[transport] 12[transport]
13PLUGINS = unix
14OPTIONS = -LERROR 14OPTIONS = -LERROR
15 15
16[testbed] 16[nat]
17OVERLAY_TOPOLOGY = CLIQUE 17RETURN_LOCAL_ADDRESSES = YES
18DISABLEV6 = YES
19USE_LOCALADDR = YES
20
21[peerinfo]
22NO_IO = YES
23
24[nse]
25WORKBITS = 0
26
27[hostlist]
28FORCESTART = NO
29AUTOSTART = NO
30
31[fs]
32FORCESTART = NO
33AUTOSTART = NO
34
35[vpn]
36FORCESTART = NO
37AUTOSTART = NO
38
39[revocation]
40FORCESTART = NO
41AUTOSTART = NO
42
43[gns]
44FORCESTART = NO
45AUTOSTART = NO
46
47[namestore]
48FORCESTART = NO
49AUTOSTART = NO
50
51[namecache]
52FORCESTART = NO
53AUTOSTART = NO
54
55[topology]
56FORCESTART = NO
57AUTOSTART = NO
18 58
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c
new file mode 100644
index 000000000..bb8d57631
--- /dev/null
+++ b/src/set/test_set_union_copy.c
@@ -0,0 +1,225 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file set/test_set_union_copy.c
23 * @brief testcase for lazy copying of union sets
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_common.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_set_service.h"
30
31
32/**
33 * Value to return from #main().
34 */
35static int ret;
36
37static struct GNUNET_PeerIdentity local_id;
38
39static struct GNUNET_SET_Handle *set1;
40
41static struct GNUNET_SET_Handle *set2;
42
43static const struct GNUNET_CONFIGURATION_Handle *config;
44
45
46static void
47add_element_str (struct GNUNET_SET_Handle *set, char *str)
48{
49 struct GNUNET_SET_Element element;
50
51 element.element_type = 0;
52 element.data = str;
53 element.size = strlen (str);
54
55 GNUNET_SET_add_element (set, &element, NULL, NULL);
56}
57
58
59static void
60remove_element_str (struct GNUNET_SET_Handle *set, char *str)
61{
62 struct GNUNET_SET_Element element;
63
64 element.element_type = 0;
65 element.data = str;
66 element.size = strlen (str);
67
68 GNUNET_SET_remove_element (set, &element, NULL, NULL);
69}
70
71
72/**
73 * Signature of the main function of a task.
74 *
75 * @param cls closure
76 * @param tc context information (why was this task triggered now)
77 */
78static void
79timeout_fail (void *cls,
80 const struct GNUNET_SCHEDULER_TaskContext *tc)
81{
82 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
83 return;
84 GNUNET_SCHEDULER_shutdown ();
85 ret = 1;
86}
87
88typedef void (*Continuation) (void *cls);
89
90
91struct CountIterClosure
92{
93 unsigned int expected_count;
94 unsigned int ongoing_count;
95 Continuation cont;
96 void *cont_cls;
97 char *what;
98};
99
100
101static int
102check_count_iter (void *cls,
103 const struct GNUNET_SET_Element *element)
104{
105 struct CountIterClosure *ci_cls = cls;
106
107 if (NULL == element)
108 {
109 if (ci_cls->expected_count != ci_cls->ongoing_count)
110 {
111 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
112 "Expected count (what: %s) to be %u, but it's actually %u\n",
113 ci_cls->what,
114 ci_cls->expected_count, ci_cls->ongoing_count);
115 ret = 1;
116 return GNUNET_NO;
117 }
118 ci_cls->cont (ci_cls->cont_cls);
119 return GNUNET_NO;
120 }
121
122 ci_cls->ongoing_count += 1;
123 return GNUNET_YES;
124}
125
126
127
128void
129check_count (struct GNUNET_SET_Handle *set,
130 char *what,
131 unsigned int expected_count,
132 Continuation cont,
133 void *cont_cls)
134{
135 struct CountIterClosure *ci_cls = GNUNET_new (struct CountIterClosure);
136
137 ci_cls->expected_count = expected_count;
138 ci_cls->ongoing_count = 0;
139 ci_cls->cont = cont;
140 ci_cls->cont_cls = cont_cls;
141 ci_cls->what = what;
142
143 GNUNET_assert (GNUNET_YES == GNUNET_SET_iterate (set, check_count_iter, ci_cls));
144}
145
146
147void test_done (void *cls)
148{
149 if (NULL != set1)
150 GNUNET_SET_destroy (set1);
151 if (NULL != set2)
152 GNUNET_SET_destroy (set2);
153
154 GNUNET_SCHEDULER_shutdown ();
155}
156
157
158void check_new_set_count (void *cls)
159{
160 check_count (set2, "new set", 2, &test_done, NULL);
161}
162
163
164void copy_done (void *cls, struct GNUNET_SET_Handle *new_set)
165{
166 printf ("copy done\n");
167 set2 = new_set;
168 remove_element_str (set2, "spam");
169 // Check that set1 didn't change.
170 check_count (set1, "old set", 3, &check_new_set_count, NULL);
171}
172
173
174void test_copy (void *cls)
175{
176 printf ("about to copy\n");
177 GNUNET_SET_copy_lazy (set1, copy_done, NULL);
178}
179
180
181
182/**
183 * Signature of the 'main' function for a (single-peer) testcase that
184 * is run using 'GNUNET_TESTING_peer_run'.
185 *
186 * @param cls closure
187 * @param cfg configuration of the peer that was started
188 * @param peer identity of the peer that was created
189 */
190static void
191run (void *cls,
192 const struct GNUNET_CONFIGURATION_Handle *cfg,
193 struct GNUNET_TESTING_Peer *peer)
194{
195 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
196 &timeout_fail,
197 NULL);
198
199 config = cfg;
200 GNUNET_TESTING_peer_get_identity (peer,
201 &local_id);
202
203 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
204 add_element_str (set1, "foo");
205 add_element_str (set1, "bar");
206 remove_element_str (set1, "foo");
207 add_element_str (set1, "spam");
208 add_element_str (set1, "eggs");
209
210 check_count (set1, "initial test", 3, &test_copy, NULL);
211}
212
213
214int
215main (int argc, char **argv)
216{
217 if (0 != GNUNET_TESTING_peer_run ("test_set_api",
218 "test_set.conf",
219 &run, NULL))
220 {
221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to start testing peer\n");
222 return 1;
223 }
224 return ret;
225}