mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-18 22:54:25 +01:00
plugins/renepay/dijkstra: improve API to remove global.
The global is an *internal* hack because dijkstra_item_mover doesn't take a context arg! It should be used with care. Easy, since all the accessors exist: we just hand in the struct dijkstra. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -2,6 +2,22 @@
|
||||
#include "config.h"
|
||||
#include <plugins/renepay/dijkstra.h>
|
||||
|
||||
/* In the heap we keep node idx, but in this structure we keep the distance
|
||||
* value associated to every node, and their position in the heap as a pointer
|
||||
* so that we can update the nodes inside the heap when the distance label is
|
||||
* changed.
|
||||
*
|
||||
* Therefore this is no longer a multipurpose heap, the node_idx must be an
|
||||
* index between 0 and less than max_num_nodes. */
|
||||
struct dijkstra {
|
||||
//
|
||||
s64 *distance;
|
||||
u32 *base;
|
||||
u32 **heapptr;
|
||||
size_t heapsize;
|
||||
struct gheap_ctx gheap_ctx;
|
||||
};
|
||||
|
||||
static const s64 INFINITE = INT64_MAX;
|
||||
|
||||
/* Required a global dijkstra for gheap. */
|
||||
@@ -29,146 +45,142 @@ static void dijkstra_item_mover(void *const dst, const void *const src)
|
||||
global_dijkstra->heapptr[src_idx] = dst;
|
||||
}
|
||||
|
||||
/* Destructor for global dijkstra. The valid free state is signalled with a
|
||||
* NULL ptr. */
|
||||
static void dijkstra_destroy(struct dijkstra *ptr UNUSED)
|
||||
{
|
||||
global_dijkstra=NULL;
|
||||
}
|
||||
|
||||
/* Manually release dijkstra resources. */
|
||||
void dijkstra_free(void)
|
||||
{
|
||||
if(global_dijkstra)
|
||||
{
|
||||
global_dijkstra = tal_free(global_dijkstra);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocation of resources for the heap. */
|
||||
void dijkstra_malloc(const tal_t *ctx, const size_t max_num_nodes)
|
||||
struct dijkstra *dijkstra_new(const tal_t *ctx, size_t max_num_nodes)
|
||||
{
|
||||
dijkstra_free();
|
||||
struct dijkstra *dijkstra = tal(ctx, struct dijkstra);
|
||||
|
||||
global_dijkstra = tal(ctx,struct dijkstra);
|
||||
tal_add_destructor(global_dijkstra,dijkstra_destroy);
|
||||
dijkstra->distance = tal_arr(dijkstra,s64,max_num_nodes);
|
||||
dijkstra->base = tal_arr(dijkstra,u32,max_num_nodes);
|
||||
dijkstra->heapptr = tal_arrz(dijkstra,u32*,max_num_nodes);
|
||||
|
||||
global_dijkstra->distance = tal_arr(global_dijkstra,s64,max_num_nodes);
|
||||
global_dijkstra->base = tal_arr(global_dijkstra,u32,max_num_nodes);
|
||||
global_dijkstra->heapptr = tal_arrz(global_dijkstra,u32*,max_num_nodes);
|
||||
dijkstra->heapsize=0;
|
||||
|
||||
global_dijkstra->heapsize=0;
|
||||
dijkstra->gheap_ctx.fanout=2;
|
||||
dijkstra->gheap_ctx.page_chunks=1024;
|
||||
dijkstra->gheap_ctx.item_size=sizeof(dijkstra->base[0]);
|
||||
dijkstra->gheap_ctx.less_comparer=dijkstra_less_comparer;
|
||||
dijkstra->gheap_ctx.less_comparer_ctx=NULL;
|
||||
dijkstra->gheap_ctx.item_mover=dijkstra_item_mover;
|
||||
|
||||
global_dijkstra->gheap_ctx.fanout=2;
|
||||
global_dijkstra->gheap_ctx.page_chunks=1024;
|
||||
global_dijkstra->gheap_ctx.item_size=sizeof(global_dijkstra->base[0]);
|
||||
global_dijkstra->gheap_ctx.less_comparer=dijkstra_less_comparer;
|
||||
global_dijkstra->gheap_ctx.less_comparer_ctx=NULL;
|
||||
global_dijkstra->gheap_ctx.item_mover=dijkstra_item_mover;
|
||||
return dijkstra;
|
||||
}
|
||||
|
||||
|
||||
void dijkstra_init(void)
|
||||
void dijkstra_init(struct dijkstra *dijkstra)
|
||||
{
|
||||
const size_t max_num_nodes = tal_count(global_dijkstra->distance);
|
||||
global_dijkstra->heapsize=0;
|
||||
const size_t max_num_nodes = tal_count(dijkstra->distance);
|
||||
dijkstra->heapsize=0;
|
||||
for(size_t i=0;i<max_num_nodes;++i)
|
||||
{
|
||||
global_dijkstra->distance[i]=INFINITE;
|
||||
global_dijkstra->heapptr[i] = NULL;
|
||||
dijkstra->distance[i]=INFINITE;
|
||||
dijkstra->heapptr[i] = NULL;
|
||||
}
|
||||
}
|
||||
size_t dijkstra_size(void)
|
||||
size_t dijkstra_size(const struct dijkstra *dijkstra)
|
||||
{
|
||||
return global_dijkstra->heapsize;
|
||||
return dijkstra->heapsize;
|
||||
}
|
||||
|
||||
size_t dijkstra_maxsize(void)
|
||||
size_t dijkstra_maxsize(const struct dijkstra *dijkstra)
|
||||
{
|
||||
return tal_count(global_dijkstra->distance);
|
||||
return tal_count(dijkstra->distance);
|
||||
}
|
||||
|
||||
static void dijkstra_append(u32 node_idx, s64 distance)
|
||||
static void dijkstra_append(struct dijkstra *dijkstra, u32 node_idx, s64 distance)
|
||||
{
|
||||
assert(dijkstra_size() < dijkstra_maxsize());
|
||||
assert(node_idx < dijkstra_maxsize());
|
||||
assert(dijkstra_size(dijkstra) < dijkstra_maxsize(dijkstra));
|
||||
assert(node_idx < dijkstra_maxsize(dijkstra));
|
||||
|
||||
const size_t pos = global_dijkstra->heapsize;
|
||||
const size_t pos = dijkstra->heapsize;
|
||||
|
||||
global_dijkstra->base[pos]=node_idx;
|
||||
global_dijkstra->distance[node_idx]=distance;
|
||||
global_dijkstra->heapptr[node_idx] = &(global_dijkstra->base[pos]);
|
||||
global_dijkstra->heapsize++;
|
||||
dijkstra->base[pos]=node_idx;
|
||||
dijkstra->distance[node_idx]=distance;
|
||||
dijkstra->heapptr[node_idx] = &(dijkstra->base[pos]);
|
||||
dijkstra->heapsize++;
|
||||
}
|
||||
void dijkstra_update(u32 node_idx, s64 distance)
|
||||
{
|
||||
assert(node_idx < dijkstra_maxsize());
|
||||
|
||||
if(!global_dijkstra->heapptr[node_idx])
|
||||
void dijkstra_update(struct dijkstra *dijkstra, u32 node_idx, s64 distance)
|
||||
{
|
||||
assert(node_idx < dijkstra_maxsize(dijkstra));
|
||||
|
||||
if(!dijkstra->heapptr[node_idx])
|
||||
{
|
||||
// not in the heap
|
||||
dijkstra_append(node_idx,distance);
|
||||
dijkstra_append(dijkstra, node_idx,distance);
|
||||
global_dijkstra = dijkstra;
|
||||
gheap_restore_heap_after_item_increase(
|
||||
&global_dijkstra->gheap_ctx,
|
||||
global_dijkstra->base,
|
||||
global_dijkstra->heapsize,
|
||||
global_dijkstra->heapptr[node_idx]
|
||||
- global_dijkstra->base);
|
||||
&dijkstra->gheap_ctx,
|
||||
dijkstra->base,
|
||||
dijkstra->heapsize,
|
||||
dijkstra->heapptr[node_idx]
|
||||
- dijkstra->base);
|
||||
global_dijkstra = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if(global_dijkstra->distance[node_idx] > distance)
|
||||
if(dijkstra->distance[node_idx] > distance)
|
||||
{
|
||||
// distance decrease
|
||||
global_dijkstra->distance[node_idx] = distance;
|
||||
dijkstra->distance[node_idx] = distance;
|
||||
|
||||
global_dijkstra = dijkstra;
|
||||
gheap_restore_heap_after_item_increase(
|
||||
&global_dijkstra->gheap_ctx,
|
||||
global_dijkstra->base,
|
||||
global_dijkstra->heapsize,
|
||||
global_dijkstra->heapptr[node_idx]
|
||||
- global_dijkstra->base);
|
||||
&dijkstra->gheap_ctx,
|
||||
dijkstra->base,
|
||||
dijkstra->heapsize,
|
||||
dijkstra->heapptr[node_idx]
|
||||
- dijkstra->base);
|
||||
global_dijkstra = NULL;
|
||||
}else
|
||||
{
|
||||
// distance increase
|
||||
global_dijkstra->distance[node_idx] = distance;
|
||||
dijkstra->distance[node_idx] = distance;
|
||||
|
||||
global_dijkstra = dijkstra;
|
||||
gheap_restore_heap_after_item_decrease(
|
||||
&global_dijkstra->gheap_ctx,
|
||||
global_dijkstra->base,
|
||||
global_dijkstra->heapsize,
|
||||
global_dijkstra->heapptr[node_idx]
|
||||
- global_dijkstra->base);
|
||||
&dijkstra->gheap_ctx,
|
||||
dijkstra->base,
|
||||
dijkstra->heapsize,
|
||||
dijkstra->heapptr[node_idx]
|
||||
- dijkstra->base);
|
||||
global_dijkstra = NULL;
|
||||
|
||||
}
|
||||
// assert(gheap_is_heap(&global_dijkstra->gheap_ctx,
|
||||
// global_dijkstra->base,
|
||||
// assert(gheap_is_heap(&dijkstra->gheap_ctx,
|
||||
// dijkstra->base,
|
||||
// dijkstra_size()));
|
||||
}
|
||||
u32 dijkstra_top(void)
|
||||
|
||||
u32 dijkstra_top(const struct dijkstra *dijkstra)
|
||||
{
|
||||
return global_dijkstra->base[0];
|
||||
return dijkstra->base[0];
|
||||
}
|
||||
bool dijkstra_empty(void)
|
||||
|
||||
bool dijkstra_empty(const struct dijkstra *dijkstra)
|
||||
{
|
||||
return global_dijkstra->heapsize==0;
|
||||
return dijkstra->heapsize==0;
|
||||
}
|
||||
void dijkstra_pop(void)
|
||||
|
||||
void dijkstra_pop(struct dijkstra *dijkstra)
|
||||
{
|
||||
if(global_dijkstra->heapsize==0)
|
||||
if(dijkstra->heapsize==0)
|
||||
return;
|
||||
|
||||
const u32 top = dijkstra_top();
|
||||
assert(global_dijkstra->heapptr[top]==global_dijkstra->base);
|
||||
const u32 top = dijkstra_top(dijkstra);
|
||||
assert(dijkstra->heapptr[top]==dijkstra->base);
|
||||
|
||||
global_dijkstra = dijkstra;
|
||||
gheap_pop_heap(
|
||||
&global_dijkstra->gheap_ctx,
|
||||
global_dijkstra->base,
|
||||
global_dijkstra->heapsize--);
|
||||
&dijkstra->gheap_ctx,
|
||||
dijkstra->base,
|
||||
dijkstra->heapsize--);
|
||||
global_dijkstra = NULL;
|
||||
|
||||
global_dijkstra->heapptr[top]=NULL;
|
||||
dijkstra->heapptr[top]=NULL;
|
||||
}
|
||||
const s64* dijkstra_distance_data(void)
|
||||
|
||||
const s64* dijkstra_distance_data(const struct dijkstra *dijkstra)
|
||||
{
|
||||
return global_dijkstra->distance;
|
||||
return dijkstra->distance;
|
||||
}
|
||||
|
||||
@@ -5,45 +5,26 @@
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <gheap.h>
|
||||
|
||||
/* In the heap we keep node idx, but in this structure we keep the distance
|
||||
* value associated to every node, and their position in the heap as a pointer
|
||||
* so that we can update the nodes inside the heap when the distance label is
|
||||
* changed.
|
||||
*
|
||||
* Therefore this is no longer a multipurpose heap, the node_idx must be an
|
||||
* index between 0 and less than max_num_nodes. */
|
||||
struct dijkstra {
|
||||
//
|
||||
s64 *distance;
|
||||
u32 *base;
|
||||
u32 **heapptr;
|
||||
size_t heapsize;
|
||||
struct gheap_ctx gheap_ctx;
|
||||
};
|
||||
|
||||
/* Allocation of resources for the heap. */
|
||||
void dijkstra_malloc(const tal_t *ctx, const size_t max_num_nodes);
|
||||
|
||||
/* Manually release dijkstra resources. */
|
||||
void dijkstra_free(void);
|
||||
struct dijkstra *dijkstra_new(const tal_t *ctx, size_t max_num_nodes);
|
||||
|
||||
/* Initialization of the heap for a new Dijkstra search. */
|
||||
void dijkstra_init(void);
|
||||
void dijkstra_init(struct dijkstra *dijkstra);
|
||||
|
||||
/* Inserts a new element in the heap. If node_idx was already in the heap then
|
||||
* its distance value is updated. */
|
||||
void dijkstra_update(u32 node_idx, s64 distance);
|
||||
void dijkstra_update(struct dijkstra *dijkstra, u32 node_idx, s64 distance);
|
||||
|
||||
u32 dijkstra_top(void);
|
||||
bool dijkstra_empty(void);
|
||||
void dijkstra_pop(void);
|
||||
u32 dijkstra_top(const struct dijkstra *dijkstra);
|
||||
bool dijkstra_empty(const struct dijkstra *dijkstra);
|
||||
void dijkstra_pop(struct dijkstra *dijkstra);
|
||||
|
||||
const s64* dijkstra_distance_data(void);
|
||||
const s64* dijkstra_distance_data(const struct dijkstra *dijkstra);
|
||||
|
||||
/* Number of elements on the heap. */
|
||||
size_t dijkstra_size(void);
|
||||
size_t dijkstra_size(const struct dijkstra *dijkstra);
|
||||
|
||||
/* Maximum number of elements the heap can host */
|
||||
size_t dijkstra_maxsize(void);
|
||||
size_t dijkstra_maxsize(const struct dijkstra *dijkstra);
|
||||
|
||||
#endif /* LIGHTNING_PLUGINS_RENEPAY_DIJKSTRA_H */
|
||||
|
||||
@@ -849,6 +849,7 @@ static int find_feasible_flow(
|
||||
/* Similar to `find_admissible_path` but use Dijkstra to optimize the distance
|
||||
* label. Stops when the target is hit. */
|
||||
static int find_optimal_path(
|
||||
struct dijkstra *dijkstra,
|
||||
const struct linear_network *linear_network,
|
||||
const struct residual_network* residual_network,
|
||||
const u32 source,
|
||||
@@ -864,15 +865,15 @@ static int find_optimal_path(
|
||||
for(size_t i=0;i<tal_count(prev);++i)
|
||||
prev[i].idx=INVALID_INDEX;
|
||||
|
||||
s64 const * const distance=dijkstra_distance_data();
|
||||
s64 const * const distance=dijkstra_distance_data(dijkstra);
|
||||
|
||||
dijkstra_init();
|
||||
dijkstra_update(source,0);
|
||||
dijkstra_init(dijkstra);
|
||||
dijkstra_update(dijkstra,source,0);
|
||||
|
||||
while(!dijkstra_empty())
|
||||
while(!dijkstra_empty(dijkstra))
|
||||
{
|
||||
u32 cur = dijkstra_top();
|
||||
dijkstra_pop();
|
||||
u32 cur = dijkstra_top(dijkstra);
|
||||
dijkstra_pop(dijkstra);
|
||||
|
||||
if(bitmap_test_bit(visited,cur))
|
||||
continue;
|
||||
@@ -905,7 +906,7 @@ static int find_optimal_path(
|
||||
if(distance[next]<=distance[cur]+cij)
|
||||
continue;
|
||||
|
||||
dijkstra_update(next,distance[cur]+cij);
|
||||
dijkstra_update(dijkstra,next,distance[cur]+cij);
|
||||
prev[next]=arc;
|
||||
}
|
||||
}
|
||||
@@ -945,6 +946,7 @@ static void zero_flow(
|
||||
* current iteration but I might be not too far from the truth.
|
||||
* It comes to mind to use cycle cancelling. */
|
||||
static int optimize_mcf(
|
||||
struct dijkstra *dijkstra,
|
||||
const struct linear_network *linear_network,
|
||||
struct residual_network *residual_network,
|
||||
const u32 source,
|
||||
@@ -959,13 +961,13 @@ static int optimize_mcf(
|
||||
zero_flow(linear_network,residual_network);
|
||||
arc_t *prev = tal_arr(this_ctx,arc_t,linear_network->max_num_nodes);
|
||||
|
||||
s64 const*const distance = dijkstra_distance_data();
|
||||
s64 const*const distance = dijkstra_distance_data(dijkstra);
|
||||
|
||||
s64 remaining_amount = amount;
|
||||
|
||||
while(remaining_amount>0)
|
||||
{
|
||||
int err = find_optimal_path(linear_network,residual_network,source,target,prev);
|
||||
int err = find_optimal_path(dijkstra,linear_network,residual_network,source,target,prev);
|
||||
if(err!=RENEPAY_ERR_OK)
|
||||
{
|
||||
// unexpected error
|
||||
@@ -1358,6 +1360,7 @@ struct flow** minflow(
|
||||
tal_t *this_ctx = tal(tmpctx,tal_t);
|
||||
|
||||
struct pay_parameters *params = tal(this_ctx,struct pay_parameters);
|
||||
struct dijkstra *dijkstra;
|
||||
|
||||
params->gossmap = gossmap;
|
||||
params->source = source;
|
||||
@@ -1397,7 +1400,7 @@ struct flow** minflow(
|
||||
struct residual_network *residual_network = tal(this_ctx,struct residual_network);
|
||||
alloc_residual_netork(linear_network,residual_network);
|
||||
|
||||
dijkstra_malloc(this_ctx,gossmap_max_node_idx(params->gossmap));
|
||||
dijkstra = dijkstra_new(this_ctx, gossmap_max_node_idx(params->gossmap));
|
||||
|
||||
const u32 target_idx = gossmap_node_idx(params->gossmap,target);
|
||||
const u32 source_idx = gossmap_node_idx(params->gossmap,source);
|
||||
@@ -1458,7 +1461,7 @@ struct flow** minflow(
|
||||
|
||||
combine_cost_function(linear_network,residual_network,mu);
|
||||
|
||||
optimize_mcf(linear_network,residual_network,
|
||||
optimize_mcf(dijkstra,linear_network,residual_network,
|
||||
source_idx,target_idx,pay_amount_sats);
|
||||
|
||||
struct flow **flow_paths;
|
||||
|
||||
@@ -11,70 +11,70 @@
|
||||
|
||||
static void insertion_in_increasing_distance(const tal_t *ctx)
|
||||
{
|
||||
dijkstra_malloc(ctx,10);
|
||||
struct dijkstra *dijkstra = dijkstra_new(ctx,10);
|
||||
|
||||
for(int i=0;i<dijkstra_maxsize();++i)
|
||||
for(int i=0;i<dijkstra_maxsize(dijkstra);++i)
|
||||
{
|
||||
dijkstra_update(i,10+i);
|
||||
assert(dijkstra_size()==(i+1));
|
||||
dijkstra_update(dijkstra,i,10+i);
|
||||
assert(dijkstra_size(dijkstra)==(i+1));
|
||||
}
|
||||
|
||||
dijkstra_update(3,3);
|
||||
assert(dijkstra_top()==3);
|
||||
dijkstra_update(dijkstra,3,3);
|
||||
assert(dijkstra_top(dijkstra)==3);
|
||||
|
||||
dijkstra_update(3,15);
|
||||
assert(dijkstra_top()==0);
|
||||
dijkstra_update(dijkstra,3,15);
|
||||
assert(dijkstra_top(dijkstra)==0);
|
||||
|
||||
dijkstra_update(3,-1);
|
||||
assert(dijkstra_top()==3);
|
||||
dijkstra_update(dijkstra,3,-1);
|
||||
assert(dijkstra_top(dijkstra)==3);
|
||||
|
||||
dijkstra_pop();
|
||||
assert(dijkstra_size()==9);
|
||||
assert(dijkstra_top()==0);
|
||||
dijkstra_pop(dijkstra);
|
||||
assert(dijkstra_size(dijkstra)==9);
|
||||
assert(dijkstra_top(dijkstra)==0);
|
||||
|
||||
// Insert again
|
||||
dijkstra_update(3,3+10);
|
||||
dijkstra_update(dijkstra,3,3+10);
|
||||
|
||||
u32 top=0;
|
||||
while(!dijkstra_empty())
|
||||
while(!dijkstra_empty(dijkstra))
|
||||
{
|
||||
assert(top==dijkstra_top());
|
||||
assert(top==dijkstra_top(dijkstra));
|
||||
top++;
|
||||
dijkstra_pop();
|
||||
dijkstra_pop(dijkstra);
|
||||
}
|
||||
}
|
||||
static void insertion_in_decreasing_distance(const tal_t *ctx)
|
||||
{
|
||||
dijkstra_malloc(ctx,10);
|
||||
struct dijkstra *dijkstra = dijkstra_new(ctx,10);
|
||||
|
||||
for(int i=0;i<dijkstra_maxsize();++i)
|
||||
for(int i=0;i<dijkstra_maxsize(dijkstra);++i)
|
||||
{
|
||||
dijkstra_update(i,10-i);
|
||||
assert(dijkstra_size()==(i+1));
|
||||
dijkstra_update(dijkstra,i,10-i);
|
||||
assert(dijkstra_size(dijkstra)==(i+1));
|
||||
}
|
||||
|
||||
dijkstra_update(3,-3);
|
||||
assert(dijkstra_top()==3);
|
||||
dijkstra_update(dijkstra,3,-3);
|
||||
assert(dijkstra_top(dijkstra)==3);
|
||||
|
||||
dijkstra_update(3,15);
|
||||
assert(dijkstra_top()==9);
|
||||
dijkstra_update(dijkstra,3,15);
|
||||
assert(dijkstra_top(dijkstra)==9);
|
||||
|
||||
dijkstra_update(3,-1);
|
||||
assert(dijkstra_top()==3);
|
||||
dijkstra_update(dijkstra,3,-1);
|
||||
assert(dijkstra_top(dijkstra)==3);
|
||||
|
||||
dijkstra_pop();
|
||||
assert(dijkstra_size()==9);
|
||||
assert(dijkstra_top()==9);
|
||||
dijkstra_pop(dijkstra);
|
||||
assert(dijkstra_size(dijkstra)==9);
|
||||
assert(dijkstra_top(dijkstra)==9);
|
||||
|
||||
// Insert again
|
||||
dijkstra_update(3,10-3);
|
||||
dijkstra_update(dijkstra,3,10-3);
|
||||
|
||||
u32 top=9;
|
||||
while(!dijkstra_empty())
|
||||
while(!dijkstra_empty(dijkstra))
|
||||
{
|
||||
assert(top==dijkstra_top());
|
||||
assert(top==dijkstra_top(dijkstra));
|
||||
top--;
|
||||
dijkstra_pop();
|
||||
dijkstra_pop(dijkstra);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,14 +82,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
common_setup(argv[0]);
|
||||
|
||||
insertion_in_increasing_distance(NULL);
|
||||
insertion_in_decreasing_distance(tmpctx);
|
||||
|
||||
// test dijkstra_free
|
||||
dijkstra_free();
|
||||
// we can call it twice, no problem
|
||||
dijkstra_free();
|
||||
|
||||
// does tal_free() cleansup correctly?
|
||||
const tal_t *this_ctx = tal(NULL,tal_t);
|
||||
insertion_in_increasing_distance(this_ctx);
|
||||
|
||||
Reference in New Issue
Block a user