gossipd: add shadow structure for local chans.

Normally we'd put a pointer into struct half_chan for local
information, but it would be NULL on 99.99% of nodes.  Instead, keep a
separate hash table.

This immediately subsumes the previous "map of local-disabled
channels", and will be enhanced further.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-09-16 20:13:51 +09:30
parent 70c4ac6d74
commit 27d9b75456
2 changed files with 83 additions and 16 deletions

View File

@ -163,6 +163,10 @@ static void destroy_routing_state(struct routing_state *rstate)
chan;
chan = uintmap_after(&rstate->chanmap, &idx))
free_chan(rstate, chan);
/* Free up our htables */
pending_cannouncement_map_clear(&rstate->pending_cannouncements);
local_chan_map_clear(&rstate->local_chan_map);
}
#if DEVELOPER
@ -175,6 +179,7 @@ static void memleak_help_routing_tables(struct htable *memtable,
memleak_remove_htable(memtable, &rstate->nodes->raw);
memleak_remove_htable(memtable, &rstate->pending_node_map->raw);
memleak_remove_htable(memtable, &rstate->pending_cannouncements.raw);
memleak_remove_htable(memtable, &rstate->local_chan_map.raw);
for (n = node_map_first(rstate->nodes, &nit);
n;
@ -204,7 +209,7 @@ struct routing_state *new_routing_state(const tal_t *ctx,
uintmap_init(&rstate->chanmap);
uintmap_init(&rstate->unupdated_chanmap);
chan_map_init(&rstate->local_disabled_map);
local_chan_map_init(&rstate->local_chan_map);
uintmap_init(&rstate->txout_failures);
rstate->pending_node_map = tal(ctx, struct pending_node_map);
@ -388,7 +393,7 @@ static void remove_chan_from_node(struct routing_state *rstate,
/* We make sure that free_chan is called on this chan! */
static void destroy_chan_check(struct chan *chan)
{
assert(chan->scid.u64 == (u64)chan);
assert(chan->sat.satoshis == (u64)chan); /* Raw: dev-hack */
}
#endif
@ -401,11 +406,8 @@ void free_chan(struct routing_state *rstate, struct chan *chan)
uintmap_del(&rstate->chanmap, chan->scid.u64);
/* Remove from local_disabled_map if it's there. */
chan_map_del(&rstate->local_disabled_map, chan);
#if DEVELOPER
chan->scid.u64 = (u64)chan;
chan->sat.satoshis = (u64)chan; /* Raw: dev-hack */
#endif
tal_free(chan);
}
@ -431,6 +433,36 @@ static void bad_gossip_order(const u8 *msg, const char *source,
details);
}
static void destroy_local_chan(struct local_chan *local_chan,
struct routing_state *rstate)
{
if (!local_chan_map_del(&rstate->local_chan_map, local_chan))
abort();
}
static struct local_chan *new_local_chan(struct routing_state *rstate,
struct chan *chan)
{
int direction;
struct local_chan *local_chan;
if (node_id_eq(&chan->nodes[0]->id, &rstate->local_id))
direction = 0;
else if (node_id_eq(&chan->nodes[1]->id, &rstate->local_id))
direction = 1;
else
return NULL;
local_chan = tal(chan, struct local_chan);
local_chan->chan = chan;
local_chan->direction = direction;
local_chan->local_disabled = false;
local_chan_map_add(&rstate->local_chan_map, local_chan);
tal_add_destructor2(local_chan, destroy_local_chan, rstate);
return local_chan;
}
struct chan *new_chan(struct routing_state *rstate,
const struct short_channel_id *scid,
const struct node_id *id1,
@ -471,6 +503,9 @@ struct chan *new_chan(struct routing_state *rstate,
init_half_chan(rstate, chan, !n1idx);
uintmap_add(&rstate->chanmap, scid->u64, chan);
/* Initialize shadow structure if it's local */
new_local_chan(rstate, chan);
return chan;
}
@ -2678,9 +2713,6 @@ void remove_all_gossip(struct routing_state *rstate)
/* Now free all the channels. */
while ((c = uintmap_first(&rstate->chanmap, &index)) != NULL) {
uintmap_del(&rstate->chanmap, index);
/* Remove from local_disabled_map if it's there. */
chan_map_del(&rstate->local_disabled_map, c);
tal_free(c);
}

View File

@ -57,6 +57,17 @@ struct chan {
struct amount_sat sat;
};
/* Shadow structure for local channels: owned by the chan above, but kept
* separately to keep `struct chan` minimal since there may be millions
* of non-local channels. */
struct local_chan {
struct chan *chan;
int direction;
/* We soft-disable local channels when a peer disconnects */
bool local_disabled;
};
/* Use this instead of tal_free(chan)! */
void free_chan(struct routing_state *rstate, struct chan *chan);
@ -78,7 +89,7 @@ static inline bool is_halfchan_enabled(const struct half_chan *hc)
}
/* Container for per-node channel pointers. Better cache performance
* than uintmap, and we don't need ordering. */
* than uintmap, and we don't need ordering. */
static inline const struct short_channel_id *chan_map_scid(const struct chan *c)
{
return &c->scid;
@ -98,6 +109,22 @@ 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);
/* Container for local channel pointers. */
static inline const struct short_channel_id *local_chan_map_scid(const struct local_chan *local_chan)
{
return &local_chan->chan->scid;
}
static inline bool local_chan_eq_scid(const struct local_chan *local_chan,
const struct short_channel_id *scid)
{
return short_channel_id_eq(scid, &local_chan->chan->scid);
}
HTABLE_DEFINE_TYPE(struct local_chan,
local_chan_map_scid, hash_scid, local_chan_eq_scid,
local_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. */
@ -244,8 +271,8 @@ struct routing_state {
* checks if we get another announcement for the same scid. */
UINTMAP(bool) txout_failures;
/* A map of (local) disabled channels by short_channel_ids */
struct chan_map local_disabled_map;
/* A map of local channels by short_channel_ids */
struct local_chan_map local_chan_map;
#if DEVELOPER
/* Override local time for gossip messages */
@ -416,26 +443,34 @@ bool handle_local_add_channel(struct routing_state *rstate, const u8 *msg,
*/
struct timeabs gossip_time_now(const struct routing_state *rstate);
static inline struct local_chan *is_local_chan(struct routing_state *rstate,
const struct chan *chan)
{
return local_chan_map_get(&rstate->local_chan_map, &chan->scid);
}
/* Because we can have millions of channels, and we only want a local_disable
* flag on ones connected to us, we keep a separate hashtable for that flag.
*/
static inline bool is_chan_local_disabled(struct routing_state *rstate,
const struct chan *chan)
{
return chan_map_get(&rstate->local_disabled_map, &chan->scid) != NULL;
struct local_chan *local_chan = is_local_chan(rstate, chan);
return local_chan && local_chan->local_disabled;
}
static inline void local_disable_chan(struct routing_state *rstate,
const struct chan *chan)
{
if (!is_chan_local_disabled(rstate, chan))
chan_map_add(&rstate->local_disabled_map, chan);
struct local_chan *local_chan = is_local_chan(rstate, chan);
local_chan->local_disabled = true;
}
static inline void local_enable_chan(struct routing_state *rstate,
const struct chan *chan)
{
chan_map_del(&rstate->local_disabled_map, chan);
struct local_chan *local_chan = is_local_chan(rstate, chan);
local_chan->local_disabled = false;
}
/* Helper to convert on-wire addresses format to wireaddrs array */