Skip to content

Commit 5046c1a

Browse files
authored
[+] switch to VirtualXID from TransactionXID, solves #674 (#675)
Turned out issuing `txid_current()` at the beginning of every chain transaction is creating a session that's sits idle in transaction for the duration of the entire chain. In current case, with a single task `{kind == PROGRAM}`, that idle transaction doesn't do anything aside from pin the `xmin` horizon and block vacuum for 6+ hours. The same issue occurs for SQL tasks that are `Remote` or `Autonomous`.
1 parent da8486a commit 5046c1a

File tree

5 files changed

+13
-10
lines changed

5 files changed

+13
-10
lines changed

internal/pgengine/access.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ chain_id, task_id, command, kind, last_run, finished, returncode, pid, output, c
3434
VALUES ($1, $2, $3, $4, clock_timestamp() - $5 :: interval, clock_timestamp(), $6, $7, NULLIF($8, ''), $9, $10, $11)`,
3535
task.ChainID, task.TaskID, task.Script, task.Kind,
3636
fmt.Sprintf("%f seconds", float64(task.Duration)/1000000),
37-
retCode, pge.Getsid(), strings.TrimSpace(output), pge.ClientName, task.Txid,
37+
retCode, pge.Getsid(), strings.TrimSpace(output), pge.ClientName, task.Vxid,
3838
task.IgnoreError)
3939
if err != nil {
4040
pge.l.WithError(err).Error("Failed to log chain element execution status")

internal/pgengine/transaction.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import (
1414
"github.com/jackc/pgx/v5/pgtype"
1515
)
1616

17-
// StartTransaction returns transaction object, transaction id and error
18-
func (pge *PgEngine) StartTransaction(ctx context.Context) (tx pgx.Tx, txid int64, err error) {
17+
// StartTransaction returns transaction object, virtual transaction id and error
18+
func (pge *PgEngine) StartTransaction(ctx context.Context) (tx pgx.Tx, vxid int64, err error) {
1919
if tx, err = pge.ConfigDb.Begin(ctx); err != nil {
2020
return
2121
}
22-
err = tx.QueryRow(ctx, "SELECT txid_current()").Scan(&txid)
22+
err = tx.QueryRow(ctx, `SELECT
23+
(split_part(virtualxid, '/', 1)::int8 << 32) | split_part(virtualxid, '/', 2)::int8
24+
FROM pg_locks
25+
WHERE pid = pg_backend_pid() AND virtualxid IS NOT NULL`).Scan(&vxid)
2326
return
2427
}
2528

internal/pgengine/transaction_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestStartTransaction(t *testing.T) {
4545
assert.Error(t, err)
4646

4747
mockPool.ExpectBegin()
48-
mockPool.ExpectQuery("SELECT txid_current()").WillReturnRows(pgxmock.NewRows([]string{"txid"}).AddRow(int64(42)))
48+
mockPool.ExpectQuery("SELECT").WillReturnRows(pgxmock.NewRows([]string{"txid"}).AddRow(int64(42)))
4949
tx, txid, err := pge.StartTransaction(ctx)
5050
assert.NotNil(t, tx)
5151
assert.EqualValues(t, 42, txid)

internal/pgengine/types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type ChainTask struct {
5353
Timeout int `db:"timeout"` // in milliseconds
5454
StartedAt time.Time `db:"-"`
5555
Duration int64 `db:"-"` // in microseconds
56-
Txid int64 `db:"-"`
56+
Vxid int64 `db:"-"`
5757
}
5858

5959
func (task *ChainTask) IsRemote() bool {

internal/scheduler/chain.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -192,20 +192,20 @@ func (sch *Scheduler) executeChain(ctx context.Context, chain Chain) {
192192
var ChainTasks []pgengine.ChainTask
193193
var bctx context.Context
194194
var cancel context.CancelFunc
195-
var txid int64
195+
var vxid int64
196196

197197
chainCtx, cancel := getTimeoutContext(ctx, sch.Config().Resource.ChainTimeout, chain.Timeout)
198198
if cancel != nil {
199199
defer cancel()
200200
}
201201

202202
chainL := sch.l.WithField("chain", chain.ChainID)
203-
tx, txid, err := sch.pgengine.StartTransaction(chainCtx)
203+
tx, vxid, err := sch.pgengine.StartTransaction(chainCtx)
204204
if err != nil {
205205
chainL.WithError(err).Error("Cannot start transaction")
206206
return
207207
}
208-
chainL = chainL.WithField("txid", txid)
208+
chainL = chainL.WithField("vxid", vxid)
209209

210210
err = sch.pgengine.GetChainElements(chainCtx, &ChainTasks, chain.ChainID)
211211
if err != nil {
@@ -217,7 +217,7 @@ func (sch *Scheduler) executeChain(ctx context.Context, chain Chain) {
217217
/* now we can loop through every element of the task chain */
218218
for _, task := range ChainTasks {
219219
task.ChainID = chain.ChainID
220-
task.Txid = txid
220+
task.Vxid = vxid
221221
l := chainL.WithField("task", task.TaskID)
222222
l.Info("Starting task")
223223
taskCtx := log.WithLogger(chainCtx, l)

0 commit comments

Comments
 (0)