@ -428,9 +428,16 @@ struct chan *new_chan(struct routing_state *rstate,
/* We hack a multimap into a uintmap to implement a minheap by cost.
/* We hack a multimap into a uintmap to implement a minheap by cost.
* This is relatively inefficient , containing an array for each cost
* This is relatively inefficient , containing an array for each cost
* value , assuming there aren ' t too many at same cost . FIXME :
* value , assuming there aren ' t too many at same cost .
* implement an array heap */
*
typedef UINTMAP ( struct node * * ) unvisited_t ;
* We further optimize by never freeing or shrinking these entries ,
* but delete by replacing with NULL . This means that we cache the
* lowest index which actually contains something , since others may
* contain empty arrays . */
struct unvisited {
u64 min_index ;
UINTMAP ( struct node * * ) map ;
} ;
static void clear_bfg ( struct node_map * nodes )
static void clear_bfg ( struct node_map * nodes )
{
{
@ -597,8 +604,31 @@ static bool hc_is_routable(struct routing_state *rstate,
& & ! is_chan_local_disabled ( rstate , chan ) ;
& & ! is_chan_local_disabled ( rstate , chan ) ;
}
}
static void unvisited_add ( struct unvisited * unvisited , struct amount_msat cost ,
struct node * * arr )
{
u64 idx = cost . millisatoshis ; /* Raw: uintmap needs u64 index */
if ( idx < unvisited - > min_index ) {
assert ( idx ) ; /* We don't allow sending 0 satoshis */
unvisited - > min_index = idx - 1 ;
}
uintmap_add ( & unvisited - > map , idx , arr ) ;
}
static struct node * * unvisited_get ( const struct unvisited * unvisited ,
struct amount_msat cost )
{
return uintmap_get ( & unvisited - > map , cost . millisatoshis ) ; /* Raw: uintmap */
}
static struct node * * unvisited_del ( struct unvisited * unvisited ,
struct amount_msat cost )
{
return uintmap_del ( & unvisited - > map , cost . millisatoshis ) ; /* Raw: uintmap */
}
static bool is_unvisited ( const struct node * node ,
static bool is_unvisited ( const struct node * node ,
const unvisited_t * unvisited )
const struct unvisited * unvisited )
{
{
struct node * * arr ;
struct node * * arr ;
struct amount_msat cost ;
struct amount_msat cost ;
@ -617,7 +647,7 @@ static bool is_unvisited(const struct node *node,
return false ;
return false ;
}
}
arr = uintmap _get ( unvisited , cost . millisatoshis ) ;
arr = unvisited _get ( unvisited , cost ) ;
for ( size_t i = 0 ; i < tal_count ( arr ) ; i + + ) {
for ( size_t i = 0 ; i < tal_count ( arr ) ; i + + ) {
if ( arr [ i ] = = node )
if ( arr [ i ] = = node )
return true ;
return true ;
@ -625,39 +655,24 @@ static bool is_unvisited(const struct node *node,
return false ;
return false ;
}
}
static void unvisited_add ( unvisited_t * unvisited , struct amount_msat cost ,
static void unvisited_del_node ( struct unvisited * unvisited ,
struct node * * arr )
{
uintmap_add ( unvisited , cost . millisatoshis , arr ) ; /* Raw: uintmap */
}
static struct node * * unvisited_del ( unvisited_t * unvisited ,
struct amount_msat cost )
{
return uintmap_del ( unvisited , cost . millisatoshis ) ; /* Raw: uintmap */
}
static void unvisited_del_node ( unvisited_t * unvisited ,
struct amount_msat cost ,
struct amount_msat cost ,
const struct node * node )
const struct node * node )
{
{
size_t i ;
struct node * * arr ;
struct node * * arr ;
/* Remove may reallocate, so we delete and re-add. */
arr = unvisited_get ( unvisited , cost ) ;
arr = unvisited_del ( unvisited , cost ) ;
for ( size_t i = 0 ; i < tal_count ( arr ) ; i + + ) {
for ( i = 0 ; arr [ i ] ! = node ; i + + )
if ( arr [ i ] = = node ) {
assert ( i < tal_count ( arr ) ) ;
arr [ i ] = NULL ;
return ;
tal_arr_remove ( & arr , i ) ;
}
if ( tal_count ( arr ) = = 0 )
}
tal_free ( arr ) ;
abort ( ) ;
else
unvisited_add ( unvisited , cost , arr ) ;
}
}
static void adjust_unvisited ( struct node * node ,
static void adjust_unvisited ( struct node * node ,
unvisited_t * unvisited ,
struct unvisited * unvisited ,
struct amount_msat cost_before ,
struct amount_msat cost_before ,
struct amount_msat total ,
struct amount_msat total ,
struct amount_msat risk ,
struct amount_msat risk ,
@ -674,17 +689,33 @@ static void adjust_unvisited(struct node *node,
node - > dijkstra . risk = risk ;
node - > dijkstra . risk = risk ;
/* Update map of unvisited nodes */
/* Update map of unvisited nodes */
arr = unvisited_del ( unvisited , cost_after ) ;
arr = unvisited_get ( unvisited , cost_after ) ;
if ( ! arr ) {
if ( arr ) {
struct node * * old_arr ;
/* Try for empty slot */
for ( size_t i = 0 ; i < tal_count ( arr ) ; i + + ) {
if ( arr [ i ] = = NULL ) {
arr [ i ] = node ;
return ;
}
}
/* Nope, expand */
old_arr = arr ;
tal_arr_expand ( & arr , node ) ;
if ( arr = = old_arr )
return ;
/* Realloc moved it; del and add again. */
unvisited_del ( unvisited , cost_after ) ;
} else {
arr = tal_arr ( unvisited , struct node * , 1 ) ;
arr = tal_arr ( unvisited , struct node * , 1 ) ;
arr [ 0 ] = node ;
arr [ 0 ] = node ;
} else
}
tal_arr_expand ( & arr , node ) ;
unvisited_add ( unvisited , cost_after , arr ) ;
unvisited_add ( unvisited , cost_after , arr ) ;
}
}
static void remove_unvisited ( struct node * node , unvisited_t * unvisited )
static void remove_unvisited ( struct node * node , struct unvisited * unvisited )
{
{
struct amount_msat cost ;
struct amount_msat cost ;
@ -704,7 +735,7 @@ static void remove_unvisited(struct node *node, unvisited_t *unvisited)
static void update_unvisited_neighbors ( struct routing_state * rstate ,
static void update_unvisited_neighbors ( struct routing_state * rstate ,
struct node * cur ,
struct node * cur ,
double riskfactor ,
double riskfactor ,
unvisited_t * unvisited )
struct unvisited * unvisited )
{
{
struct chan_map_iter i ;
struct chan_map_iter i ;
struct chan * chan ;
struct chan * chan ;
@ -746,20 +777,23 @@ static void update_unvisited_neighbors(struct routing_state *rstate,
}
}
}
}
static struct node * first_unvisited ( unvisited_t * unvisited )
static struct node * first_unvisited ( struct unvisited * unvisited )
{
{
u64 idx ;
struct node * * arr ;
struct node * * arr = uintmap_first ( unvisited , & idx ) ;
while ( ( arr = uintmap_after ( & unvisited - > map , & unvisited - > min_index ) ) ) {
for ( size_t i = 0 ; i < tal_count ( arr ) ; i + + )
if ( arr [ i ] )
return arr [ i ] ;
}
if ( arr )
return arr [ 0 ] ;
return NULL ;
return NULL ;
}
}
static void dijkstra ( struct routing_state * rstate ,
static void dijkstra ( struct routing_state * rstate ,
const struct node * dst ,
const struct node * dst ,
double riskfactor ,
double riskfactor ,
unvisited_t * unvisited )
struct unvisited * unvisited )
{
{
struct node * cur ;
struct node * cur ;
@ -854,18 +888,19 @@ static struct chan **build_route(const tal_t *ctx,
return route ;
return route ;
}
}
static unvisited_t * dijkstra_prepare ( const tal_t * ctx ,
static struct unvisited * dijkstra_prepare ( const tal_t * ctx ,
struct routing_state * rstate ,
struct routing_state * rstate ,
struct node * src ,
struct node * src ,
struct amount_msat msat )
struct amount_msat msat )
{
{
struct node_map_iter it ;
struct node_map_iter it ;
unvisited_t * unvisited ;
struct unvisited * unvisited ;
struct node * n ;
struct node * n ;
struct node * * arr ;
struct node * * arr ;
unvisited = tal ( ctx , unvisited_t ) ;
unvisited = tal ( tmpctx , struct unvisited ) ;
uintmap_init ( unvisited ) ;
uintmap_init ( & unvisited - > map ) ;
unvisited - > min_index = UINT64_MAX ;
/* Reset all the information. */
/* Reset all the information. */
for ( n = node_map_first ( rstate - > nodes , & it ) ;
for ( n = node_map_first ( rstate - > nodes , & it ) ;
@ -887,15 +922,15 @@ static unvisited_t *dijkstra_prepare(const tal_t *ctx,
return unvisited ;
return unvisited ;
}
}
static void dijkstra_cleanup ( unvisited_t * unvisited )
static void dijkstra_cleanup ( struct unvisited * unvisited )
{
{
struct node * * arr ;
struct node * * arr ;
u64 idx ;
u64 idx ;
/* uintmap uses malloc, so manual cleaning needed */
/* uintmap uses malloc, so manual cleaning needed */
while ( ( arr = uintmap_first ( unvisited , & idx ) ) ! = NULL ) {
while ( ( arr = uintmap_first ( & unvisited - > map , & idx ) ) ! = NULL ) {
tal_free ( arr ) ;
tal_free ( arr ) ;
uintmap_del ( unvisited , idx ) ;
uintmap_del ( & unvisited - > map , idx ) ;
}
}
tal_free ( unvisited ) ;
tal_free ( unvisited ) ;
}
}
@ -911,7 +946,7 @@ find_route_dijkstra(const tal_t *ctx, struct routing_state *rstate,
struct amount_msat * fee )
struct amount_msat * fee )
{
{
struct node * src , * dst ;
struct node * src , * dst ;
unvisited_t * unvisited ;
struct unvisited * unvisited ;
/* Note: we map backwards, since we know the amount of satoshi we want
/* Note: we map backwards, since we know the amount of satoshi we want
* at the end , and need to derive how much we need to send . */
* at the end , and need to derive how much we need to send . */
@ -2199,6 +2234,9 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate,
base_seed . u . u64 [ 0 ] = base_seed . u . u64 [ 1 ] = seed ;
base_seed . u . u64 [ 0 ] = base_seed . u . u64 [ 1 ] = seed ;
if ( amount_msat_eq ( msat , AMOUNT_MSAT ( 0 ) ) )
return NULL ;
/* Temporarily set excluded channels' capacity to zero. */
/* Temporarily set excluded channels' capacity to zero. */
for ( size_t i = 0 ; i < tal_count ( excluded ) ; i + + ) {
for ( size_t i = 0 ; i < tal_count ( excluded ) ; i + + ) {
struct chan * chan = get_channel ( rstate , & excluded [ i ] . scid ) ;
struct chan * chan = get_channel ( rstate , & excluded [ i ] . scid ) ;