Skip to content

Commit

Permalink
wallet/db.c, wallet/wallet.c: Add a partial index to speed up startup.
Browse files Browse the repository at this point in the history
Closes: #4901

Tested by `EXPLAIN QUERY PLAN` on sqlite3; #4901 shows the result from
@whitslack doing a similar partial index on PostgreSQL on his ~1000 chan
node.

ChangeLog-Added: db: Speed up loading of pending HTLCs during startup by using a partial index.
  • Loading branch information
ZmnSCPxj committed Nov 29, 2021
1 parent 35c6f90 commit 7c63ce4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
10 changes: 10 additions & 0 deletions wallet/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/htlc_state.h>
#include <common/key_derive.h>
#include <common/onionreply.h>
#include <common/version.h>
Expand Down Expand Up @@ -858,6 +860,14 @@ static struct migration dbmigrations[] = {

/* Issue #4887: reset the payments.id sequence after the migration above. Since this is a SELECT statement that would otherwise fail, make it an INSERT into the `vars` table.*/
{SQL("/*PSQL*/INSERT INTO vars (name, intval) VALUES ('payment_id_reset', setval(pg_get_serial_sequence('payments', 'id'), COALESCE((SELECT MAX(id)+1 FROM payments), 1)))"), NULL},

/* Issue #4901: Partial index speeds up startup on nodes with ~1000 channels. */
{&SQL("CREATE INDEX channel_htlcs_speedup_unresolved_idx"
" ON channel_htlcs(channel_id, direction)"
" WHERE hstate NOT IN (9, 19);")
[BUILD_ASSERT_OR_ZERO( 9 == RCVD_REMOVE_ACK_REVOCATION) +
BUILD_ASSERT_OR_ZERO(19 == SENT_REMOVE_ACK_REVOCATION)],
NULL},
};

/* Leak tracking. */
Expand Down
18 changes: 15 additions & 3 deletions wallet/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -2734,10 +2734,16 @@ bool wallet_htlcs_load_in_for_channel(struct wallet *wallet,
" FROM channel_htlcs"
" WHERE direction= ?"
" AND channel_id= ?"
" AND hstate != ?"));
" AND hstate NOT IN (?, ?)"));
db_bind_int(stmt, 0, DIRECTION_INCOMING);
db_bind_u64(stmt, 1, chan->dbid);
db_bind_int(stmt, 2, SENT_REMOVE_ACK_REVOCATION);
/* We need to generate `hstate NOT IN (9, 19)` in order to match
* the `WHERE` clause of the database index; incoming HTLCs will
* never actually get the state `RCVD_REMOVE_ACK_REVOCATION`.
* See https://sqlite.org/partialindex.html#queries_using_partial_indexes
*/
db_bind_int(stmt, 2, RCVD_REMOVE_ACK_REVOCATION); /* Not gonna happen. */
db_bind_int(stmt, 3, SENT_REMOVE_ACK_REVOCATION);
db_query_prepared(stmt);

while (db_step(stmt)) {
Expand Down Expand Up @@ -2780,10 +2786,16 @@ bool wallet_htlcs_load_out_for_channel(struct wallet *wallet,
" FROM channel_htlcs"
" WHERE direction = ?"
" AND channel_id = ?"
" AND hstate != ?"));
" AND hstate NOT IN (?, ?)"));
db_bind_int(stmt, 0, DIRECTION_OUTGOING);
db_bind_u64(stmt, 1, chan->dbid);
/* We need to generate `hstate NOT IN (9, 19)` in order to match
* the `WHERE` clause of the database index; outgoing HTLCs will
* never actually get the state `SENT_REMOVE_ACK_REVOCATION`.
* See https://sqlite.org/partialindex.html#queries_using_partial_indexes
*/
db_bind_int(stmt, 2, RCVD_REMOVE_ACK_REVOCATION);
db_bind_int(stmt, 3, SENT_REMOVE_ACK_REVOCATION); /* Not gonna happen. */
db_query_prepared(stmt);

while (db_step(stmt)) {
Expand Down

0 comments on commit 7c63ce4

Please sign in to comment.