Example #1
0
/**
 * 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);
}
Example #2
0
/**
 * 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));
	}
}
Example #3
0
/**
 * 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);
}
Example #4
0
/**
 * 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));
	}
}
Example #5
0
/**
 * 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));
}
Example #6
0
/**
 * 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);
}