aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-04-25 17:29:47 +0200
committerChristian Grothoff <christian@grothoff.org>2018-04-25 17:29:47 +0200
commit34dc12c0a43a253857d2711b8fa1d18c18d01367 (patch)
tree2a367c0f939cb099a700a41ec66fdd33bfa50ed8 /src
parent303334e67262bb6121dfbd245c66535f259d08af (diff)
downloadgnunet-34dc12c0a43a253857d2711b8fa1d18c18d01367.tar.gz
gnunet-34dc12c0a43a253857d2711b8fa1d18c18d01367.zip
first (untested) implementation of batch iteration over NAMESTORE to speed up initial data import
Diffstat (limited to 'src')
-rw-r--r--src/namestore/gnunet-zoneimport.c294
1 files changed, 213 insertions, 81 deletions
diff --git a/src/namestore/gnunet-zoneimport.c b/src/namestore/gnunet-zoneimport.c
index faef436ac..097f34532 100644
--- a/src/namestore/gnunet-zoneimport.c
+++ b/src/namestore/gnunet-zoneimport.c
@@ -47,6 +47,11 @@
47 */ 47 */
48#define MAX_RETRIES 5 48#define MAX_RETRIES 5
49 49
50/**
51 * How many requests do we request from NAMESTORE in one batch
52 * during our initial iteration?
53 */
54#define NS_BATCH_SIZE 1024
50 55
51/** 56/**
52 * Some zones may include authoritative records for other 57 * Some zones may include authoritative records for other
@@ -220,11 +225,6 @@ static unsigned int failures;
220static unsigned int records; 225static unsigned int records;
221 226
222/** 227/**
223 * #GNUNET_YES if we have more work to be read from `stdin`.
224 */
225static int stdin_waiting;
226
227/**
228 * Heap of all requests to perform, sorted by 228 * Heap of all requests to perform, sorted by
229 * the time we should next do the request (i.e. by expires). 229 * the time we should next do the request (i.e. by expires).
230 */ 230 */
@@ -246,6 +246,18 @@ static struct Request *req_tail;
246static struct GNUNET_SCHEDULER_Task *t; 246static struct GNUNET_SCHEDULER_Task *t;
247 247
248/** 248/**
249 * Hash map of requests for which we may still get a response from
250 * the namestore. Set to NULL once the initial namestore iteration
251 * is done.
252 */
253static struct GNUNET_CONTAINER_MultiHashMap *ns_pending;
254
255/**
256 * Current zone iteration handle.
257 */
258static struct GNUNET_NAMESTORE_ZoneIterator *zone_it;
259
260/**
249 * Head of list of zones we are managing. 261 * Head of list of zones we are managing.
250 */ 262 */
251static struct Zone *zone_head; 263static struct Zone *zone_head;
@@ -255,6 +267,11 @@ static struct Zone *zone_head;
255 */ 267 */
256static struct Zone *zone_tail; 268static struct Zone *zone_tail;
257 269
270/**
271 * After how many more results must #ns_lookup_result_cb() ask
272 * the namestore for more?
273 */
274static uint64_t ns_iterator_trigger_next;
258 275
259/** 276/**
260 * Callback for #for_all_records 277 * Callback for #for_all_records
@@ -394,16 +411,18 @@ build_dns_query (struct Request *req,
394} 411}
395 412
396 413
414
397/** 415/**
398 * Free @a req and data structures reachable from it. 416 * Free records associated with @a req.
399 * 417 *
400 * @param req request to free 418 * @param req request to free records of
401 */ 419 */
402static void 420static void
403free_request (struct Request *req) 421free_records (struct Request *req)
404{ 422{
405 struct Record *rec; 423 struct Record *rec;
406 424
425 /* Free records */
407 while (NULL != (rec = req->rec_head)) 426 while (NULL != (rec = req->rec_head))
408 { 427 {
409 GNUNET_CONTAINER_DLL_remove (req->rec_head, 428 GNUNET_CONTAINER_DLL_remove (req->rec_head,
@@ -411,6 +430,18 @@ free_request (struct Request *req)
411 rec); 430 rec);
412 GNUNET_free (rec); 431 GNUNET_free (rec);
413 } 432 }
433}
434
435
436/**
437 * Free @a req and data structures reachable from it.
438 *
439 * @param req request to free
440 */
441static void
442free_request (struct Request *req)
443{
444 free_records (req);
414 GNUNET_free (req); 445 GNUNET_free (req);
415} 446}
416 447
@@ -877,7 +908,6 @@ store_completed_cb (void *cls,
877 static struct GNUNET_TIME_Absolute last; 908 static struct GNUNET_TIME_Absolute last;
878 static unsigned int pdot; 909 static unsigned int pdot;
879 struct Request *req = cls; 910 struct Request *req = cls;
880 struct Record *rec;
881 911
882 req->qe = NULL; 912 req->qe = NULL;
883 pending--; 913 pending--;
@@ -908,14 +938,7 @@ store_completed_cb (void *cls,
908 GNUNET_YES)); 938 GNUNET_YES));
909 } 939 }
910 } 940 }
911 /* Free records */ 941 free_records (req);
912 while (NULL != (rec = req->rec_head))
913 {
914 GNUNET_CONTAINER_DLL_remove (req->rec_head,
915 req->rec_tail,
916 rec);
917 GNUNET_free (rec);
918 }
919} 942}
920 943
921 944
@@ -1148,6 +1171,29 @@ process_queue (void *cls)
1148 1171
1149 1172
1150/** 1173/**
1174 * Iterator called during #do_shutdown() to free requests in
1175 * the #ns_pending map.
1176 *
1177 * @param cls NULL
1178 * @param key unused
1179 * @param value the `struct Request` to free
1180 * @return #GNUNET_OK
1181 */
1182static int
1183free_request_it (void *cls,
1184 const struct GNUNET_HashCode *key,
1185 void *value)
1186{
1187 struct Request *req = value;
1188
1189 (void) cls;
1190 (void) key;
1191 free_request (req);
1192 return GNUNET_OK;
1193}
1194
1195
1196/**
1151 * Clean up and terminate the process. 1197 * Clean up and terminate the process.
1152 * 1198 *
1153 * @param cls NULL 1199 * @param cls NULL
@@ -1185,6 +1231,11 @@ do_shutdown (void *cls)
1185 GNUNET_NAMESTORE_cancel (req->qe); 1231 GNUNET_NAMESTORE_cancel (req->qe);
1186 free_request (req); 1232 free_request (req);
1187 } 1233 }
1234 if (NULL != zone_it)
1235 {
1236 GNUNET_NAMESTORE_zone_iteration_stop (zone_it);
1237 zone_it = NULL;
1238 }
1188 if (NULL != ns) 1239 if (NULL != ns)
1189 { 1240 {
1190 GNUNET_NAMESTORE_disconnect (ns); 1241 GNUNET_NAMESTORE_disconnect (ns);
@@ -1200,6 +1251,14 @@ do_shutdown (void *cls)
1200 GNUNET_CONTAINER_heap_destroy (req_heap); 1251 GNUNET_CONTAINER_heap_destroy (req_heap);
1201 req_heap = NULL; 1252 req_heap = NULL;
1202 } 1253 }
1254 if (NULL != ns_pending)
1255 {
1256 GNUNET_CONTAINER_multihashmap_iterate (ns_pending,
1257 &free_request_it,
1258 NULL);
1259 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1260 ns_pending = NULL;
1261 }
1203 while (NULL != (zone = zone_head)) 1262 while (NULL != (zone = zone_head))
1204 { 1263 {
1205 GNUNET_CONTAINER_DLL_remove (zone_head, 1264 GNUNET_CONTAINER_DLL_remove (zone_head,
@@ -1212,75 +1271,75 @@ do_shutdown (void *cls)
1212 1271
1213 1272
1214/** 1273/**
1215 * Begin processing hostnames from stdin.
1216 *
1217 * @param cls NULL
1218 */
1219static void
1220process_stdin (void *cls);
1221
1222
1223/**
1224 * If applicable, continue processing from stdin.
1225 */
1226static void
1227continue_stdin ()
1228{
1229 if ( (pending < THRESH) &&
1230 (stdin_waiting) )
1231 {
1232 if (NULL != t)
1233 GNUNET_SCHEDULER_cancel (t);
1234 t = GNUNET_SCHEDULER_add_now (&process_stdin,
1235 NULL);
1236 }
1237}
1238
1239
1240/**
1241 * Function called if #GNUNET_NAMESTORE_records_lookup() failed. 1274 * Function called if #GNUNET_NAMESTORE_records_lookup() failed.
1242 * Continues resolution based on assumption namestore has no data. 1275 * Just logs an error.
1243 * 1276 *
1244 * @param cls a `struct Request` 1277 * @param cls a `struct Zone`
1245 */ 1278 */
1246static void 1279static void
1247ns_lookup_error_cb (void *cls) 1280ns_lookup_error_cb (void *cls)
1248{ 1281{
1249 struct Request *req = cls; 1282 struct Zone *zone = cls;
1250 1283
1251 req->qe = NULL;
1252 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1284 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1253 "Failed to load data from namestore for `%s'\n", 1285 "Failed to load data from namestore for zone `%s'\n",
1254 req->hostname); 1286 zone->domain);
1255 insert_sorted (req);
1256 pending--;
1257 continue_stdin ();
1258} 1287}
1259 1288
1260 1289
1261/** 1290/**
1262 * Process a record that was stored in the namestore. 1291 * Process a record that was stored in the namestore.
1263 * 1292 *
1264 * @param cls a `struct Request *` 1293 * @param cls a `struct Zone *`
1265 * @param zone private key of the zone 1294 * @param key private key of the zone
1266 * @param label label of the records 1295 * @param label label of the records
1267 * @param rd_count number of entries in @a rd array, 0 if label was deleted 1296 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1268 * @param rd array of records with data to store 1297 * @param rd array of records with data to store
1269 */ 1298 */
1270static void 1299static void
1271ns_lookup_result_cb (void *cls, 1300ns_lookup_result_cb (void *cls,
1272 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, 1301 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
1273 const char *label, 1302 const char *label,
1274 unsigned int rd_count, 1303 unsigned int rd_count,
1275 const struct GNUNET_GNSRECORD_Data *rd) 1304 const struct GNUNET_GNSRECORD_Data *rd)
1276{ 1305{
1277 struct Request *req = cls; 1306 struct Zone *zone = cls;
1307 struct Request *req;
1308 struct GNUNET_HashCode hc;
1309 char *fqdn;
1278 1310
1279 req->qe = NULL; 1311 ns_iterator_trigger_next--;
1280 pending--; 1312 if (0 == ns_iterator_trigger_next)
1281 GNUNET_break (0 == memcmp (zone, 1313 {
1314 ns_iterator_trigger_next = NS_BATCH_SIZE;
1315 GNUNET_NAMESTORE_zone_iterator_next (zone_it,
1316 ns_iterator_trigger_next);
1317 }
1318 GNUNET_asprintf (&fqdn,
1319 "%s.%s",
1320 label,
1321 zone->domain);
1322 GNUNET_CRYPTO_hash (fqdn,
1323 strlen (fqdn) + 1,
1324 &hc);
1325 GNUNET_free (fqdn);
1326 req = GNUNET_CONTAINER_multihashmap_get (ns_pending,
1327 &hc);
1328 if (NULL == req)
1329 {
1330 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1331 "Ignoring record `%s' in zone `%s': not on my list!\n",
1332 label,
1333 zone->domain);
1334 return;
1335 }
1336 GNUNET_assert (GNUNET_OK ==
1337 GNUNET_CONTAINER_multihashmap_remove (ns_pending,
1338 &hc,
1339 req));
1340 GNUNET_break (0 == memcmp (key,
1282 &req->zone->key, 1341 &req->zone->key,
1283 sizeof (*zone))); 1342 sizeof (*key)));
1284 GNUNET_break (0 == strcasecmp (label, 1343 GNUNET_break (0 == strcasecmp (label,
1285 get_label (req))); 1344 get_label (req)));
1286 for (unsigned int i=0;i<rd_count;i++) 1345 for (unsigned int i=0;i<rd_count;i++)
@@ -1323,12 +1382,13 @@ ns_lookup_result_cb (void *cls,
1323 pos, 1382 pos,
1324 req->hostname); 1383 req->hostname);
1325 } 1384 }
1385 free_records (req);
1386
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Adding `%s' to worklist to start at %s\n", 1388 "Adding `%s' to worklist to start at %s\n",
1328 req->hostname, 1389 req->hostname,
1329 GNUNET_STRINGS_absolute_time_to_string (req->expires)); 1390 GNUNET_STRINGS_absolute_time_to_string (req->expires));
1330 insert_sorted (req); 1391 insert_sorted (req);
1331 continue_stdin ();
1332} 1392}
1333 1393
1334 1394
@@ -1344,6 +1404,7 @@ queue (const char *hostname)
1344 const char *dot; 1404 const char *dot;
1345 struct Zone *zone; 1405 struct Zone *zone;
1346 size_t hlen; 1406 size_t hlen;
1407 struct GNUNET_HashCode hc;
1347 1408
1348 if (GNUNET_OK != 1409 if (GNUNET_OK !=
1349 GNUNET_DNSPARSER_check_name (hostname)) 1410 GNUNET_DNSPARSER_check_name (hostname))
@@ -1352,7 +1413,6 @@ queue (const char *hostname)
1352 "Refusing invalid hostname `%s'\n", 1413 "Refusing invalid hostname `%s'\n",
1353 hostname); 1414 hostname);
1354 rejects++; 1415 rejects++;
1355 continue_stdin ();
1356 return; 1416 return;
1357 } 1417 }
1358 dot = strchr (hostname, 1418 dot = strchr (hostname,
@@ -1363,7 +1423,6 @@ queue (const char *hostname)
1363 "Refusing invalid hostname `%s' (lacks '.')\n", 1423 "Refusing invalid hostname `%s' (lacks '.')\n",
1364 hostname); 1424 hostname);
1365 rejects++; 1425 rejects++;
1366 continue_stdin ();
1367 return; 1426 return;
1368 } 1427 }
1369 for (zone = zone_head; NULL != zone; zone = zone->next) 1428 for (zone = zone_head; NULL != zone; zone = zone->next)
@@ -1376,7 +1435,6 @@ queue (const char *hostname)
1376 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1377 "Domain name `%s' not in ego list!\n", 1436 "Domain name `%s' not in ego list!\n",
1378 dot + 1); 1437 dot + 1);
1379 continue_stdin ();
1380 return; 1438 return;
1381 } 1439 }
1382 1440
@@ -1390,13 +1448,91 @@ queue (const char *hostname)
1390 hlen); 1448 hlen);
1391 req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 1449 req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1392 UINT16_MAX); 1450 UINT16_MAX);
1393 req->qe = GNUNET_NAMESTORE_records_lookup (ns, 1451 GNUNET_CRYPTO_hash (req->hostname,
1394 &req->zone->key, 1452 hlen,
1395 get_label (req), 1453 &hc);
1396 &ns_lookup_error_cb, 1454 if (GNUNET_OK !=
1397 req, 1455 GNUNET_CONTAINER_multihashmap_put (ns_pending,
1398 &ns_lookup_result_cb, 1456 &hc,
1399 req); 1457 req,
1458 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1461 "Duplicate hostname `%s' ignored\n",
1462 hostname);
1463 GNUNET_free (req);
1464 return;
1465 }
1466}
1467
1468
1469/**
1470 * We have completed the initial iteration over the namestore's database.
1471 * This function is called on each of the remaining records in
1472 * #move_to_queue to #queue() them, as we will simply not find existing
1473 * records for them any longer.
1474 *
1475 * @param cls NULL
1476 * @param key unused
1477 * @param value a `struct Request`
1478 * @return #GNUNET_OK (continue to iterate)
1479 */
1480static int
1481move_to_queue (void *cls,
1482 const struct GNUNET_HashCode *key,
1483 void *value)
1484{
1485 struct Request *req = value;
1486
1487 (void) cls;
1488 (void) key;
1489 insert_sorted (req);
1490 return GNUNET_OK;
1491}
1492
1493
1494/**
1495 * Iterate over all of the zones we care about and see which records
1496 * we may need to re-fetch when.
1497 *
1498 * @param cls NULL
1499 */
1500static void
1501iterate_zones (void *cls)
1502{
1503 static struct Zone *last;
1504
1505 (void) cls;
1506 zone_it = NULL;
1507 GNUNET_assert (NULL != zone_tail);
1508 if (zone_tail == last)
1509 {
1510 GNUNET_assert (NULL == t);
1511 /* Done iterating over relevant zones in NAMESTORE, move
1512 rest of hash map to work queue as well. */
1513 GNUNET_CONTAINER_multihashmap_iterate (ns_pending,
1514 &move_to_queue,
1515 NULL);
1516 GNUNET_CONTAINER_multihashmap_destroy (ns_pending);
1517 ns_pending = NULL;
1518 t = GNUNET_SCHEDULER_add_now (&process_queue,
1519 NULL);
1520 return;
1521 }
1522 if (NULL == last)
1523 last = zone_head;
1524 else
1525 last = last->next;
1526 ns_iterator_trigger_next = 1;
1527 zone_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1528 &last->key,
1529 &ns_lookup_error_cb,
1530 NULL,
1531 &ns_lookup_result_cb,
1532 last,
1533 &iterate_zones,
1534 NULL);
1535
1400} 1536}
1401 1537
1402 1538
@@ -1419,10 +1555,10 @@ process_stdin (void *cls)
1419 GNUNET_IDENTITY_disconnect (id); 1555 GNUNET_IDENTITY_disconnect (id);
1420 id = NULL; 1556 id = NULL;
1421 } 1557 }
1422 if (NULL != 1558 while (NULL !=
1423 fgets (hn, 1559 fgets (hn,
1424 sizeof (hn), 1560 sizeof (hn),
1425 stdin)) 1561 stdin))
1426 { 1562 {
1427 if (strlen(hn) > 0) 1563 if (strlen(hn) > 0)
1428 hn[strlen(hn)-1] = '\0'; /* eat newline */ 1564 hn[strlen(hn)-1] = '\0'; /* eat newline */
@@ -1441,12 +1577,9 @@ process_stdin (void *cls)
1441 GNUNET_YES)); 1577 GNUNET_YES));
1442 } 1578 }
1443 queue (hn); 1579 queue (hn);
1444 return;
1445 } 1580 }
1446 stdin_waiting = GNUNET_NO;
1447 fprintf (stderr, "\n"); 1581 fprintf (stderr, "\n");
1448 t = GNUNET_SCHEDULER_add_now (&process_queue, 1582 iterate_zones (NULL);
1449 NULL);
1450} 1583}
1451 1584
1452 1585
@@ -1496,14 +1629,13 @@ identity_cb (void *cls,
1496 { 1629 {
1497 if (NULL != zone_head) 1630 if (NULL != zone_head)
1498 { 1631 {
1499 stdin_waiting = GNUNET_YES;
1500 t = GNUNET_SCHEDULER_add_now (&process_stdin, 1632 t = GNUNET_SCHEDULER_add_now (&process_stdin,
1501 NULL); 1633 NULL);
1502 } 1634 }
1503 else 1635 else
1504 { 1636 {
1505 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1506 "Specified zone not found\n"); 1638 "No zone found\n");
1507 GNUNET_SCHEDULER_shutdown (); 1639 GNUNET_SCHEDULER_shutdown ();
1508 return; 1640 return;
1509 } 1641 }