diff options
author | Florian Dold <florian.dold@gmail.com> | 2015-08-30 00:44:11 +0000 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2015-08-30 00:44:11 +0000 |
commit | 7936cab9bd741a9ff30362c8495daa29f1874b2e (patch) | |
tree | 33606962451dcb4b15dabff20f605a5c58f1cc72 /src/set | |
parent | 38963d1e81332032e0ac774f4f2c6b804c38802a (diff) | |
download | gnunet-7936cab9bd741a9ff30362c8495daa29f1874b2e.tar.gz gnunet-7936cab9bd741a9ff30362c8495daa29f1874b2e.zip |
work in progress: fix set bug, implement lazy copy
Diffstat (limited to 'src/set')
-rw-r--r-- | src/set/gnunet-service-set.c | 414 | ||||
-rw-r--r-- | src/set/gnunet-service-set.h | 121 | ||||
-rw-r--r-- | src/set/gnunet-service-set_intersection.c | 12 | ||||
-rw-r--r-- | src/set/gnunet-service-set_union.c | 14 | ||||
-rw-r--r-- | src/set/set.h | 35 | ||||
-rw-r--r-- | src/set/set_api.c | 161 |
6 files changed, 643 insertions, 114 deletions
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c index f2c5c4322..b2ad01d1b 100644 --- a/src/set/gnunet-service-set.c +++ b/src/set/gnunet-service-set.c | |||
@@ -72,6 +72,16 @@ struct Listener | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | 74 | ||
75 | struct LazyCopyRequest | ||
76 | { | ||
77 | struct Set *source_set; | ||
78 | uint32_t cookie; | ||
79 | |||
80 | struct LazyCopyRequest *prev; | ||
81 | struct LazyCopyRequest *next; | ||
82 | }; | ||
83 | |||
84 | |||
75 | /** | 85 | /** |
76 | * Configuration of our local peer. | 86 | * Configuration of our local peer. |
77 | */ | 87 | */ |
@@ -115,6 +125,11 @@ static struct Operation *incoming_head; | |||
115 | */ | 125 | */ |
116 | static struct Operation *incoming_tail; | 126 | static struct Operation *incoming_tail; |
117 | 127 | ||
128 | static struct LazyCopyRequest *lazy_copy_head; | ||
129 | static struct LazyCopyRequest *lazy_copy_tail; | ||
130 | |||
131 | static uint32_t lazy_copy_cookie = 1; | ||
132 | |||
118 | /** | 133 | /** |
119 | * Counter for allocating unique IDs for clients, used to identify | 134 | * Counter for allocating unique IDs for clients, used to identify |
120 | * incoming operation requests from remote peers, that the client can | 135 | * incoming operation requests from remote peers, that the client can |
@@ -253,20 +268,20 @@ garbage_collect_cb (void *cls, | |||
253 | const struct GNUNET_HashCode *key, | 268 | const struct GNUNET_HashCode *key, |
254 | void *value) | 269 | void *value) |
255 | { | 270 | { |
256 | struct GarbageContext *gc = cls; | 271 | //struct GarbageContext *gc = cls; |
257 | struct ElementEntry *ee = value; | 272 | //struct ElementEntry *ee = value; |
258 | 273 | ||
259 | if (GNUNET_YES != ee->removed) | 274 | //if (GNUNET_YES != ee->removed) |
260 | return GNUNET_OK; | 275 | // return GNUNET_OK; |
261 | if ( (gc->max_op_generation < ee->generation_added) || | 276 | //if ( (gc->max_op_generation < ee->generation_added) || |
262 | (ee->generation_removed > gc->min_op_generation) ) | 277 | // (ee->generation_removed > gc->min_op_generation) ) |
263 | { | 278 | //{ |
264 | GNUNET_assert (GNUNET_YES == | 279 | // GNUNET_assert (GNUNET_YES == |
265 | GNUNET_CONTAINER_multihashmap_remove (gc->map, | 280 | // GNUNET_CONTAINER_multihashmap_remove (gc->map, |
266 | key, | 281 | // key, |
267 | ee)); | 282 | // ee)); |
268 | GNUNET_free (ee); | 283 | // GNUNET_free (ee); |
269 | } | 284 | //} |
270 | return GNUNET_OK; | 285 | return GNUNET_OK; |
271 | } | 286 | } |
272 | 287 | ||
@@ -293,12 +308,91 @@ collect_generation_garbage (struct Set *set) | |||
293 | gc.max_op_generation = GNUNET_MAX (gc.max_op_generation, | 308 | gc.max_op_generation = GNUNET_MAX (gc.max_op_generation, |
294 | op->generation_created); | 309 | op->generation_created); |
295 | } | 310 | } |
296 | gc.map = set->elements; | 311 | gc.map = set->content->elements; |
297 | GNUNET_CONTAINER_multihashmap_iterate (set->elements, | 312 | GNUNET_CONTAINER_multihashmap_iterate (set->content->elements, |
298 | &garbage_collect_cb, | 313 | &garbage_collect_cb, |
299 | &gc); | 314 | &gc); |
300 | } | 315 | } |
301 | 316 | ||
317 | int | ||
318 | is_excluded_generation (unsigned int generation, | ||
319 | struct GenerationRange *excluded, | ||
320 | unsigned int excluded_size) | ||
321 | { | ||
322 | unsigned int i; | ||
323 | |||
324 | for (i = 0; i < excluded_size; i++) | ||
325 | { | ||
326 | if ( (generation >= excluded[i].start) && (generation < excluded[i].end) ) | ||
327 | return GNUNET_YES; | ||
328 | } | ||
329 | |||
330 | return GNUNET_NO; | ||
331 | } | ||
332 | |||
333 | |||
334 | int | ||
335 | is_element_of_generation (struct ElementEntry *ee, | ||
336 | unsigned int query_generation, | ||
337 | struct GenerationRange *excluded, | ||
338 | unsigned int excluded_size) | ||
339 | { | ||
340 | struct MutationEvent *mut; | ||
341 | int is_present; | ||
342 | |||
343 | if (NULL == ee->mutations) | ||
344 | return GNUNET_YES; | ||
345 | |||
346 | if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size)) | ||
347 | { | ||
348 | GNUNET_break (0); | ||
349 | return GNUNET_NO; | ||
350 | } | ||
351 | |||
352 | is_present = GNUNET_YES; | ||
353 | |||
354 | // Could be made faster with binary search, but lists | ||
355 | // are small, so why bother. | ||
356 | for (mut = ee->mutations; 0 != mut->generation; mut++) | ||
357 | { | ||
358 | if ( (mut->generation > query_generation) || | ||
359 | (GNUNET_YES == is_excluded_generation (mut->generation, excluded, excluded_size)) ) | ||
360 | { | ||
361 | continue; | ||
362 | } | ||
363 | |||
364 | // This would be an inconsistency in how we manage mutations. | ||
365 | if ( (GNUNET_YES == is_present) && (GNUNET_YES == mut->added) ) | ||
366 | GNUNET_assert (0); | ||
367 | |||
368 | is_present = mut->added; | ||
369 | } | ||
370 | |||
371 | return GNUNET_YES; | ||
372 | } | ||
373 | |||
374 | |||
375 | int | ||
376 | _GSS_is_element_of_set (struct ElementEntry *ee, | ||
377 | struct Set *set) | ||
378 | { | ||
379 | return is_element_of_generation (ee, | ||
380 | set->current_generation, | ||
381 | set->excluded_generations, | ||
382 | set->excluded_generations_size); | ||
383 | } | ||
384 | |||
385 | |||
386 | int | ||
387 | _GSS_is_element_of_operation (struct ElementEntry *ee, | ||
388 | struct Operation *op) | ||
389 | { | ||
390 | return is_element_of_generation (ee, | ||
391 | op->generation_created, | ||
392 | op->spec->set->excluded_generations, | ||
393 | op->spec->set->excluded_generations_size); | ||
394 | } | ||
395 | |||
302 | 396 | ||
303 | /** | 397 | /** |
304 | * Destroy the given operation. Call the implementation-specific | 398 | * Destroy the given operation. Call the implementation-specific |
@@ -371,6 +465,8 @@ destroy_elements_iterator (void *cls, | |||
371 | { | 465 | { |
372 | struct ElementEntry *ee = value; | 466 | struct ElementEntry *ee = value; |
373 | 467 | ||
468 | GNUNET_free_non_null (ee->mutations); | ||
469 | |||
374 | GNUNET_free (ee); | 470 | GNUNET_free (ee); |
375 | return GNUNET_YES; | 471 | return GNUNET_YES; |
376 | } | 472 | } |
@@ -412,17 +508,31 @@ set_destroy (struct Set *set) | |||
412 | set->iter = NULL; | 508 | set->iter = NULL; |
413 | set->iteration_id++; | 509 | set->iteration_id++; |
414 | } | 510 | } |
415 | if (NULL != set->elements) | ||
416 | { | 511 | { |
417 | GNUNET_CONTAINER_multihashmap_iterate (set->elements, | 512 | struct SetContent *content; |
418 | &destroy_elements_iterator, | 513 | |
419 | NULL); | 514 | content = set->content; |
420 | GNUNET_CONTAINER_multihashmap_destroy (set->elements); | 515 | set->content = NULL; |
421 | set->elements = NULL; | 516 | GNUNET_assert (0 != content->refcount); |
517 | content->refcount -= 1; | ||
518 | if (0 == content->refcount) | ||
519 | { | ||
520 | GNUNET_assert (NULL != content->elements); | ||
521 | GNUNET_CONTAINER_multihashmap_iterate (content->elements, | ||
522 | &destroy_elements_iterator, | ||
523 | NULL); | ||
524 | GNUNET_CONTAINER_multihashmap_destroy (content->elements); | ||
525 | content->elements = NULL; | ||
526 | } | ||
422 | } | 527 | } |
528 | GNUNET_free_non_null (set->excluded_generations); | ||
529 | set->excluded_generations = NULL; | ||
423 | GNUNET_CONTAINER_DLL_remove (sets_head, | 530 | GNUNET_CONTAINER_DLL_remove (sets_head, |
424 | sets_tail, | 531 | sets_tail, |
425 | set); | 532 | set); |
533 | |||
534 | // FIXME: remove from lazy copy requests | ||
535 | |||
426 | GNUNET_free (set); | 536 | GNUNET_free (set); |
427 | } | 537 | } |
428 | 538 | ||
@@ -722,10 +832,10 @@ handle_client_iterate (void *cls, | |||
722 | } | 832 | } |
723 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 833 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
724 | "Iterating set with %u elements\n", | 834 | "Iterating set with %u elements\n", |
725 | GNUNET_CONTAINER_multihashmap_size (set->elements)); | 835 | GNUNET_CONTAINER_multihashmap_size (set->content->elements)); |
726 | GNUNET_SERVER_receive_done (client, | 836 | GNUNET_SERVER_receive_done (client, |
727 | GNUNET_OK); | 837 | GNUNET_OK); |
728 | set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->elements); | 838 | set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); |
729 | send_client_element (set); | 839 | send_client_element (set); |
730 | } | 840 | } |
731 | 841 | ||
@@ -773,8 +883,11 @@ handle_client_create_set (void *cls, | |||
773 | GNUNET_SERVER_client_disconnect (client); | 883 | GNUNET_SERVER_client_disconnect (client); |
774 | return; | 884 | return; |
775 | } | 885 | } |
886 | set->operation = ntohl (msg->operation); | ||
776 | set->state = set->vt->create (); | 887 | set->state = set->vt->create (); |
777 | set->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | 888 | set->content = GNUNET_new (struct SetContent); |
889 | set->content->refcount = 1; | ||
890 | set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
778 | set->client = client; | 891 | set->client = client; |
779 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); | 892 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); |
780 | GNUNET_CONTAINER_DLL_insert (sets_head, | 893 | GNUNET_CONTAINER_DLL_insert (sets_head, |
@@ -895,7 +1008,7 @@ handle_client_add (void *cls, | |||
895 | const struct GNUNET_SET_ElementMessage *msg; | 1008 | const struct GNUNET_SET_ElementMessage *msg; |
896 | struct GNUNET_SET_Element el; | 1009 | struct GNUNET_SET_Element el; |
897 | struct ElementEntry *ee; | 1010 | struct ElementEntry *ee; |
898 | struct ElementEntry *ee_dup; | 1011 | struct GNUNET_HashCode hash; |
899 | 1012 | ||
900 | set = set_get (client); | 1013 | set = set_get (client); |
901 | if (NULL == set) | 1014 | if (NULL == set) |
@@ -913,28 +1026,43 @@ handle_client_add (void *cls, | |||
913 | "Client inserts element of size %u\n", | 1026 | "Client inserts element of size %u\n", |
914 | el.size); | 1027 | el.size); |
915 | el.data = &msg[1]; | 1028 | el.data = &msg[1]; |
916 | ee = GNUNET_malloc (el.size + sizeof *ee); | 1029 | GNUNET_CRYPTO_hash (el.data, |
917 | ee->element.size = el.size; | ||
918 | memcpy (&ee[1], | ||
919 | el.data, | ||
920 | el.size); | ||
921 | ee->element.data = &ee[1]; | ||
922 | ee->generation_added = set->current_generation; | ||
923 | ee->remote = GNUNET_NO; | ||
924 | GNUNET_CRYPTO_hash (ee->element.data, | ||
925 | el.size, | 1030 | el.size, |
926 | &ee->element_hash); | 1031 | &hash); |
927 | ee_dup = GNUNET_CONTAINER_multihashmap_get (set->elements, | 1032 | |
928 | &ee->element_hash); | 1033 | ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, |
929 | if (NULL != ee_dup) | 1034 | &hash); |
1035 | |||
1036 | if (NULL == ee) | ||
930 | { | 1037 | { |
1038 | ee = GNUNET_malloc (el.size + sizeof *ee); | ||
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)) { | ||
931 | /* same element inserted twice */ | 1049 | /* same element inserted twice */ |
932 | GNUNET_break (0); | 1050 | GNUNET_break (0); |
933 | GNUNET_free (ee); | ||
934 | return; | 1051 | return; |
935 | } | 1052 | } |
1053 | |||
1054 | if (0 != set->current_generation) | ||
1055 | { | ||
1056 | struct MutationEvent mut = { | ||
1057 | .generation = set->current_generation, | ||
1058 | .added = GNUNET_YES | ||
1059 | }; | ||
1060 | GNUNET_array_append (ee->mutations, ee->mutations_size, mut); | ||
1061 | ee->mutations_size += 1; | ||
1062 | } | ||
1063 | |||
936 | GNUNET_break (GNUNET_YES == | 1064 | GNUNET_break (GNUNET_YES == |
937 | GNUNET_CONTAINER_multihashmap_put (set->elements, | 1065 | GNUNET_CONTAINER_multihashmap_put (set->content->elements, |
938 | &ee->element_hash, | 1066 | &ee->element_hash, |
939 | ee, | 1067 | ee, |
940 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 1068 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
@@ -980,7 +1108,7 @@ handle_client_remove (void *cls, | |||
980 | GNUNET_CRYPTO_hash (el.data, | 1108 | GNUNET_CRYPTO_hash (el.data, |
981 | el.size, | 1109 | el.size, |
982 | &hash); | 1110 | &hash); |
983 | ee = GNUNET_CONTAINER_multihashmap_get (set->elements, | 1111 | ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, |
984 | &hash); | 1112 | &hash); |
985 | if (NULL == ee) | 1113 | if (NULL == ee) |
986 | { | 1114 | { |
@@ -988,18 +1116,65 @@ handle_client_remove (void *cls, | |||
988 | GNUNET_break (0); | 1116 | GNUNET_break (0); |
989 | return; | 1117 | return; |
990 | } | 1118 | } |
991 | if (GNUNET_YES == ee->removed) | 1119 | if (GNUNET_NO == _GSS_is_element_of_set (ee, set)) |
992 | { | 1120 | { |
993 | /* Client tried to remove element twice */ | 1121 | /* Client tried to remove element twice */ |
994 | GNUNET_break (0); | 1122 | GNUNET_break (0); |
995 | return; | 1123 | return; |
996 | } | 1124 | } |
997 | ee->removed = GNUNET_YES; | 1125 | else if (0 == set->current_generation) |
998 | ee->generation_removed = 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 | } | ||
999 | set->vt->remove (set->state, ee); | 1140 | set->vt->remove (set->state, ee); |
1000 | } | 1141 | } |
1001 | 1142 | ||
1002 | 1143 | ||
1144 | |||
1145 | /** | ||
1146 | * Advance the current generation of a set, | ||
1147 | * adding exclusion ranges if necessary. | ||
1148 | * | ||
1149 | * @param set the set where we want to advance the generation | ||
1150 | */ | ||
1151 | static void | ||
1152 | advance_generation (struct Set *set) | ||
1153 | { | ||
1154 | struct GenerationRange r; | ||
1155 | |||
1156 | if (set->current_generation == set->content->latest_generation) | ||
1157 | { | ||
1158 | set->content->latest_generation += 1; | ||
1159 | set->current_generation += 1; | ||
1160 | return; | ||
1161 | } | ||
1162 | |||
1163 | GNUNET_assert (set->current_generation < set->content->latest_generation); | ||
1164 | |||
1165 | r.start = set->current_generation + 1; | ||
1166 | r.end = set->content->latest_generation + 1; | ||
1167 | |||
1168 | set->content->latest_generation = r.end; | ||
1169 | set->current_generation = r.end; | ||
1170 | |||
1171 | GNUNET_array_append (set->excluded_generations, | ||
1172 | set->excluded_generations_size, | ||
1173 | r); | ||
1174 | |||
1175 | set->excluded_generations_size += 1; | ||
1176 | } | ||
1177 | |||
1003 | /** | 1178 | /** |
1004 | * Called when a client wants to initiate a set operation with another | 1179 | * Called when a client wants to initiate a set operation with another |
1005 | * peer. Initiates the CADET connection to the listener and sends the | 1180 | * peer. Initiates the CADET connection to the listener and sends the |
@@ -1040,7 +1215,12 @@ handle_client_evaluate (void *cls, | |||
1040 | context = GNUNET_MQ_extract_nested_mh (msg); | 1215 | context = GNUNET_MQ_extract_nested_mh (msg); |
1041 | op = GNUNET_new (struct Operation); | 1216 | op = GNUNET_new (struct Operation); |
1042 | op->spec = spec; | 1217 | op->spec = spec; |
1043 | op->generation_created = set->current_generation++; | 1218 | |
1219 | // Advance generation values, so that | ||
1220 | // mutations won't interfer with the running operation. | ||
1221 | op->generation_created = set->current_generation; | ||
1222 | advance_generation (set); | ||
1223 | |||
1044 | op->vt = set->vt; | 1224 | op->vt = set->vt; |
1045 | GNUNET_CONTAINER_DLL_insert (set->ops_head, | 1225 | GNUNET_CONTAINER_DLL_insert (set->ops_head, |
1046 | set->ops_tail, | 1226 | set->ops_tail, |
@@ -1109,6 +1289,135 @@ handle_client_iter_ack (void *cls, | |||
1109 | 1289 | ||
1110 | /** | 1290 | /** |
1111 | * Handle a request from the client to | 1291 | * Handle a request from the client to |
1292 | * copy a set. | ||
1293 | * | ||
1294 | * @param cls unused | ||
1295 | * @param client the client | ||
1296 | * @param mh the message | ||
1297 | */ | ||
1298 | static void | ||
1299 | handle_client_copy_lazy_prepare (void *cls, | ||
1300 | struct GNUNET_SERVER_Client *client, | ||
1301 | const struct GNUNET_MessageHeader *mh) | ||
1302 | { | ||
1303 | struct Set *set; | ||
1304 | struct LazyCopyRequest *cr; | ||
1305 | |||
1306 | set = set_get (client); | ||
1307 | if (NULL == set) | ||
1308 | { | ||
1309 | /* client without a set requested an operation */ | ||
1310 | GNUNET_break (0); | ||
1311 | GNUNET_SERVER_client_disconnect (client); | ||
1312 | return; | ||
1313 | } | ||
1314 | |||
1315 | cr = GNUNET_new (struct LazyCopyRequest); | ||
1316 | |||
1317 | cr->cookie = lazy_copy_cookie; | ||
1318 | lazy_copy_cookie += 1; | ||
1319 | cr->source_set = set; | ||
1320 | |||
1321 | GNUNET_CONTAINER_DLL_insert (lazy_copy_head, | ||
1322 | lazy_copy_tail, | ||
1323 | cr); | ||
1324 | GNUNET_SERVER_receive_done (client, | ||
1325 | GNUNET_OK); | ||
1326 | } | ||
1327 | |||
1328 | |||
1329 | /** | ||
1330 | * Handle a request from the client to | ||
1331 | * connect to a copy of a set. | ||
1332 | * | ||
1333 | * @param cls unused | ||
1334 | * @param client the client | ||
1335 | * @param mh the message | ||
1336 | */ | ||
1337 | static void | ||
1338 | handle_client_copy_lazy_connect (void *cls, | ||
1339 | struct GNUNET_SERVER_Client *client, | ||
1340 | const struct GNUNET_MessageHeader *mh) | ||
1341 | { | ||
1342 | struct LazyCopyRequest *cr; | ||
1343 | const struct GNUNET_SET_CopyLazyConnectMessage *msg = | ||
1344 | (const struct GNUNET_SET_CopyLazyConnectMessage *) mh; | ||
1345 | struct Set *set; | ||
1346 | int found; | ||
1347 | |||
1348 | if (NULL != set_get (client)) | ||
1349 | { | ||
1350 | /* There can only be one set per client */ | ||
1351 | GNUNET_break (0); | ||
1352 | GNUNET_SERVER_client_disconnect (client); | ||
1353 | return; | ||
1354 | } | ||
1355 | |||
1356 | found = GNUNET_NO; | ||
1357 | |||
1358 | for (cr = lazy_copy_head; NULL != cr; cr = cr->next) | ||
1359 | { | ||
1360 | if (cr->cookie == msg->cookie) | ||
1361 | { | ||
1362 | found = GNUNET_YES; | ||
1363 | break; | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | if (GNUNET_NO == found) | ||
1368 | { | ||
1369 | /* client asked for copy with cookie we don't know */ | ||
1370 | GNUNET_break (0); | ||
1371 | GNUNET_SERVER_client_disconnect (client); | ||
1372 | return; | ||
1373 | } | ||
1374 | |||
1375 | GNUNET_CONTAINER_DLL_remove (lazy_copy_head, | ||
1376 | lazy_copy_tail, | ||
1377 | cr); | ||
1378 | |||
1379 | set = GNUNET_new (struct Set); | ||
1380 | |||
1381 | switch (cr->source_set->operation) | ||
1382 | { | ||
1383 | case GNUNET_SET_OPERATION_INTERSECTION: | ||
1384 | set->vt = _GSS_intersection_vt (); | ||
1385 | break; | ||
1386 | case GNUNET_SET_OPERATION_UNION: | ||
1387 | set->vt = _GSS_union_vt (); | ||
1388 | break; | ||
1389 | default: | ||
1390 | GNUNET_assert (0); | ||
1391 | return; | ||
1392 | } | ||
1393 | |||
1394 | if (NULL == set->vt->copy_state) { | ||
1395 | /* Lazy copy not supported for this set operation */ | ||
1396 | GNUNET_break (0); | ||
1397 | GNUNET_free (set); | ||
1398 | GNUNET_free (cr); | ||
1399 | return; | ||
1400 | } | ||
1401 | |||
1402 | set->operation = cr->source_set->operation; | ||
1403 | set->state = set->vt->copy_state (set); | ||
1404 | set->content = cr->source_set->content; | ||
1405 | set->content->refcount += 1; | ||
1406 | set->client = client; | ||
1407 | set->client_mq = GNUNET_MQ_queue_for_server_client (client); | ||
1408 | GNUNET_CONTAINER_DLL_insert (sets_head, | ||
1409 | sets_tail, | ||
1410 | set); | ||
1411 | |||
1412 | GNUNET_free (cr); | ||
1413 | |||
1414 | GNUNET_SERVER_receive_done (client, | ||
1415 | GNUNET_OK); | ||
1416 | } | ||
1417 | |||
1418 | |||
1419 | /** | ||
1420 | * Handle a request from the client to | ||
1112 | * cancel a running set operation. | 1421 | * cancel a running set operation. |
1113 | * | 1422 | * |
1114 | * @param cls unused | 1423 | * @param cls unused |
@@ -1226,7 +1535,12 @@ handle_client_accept (void *cls, | |||
1226 | op); | 1535 | op); |
1227 | op->spec->client_request_id = ntohl (msg->request_id); | 1536 | op->spec->client_request_id = ntohl (msg->request_id); |
1228 | op->spec->result_mode = ntohl (msg->result_mode); | 1537 | op->spec->result_mode = ntohl (msg->result_mode); |
1229 | op->generation_created = set->current_generation++; | 1538 | |
1539 | // Advance generation values, so that | ||
1540 | // mutations won't interfer with the running operation. | ||
1541 | op->generation_created = set->current_generation; | ||
1542 | advance_generation (set); | ||
1543 | |||
1230 | op->vt = set->vt; | 1544 | op->vt = set->vt; |
1231 | op->vt->accept (op); | 1545 | op->vt->accept (op); |
1232 | GNUNET_SERVER_receive_done (client, | 1546 | GNUNET_SERVER_receive_done (client, |
@@ -1497,6 +1811,12 @@ run (void *cls, | |||
1497 | { &handle_client_cancel, NULL, | 1811 | { &handle_client_cancel, NULL, |
1498 | GNUNET_MESSAGE_TYPE_SET_CANCEL, | 1812 | GNUNET_MESSAGE_TYPE_SET_CANCEL, |
1499 | sizeof (struct GNUNET_SET_CancelMessage)}, | 1813 | sizeof (struct GNUNET_SET_CancelMessage)}, |
1814 | { &handle_client_copy_lazy_prepare, NULL, | ||
1815 | GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE, | ||
1816 | sizeof (struct GNUNET_MessageHeader)}, | ||
1817 | { &handle_client_copy_lazy_connect, NULL, | ||
1818 | GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT, | ||
1819 | sizeof (struct GNUNET_SET_CopyLazyConnectMessage)}, | ||
1500 | { NULL, NULL, 0, 0} | 1820 | { NULL, NULL, 0, 0} |
1501 | }; | 1821 | }; |
1502 | static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { | 1822 | static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { |
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h index 8d671ac81..d23291c82 100644 --- a/src/set/gnunet-service-set.h +++ b/src/set/gnunet-service-set.h | |||
@@ -211,6 +211,10 @@ typedef void | |||
211 | (*CancelImpl) (struct Operation *op); | 211 | (*CancelImpl) (struct Operation *op); |
212 | 212 | ||
213 | 213 | ||
214 | typedef struct SetState * | ||
215 | (*CopyStateImpl) (struct Set *op); | ||
216 | |||
217 | |||
214 | /** | 218 | /** |
215 | * Dispatch table for a specific set operation. Every set operation | 219 | * Dispatch table for a specific set operation. Every set operation |
216 | * has to implement the callback in this struct. | 220 | * has to implement the callback in this struct. |
@@ -261,6 +265,30 @@ struct SetVT | |||
261 | * Callback for canceling an operation by its ID. | 265 | * Callback for canceling an operation by its ID. |
262 | */ | 266 | */ |
263 | CancelImpl cancel; | 267 | CancelImpl cancel; |
268 | |||
269 | CopyStateImpl copy_state; | ||
270 | }; | ||
271 | |||
272 | |||
273 | /** | ||
274 | * MutationEvent gives information about changes | ||
275 | * to an element (removal / addition) in a set content. | ||
276 | */ | ||
277 | struct MutationEvent | ||
278 | { | ||
279 | /** | ||
280 | * First generation affected by this mutation event. | ||
281 | * | ||
282 | * If @a generation is 0, this mutation event is a list | ||
283 | * sentinel element. | ||
284 | */ | ||
285 | unsigned int generation; | ||
286 | |||
287 | /** | ||
288 | * If @a added is #GNUNET_YES, then this is a | ||
289 | * `remove` event, otherwise it is an `add` event. | ||
290 | */ | ||
291 | int added; | ||
264 | }; | 292 | }; |
265 | 293 | ||
266 | 294 | ||
@@ -285,22 +313,17 @@ struct ElementEntry | |||
285 | struct GNUNET_HashCode element_hash; | 313 | struct GNUNET_HashCode element_hash; |
286 | 314 | ||
287 | /** | 315 | /** |
288 | * Generation the element was added by the client. | 316 | * If @a mutations is not NULL, it contains |
289 | * Operations of earlier generations will not consider the element. | 317 | * a list of mutations, ordered by increasing generation. |
290 | */ | 318 | * The list is terminated by a sentinel event with `generation` |
291 | unsigned int generation_added; | 319 | * set to 0. |
292 | 320 | * | |
293 | /** | 321 | * If @a mutations is NULL, then this element exists in all generations |
294 | * Generation the element was removed by the client. | 322 | * of the respective set content this element belongs to. |
295 | * Operations of later generations will not consider the element. | ||
296 | * Only valid if @e removed is #GNUNET_YES. | ||
297 | */ | 323 | */ |
298 | unsigned int generation_removed; | 324 | struct MutationEvent *mutations; |
299 | 325 | ||
300 | /** | 326 | unsigned int mutations_size; |
301 | * #GNUNET_YES if the element has been removed in some generation. | ||
302 | */ | ||
303 | int removed; | ||
304 | 327 | ||
305 | /** | 328 | /** |
306 | * #GNUNET_YES if the element is a remote element, and does not belong | 329 | * #GNUNET_YES if the element is a remote element, and does not belong |
@@ -323,12 +346,12 @@ struct Operation | |||
323 | const struct SetVT *vt; | 346 | const struct SetVT *vt; |
324 | 347 | ||
325 | /** | 348 | /** |
326 | * Tunnel to the peer. | 349 | * Channel to the peer. |
327 | */ | 350 | */ |
328 | struct GNUNET_CADET_Channel *channel; | 351 | struct GNUNET_CADET_Channel *channel; |
329 | 352 | ||
330 | /** | 353 | /** |
331 | * Message queue for the tunnel. | 354 | * Message queue for the channel. |
332 | */ | 355 | */ |
333 | struct GNUNET_MQ_Handle *mq; | 356 | struct GNUNET_MQ_Handle *mq; |
334 | 357 | ||
@@ -366,7 +389,7 @@ struct Operation | |||
366 | * Timeout task, if the incoming peer has not been accepted | 389 | * Timeout task, if the incoming peer has not been accepted |
367 | * after the timeout, it will be disconnected. | 390 | * after the timeout, it will be disconnected. |
368 | */ | 391 | */ |
369 | struct GNUNET_SCHEDULER_Task * timeout_task; | 392 | struct GNUNET_SCHEDULER_Task *timeout_task; |
370 | 393 | ||
371 | /** | 394 | /** |
372 | * Unique request id for the request from a remote peer, sent to the | 395 | * Unique request id for the request from a remote peer, sent to the |
@@ -397,6 +420,41 @@ struct Operation | |||
397 | 420 | ||
398 | 421 | ||
399 | /** | 422 | /** |
423 | * SetContent stores the actual set elements, | ||
424 | * which may be shared by multiple generations derived | ||
425 | * from one set. | ||
426 | */ | ||
427 | struct SetContent | ||
428 | { | ||
429 | /** | ||
430 | * Number of references to the content. | ||
431 | */ | ||
432 | unsigned int refcount; | ||
433 | |||
434 | /** | ||
435 | * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`. | ||
436 | */ | ||
437 | struct GNUNET_CONTAINER_MultiHashMap *elements; | ||
438 | |||
439 | unsigned int latest_generation; | ||
440 | }; | ||
441 | |||
442 | |||
443 | struct GenerationRange | ||
444 | { | ||
445 | /** | ||
446 | * First generation that is excluded. | ||
447 | */ | ||
448 | unsigned int start; | ||
449 | |||
450 | /** | ||
451 | * Generation after the last excluded generation. | ||
452 | */ | ||
453 | unsigned int end; | ||
454 | }; | ||
455 | |||
456 | |||
457 | /** | ||
400 | * A set that supports a specific operation with other peers. | 458 | * A set that supports a specific operation with other peers. |
401 | */ | 459 | */ |
402 | struct Set | 460 | struct Set |
@@ -444,11 +502,6 @@ struct Set | |||
444 | struct GNUNET_CONTAINER_MultiHashMapIterator *iter; | 502 | struct GNUNET_CONTAINER_MultiHashMapIterator *iter; |
445 | 503 | ||
446 | /** | 504 | /** |
447 | * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`. | ||
448 | */ | ||
449 | struct GNUNET_CONTAINER_MultiHashMap *elements; | ||
450 | |||
451 | /** | ||
452 | * Evaluate operations are held in a linked list. | 505 | * Evaluate operations are held in a linked list. |
453 | */ | 506 | */ |
454 | struct Operation *ops_head; | 507 | struct Operation *ops_head; |
@@ -460,11 +513,18 @@ struct Set | |||
460 | 513 | ||
461 | /** | 514 | /** |
462 | * Current generation, that is, number of previously executed | 515 | * Current generation, that is, number of previously executed |
463 | * operations on this set | 516 | * operations and lazy copies on the underlying set content. |
464 | */ | 517 | */ |
465 | unsigned int current_generation; | 518 | unsigned int current_generation; |
466 | 519 | ||
467 | /** | 520 | /** |
521 | * List of generations we have to exclude, due to lazy copies. | ||
522 | */ | ||
523 | struct GenerationRange *excluded_generations; | ||
524 | |||
525 | unsigned int excluded_generations_size; | ||
526 | |||
527 | /** | ||
468 | * Type of operation supported for this set | 528 | * Type of operation supported for this set |
469 | */ | 529 | */ |
470 | enum GNUNET_SET_OperationType operation; | 530 | enum GNUNET_SET_OperationType operation; |
@@ -475,6 +535,12 @@ struct Set | |||
475 | */ | 535 | */ |
476 | uint16_t iteration_id; | 536 | uint16_t iteration_id; |
477 | 537 | ||
538 | /** | ||
539 | * Content, possibly shared by multiple sets, | ||
540 | * and thus reference counted. | ||
541 | */ | ||
542 | struct SetContent *content; | ||
543 | |||
478 | }; | 544 | }; |
479 | 545 | ||
480 | 546 | ||
@@ -510,4 +576,13 @@ const struct SetVT * | |||
510 | _GSS_intersection_vt (void); | 576 | _GSS_intersection_vt (void); |
511 | 577 | ||
512 | 578 | ||
579 | int | ||
580 | _GSS_is_element_of_set (struct ElementEntry *ee, | ||
581 | struct Set *set); | ||
582 | |||
583 | int | ||
584 | _GSS_is_element_of_operation (struct ElementEntry *ee, | ||
585 | struct Operation *op); | ||
586 | |||
587 | |||
513 | #endif | 588 | #endif |
diff --git a/src/set/gnunet-service-set_intersection.c b/src/set/gnunet-service-set_intersection.c index 55e66a229..a6723e019 100644 --- a/src/set/gnunet-service-set_intersection.c +++ b/src/set/gnunet-service-set_intersection.c | |||
@@ -239,8 +239,7 @@ filtered_map_initialization (void *cls, | |||
239 | GNUNET_h2s (&ee->element_hash), | 239 | GNUNET_h2s (&ee->element_hash), |
240 | ee->element.size); | 240 | ee->element.size); |
241 | 241 | ||
242 | if ( (op->generation_created < ee->generation_removed) && | 242 | if (_GSS_is_element_of_operation (ee, op)) |
243 | (op->generation_created >= ee->generation_added) ) | ||
244 | { | 243 | { |
245 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 244 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
246 | "Reduced initialization, not starting with %s:%u (wrong generation)\n", | 245 | "Reduced initialization, not starting with %s:%u (wrong generation)\n", |
@@ -617,7 +616,7 @@ process_bf (struct Operation *op) | |||
617 | op->state->phase, | 616 | op->state->phase, |
618 | op->spec->remote_element_count, | 617 | op->spec->remote_element_count, |
619 | op->state->my_element_count, | 618 | op->state->my_element_count, |
620 | GNUNET_CONTAINER_multihashmap_size (op->spec->set->elements)); | 619 | GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements)); |
621 | switch (op->state->phase) | 620 | switch (op->state->phase) |
622 | { | 621 | { |
623 | case PHASE_INITIAL: | 622 | case PHASE_INITIAL: |
@@ -631,7 +630,7 @@ process_bf (struct Operation *op) | |||
631 | = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count, | 630 | = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count, |
632 | GNUNET_YES); | 631 | GNUNET_YES); |
633 | op->state->my_element_count = 0; | 632 | op->state->my_element_count = 0; |
634 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements, | 633 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, |
635 | &filtered_map_initialization, | 634 | &filtered_map_initialization, |
636 | op); | 635 | op); |
637 | break; | 636 | break; |
@@ -786,8 +785,7 @@ initialize_map_unfiltered (void *cls, | |||
786 | struct ElementEntry *ee = value; | 785 | struct ElementEntry *ee = value; |
787 | struct Operation *op = cls; | 786 | struct Operation *op = cls; |
788 | 787 | ||
789 | if ( (op->generation_created < ee->generation_removed) && | 788 | if (_GSS_is_element_of_operation (ee, op)) |
790 | (op->generation_created >= ee->generation_added) ) | ||
791 | return GNUNET_YES; /* element not live in operation's generation */ | 789 | return GNUNET_YES; /* element not live in operation's generation */ |
792 | GNUNET_CRYPTO_hash_xor (&op->state->my_xor, | 790 | GNUNET_CRYPTO_hash_xor (&op->state->my_xor, |
793 | &ee->element_hash, | 791 | &ee->element_hash, |
@@ -840,7 +838,7 @@ begin_bf_exchange (struct Operation *op) | |||
840 | op->state->my_elements | 838 | op->state->my_elements |
841 | = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, | 839 | = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count, |
842 | GNUNET_YES); | 840 | GNUNET_YES); |
843 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements, | 841 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, |
844 | &initialize_map_unfiltered, | 842 | &initialize_map_unfiltered, |
845 | op); | 843 | op); |
846 | send_bloomfilter (op); | 844 | send_bloomfilter (op); |
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c index b088ff634..b09e9d2a6 100644 --- a/src/set/gnunet-service-set_union.c +++ b/src/set/gnunet-service-set_union.c | |||
@@ -515,18 +515,16 @@ init_key_to_element_iterator (void *cls, | |||
515 | void *value) | 515 | void *value) |
516 | { | 516 | { |
517 | struct Operation *op = cls; | 517 | struct Operation *op = cls; |
518 | struct ElementEntry *e = value; | 518 | struct ElementEntry *ee = value; |
519 | 519 | ||
520 | /* make sure that the element belongs to the set at the time | 520 | /* make sure that the element belongs to the set at the time |
521 | * of creating the operation */ | 521 | * of creating the operation */ |
522 | if ( (e->generation_added > op->generation_created) || | 522 | if (GNUNET_NO == _GSS_is_element_of_operation (ee, op)) |
523 | ( (GNUNET_YES == e->removed) && | ||
524 | (e->generation_removed < op->generation_created))) | ||
525 | return GNUNET_YES; | 523 | return GNUNET_YES; |
526 | 524 | ||
527 | GNUNET_assert (GNUNET_NO == e->remote); | 525 | GNUNET_assert (GNUNET_NO == ee->remote); |
528 | 526 | ||
529 | op_register_element (op, e); | 527 | op_register_element (op, ee); |
530 | return GNUNET_YES; | 528 | return GNUNET_YES; |
531 | } | 529 | } |
532 | 530 | ||
@@ -546,9 +544,9 @@ prepare_ibf (struct Operation *op, | |||
546 | { | 544 | { |
547 | unsigned int len; | 545 | unsigned int len; |
548 | 546 | ||
549 | len = GNUNET_CONTAINER_multihashmap_size (op->spec->set->elements); | 547 | len = GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements); |
550 | op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); | 548 | op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); |
551 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->elements, | 549 | GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, |
552 | init_key_to_element_iterator, op); | 550 | init_key_to_element_iterator, op); |
553 | } | 551 | } |
554 | if (NULL != op->state->local_ibf) | 552 | if (NULL != op->state->local_ibf) |
diff --git a/src/set/set.h b/src/set/set.h index b5750ae3a..0dccf2a51 100644 --- a/src/set/set.h +++ b/src/set/set.h | |||
@@ -308,6 +308,41 @@ struct GNUNET_SET_IterAckMessage | |||
308 | uint32_t send_more; | 308 | uint32_t send_more; |
309 | }; | 309 | }; |
310 | 310 | ||
311 | |||
312 | /** | ||
313 | * Server responds to a lazy copy request. | ||
314 | */ | ||
315 | struct GNUNET_SET_CopyLazyResponseMessage | ||
316 | { | ||
317 | /** | ||
318 | * Type: #GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE | ||
319 | */ | ||
320 | struct GNUNET_MessageHeader header; | ||
321 | |||
322 | /** | ||
323 | * Temporary name for the copied set. | ||
324 | */ | ||
325 | uint32_t cookie; | ||
326 | }; | ||
327 | |||
328 | |||
329 | /** | ||
330 | * Client connects to a lazily copied set. | ||
331 | */ | ||
332 | struct GNUNET_SET_CopyLazyConnectMessage | ||
333 | { | ||
334 | /** | ||
335 | * Type: #GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT | ||
336 | */ | ||
337 | struct GNUNET_MessageHeader header; | ||
338 | |||
339 | /** | ||
340 | * Temporary name for the copied set. | ||
341 | */ | ||
342 | uint32_t cookie; | ||
343 | }; | ||
344 | |||
345 | |||
311 | GNUNET_NETWORK_STRUCT_END | 346 | GNUNET_NETWORK_STRUCT_END |
312 | 347 | ||
313 | #endif | 348 | #endif |
diff --git a/src/set/set_api.c b/src/set/set_api.c index 04ae019d0..aadc93678 100644 --- a/src/set/set_api.c +++ b/src/set/set_api.c | |||
@@ -33,6 +33,17 @@ | |||
33 | 33 | ||
34 | #define LOG(kind,...) GNUNET_log_from (kind, "set-api",__VA_ARGS__) | 34 | #define LOG(kind,...) GNUNET_log_from (kind, "set-api",__VA_ARGS__) |
35 | 35 | ||
36 | struct SetCopyRequest | ||
37 | { | ||
38 | struct SetCopyRequest *next; | ||
39 | |||
40 | struct SetCopyRequest *prev; | ||
41 | |||
42 | void *cls; | ||
43 | |||
44 | GNUNET_SET_CopyReadyCallback cb; | ||
45 | }; | ||
46 | |||
36 | /** | 47 | /** |
37 | * Opaque handle to a set. | 48 | * Opaque handle to a set. |
38 | */ | 49 | */ |
@@ -84,6 +95,21 @@ struct GNUNET_SET_Handle | |||
84 | * created so far to match replies with iterators. | 95 | * created so far to match replies with iterators. |
85 | */ | 96 | */ |
86 | uint16_t iteration_id; | 97 | uint16_t iteration_id; |
98 | |||
99 | /** | ||
100 | * Configuration, needed when creating (lazy) copies. | ||
101 | */ | ||
102 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
103 | |||
104 | /** | ||
105 | * Doubly linked list of copy requests. | ||
106 | */ | ||
107 | struct SetCopyRequest *copy_req_head; | ||
108 | |||
109 | /** | ||
110 | * Doubly linked list of copy requests. | ||
111 | */ | ||
112 | struct SetCopyRequest *copy_req_tail; | ||
87 | }; | 113 | }; |
88 | 114 | ||
89 | 115 | ||
@@ -213,6 +239,55 @@ struct GNUNET_SET_ListenHandle | |||
213 | }; | 239 | }; |
214 | 240 | ||
215 | 241 | ||
242 | /* mutual recursion with handle_copy_lazy */ | ||
243 | static struct GNUNET_SET_Handle * | ||
244 | create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
245 | enum GNUNET_SET_OperationType op, | ||
246 | uint32_t *cookie); | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Handle element for iteration over the set. Notifies the | ||
251 | * iterator and sends an acknowledgement to the service. | ||
252 | * | ||
253 | * @param cls the `struct GNUNET_SET_Handle *` | ||
254 | * @param mh the message | ||
255 | */ | ||
256 | static void | ||
257 | handle_copy_lazy (void *cls, | ||
258 | const struct GNUNET_MessageHeader *mh) | ||
259 | { | ||
260 | struct GNUNET_SET_CopyLazyResponseMessage *msg; | ||
261 | struct GNUNET_SET_Handle *set = cls; | ||
262 | struct SetCopyRequest *req; | ||
263 | struct GNUNET_SET_Handle *new_set; | ||
264 | |||
265 | msg = (struct GNUNET_SET_CopyLazyResponseMessage *) mh; | ||
266 | |||
267 | req = set->copy_req_head; | ||
268 | |||
269 | if (NULL == req) | ||
270 | { | ||
271 | /* Service sent us unsolicited lazy copy response */ | ||
272 | GNUNET_break (0); | ||
273 | return; | ||
274 | } | ||
275 | |||
276 | GNUNET_CONTAINER_DLL_remove (set->copy_req_head, | ||
277 | set->copy_req_tail, | ||
278 | req); | ||
279 | |||
280 | |||
281 | // We pass none as operation here, since it doesn't matter when | ||
282 | // cloning. | ||
283 | new_set = create_internal (set->cfg, GNUNET_SET_OPERATION_NONE, &msg->cookie); | ||
284 | |||
285 | req->cb (req->cls, new_set); | ||
286 | |||
287 | GNUNET_free (req); | ||
288 | } | ||
289 | |||
290 | |||
216 | /** | 291 | /** |
217 | * Handle element for iteration over the set. Notifies the | 292 | * Handle element for iteration over the set. Notifies the |
218 | * iterator and sends an acknowledgement to the service. | 293 | * iterator and sends an acknowledgement to the service. |
@@ -455,20 +530,10 @@ handle_client_set_error (void *cls, | |||
455 | } | 530 | } |
456 | 531 | ||
457 | 532 | ||
458 | /** | 533 | static struct GNUNET_SET_Handle * |
459 | * Create an empty set, supporting the specified operation. | 534 | create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg, |
460 | * | 535 | enum GNUNET_SET_OperationType op, |
461 | * @param cfg configuration to use for connecting to the | 536 | uint32_t *cookie) |
462 | * set service | ||
463 | * @param op operation supported by the set | ||
464 | * Note that the operation has to be specified | ||
465 | * beforehand, as certain set operations need to maintain | ||
466 | * data structures spefific to the operation | ||
467 | * @return a handle to the set | ||
468 | */ | ||
469 | struct GNUNET_SET_Handle * | ||
470 | GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
471 | enum GNUNET_SET_OperationType op) | ||
472 | { | 537 | { |
473 | static const struct GNUNET_MQ_MessageHandler mq_handlers[] = { | 538 | static const struct GNUNET_MQ_MessageHandler mq_handlers[] = { |
474 | { &handle_result, | 539 | { &handle_result, |
@@ -480,17 +545,22 @@ GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
480 | { &handle_iter_done, | 545 | { &handle_iter_done, |
481 | GNUNET_MESSAGE_TYPE_SET_ITER_DONE, | 546 | GNUNET_MESSAGE_TYPE_SET_ITER_DONE, |
482 | sizeof (struct GNUNET_MessageHeader) }, | 547 | sizeof (struct GNUNET_MessageHeader) }, |
548 | { &handle_copy_lazy, | ||
549 | GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE, | ||
550 | sizeof (struct GNUNET_SET_CopyLazyResponseMessage) }, | ||
483 | GNUNET_MQ_HANDLERS_END | 551 | GNUNET_MQ_HANDLERS_END |
484 | }; | 552 | }; |
485 | struct GNUNET_SET_Handle *set; | 553 | struct GNUNET_SET_Handle *set; |
486 | struct GNUNET_MQ_Envelope *mqm; | 554 | struct GNUNET_MQ_Envelope *mqm; |
487 | struct GNUNET_SET_CreateMessage *msg; | 555 | struct GNUNET_SET_CreateMessage *create_msg; |
556 | struct GNUNET_SET_CopyLazyConnectMessage *copy_msg; | ||
488 | 557 | ||
489 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
490 | "Creating new set (operation %u)\n", | 559 | "Creating new set (operation %u)\n", |
491 | op); | 560 | op); |
492 | set = GNUNET_new (struct GNUNET_SET_Handle); | 561 | set = GNUNET_new (struct GNUNET_SET_Handle); |
493 | set->client = GNUNET_CLIENT_connect ("set", cfg); | 562 | set->client = GNUNET_CLIENT_connect ("set", cfg); |
563 | set->cfg = cfg; | ||
494 | if (NULL == set->client) | 564 | if (NULL == set->client) |
495 | { | 565 | { |
496 | GNUNET_free (set); | 566 | GNUNET_free (set); |
@@ -501,15 +571,44 @@ GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
501 | &handle_client_set_error, | 571 | &handle_client_set_error, |
502 | set); | 572 | set); |
503 | GNUNET_assert (NULL != set->mq); | 573 | GNUNET_assert (NULL != set->mq); |
504 | mqm = GNUNET_MQ_msg (msg, | 574 | |
505 | GNUNET_MESSAGE_TYPE_SET_CREATE); | 575 | if (NULL == cookie) |
506 | msg->operation = htonl (op); | 576 | { |
577 | mqm = GNUNET_MQ_msg (create_msg, | ||
578 | GNUNET_MESSAGE_TYPE_SET_CREATE); | ||
579 | create_msg->operation = htonl (op); | ||
580 | } | ||
581 | else | ||
582 | { | ||
583 | mqm = GNUNET_MQ_msg (copy_msg, | ||
584 | GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT); | ||
585 | copy_msg->cookie = *cookie; | ||
586 | } | ||
507 | GNUNET_MQ_send (set->mq, mqm); | 587 | GNUNET_MQ_send (set->mq, mqm); |
508 | return set; | 588 | return set; |
509 | } | 589 | } |
510 | 590 | ||
511 | 591 | ||
512 | /** | 592 | /** |
593 | * Create an empty set, supporting the specified operation. | ||
594 | * | ||
595 | * @param cfg configuration to use for connecting to the | ||
596 | * set service | ||
597 | * @param op operation supported by the set | ||
598 | * Note that the operation has to be specified | ||
599 | * beforehand, as certain set operations need to maintain | ||
600 | * data structures spefific to the operation | ||
601 | * @return a handle to the set | ||
602 | */ | ||
603 | struct GNUNET_SET_Handle * | ||
604 | GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
605 | enum GNUNET_SET_OperationType op) | ||
606 | { | ||
607 | return create_internal (cfg, op, NULL); | ||
608 | } | ||
609 | |||
610 | |||
611 | /** | ||
513 | * Add an element to the given set. After the element has been added | 612 | * Add an element to the given set. After the element has been added |
514 | * (in the sense of being transmitted to the set service), @a cont | 613 | * (in the sense of being transmitted to the set service), @a cont |
515 | * will be called. Multiple calls to GNUNET_SET_add_element() can be | 614 | * will be called. Multiple calls to GNUNET_SET_add_element() can be |
@@ -976,19 +1075,23 @@ GNUNET_SET_iterate (struct GNUNET_SET_Handle *set, | |||
976 | } | 1075 | } |
977 | 1076 | ||
978 | 1077 | ||
979 | /** | ||
980 | * Stop iteration over all elements in the given set. Can only | ||
981 | * be called before the iteration has "naturally" completed its | ||
982 | * turn. | ||
983 | * | ||
984 | * @param set the set to stop iterating over | ||
985 | */ | ||
986 | void | 1078 | void |
987 | GNUNET_SET_iterate_cancel (struct GNUNET_SET_Handle *set) | 1079 | GNUNET_SET_copy_lazy (struct GNUNET_SET_Handle *set, |
1080 | GNUNET_SET_CopyReadyCallback cb, | ||
1081 | void *cls) | ||
988 | { | 1082 | { |
989 | GNUNET_assert (NULL != set->iterator); | 1083 | struct GNUNET_MQ_Envelope *ev; |
990 | set->iterator = NULL; | 1084 | struct SetCopyRequest *req; |
991 | set->iteration_id++; | 1085 | |
1086 | ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE); | ||
1087 | GNUNET_MQ_send (set->mq, ev); | ||
1088 | |||
1089 | req = GNUNET_new (struct SetCopyRequest); | ||
1090 | req->cb = cb; | ||
1091 | req->cls = cls; | ||
1092 | GNUNET_CONTAINER_DLL_insert (set->copy_req_head, | ||
1093 | set->copy_req_tail, | ||
1094 | req); | ||
992 | } | 1095 | } |
993 | 1096 | ||
994 | 1097 | ||