diff options
author | Florian Dold <florian.dold@gmail.com> | 2015-08-30 20:54:44 +0000 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2015-08-30 20:54:44 +0000 |
commit | 2e25d8c868521f318381a8b87c9f8c1c7c402b7c (patch) | |
tree | a5d9b8fca78e55da9d8c62ff8fe6d1d480a459e0 /src/set | |
parent | c92948f72526fe599680c06cbe80d0ffdc11f597 (diff) | |
download | gnunet-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.am | 10 | ||||
-rw-r--r-- | src/set/gnunet-service-set.c | 363 | ||||
-rw-r--r-- | src/set/gnunet-service-set.h | 36 | ||||
-rw-r--r-- | src/set/gnunet-service-set_union.c | 12 | ||||
-rw-r--r-- | src/set/set_api.c | 12 | ||||
-rw-r--r-- | src/set/test_set.conf | 48 | ||||
-rw-r--r-- | src/set/test_set_union_copy.c | 225 |
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 | |||
67 | check_PROGRAMS = \ | 67 | check_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 | ||
71 | endif | 72 | endif |
72 | 73 | ||
73 | if ENABLE_TEST_RUN | 74 | if 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 | ||
100 | test_set_union_copy_SOURCES = \ | ||
101 | test_set_union_copy.c | ||
102 | test_set_union_copy_LDADD = \ | ||
103 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
104 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
105 | libgnunetset.la | ||
106 | |||
99 | EXTRA_DIST = \ | 107 | EXTRA_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 | ||
783 | static void | ||
784 | execute_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 | |||
844 | static void | ||
845 | execute_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 | |||
898 | static void | ||
899 | execute_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 | */ |
1002 | static void | 1198 | static void |
1003 | handle_client_add (void *cls, | 1199 | handle_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 | */ | ||
1081 | static void | ||
1082 | handle_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 | ||
476 | struct 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 | ||
1455 | static struct SetState * | ||
1456 | union_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] |
3 | GNUNET_TEST_HOME = /tmp/test-gnunet-set/ | 2 | GNUNET_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 | 10 | OPTIONS = -L INFO |
12 | 11 | ||
13 | [transport] | 12 | [transport] |
13 | PLUGINS = unix | ||
14 | OPTIONS = -LERROR | 14 | OPTIONS = -LERROR |
15 | 15 | ||
16 | [testbed] | 16 | [nat] |
17 | OVERLAY_TOPOLOGY = CLIQUE | 17 | RETURN_LOCAL_ADDRESSES = YES |
18 | DISABLEV6 = YES | ||
19 | USE_LOCALADDR = YES | ||
20 | |||
21 | [peerinfo] | ||
22 | NO_IO = YES | ||
23 | |||
24 | [nse] | ||
25 | WORKBITS = 0 | ||
26 | |||
27 | [hostlist] | ||
28 | FORCESTART = NO | ||
29 | AUTOSTART = NO | ||
30 | |||
31 | [fs] | ||
32 | FORCESTART = NO | ||
33 | AUTOSTART = NO | ||
34 | |||
35 | [vpn] | ||
36 | FORCESTART = NO | ||
37 | AUTOSTART = NO | ||
38 | |||
39 | [revocation] | ||
40 | FORCESTART = NO | ||
41 | AUTOSTART = NO | ||
42 | |||
43 | [gns] | ||
44 | FORCESTART = NO | ||
45 | AUTOSTART = NO | ||
46 | |||
47 | [namestore] | ||
48 | FORCESTART = NO | ||
49 | AUTOSTART = NO | ||
50 | |||
51 | [namecache] | ||
52 | FORCESTART = NO | ||
53 | AUTOSTART = NO | ||
54 | |||
55 | [topology] | ||
56 | FORCESTART = NO | ||
57 | AUTOSTART = 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 | */ | ||
35 | static int ret; | ||
36 | |||
37 | static struct GNUNET_PeerIdentity local_id; | ||
38 | |||
39 | static struct GNUNET_SET_Handle *set1; | ||
40 | |||
41 | static struct GNUNET_SET_Handle *set2; | ||
42 | |||
43 | static const struct GNUNET_CONFIGURATION_Handle *config; | ||
44 | |||
45 | |||
46 | static void | ||
47 | add_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 | |||
59 | static void | ||
60 | remove_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 | */ | ||
78 | static void | ||
79 | timeout_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 | |||
88 | typedef void (*Continuation) (void *cls); | ||
89 | |||
90 | |||
91 | struct 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 | |||
101 | static int | ||
102 | check_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 | |||
128 | void | ||
129 | check_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 | |||
147 | void 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 | |||
158 | void check_new_set_count (void *cls) | ||
159 | { | ||
160 | check_count (set2, "new set", 2, &test_done, NULL); | ||
161 | } | ||
162 | |||
163 | |||
164 | void 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 | |||
174 | void 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 | */ | ||
190 | static void | ||
191 | run (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 | |||
214 | int | ||
215 | main (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 | } | ||