From 218aa9eaa810efe84ba661a4a1ca42c299fe8cef Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 12 Aug 2025 15:37:40 +0200 Subject: [PATCH] graph/db: move sanity check out of insertChannel We do this so that this lookup is only done in the situation it is actually needed. During a migration, we dont need to special case this AlreadyExists error since we will terminate the transaction either way. So there is no need for the extra lookup during the migration. A timing analysis showed that this query was significantly impacting the performance of the migration when run with a postgres backend. --- graph/db/sql_store.go | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index 1c913b78c..40d5525d2 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -591,15 +591,29 @@ func (s *SQLStore) AddChannelEdge(ctx context.Context, alreadyExists = false }, Do: func(tx SQLQueries) error { - _, err := insertChannel(ctx, tx, edge) + chanIDB := channelIDToBytes(edge.ChannelID) - // Silence ErrEdgeAlreadyExist so that the batch can - // succeed, but propagate the error via local state. - if errors.Is(err, ErrEdgeAlreadyExist) { + // Make sure that the channel doesn't already exist. We + // do this explicitly instead of relying on catching a + // unique constraint error because relying on SQL to + // throw that error would abort the entire batch of + // transactions. + _, err := tx.GetChannelBySCID( + ctx, sqlc.GetChannelBySCIDParams{ + Scid: chanIDB, + Version: int16(ProtocolV1), + }, + ) + if err == nil { alreadyExists = true return nil + } else if !errors.Is(err, sql.ErrNoRows) { + return fmt.Errorf("unable to fetch channel: %w", + err) } + _, err = insertChannel(ctx, tx, edge) + return err }, OnCommit: func(err error) error { @@ -3767,24 +3781,6 @@ type dbChanInfo struct { func insertChannel(ctx context.Context, db SQLQueries, edge *models.ChannelEdgeInfo) (*dbChanInfo, error) { - chanIDB := channelIDToBytes(edge.ChannelID) - - // Make sure that the channel doesn't already exist. We do this - // explicitly instead of relying on catching a unique constraint error - // because relying on SQL to throw that error would abort the entire - // batch of transactions. - _, err := db.GetChannelBySCID( - ctx, sqlc.GetChannelBySCIDParams{ - Scid: chanIDB, - Version: int16(ProtocolV1), - }, - ) - if err == nil { - return nil, ErrEdgeAlreadyExist - } else if !errors.Is(err, sql.ErrNoRows) { - return nil, fmt.Errorf("unable to fetch channel: %w", err) - } - // Make sure that at least a "shell" entry for each node is present in // the nodes table. node1DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey1Bytes) @@ -3804,7 +3800,7 @@ func insertChannel(ctx context.Context, db SQLQueries, createParams := sqlc.CreateChannelParams{ Version: int16(ProtocolV1), - Scid: chanIDB, + Scid: channelIDToBytes(edge.ChannelID), NodeID1: node1DBID, NodeID2: node2DBID, Outpoint: edge.ChannelPoint.String(),