gossipd: use pointer to hash table for channels in node.

We actually reduce the size of struct node by 1 pointer, which
is mildly smaller.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2023-01-12 11:42:17 +10:30
parent 4200371020
commit 94e8ce030a
2 changed files with 37 additions and 37 deletions

View File

@@ -134,44 +134,43 @@ static struct node_map *new_node_map(const tal_t *ctx)
/* We use a simple array (with NULL entries) until we have too many. */ /* We use a simple array (with NULL entries) until we have too many. */
static bool node_uses_chan_map(const struct node *node) static bool node_uses_chan_map(const struct node *node)
{ {
/* This is a layering violation: last entry in htable is the table ptr, return node->chan_map;
* which is never NULL */
return node->chans.arr[NUM_IMMEDIATE_CHANS] != NULL;
} }
/* When simple array fills, use a htable. */ /* When simple array fills, use a htable. */
static void convert_node_to_chan_map(struct node *node) static void convert_node_to_chan_map(struct node *node)
{ {
struct chan *chans[NUM_IMMEDIATE_CHANS]; assert(!node_uses_chan_map(node));
node->chan_map = tal(node, struct chan_map);
memcpy(chans, node->chans.arr, sizeof(chans)); chan_map_init_sized(node->chan_map, ARRAY_SIZE(node->chan_arr) + 1);
chan_map_init_sized(&node->chans.map, NUM_IMMEDIATE_CHANS + 1);
assert(node_uses_chan_map(node)); assert(node_uses_chan_map(node));
for (size_t i = 0; i < ARRAY_SIZE(chans); i++) for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); i++) {
chan_map_add(&node->chans.map, chans[i]); chan_map_add(node->chan_map, node->chan_arr[i]);
node->chan_arr[i] = NULL;
}
} }
static void add_chan(struct node *node, struct chan *chan) static void add_chan(struct node *node, struct chan *chan)
{ {
if (!node_uses_chan_map(node)) { if (!node_uses_chan_map(node)) {
for (size_t i = 0; i < NUM_IMMEDIATE_CHANS; i++) { for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); i++) {
if (node->chans.arr[i] == NULL) { if (node->chan_arr[i] == NULL) {
node->chans.arr[i] = chan; node->chan_arr[i] = chan;
return; return;
} }
} }
convert_node_to_chan_map(node); convert_node_to_chan_map(node);
} }
chan_map_add(&node->chans.map, chan); chan_map_add(node->chan_map, chan);
} }
static struct chan *next_chan_arr(const struct node *node, static struct chan *next_chan_arr(const struct node *node,
struct chan_map_iter *i) struct chan_map_iter *i)
{ {
while (i->i.off < NUM_IMMEDIATE_CHANS) { while (i->i.off < ARRAY_SIZE(node->chan_arr)) {
if (node->chans.arr[i->i.off]) if (node->chan_arr[i->i.off])
return node->chans.arr[i->i.off]; return node->chan_arr[i->i.off];
i->i.off++; i->i.off++;
} }
return NULL; return NULL;
@@ -184,7 +183,7 @@ struct chan *first_chan(const struct node *node, struct chan_map_iter *i)
return next_chan_arr(node, i); return next_chan_arr(node, i);
} }
return chan_map_first(&node->chans.map, i); return chan_map_first(node->chan_map, i);
} }
struct chan *next_chan(const struct node *node, struct chan_map_iter *i) struct chan *next_chan(const struct node *node, struct chan_map_iter *i)
@@ -194,7 +193,7 @@ struct chan *next_chan(const struct node *node, struct chan_map_iter *i)
return next_chan_arr(node, i); return next_chan_arr(node, i);
} }
return chan_map_next(&node->chans.map, i); return chan_map_next(node->chan_map, i);
} }
static void destroy_routing_state(struct routing_state *rstate) static void destroy_routing_state(struct routing_state *rstate)
@@ -241,7 +240,7 @@ static void memleak_help_routing_tables(struct htable *memtable,
n; n;
n = node_map_next(rstate->nodes, &nit)) { n = node_map_next(rstate->nodes, &nit)) {
if (node_uses_chan_map(n)) if (node_uses_chan_map(n))
memleak_scan_htable(memtable, &n->chans.map.raw); memleak_scan_htable(memtable, &n->chan_map->raw);
} }
} }
#endif /* DEVELOPER */ #endif /* DEVELOPER */
@@ -360,7 +359,7 @@ static void destroy_node(struct node *node, struct routing_state *rstate)
/* Free htable if we need. */ /* Free htable if we need. */
if (node_uses_chan_map(node)) if (node_uses_chan_map(node))
chan_map_clear(&node->chans.map); chan_map_clear(node->chan_map);
} }
struct node *get_node(struct routing_state *rstate, struct node *get_node(struct routing_state *rstate,
@@ -378,7 +377,8 @@ static struct node *new_node(struct routing_state *rstate,
n = tal(rstate, struct node); n = tal(rstate, struct node);
n->id = *id; n->id = *id;
memset(n->chans.arr, 0, sizeof(n->chans.arr)); memset(n->chan_arr, 0, sizeof(n->chan_arr));
n->chan_map = NULL;
broadcastable_init(&n->bcast); broadcastable_init(&n->bcast);
broadcastable_init(&n->rgraph); broadcastable_init(&n->rgraph);
n->tokens = TOKEN_MAX; n->tokens = TOKEN_MAX;
@@ -476,16 +476,16 @@ static void remove_chan_from_node(struct routing_state *rstate,
if (!node_uses_chan_map(node)) { if (!node_uses_chan_map(node)) {
num_chans = 0; num_chans = 0;
for (size_t i = 0; i < NUM_IMMEDIATE_CHANS; i++) { for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); i++) {
if (node->chans.arr[i] == chan) if (node->chan_arr[i] == chan)
node->chans.arr[i] = NULL; node->chan_arr[i] = NULL;
else if (node->chans.arr[i] != NULL) else if (node->chan_arr[i] != NULL)
num_chans++; num_chans++;
} }
} else { } else {
if (!chan_map_del(&node->chans.map, chan)) if (!chan_map_del(node->chan_map, chan))
abort(); abort();
num_chans = chan_map_count(&node->chans.map); num_chans = chan_map_count(node->chan_map);
} }
/* Last channel? Simply delete node (and associated announce) */ /* Last channel? Simply delete node (and associated announce) */
@@ -2078,7 +2078,7 @@ void remove_all_gossip(struct routing_state *rstate)
while ((n = node_map_first(rstate->nodes, &nit)) != NULL) { while ((n = node_map_first(rstate->nodes, &nit)) != NULL) {
tal_del_destructor2(n, destroy_node, rstate); tal_del_destructor2(n, destroy_node, rstate);
if (node_uses_chan_map(n)) if (node_uses_chan_map(n))
chan_map_clear(&n->chans.map); chan_map_clear(n->chan_map);
node_map_del(rstate->nodes, n); node_map_del(rstate->nodes, n);
tal_free(n); tal_free(n);
} }

View File

@@ -98,11 +98,6 @@ static inline bool chan_eq_scid(const struct chan *c,
HTABLE_DEFINE_TYPE(struct chan, chan_map_scid, hash_scid, chan_eq_scid, chan_map); HTABLE_DEFINE_TYPE(struct chan, chan_map_scid, hash_scid, chan_eq_scid, chan_map);
/* For a small number of channels (by far the most common) we use a simple
* array, with empty buckets NULL. For larger, we use a proper hash table,
* with the extra allocation that implies. */
#define NUM_IMMEDIATE_CHANS (sizeof(struct chan_map) / sizeof(struct chan *) - 1)
struct node { struct node {
struct node_id id; struct node_id id;
@@ -117,10 +112,15 @@ struct node {
u8 tokens; u8 tokens;
/* Channels connecting us to other nodes */ /* Channels connecting us to other nodes */
union { /* For a small number of channels (by far the most common) we
struct chan_map map; * use a simple array, with empty buckets NULL. For larger, we use a
struct chan *arr[NUM_IMMEDIATE_CHANS+1]; * proper hash table, with the extra allocations that implies.
} chans; *
* As of November 2022, 5 or 6 gives the optimal size.
*/
struct chan *chan_arr[6];
/* If we have more than that, we use a hash. */
struct chan_map *chan_map;
}; };
const struct node_id *node_map_keyof_node(const struct node *n); const struct node_id *node_map_keyof_node(const struct node *n);