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. */
static bool node_uses_chan_map(const struct node *node)
{
/* This is a layering violation: last entry in htable is the table ptr,
* which is never NULL */
return node->chans.arr[NUM_IMMEDIATE_CHANS] != NULL;
return node->chan_map;
}
/* When simple array fills, use a htable. */
static void convert_node_to_chan_map(struct node *node)
{
struct chan *chans[NUM_IMMEDIATE_CHANS];
memcpy(chans, node->chans.arr, sizeof(chans));
chan_map_init_sized(&node->chans.map, NUM_IMMEDIATE_CHANS + 1);
assert(!node_uses_chan_map(node));
node->chan_map = tal(node, struct chan_map);
chan_map_init_sized(node->chan_map, ARRAY_SIZE(node->chan_arr) + 1);
assert(node_uses_chan_map(node));
for (size_t i = 0; i < ARRAY_SIZE(chans); i++)
chan_map_add(&node->chans.map, chans[i]);
for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); 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)
{
if (!node_uses_chan_map(node)) {
for (size_t i = 0; i < NUM_IMMEDIATE_CHANS; i++) {
if (node->chans.arr[i] == NULL) {
node->chans.arr[i] = chan;
for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); i++) {
if (node->chan_arr[i] == NULL) {
node->chan_arr[i] = chan;
return;
}
}
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,
struct chan_map_iter *i)
{
while (i->i.off < NUM_IMMEDIATE_CHANS) {
if (node->chans.arr[i->i.off])
return node->chans.arr[i->i.off];
while (i->i.off < ARRAY_SIZE(node->chan_arr)) {
if (node->chan_arr[i->i.off])
return node->chan_arr[i->i.off];
i->i.off++;
}
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 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)
@ -194,7 +193,7 @@ struct chan *next_chan(const struct node *node, struct chan_map_iter *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)
@ -241,7 +240,7 @@ static void memleak_help_routing_tables(struct htable *memtable,
n;
n = node_map_next(rstate->nodes, &nit)) {
if (node_uses_chan_map(n))
memleak_scan_htable(memtable, &n->chans.map.raw);
memleak_scan_htable(memtable, &n->chan_map->raw);
}
}
#endif /* DEVELOPER */
@ -360,7 +359,7 @@ static void destroy_node(struct node *node, struct routing_state *rstate)
/* Free htable if we need. */
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,
@ -378,7 +377,8 @@ static struct node *new_node(struct routing_state *rstate,
n = tal(rstate, struct node);
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->rgraph);
n->tokens = TOKEN_MAX;
@ -476,16 +476,16 @@ static void remove_chan_from_node(struct routing_state *rstate,
if (!node_uses_chan_map(node)) {
num_chans = 0;
for (size_t i = 0; i < NUM_IMMEDIATE_CHANS; i++) {
if (node->chans.arr[i] == chan)
node->chans.arr[i] = NULL;
else if (node->chans.arr[i] != NULL)
for (size_t i = 0; i < ARRAY_SIZE(node->chan_arr); i++) {
if (node->chan_arr[i] == chan)
node->chan_arr[i] = NULL;
else if (node->chan_arr[i] != NULL)
num_chans++;
}
} else {
if (!chan_map_del(&node->chans.map, chan))
if (!chan_map_del(node->chan_map, chan))
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) */
@ -2078,7 +2078,7 @@ void remove_all_gossip(struct routing_state *rstate)
while ((n = node_map_first(rstate->nodes, &nit)) != NULL) {
tal_del_destructor2(n, destroy_node, rstate);
if (node_uses_chan_map(n))
chan_map_clear(&n->chans.map);
chan_map_clear(n->chan_map);
node_map_del(rstate->nodes, 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);
/* 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_id id;
@ -117,10 +112,15 @@ struct node {
u8 tokens;
/* Channels connecting us to other nodes */
union {
struct chan_map map;
struct chan *arr[NUM_IMMEDIATE_CHANS+1];
} chans;
/* 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 allocations that implies.
*
* 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);