From 27d9b75456ca2cdc54c4d596803e0471776bdcda Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 16 Sep 2019 20:13:51 +0930 Subject: [PATCH] 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 --- gossipd/routing.c | 50 ++++++++++++++++++++++++++++++++++++++--------- gossipd/routing.h | 49 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 16 deletions(-) diff --git a/gossipd/routing.c b/gossipd/routing.c index 43ffca6d3..8fa6c3e10 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -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); } diff --git a/gossipd/routing.h b/gossipd/routing.h index c0e01e80e..ec64b4fb6 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -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 */