/** * Build the PATRICIA that maps a message name string into our internal * message ID. */ static void g2_msg_build_map(void) { uint i; STATIC_ASSERT(G2_MSG_MAX == G_N_ELEMENTS(g2_msg_english_names)); STATIC_ASSERT(G2_MSG_MAX == G_N_ELEMENTS(g2_msg_symbolic_names)); g_assert(NULL == g2_msg_pt); /* * We must be prepared to handle all the possible packet names, not just * the ones we know. Therefore, the PATRICIA key size is computed to be * able to handle the maximum architected size. */ g2_msg_pt = patricia_create(G2_FRAME_NAME_LEN_MAX * 8); /* Size in bits */ for (i = 0; i < G_N_ELEMENTS(g2_msg_symbolic_names); i++) { const char *key = g2_msg_symbolic_names[i]; size_t len = strlen(key); patricia_insert_k(g2_msg_pt, key, len * 8, int_to_pointer(i)); } }
/** * Create a map implemented as a PATRICIA tree with constant-width keys. * * @param keybits the size of all the keys, in bits. */ map_t * map_create_patricia(size_t keybits) { map_t *m; WALLOC(m); m->magic = MAP_MAGIC; m->type = MAP_PATRICIA; m->u.pt = patricia_create(keybits); return m; }
/* * Offload keys to remote node, as appropriate. * * Firstly we only consider remote nodes whose KUID falls within our k-ball. * * Secondly, we are only considering remote nodes that end-up being in our * routing table (i.e. ones which are close enough to us to get room in the * table, which also means they're not firewalled nor going to shutdown soon). * This is normally ensured by our caller. * * Thirdly, we are only going to consider keys closer to the node than we are * and for which we are the closest among our k-closest nodes, to avoid too * many redundant STORE operations. */ void keys_offload(const knode_t *kn) { struct offload_context ctx; unsigned n; knode_t *kclosest[KDA_K]; /* Our known k-closest nodes */ bool debug; knode_check(kn); if (kn->flags & (KNODE_F_FIREWALLED | KNODE_F_SHUTDOWNING)) return; if ( !dht_bootstrapped() || /* Not bootstrapped */ !keys_within_kball(kn->id) || /* Node KUID outside our k-ball */ 0 == hikset_count(keys) /* No keys held */ ) return; debug = GNET_PROPERTY(dht_storage_debug) > 1 || GNET_PROPERTY(dht_publish_debug) > 1; if (debug) g_debug("DHT preparing key offloading to %s", knode_to_string(kn)); gnet_stats_inc_general(GNR_DHT_KEY_OFFLOADING_CHECKS); ctx.our_kuid = get_our_kuid(); ctx.remote_kuid = kn->id; ctx.found = NULL; ctx.count = 0; /* * We need to have KDA_K closest known alive neighbours in order to * be able to select proper keys to offload. * * Note that we make sure to NOT include the new node in our k-closest set * since it would always be closer than ourselves to keys we wish to * offload to it... */ n = dht_fill_closest(ctx.our_kuid, kclosest, G_N_ELEMENTS(kclosest), ctx.remote_kuid, TRUE); if (n < G_N_ELEMENTS(kclosest)) { if (debug) g_warning("DHT got only %u closest alive nodes, cannot offload", n); return; } /* * Prepare a PATRICIA containing the ID of our k-closest alive nodes * plus ourselves. */ ctx.kclosest = patricia_create(KUID_RAW_BITSIZE); for (n = 0; n < G_N_ELEMENTS(kclosest); n++) { patricia_insert(ctx.kclosest, kclosest[n]->id, kclosest[n]->id); } patricia_insert(ctx.kclosest, ctx.our_kuid, ctx.our_kuid); /* * Select offloading candidate keys. */ hikset_foreach(keys, keys_offload_prepare, &ctx); patricia_destroy(ctx.kclosest); if (debug) { g_debug("DHT found %u/%zu offloading candidate%s", ctx.count, hikset_count(keys), plural(ctx.count)); } if (ctx.count) publish_offload(kn, ctx.found); pslist_free_null(&ctx.found); }
/** * 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); }