sqldb+graph/db: prune graph nodes in a single query

Update the pruneGraphNodes routine to prune the graph nodes in a single
query instead of two.
This commit is contained in:
Elle Mouton committed 2025-06-30 18:41:28 +02:00
1 parent 714e528a3a
commit f1b7ccc6b2
4 files changed
+65 -81

No files matched your search

+9 -18
View File
@@ -64,7 +64,7 @@ type SQLQueries interface {
ListNodesPaginated(ctx context.Context, arg sqlc.ListNodesPaginatedParams) ([]sqlc.Node, error) ListNodesPaginated(ctx context.Context, arg sqlc.ListNodesPaginatedParams) ([]sqlc.Node, error)
ListNodeIDsAndPubKeys(ctx context.Context, arg sqlc.ListNodeIDsAndPubKeysParams) ([]sqlc.ListNodeIDsAndPubKeysRow, error) ListNodeIDsAndPubKeys(ctx context.Context, arg sqlc.ListNodeIDsAndPubKeysParams) ([]sqlc.ListNodeIDsAndPubKeysRow, error)
IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error) IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error)
GetUnconnectedNodes(ctx context.Context) ([]sqlc.GetUnconnectedNodesRow, error) DeleteUnconnectedNodes(ctx context.Context) ([][]byte, error)
DeleteNodeByPubKey(ctx context.Context, arg sqlc.DeleteNodeByPubKeyParams) (sql.Result, error) DeleteNodeByPubKey(ctx context.Context, arg sqlc.DeleteNodeByPubKeyParams) (sql.Result, error)
DeleteNode(ctx context.Context, id int64) error DeleteNode(ctx context.Context, id int64) error
@@ -2551,30 +2551,21 @@ func (s *SQLStore) PruneTip() (*chainhash.Hash, uint32, error) {
func (s *SQLStore) pruneGraphNodes(ctx context.Context, func (s *SQLStore) pruneGraphNodes(ctx context.Context,
db SQLQueries) ([]route.Vertex, error) { db SQLQueries) ([]route.Vertex, error) {
// Fetch all un-connected nodes from the database. nodeKeys, err := db.DeleteUnconnectedNodes(ctx)
// NOTE: this will not include any nodes that are listed in the
// source table.
nodes, err := db.GetUnconnectedNodes(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to fetch unconnected nodes: %w", return nil, fmt.Errorf("unable to delete unconnected "+
err) "nodes: %w", err)
} }
prunedNodes := make([]route.Vertex, 0, len(nodes)) prunedNodes := make([]route.Vertex, len(nodeKeys))
for _, node := range nodes { for i, nodeKey := range nodeKeys {
// TODO(elle): update to use sqlc.slice() once that works. pub, err := route.NewVertexFromBytes(nodeKey)
if err = db.DeleteNode(ctx, node.ID); err != nil {
return nil, fmt.Errorf("unable to delete "+
"node(id=%d): %w", node.ID, err)
}
pubKey, err := route.NewVertexFromBytes(node.PubKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to parse pubkey "+ return nil, fmt.Errorf("unable to parse pubkey "+
"for node(id=%d): %w", node.ID, err) "from bytes: %w", err)
} }
prunedNodes = append(prunedNodes, pubKey) prunedNodes[i] = pub
} }
return prunedNodes, nil return prunedNodes, nil
+40 -45
View File
@@ -244,6 +244,46 @@ func (q *Queries) DeletePruneLogEntriesInRange(ctx context.Context, arg DeletePr
return err return err
} }
const deleteUnconnectedNodes = `-- name: DeleteUnconnectedNodes :many
DELETE FROM nodes
WHERE
-- Ignore any of our source nodes.
NOT EXISTS (
SELECT 1
FROM source_nodes sn
WHERE sn.node_id = nodes.id
)
-- Select all nodes that do not have any channels.
AND NOT EXISTS (
SELECT 1
FROM channels c
WHERE c.node_id_1 = nodes.id OR c.node_id_2 = nodes.id
) RETURNING pub_key
`
func (q *Queries) DeleteUnconnectedNodes(ctx context.Context) ([][]byte, error) {
rows, err := q.db.QueryContext(ctx, deleteUnconnectedNodes)
if err != nil {
return nil, err
}
defer rows.Close()
var items [][]byte
for rows.Next() {
var pub_key []byte
if err := rows.Scan(&pub_key); err != nil {
return nil, err
}
items = append(items, pub_key)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const deleteZombieChannel = `-- name: DeleteZombieChannel :execresult const deleteZombieChannel = `-- name: DeleteZombieChannel :execresult
DELETE FROM zombie_channels DELETE FROM zombie_channels
WHERE scid = $1 WHERE scid = $1
@@ -1388,51 +1428,6 @@ func (q *Queries) GetSourceNodesByVersion(ctx context.Context, version int16) ([
return items, nil return items, nil
} }
const getUnconnectedNodes = `-- name: GetUnconnectedNodes :many
SELECT n.id, n.pub_key
FROM nodes n
WHERE NOT EXISTS (
SELECT 1
FROM channels c
WHERE c.node_id_1 = n.id OR c.node_id_2 = n.id
)
AND NOT EXISTS (
SELECT 1
FROM source_nodes sn
WHERE sn.node_id = n.id
)
`
type GetUnconnectedNodesRow struct {
ID int64
PubKey []byte
}
// Select all nodes that do not have any channels.
// Ignore any of our source nodes.
func (q *Queries) GetUnconnectedNodes(ctx context.Context) ([]GetUnconnectedNodesRow, error) {
rows, err := q.db.QueryContext(ctx, getUnconnectedNodes)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetUnconnectedNodesRow
for rows.Next() {
var i GetUnconnectedNodesRow
if err := rows.Scan(&i.ID, &i.PubKey); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getV1DisabledSCIDs = `-- name: GetV1DisabledSCIDs :many const getV1DisabledSCIDs = `-- name: GetV1DisabledSCIDs :many
SELECT c.scid SELECT c.scid
FROM channels c FROM channels c
+1 -3
View File
@@ -27,6 +27,7 @@ type Querier interface {
DeleteNodeByPubKey(ctx context.Context, arg DeleteNodeByPubKeyParams) (sql.Result, error) DeleteNodeByPubKey(ctx context.Context, arg DeleteNodeByPubKeyParams) (sql.Result, error)
DeleteNodeFeature(ctx context.Context, arg DeleteNodeFeatureParams) error DeleteNodeFeature(ctx context.Context, arg DeleteNodeFeatureParams) error
DeletePruneLogEntriesInRange(ctx context.Context, arg DeletePruneLogEntriesInRangeParams) error DeletePruneLogEntriesInRange(ctx context.Context, arg DeletePruneLogEntriesInRangeParams) error
DeleteUnconnectedNodes(ctx context.Context) ([][]byte, error)
DeleteZombieChannel(ctx context.Context, arg DeleteZombieChannelParams) (sql.Result, error) DeleteZombieChannel(ctx context.Context, arg DeleteZombieChannelParams) (sql.Result, error)
FetchAMPSubInvoiceHTLCs(ctx context.Context, arg FetchAMPSubInvoiceHTLCsParams) ([]FetchAMPSubInvoiceHTLCsRow, error) FetchAMPSubInvoiceHTLCs(ctx context.Context, arg FetchAMPSubInvoiceHTLCsParams) ([]FetchAMPSubInvoiceHTLCsRow, error)
FetchAMPSubInvoices(ctx context.Context, arg FetchAMPSubInvoicesParams) ([]AmpSubInvoice, error) FetchAMPSubInvoices(ctx context.Context, arg FetchAMPSubInvoicesParams) ([]AmpSubInvoice, error)
@@ -66,9 +67,6 @@ type Querier interface {
GetPublicV1ChannelsBySCID(ctx context.Context, arg GetPublicV1ChannelsBySCIDParams) ([]Channel, error) GetPublicV1ChannelsBySCID(ctx context.Context, arg GetPublicV1ChannelsBySCIDParams) ([]Channel, error)
GetSCIDByOutpoint(ctx context.Context, arg GetSCIDByOutpointParams) ([]byte, error) GetSCIDByOutpoint(ctx context.Context, arg GetSCIDByOutpointParams) ([]byte, error)
GetSourceNodesByVersion(ctx context.Context, version int16) ([]GetSourceNodesByVersionRow, error) GetSourceNodesByVersion(ctx context.Context, version int16) ([]GetSourceNodesByVersionRow, error)
// Select all nodes that do not have any channels.
// Ignore any of our source nodes.
GetUnconnectedNodes(ctx context.Context) ([]GetUnconnectedNodesRow, error)
// NOTE: this is V1 specific since for V1, disabled is a // NOTE: this is V1 specific since for V1, disabled is a
// simple, single boolean. The proposed V2 policy // simple, single boolean. The proposed V2 policy
// structure will have a more complex disabled bit vector // structure will have a more complex disabled bit vector
+15 -15
View File
@@ -65,21 +65,21 @@ SELECT EXISTS (
AND n.pub_key = $1 AND n.pub_key = $1
); );
-- name: GetUnconnectedNodes :many -- name: DeleteUnconnectedNodes :many
SELECT n.id, n.pub_key DELETE FROM nodes
FROM nodes n WHERE
-- Select all nodes that do not have any channels. -- Ignore any of our source nodes.
WHERE NOT EXISTS ( NOT EXISTS (
SELECT 1 SELECT 1
FROM channels c FROM source_nodes sn
WHERE c.node_id_1 = n.id OR c.node_id_2 = n.id WHERE sn.node_id = nodes.id
) )
-- Ignore any of our source nodes. -- Select all nodes that do not have any channels.
AND NOT EXISTS ( AND NOT EXISTS (
SELECT 1 SELECT 1
FROM source_nodes sn FROM channels c
WHERE sn.node_id = n.id WHERE c.node_id_1 = nodes.id OR c.node_id_2 = nodes.id
); ) RETURNING pub_key;
-- name: DeleteNodeByPubKey :execresult -- name: DeleteNodeByPubKey :execresult
DELETE FROM nodes DELETE FROM nodes