mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
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:
parent
70c4ac6d74
commit
27d9b75456
@ -163,6 +163,10 @@ static void destroy_routing_state(struct routing_state *rstate)
|
|||||||
chan;
|
chan;
|
||||||
chan = uintmap_after(&rstate->chanmap, &idx))
|
chan = uintmap_after(&rstate->chanmap, &idx))
|
||||||
free_chan(rstate, chan);
|
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
|
#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->nodes->raw);
|
||||||
memleak_remove_htable(memtable, &rstate->pending_node_map->raw);
|
memleak_remove_htable(memtable, &rstate->pending_node_map->raw);
|
||||||
memleak_remove_htable(memtable, &rstate->pending_cannouncements.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);
|
for (n = node_map_first(rstate->nodes, &nit);
|
||||||
n;
|
n;
|
||||||
@ -204,7 +209,7 @@ struct routing_state *new_routing_state(const tal_t *ctx,
|
|||||||
|
|
||||||
uintmap_init(&rstate->chanmap);
|
uintmap_init(&rstate->chanmap);
|
||||||
uintmap_init(&rstate->unupdated_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);
|
uintmap_init(&rstate->txout_failures);
|
||||||
|
|
||||||
rstate->pending_node_map = tal(ctx, struct pending_node_map);
|
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! */
|
/* We make sure that free_chan is called on this chan! */
|
||||||
static void destroy_chan_check(struct chan *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
|
#endif
|
||||||
|
|
||||||
@ -401,11 +406,8 @@ void free_chan(struct routing_state *rstate, struct chan *chan)
|
|||||||
|
|
||||||
uintmap_del(&rstate->chanmap, chan->scid.u64);
|
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
|
#if DEVELOPER
|
||||||
chan->scid.u64 = (u64)chan;
|
chan->sat.satoshis = (u64)chan; /* Raw: dev-hack */
|
||||||
#endif
|
#endif
|
||||||
tal_free(chan);
|
tal_free(chan);
|
||||||
}
|
}
|
||||||
@ -431,6 +433,36 @@ static void bad_gossip_order(const u8 *msg, const char *source,
|
|||||||
details);
|
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,
|
struct chan *new_chan(struct routing_state *rstate,
|
||||||
const struct short_channel_id *scid,
|
const struct short_channel_id *scid,
|
||||||
const struct node_id *id1,
|
const struct node_id *id1,
|
||||||
@ -471,6 +503,9 @@ struct chan *new_chan(struct routing_state *rstate,
|
|||||||
init_half_chan(rstate, chan, !n1idx);
|
init_half_chan(rstate, chan, !n1idx);
|
||||||
|
|
||||||
uintmap_add(&rstate->chanmap, scid->u64, chan);
|
uintmap_add(&rstate->chanmap, scid->u64, chan);
|
||||||
|
|
||||||
|
/* Initialize shadow structure if it's local */
|
||||||
|
new_local_chan(rstate, chan);
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2678,9 +2713,6 @@ void remove_all_gossip(struct routing_state *rstate)
|
|||||||
/* Now free all the channels. */
|
/* Now free all the channels. */
|
||||||
while ((c = uintmap_first(&rstate->chanmap, &index)) != NULL) {
|
while ((c = uintmap_first(&rstate->chanmap, &index)) != NULL) {
|
||||||
uintmap_del(&rstate->chanmap, index);
|
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);
|
tal_free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,17 @@ struct chan {
|
|||||||
struct amount_sat sat;
|
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)! */
|
/* Use this instead of tal_free(chan)! */
|
||||||
void free_chan(struct routing_state *rstate, struct chan *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
|
/* 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)
|
static inline const struct short_channel_id *chan_map_scid(const struct chan *c)
|
||||||
{
|
{
|
||||||
return &c->scid;
|
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);
|
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
|
/* 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,
|
* array, with empty buckets NULL. For larger, we use a proper hash table,
|
||||||
* with the extra allocation that implies. */
|
* with the extra allocation that implies. */
|
||||||
@ -244,8 +271,8 @@ struct routing_state {
|
|||||||
* checks if we get another announcement for the same scid. */
|
* checks if we get another announcement for the same scid. */
|
||||||
UINTMAP(bool) txout_failures;
|
UINTMAP(bool) txout_failures;
|
||||||
|
|
||||||
/* A map of (local) disabled channels by short_channel_ids */
|
/* A map of local channels by short_channel_ids */
|
||||||
struct chan_map local_disabled_map;
|
struct local_chan_map local_chan_map;
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
/* Override local time for gossip messages */
|
/* 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);
|
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
|
/* 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.
|
* 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,
|
static inline bool is_chan_local_disabled(struct routing_state *rstate,
|
||||||
const struct chan *chan)
|
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,
|
static inline void local_disable_chan(struct routing_state *rstate,
|
||||||
const struct chan *chan)
|
const struct chan *chan)
|
||||||
{
|
{
|
||||||
if (!is_chan_local_disabled(rstate, chan))
|
struct local_chan *local_chan = is_local_chan(rstate, chan);
|
||||||
chan_map_add(&rstate->local_disabled_map, chan);
|
local_chan->local_disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void local_enable_chan(struct routing_state *rstate,
|
static inline void local_enable_chan(struct routing_state *rstate,
|
||||||
const struct chan *chan)
|
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 */
|
/* Helper to convert on-wire addresses format to wireaddrs array */
|
||||||
|
Loading…
Reference in New Issue
Block a user