• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 12231552240

09 Dec 2024 08:17AM UTC coverage: 58.955% (+0.02%) from 58.933%
12231552240

Pull #9242

github

aakselrod
go.mod: update btcwallet to latest to eliminate waddrmgr deadlock
Pull Request #9242: Reapply #8644

24 of 40 new or added lines in 3 files covered. (60.0%)

89 existing lines in 18 files now uncovered.

133525 of 226485 relevant lines covered (58.96%)

19398.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.81
/sqldb/sqlerrors.go
1
//go:build !js && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64))
2

3
package sqldb
4

5
import (
6
        "errors"
7
        "fmt"
8
        "strings"
9

10
        "github.com/jackc/pgconn"
11
        "github.com/jackc/pgerrcode"
12
        "modernc.org/sqlite"
13
        sqlite3 "modernc.org/sqlite/lib"
14
)
15

16
var (
17
        // ErrRetriesExceeded is returned when a transaction is retried more
18
        // than the max allowed valued without a success.
19
        ErrRetriesExceeded = errors.New("db tx retries exceeded")
20

21
        // postgresErrMsgs are strings that signify retriable errors resulting
22
        // from serialization failures.
23
        postgresErrMsgs = []string{
24
                "could not serialize access",
25
                "current transaction is aborted",
26
                "not enough elements in RWConflictPool",
27
                "deadlock detected",
28
        }
29
)
30

31
// MapSQLError attempts to interpret a given error as a database agnostic SQL
32
// error.
33
func MapSQLError(err error) error {
114✔
34
        if err == nil {
114✔
35
                return nil
×
36
        }
×
37

38
        // Attempt to interpret the error as a sqlite error.
39
        var sqliteErr *sqlite.Error
114✔
40
        if errors.As(err, &sqliteErr) {
123✔
41
                return parseSqliteError(sqliteErr)
9✔
42
        }
9✔
43

44
        // Attempt to interpret the error as a postgres error.
45
        var pqErr *pgconn.PgError
105✔
46
        if errors.As(err, &pqErr) {
114✔
47
                return parsePostgresError(pqErr)
9✔
48
        }
9✔
49

50
        // Sometimes the error won't be properly wrapped, so we'll need to
51
        // inspect raw error itself to detect something we can wrap properly.
52
        // This handles a postgres variant of the error.
53
        for _, postgresErrMsg := range postgresErrMsgs {
477✔
54
                if strings.Contains(err.Error(), postgresErrMsg) {
382✔
55
                        return &ErrSerializationError{
1✔
56
                                DBError: err,
1✔
57
                        }
1✔
58
                }
1✔
59
        }
60

61
        // We'll also attempt to catch this for sqlite, that uses a slightly
62
        // different error message. This is taken from:
63
        // https://gitlab.com/cznic/sqlite/-/blob/v1.25.0/sqlite.go#L75.
64
        const sqliteErrMsg = "SQLITE_BUSY"
95✔
65
        if strings.Contains(err.Error(), sqliteErrMsg) {
95✔
66
                return &ErrSerializationError{
×
67
                        DBError: err,
×
68
                }
×
69
        }
×
70

71
        // Return original error if it could not be classified as a database
72
        // specific error.
73
        return err
95✔
74
}
75

76
// parsePostgresError attempts to parse a sqlite error as a database agnostic
77
// SQL error.
78
func parseSqliteError(sqliteErr *sqlite.Error) error {
9✔
79
        switch sqliteErr.Code() {
9✔
80
        // Handle unique constraint violation error.
81
        case sqlite3.SQLITE_CONSTRAINT_UNIQUE:
8✔
82
                return &ErrSQLUniqueConstraintViolation{
8✔
83
                        DBError: sqliteErr,
8✔
84
                }
8✔
85

86
        case sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY:
1✔
87
                return &ErrSQLUniqueConstraintViolation{
1✔
88
                        DBError: sqliteErr,
1✔
89
                }
1✔
90

91
        // Database is currently busy, so we'll need to try again.
92
        case sqlite3.SQLITE_BUSY:
×
93
                return &ErrSerializationError{
×
94
                        DBError: sqliteErr,
×
95
                }
×
96

97
        default:
×
98
                return fmt.Errorf("unknown sqlite error: %w", sqliteErr)
×
99
        }
100
}
101

102
// parsePostgresError attempts to parse a postgres error as a database agnostic
103
// SQL error.
104
func parsePostgresError(pqErr *pgconn.PgError) error {
9✔
105
        switch pqErr.Code {
9✔
106
        // Handle unique constraint violation error.
107
        case pgerrcode.UniqueViolation:
9✔
108
                return &ErrSQLUniqueConstraintViolation{
9✔
109
                        DBError: pqErr,
9✔
110
                }
9✔
111

112
        // Unable to serialize the transaction, so we'll need to try again.
113
        case pgerrcode.SerializationFailure:
×
114
                return &ErrSerializationError{
×
115
                        DBError: pqErr,
×
116
                }
×
117

118
        // In failed SQL transaction because we didn't catch a previous
119
        // serialization error, so return this one as a serialization error.
NEW
120
        case pgerrcode.InFailedSQLTransaction:
×
NEW
121
                return &ErrSerializationError{
×
NEW
122
                        DBError: pqErr,
×
NEW
123
                }
×
124

125
        // Deadlock detedted because of a serialization error, so return this
126
        // one as a serialization error.
NEW
127
        case pgerrcode.DeadlockDetected:
×
NEW
128
                return &ErrSerializationError{
×
NEW
129
                        DBError: pqErr,
×
NEW
130
                }
×
131

132
        default:
×
133
                return fmt.Errorf("unknown postgres error: %w", pqErr)
×
134
        }
135
}
136

137
// ErrSQLUniqueConstraintViolation is an error type which represents a database
138
// agnostic SQL unique constraint violation.
139
type ErrSQLUniqueConstraintViolation struct {
140
        DBError error
141
}
142

143
func (e ErrSQLUniqueConstraintViolation) Error() string {
80✔
144
        return fmt.Sprintf("sql unique constraint violation: %v", e.DBError)
80✔
145
}
80✔
146

147
// ErrSerializationError is an error type which represents a database agnostic
148
// error that a transaction couldn't be serialized with other concurrent db
149
// transactions.
150
type ErrSerializationError struct {
151
        DBError error
152
}
153

154
// Unwrap returns the wrapped error.
155
func (e ErrSerializationError) Unwrap() error {
×
156
        return e.DBError
×
157
}
×
158

159
// Error returns the error message.
160
func (e ErrSerializationError) Error() string {
1✔
161
        return e.DBError.Error()
1✔
162
}
1✔
163

164
// IsSerializationError returns true if the given error is a serialization
165
// error.
166
func IsSerializationError(err error) bool {
96✔
167
        var serializationError *ErrSerializationError
96✔
168
        return errors.As(err, &serializationError)
96✔
169
}
96✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc