Skip to content

Commit 2f8cf7a

Browse files
committed
move to pglocks.go file
1 parent 6646d04 commit 2f8cf7a

File tree

2 files changed

+119
-95
lines changed

2 files changed

+119
-95
lines changed

coderd/database/db.go

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ import (
1212
"context"
1313
"database/sql"
1414
"errors"
15-
"fmt"
16-
"sort"
17-
"strings"
1815
"time"
1916

2017
"github.com/jmoiron/sqlx"
@@ -138,98 +135,6 @@ func (q *sqlQuerier) Ping(ctx context.Context) (time.Duration, error) {
138135
return time.Since(start), err
139136
}
140137

141-
type PGLocks []PGLock
142-
143-
func (l PGLocks) String() string {
144-
// Try to group things together by relation name.
145-
sort.Slice(l, func(i, j int) bool {
146-
return safeString(l[i].RelationName) < safeString(l[j].RelationName)
147-
})
148-
149-
var out strings.Builder
150-
for i, lock := range l {
151-
if i != 0 {
152-
out.WriteString("\n")
153-
}
154-
out.WriteString(lock.String())
155-
}
156-
return out.String()
157-
}
158-
159-
// PGLock docs see: https://www.postgresql.org/docs/current/view-pg-locks.html#VIEW-PG-LOCKS
160-
type PGLock struct {
161-
// LockType see: https://www.postgresql.org/docs/current/monitoring-stats.html#WAIT-EVENT-LOCK-TABLE
162-
LockType *string `db:"locktype"`
163-
Database *string `db:"database"` // oid
164-
Relation *string `db:"relation"` // oid
165-
RelationName *string `db:"relation_name"`
166-
Page *int `db:"page"`
167-
Tuple *int `db:"tuple"`
168-
VirtualXID *string `db:"virtualxid"`
169-
TransactionID *string `db:"transactionid"` // xid
170-
ClassID *string `db:"classid"` // oid
171-
ObjID *string `db:"objid"` // oid
172-
ObjSubID *int `db:"objsubid"`
173-
VirtualTransaction *string `db:"virtualtransaction"`
174-
PID int `db:"pid"`
175-
Mode *string `db:"mode"`
176-
Granted bool `db:"granted"`
177-
FastPath *bool `db:"fastpath"`
178-
WaitStart *time.Time `db:"waitstart"`
179-
}
180-
181-
func (l PGLock) String() string {
182-
granted := "granted"
183-
if !l.Granted {
184-
granted = "waiting"
185-
}
186-
var details string
187-
switch safeString(l.LockType) {
188-
case "relation":
189-
details = ""
190-
case "page":
191-
details = fmt.Sprintf("page=%d", *l.Page)
192-
case "tuple":
193-
details = fmt.Sprintf("page=%d tuple=%d", *l.Page, *l.Tuple)
194-
case "virtualxid":
195-
details = "waiting to acquire virtual tx id lock"
196-
default:
197-
details = "???"
198-
}
199-
return fmt.Sprintf("%d-%5s [%s] %s/%s/%s: %s",
200-
l.PID,
201-
safeString(l.TransactionID),
202-
granted,
203-
safeString(l.RelationName),
204-
safeString(l.LockType),
205-
safeString(l.Mode),
206-
details,
207-
)
208-
}
209-
210-
// PGLocks returns a list of all locks in the database currently in use.
211-
func (q *sqlQuerier) PGLocks(ctx context.Context) (PGLocks, error) {
212-
rows, err := q.sdb.QueryContext(ctx, `
213-
SELECT
214-
relation::regclass AS relation_name,
215-
*
216-
FROM pg_locks;
217-
`)
218-
if err != nil {
219-
return nil, err
220-
}
221-
222-
defer rows.Close()
223-
224-
var locks []PGLock
225-
err = sqlx.StructScan(rows, &locks)
226-
if err != nil {
227-
return nil, err
228-
}
229-
230-
return locks, err
231-
}
232-
233138
func DefaultTXOptions() *TxOptions {
234139
return &TxOptions{
235140
Isolation: sql.LevelDefault,

coderd/database/pglocks.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package database
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"reflect"
7+
"sort"
8+
"strings"
9+
"time"
10+
11+
"github.com/jmoiron/sqlx"
12+
13+
"github.com/coder/coder/v2/coderd/util/slice"
14+
)
15+
16+
// PGLock docs see: https://www.postgresql.org/docs/current/view-pg-locks.html#VIEW-PG-LOCKS
17+
type PGLock struct {
18+
// LockType see: https://www.postgresql.org/docs/current/monitoring-stats.html#WAIT-EVENT-LOCK-TABLE
19+
LockType *string `db:"locktype"`
20+
Database *string `db:"database"` // oid
21+
Relation *string `db:"relation"` // oid
22+
RelationName *string `db:"relation_name"`
23+
Page *int `db:"page"`
24+
Tuple *int `db:"tuple"`
25+
VirtualXID *string `db:"virtualxid"`
26+
TransactionID *string `db:"transactionid"` // xid
27+
ClassID *string `db:"classid"` // oid
28+
ObjID *string `db:"objid"` // oid
29+
ObjSubID *int `db:"objsubid"`
30+
VirtualTransaction *string `db:"virtualtransaction"`
31+
PID int `db:"pid"`
32+
Mode *string `db:"mode"`
33+
Granted bool `db:"granted"`
34+
FastPath *bool `db:"fastpath"`
35+
WaitStart *time.Time `db:"waitstart"`
36+
}
37+
38+
func (l PGLock) Equal(b PGLock) bool {
39+
// Lazy, but hope this works
40+
return reflect.DeepEqual(l, b)
41+
}
42+
43+
func (l PGLock) String() string {
44+
granted := "granted"
45+
if !l.Granted {
46+
granted = "waiting"
47+
}
48+
var details string
49+
switch safeString(l.LockType) {
50+
case "relation":
51+
details = ""
52+
case "page":
53+
details = fmt.Sprintf("page=%d", *l.Page)
54+
case "tuple":
55+
details = fmt.Sprintf("page=%d tuple=%d", *l.Page, *l.Tuple)
56+
case "virtualxid":
57+
details = "waiting to acquire virtual tx id lock"
58+
default:
59+
details = "???"
60+
}
61+
return fmt.Sprintf("%d-%5s [%s] %s/%s/%s: %s",
62+
l.PID,
63+
safeString(l.TransactionID),
64+
granted,
65+
safeString(l.RelationName),
66+
safeString(l.LockType),
67+
safeString(l.Mode),
68+
details,
69+
)
70+
}
71+
72+
// PGLocks returns a list of all locks in the database currently in use.
73+
func (q *sqlQuerier) PGLocks(ctx context.Context) (PGLocks, error) {
74+
rows, err := q.sdb.QueryContext(ctx, `
75+
SELECT
76+
relation::regclass AS relation_name,
77+
*
78+
FROM pg_locks;
79+
`)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
defer rows.Close()
85+
86+
var locks []PGLock
87+
err = sqlx.StructScan(rows, &locks)
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
return locks, err
93+
}
94+
95+
type PGLocks []PGLock
96+
97+
func (l PGLocks) String() string {
98+
// Try to group things together by relation name.
99+
sort.Slice(l, func(i, j int) bool {
100+
return safeString(l[i].RelationName) < safeString(l[j].RelationName)
101+
})
102+
103+
var out strings.Builder
104+
for i, lock := range l {
105+
if i != 0 {
106+
out.WriteString("\n")
107+
}
108+
out.WriteString(lock.String())
109+
}
110+
return out.String()
111+
}
112+
113+
// Difference returns the difference between two sets of locks.
114+
// This is helpful to determine what changed between the two sets.
115+
func (l PGLocks) Difference(to PGLocks) (new PGLocks, removed PGLocks) {
116+
return slice.SymmetricDifferenceFunc(l, to, func(a, b PGLock) bool {
117+
return a.Equal(b)
118+
})
119+
}

0 commit comments

Comments
 (0)