Skip to content

Commit 87c0076

Browse files
committed
askrene: speed up when using large number of layers.
Simple bench. Before: Creating 20,000 layers: 32 seconds After: Creating 20,000 layers: 13 seconds Creating 50,000 layers: 30 seconds Creating 100,000 layers: 57 seconds Signed-off-by: Rusty Russell <[email protected]>
1 parent ed43977 commit 87c0076

File tree

5 files changed

+48
-22
lines changed

5 files changed

+48
-22
lines changed

plugins/askrene/askrene.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ static const char *init(struct command *init_cmd,
13961396
struct askrene *askrene = get_askrene(plugin);
13971397

13981398
askrene->plugin = plugin;
1399-
list_head_init(&askrene->layers);
1399+
askrene->layers = new_layer_name_hash(askrene);
14001400
askrene->reserved = new_reserve_htable(askrene);
14011401
askrene->gossmap = gossmap_load(askrene, GOSSIP_STORE_FILENAME,
14021402
plugin_gossmap_logcb, plugin);

plugins/askrene/askrene.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ struct route {
2424
struct askrene {
2525
struct plugin *plugin;
2626
struct gossmap *gossmap;
27-
/* List of layers */
28-
struct list_head layers;
27+
/* Hash table of layers by name */
28+
struct layer_name_hash *layers;
2929
/* In-flight payment attempts */
3030
struct reserve_htable *reserved;
3131
/* Compact cache of gossmap capacities */

plugins/askrene/layer.c

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ HTABLE_DEFINE_NODUPS_TYPE(struct node_bias, bias_nodeid, hash_nodeid,
146146
bias_eq_nodeid, node_bias_hash);
147147

148148
struct layer {
149-
/* Inside global list of layers */
150-
struct list_node list;
151-
152149
/* Convenience pointer to askrene */
153150
struct askrene *askrene;
154151

@@ -177,6 +174,25 @@ struct layer {
177174
struct node_id *disabled_nodes;
178175
};
179176

177+
static size_t hash_str(const char *str)
178+
{
179+
return siphash24(siphash_seed(), str, strlen(str));
180+
}
181+
182+
static bool layer_eq_name(const struct layer *l,
183+
const char *name)
184+
{
185+
return streq(l->name, name);
186+
}
187+
188+
HTABLE_DEFINE_NODUPS_TYPE(struct layer, layer_name, hash_str,
189+
layer_eq_name, layer_name_hash);
190+
191+
struct layer_name_hash *new_layer_name_hash(const tal_t *ctx)
192+
{
193+
return new_htable(ctx, layer_name_hash);
194+
}
195+
180196
struct layer *new_temp_layer(const tal_t *ctx, struct askrene *askrene, const char *name TAKES)
181197
{
182198
struct layer *l = tal(ctx, struct layer);
@@ -196,7 +212,8 @@ struct layer *new_temp_layer(const tal_t *ctx, struct askrene *askrene, const ch
196212

197213
static void destroy_layer(struct layer *l, struct askrene *askrene)
198214
{
199-
list_del_from(&askrene->layers, &l->list);
215+
if (!layer_name_hash_del(askrene->layers, l))
216+
abort();
200217
}
201218

202219
/* Low-level versions of routines which do *not* save (used for loading, too) */
@@ -205,7 +222,7 @@ static struct layer *add_layer(struct askrene *askrene, const char *name TAKES,
205222
struct layer *l = new_temp_layer(askrene, askrene, name);
206223
l->persistent = persistent;
207224
assert(!find_layer(askrene, l->name));
208-
list_add(&askrene->layers, &l->list);
225+
layer_name_hash_add(askrene->layers, l);
209226
tal_add_destructor2(l, destroy_layer, askrene);
210227
return l;
211228
}
@@ -847,12 +864,7 @@ struct layer *new_layer(struct askrene *askrene,
847864

848865
struct layer *find_layer(struct askrene *askrene, const char *name)
849866
{
850-
struct layer *l;
851-
list_for_each(&askrene->layers, l, list) {
852-
if (streq(l->name, name))
853-
return l;
854-
}
855-
return NULL;
867+
return layer_name_hash_get(askrene->layers, name);
856868
}
857869

858870
const char *layer_name(const struct layer *layer)
@@ -1295,17 +1307,21 @@ static void json_add_layer(struct json_stream *js,
12951307
}
12961308

12971309
void json_add_layers(struct json_stream *js,
1298-
struct askrene *askrene,
1310+
const struct askrene *askrene,
12991311
const char *fieldname,
13001312
const struct layer *layer)
13011313
{
1302-
struct layer *l;
1303-
13041314
json_array_start(js, fieldname);
1305-
list_for_each(&askrene->layers, l, list) {
1306-
if (layer && l != layer)
1307-
continue;
1308-
json_add_layer(js, NULL, l);
1315+
if (layer) {
1316+
json_add_layer(js, NULL, layer);
1317+
} else {
1318+
struct layer_name_hash_iter it;
1319+
1320+
for (struct layer *l = layer_name_hash_first(askrene->layers, &it);
1321+
l;
1322+
l = layer_name_hash_next(askrene->layers, &it)) {
1323+
json_add_layer(js, NULL, l);
1324+
}
13091325
}
13101326
json_array_end(js);
13111327
}

plugins/askrene/layer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ struct askrene;
1717
struct layer;
1818
struct json_stream;
1919

20+
/* Create a layer hash table */
21+
struct layer_name_hash *new_layer_name_hash(const tal_t *ctx);
22+
2023
/* Look up a layer by name. */
2124
struct layer *find_layer(struct askrene *askrene, const char *name);
2225

@@ -120,7 +123,7 @@ void layer_add_disabled_node(struct layer *layer, const struct node_id *node);
120123

121124
/* Print out a json object for this layer, or all if layer is NULL */
122125
void json_add_layers(struct json_stream *js,
123-
struct askrene *askrene,
126+
const struct askrene *askrene,
124127
const char *fieldname,
125128
const struct layer *layer);
126129

tests/benchmark.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,10 @@ def test_spam_listcommands(node_factory, bitcoind, benchmark):
228228

229229
# This calls "listinvoice" 100,000 times (which doesn't need a transaction commit)
230230
benchmark(l1.rpc.spamlistcommand, 100_000)
231+
232+
233+
def test_askrene_layers(node_factory):
234+
l1 = get_bench_node(node_factory)
235+
NUM_LAYERS = 100_000
236+
for i in range(NUM_LAYERS):
237+
l1.rpc.askrene_create_layer(f'test_askrene_layers-{i}')

0 commit comments

Comments
 (0)