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

lightningnetwork / lnd / 11934293069

20 Nov 2024 01:22PM UTC coverage: 58.969% (+0.02%) from 58.951%
11934293069

Pull #9242

github

aakselrod
testing: get goroutines from sweeper when deadlocked at shutdown
Pull Request #9242: Reapply #8644

50 of 83 new or added lines in 4 files covered. (60.24%)

63 existing lines in 14 files now uncovered.

132805 of 225212 relevant lines covered (58.97%)

19552.57 hits per line

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

51.35
/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 = []string{
22
                "could not serialize access",
23
                "current transaction is aborted",
24
                "not enough elements in RWConflictPool",
25
                "deadlock detected",
26
        }
27
)
28

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

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

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

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

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

69
        // Return original error if it could not be classified as a database
70
        // specific error.
71
        return err
94✔
72
}
73

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

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

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

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

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

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

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

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

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

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

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

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

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

157
// Error returns the error message.
158
func (e ErrSerializationError) Error() string {
×
159
        return e.DBError.Error()
×
160
}
×
161

162
// IsSerializationError returns true if the given error is a serialization
163
// error.
164
func IsSerializationError(err error) bool {
94✔
165
        var serializationError *ErrSerializationError
94✔
166
        return errors.As(err, &serializationError)
94✔
167
}
94✔
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