/** * Close local key management. */ G_GNUC_COLD void keys_close(void) { values_close(); dbstore_close(db_keydata, settings_dht_db_dir(), db_keybase); db_keydata = NULL; if (keys) { hikset_foreach(keys, keys_free_kv, NULL); hikset_free_null(&keys); } kuid_atom_free_null(&kball.furthest); kuid_atom_free_null(&kball.closest); gnet_stats_set_general(GNR_DHT_KEYS_HELD, 0); gnet_stats_set_general(GNR_DHT_CACHED_KEYS_HELD, 0); cq_cancel(&kball_ev); cq_periodic_remove(&keys_periodic_ev); cq_periodic_remove(&keys_sync_ev); }
/** * Prune the database of banned GUIDs, removing expired entries. */ static void guid_prune_old(void) { if (GNET_PROPERTY(guid_debug)) g_debug("GUID pruning expired entries (%zu)", dbmw_count(db_guid)); dbmw_foreach_remove(db_guid, guid_prune_old_entries, NULL); gnet_stats_set_general(GNR_BANNED_GUID_HELD, dbmw_count(db_guid)); if (GNET_PROPERTY(guid_debug)) { g_debug("GUID pruned expired entries (%zu remaining)", dbmw_count(db_guid)); } }
/** * Prune the database, removing old entries not updated since at least * STABLE_EXPIRE seconds and which have less than STABLE_PROBA chance of * still being alive, given our probability density function. */ static void stable_prune_old(void) { if (GNET_PROPERTY(dht_stable_debug)) { g_debug("DHT STABLE pruning old stable node records (%lu)", (unsigned long) dbmw_count(db_lifedata)); } dbmw_foreach_remove(db_lifedata, prune_old, NULL); gnet_stats_set_general(GNR_DHT_STABLE_NODES_HELD, dbmw_count(db_lifedata)); if (GNET_PROPERTY(dht_stable_debug)) { g_debug("DHT STABLE pruned old stable node records (%lu remaining)", (unsigned long) dbmw_count(db_lifedata)); } dbstore_shrink(db_lifedata); }
/** * Prune the database, removing expired tokens. */ static void tcache_prune_old(void) { size_t pruned; if (GNET_PROPERTY(dht_tcache_debug)) { g_debug("DHT TCACHE pruning expired tokens (%zu)", dbmw_count(db_tokdata)); } pruned = dbmw_foreach_remove(db_tokdata, tk_prune_old, NULL); gnet_stats_set_general(GNR_DHT_CACHED_TOKENS_HELD, dbmw_count(db_tokdata)); if (GNET_PROPERTY(dht_tcache_debug)) { g_debug("DHT TCACHE pruned expired tokens (%zu pruned, %zu remaining)", pruned, dbmw_count(db_tokdata)); } }
/** * Recreate keyinfo data from persisted information. */ static G_GNUC_COLD void keys_init_keyinfo(void) { struct keys_create_context ctx; if (GNET_PROPERTY(dht_keys_debug)) { size_t count = dbmw_count(db_keydata); g_debug("DHT KEYS scanning %u persisted key%s", (unsigned) count, plural(count)); } ctx.our_kuid = get_our_kuid(); ctx.dbkeys = hset_create(HASH_KEY_FIXED, sizeof(uint64)); dbmw_foreach_remove(db_keydata, reload_ki, &ctx); if (GNET_PROPERTY(dht_keys_debug)) { size_t count = dbmw_count(db_keydata); g_debug("DHT KEYS kept %u key%s, now loading associated values", (unsigned) count, plural(count)); } /* * FIXME: * Unfortunately, we have to reset the keydata database for each of * the keys we're going to recreate, because the logic adding values * back to the key will fill each of the keydata appropriately, and it * expects the amount of values in the keyinfo and the keydata to match. * * Therefore, we need to rename the old keydata database, open a new one, * write empty keydata values in it, then discard the old keydata if * everything goes well. In case of a crash in the middle of the * restoration, we'll be able to recover by opening the old keydata first * if it exists. * * It is far from critical though: if we reset the keydata database and * we crash in the middle of the restore, then we'll lose all the persisted * keys and values and will simply restart with an empty storage. * * Given the contorsions needed to fix that, and the little value for * the user, just leaving a FIXME note. * --RAM, 2012-11-17 */ hikset_foreach(keys, keys_reset_keydata, NULL); values_init_data(ctx.dbkeys); hset_foreach(ctx.dbkeys, keys_free_dbkey, NULL); hset_free_null(&ctx.dbkeys); hikset_foreach_remove(keys, keys_discard_if_empty, NULL); dbmw_foreach_remove(db_keydata, keys_delete_if_empty, NULL); dbstore_compact(db_keydata); g_soft_assert_log(hikset_count(keys) == dbmw_count(db_keydata), "keys reloaded: %zu, key data persisted: %zu", hikset_count(keys), dbmw_count(db_keydata)); if (GNET_PROPERTY(dht_keys_debug)) { g_debug("DHT KEYS reloaded %zu key%s", hikset_count(keys), plural(hikset_count(keys))); } gnet_stats_set_general(GNR_DHT_KEYS_HELD, hikset_count(keys)); }
/** * Update k-ball information. */ void keys_update_kball(void) { kuid_t *our_kuid = get_our_kuid(); knode_t **kvec; int kcnt; patricia_t *pt; int i; WALLOC_ARRAY(kvec, KDA_K); kcnt = dht_fill_closest(our_kuid, kvec, KDA_K, NULL, TRUE); kball.seeded = TRUE; /* * If we know of no alive nodes yet, request any node we have in the * routing table, even "zombies". If we get less than KDA_K of these, * we definitively know not enough about the DHT structure yet! */ if (0 == kcnt) { kcnt = dht_fill_closest(our_kuid, kvec, KDA_K, NULL, FALSE); if (kcnt < KDA_K) kball.seeded = FALSE; } pt = patricia_create(KUID_RAW_BITSIZE); for (i = 0; i < kcnt; i++) { knode_t *kn = kvec[i]; patricia_insert(pt, kn->id, kn); } if (patricia_count(pt)) { knode_t *furthest = patricia_furthest(pt, our_kuid); knode_t *closest = patricia_closest(pt, our_kuid); size_t fbits; size_t cbits; kuid_atom_change(&kball.furthest, furthest->id); kuid_atom_change(&kball.closest, closest->id); fbits = kuid_common_prefix(kball.furthest, our_kuid); cbits = kuid_common_prefix(kball.closest, our_kuid); g_assert(fbits <= cbits); g_assert(cbits <= KUID_RAW_BITSIZE); if (GNET_PROPERTY(dht_debug)) { uint8 width = cbits - fbits; g_debug("DHT %sk-ball %s %u bit%s (was %u-bit wide)", kball.seeded ? "" : "(not seeded yet) ", width == kball.width ? "remained at" : width > kball.width ? "expanded to" : "shrunk to", width, plural(width), kball.width); g_debug("DHT k-ball closest (%zu common bit%s) is %s", cbits, plural(cbits), knode_to_string(closest)); g_debug("DHT k-ball furthest (%zu common bit%s) is %s", fbits, plural(fbits), knode_to_string(furthest)); } STATIC_ASSERT(KUID_RAW_BITSIZE < 256); kball.furthest_bits = fbits & 0xff; kball.closest_bits = cbits & 0xff; kball.width = (cbits - fbits) & 0xff; kball.theoretical_bits = dht_get_kball_furthest() & 0xff; gnet_stats_set_general(GNR_DHT_KBALL_FURTHEST, kball.furthest_bits); gnet_stats_set_general(GNR_DHT_KBALL_CLOSEST, kball.closest_bits); } WFREE_ARRAY(kvec, KDA_K); patricia_destroy(pt); }