aboutsummaryrefslogtreecommitdiff
path: root/src/set
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2015-08-30 00:44:11 +0000
committerFlorian Dold <florian.dold@gmail.com>2015-08-30 00:44:11 +0000
commit7936cab9bd741a9ff30362c8495daa29f1874b2e (patch)
tree33606962451dcb4b15dabff20f605a5c58f1cc72 /src/set
parent38963d1e81332032e0ac774f4f2c6b804c38802a (diff)
downloadgnunet-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.c414
-rw-r--r--src/set/gnunet-service-set.h121
-rw-r--r--src/set/gnunet-service-set_intersection.c12
-rw-r--r--src/set/gnunet-service-set_union.c14
-rw-r--r--src/set/set.h35
-rw-r--r--src/set/set_api.c161
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
75struct 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 */
116static struct Operation *incoming_tail; 126static struct Operation *incoming_tail;
117 127
128static struct LazyCopyRequest *lazy_copy_head;
129static struct LazyCopyRequest *lazy_copy_tail;
130
131static 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
317int
318is_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
334int
335is_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
375int
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
386int
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 */
1151static void
1152advance_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 */
1298static void
1299handle_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 */
1337static void
1338handle_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
214typedef 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 */
277struct 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 */
427struct 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
443struct 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 */
402struct Set 460struct 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
579int
580_GSS_is_element_of_set (struct ElementEntry *ee,
581 struct Set *set);
582
583int
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 */
315struct 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 */
332struct 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
311GNUNET_NETWORK_STRUCT_END 346GNUNET_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
36struct 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 */
243static struct GNUNET_SET_Handle *
244create_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 */
256static void
257handle_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/** 533static struct GNUNET_SET_Handle *
459 * Create an empty set, supporting the specified operation. 534create_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 */
469struct GNUNET_SET_Handle *
470GNUNET_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 */
603struct GNUNET_SET_Handle *
604GNUNET_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 */
986void 1078void
987GNUNET_SET_iterate_cancel (struct GNUNET_SET_Handle *set) 1079GNUNET_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