Skip to content

Commit

Permalink
Merge pull request #2 from noborus/progress_copy
Browse files Browse the repository at this point in the history
Added support for pg_stat_progress_copy
  • Loading branch information
noborus authored Nov 29, 2021
2 parents c8b5958 + dd0ea99 commit 4f55073
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
build:
strategy:
matrix:
go-version: [ '1.16' ]
go-version: [ '1.17' ]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.16
go-version: 1.17
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

A CUI tool that monitors PostgreSQL's pg_stat_progress*.

Supported progress reports are ANALYZE, CLUSTER, CREATE INDEX, VACUUM, and BASE_BACKUP.
Supported progress reports are ANALYZE, CLUSTER, CREATE INDEX, VACUUM, COPY, and BASE_BACKUP.
See [Progress Reporting](https://www.postgresql.org/docs/current/progress-reporting.html) for more information.

![pgsp.png](https://raw.githubusercontent.com/noborus/pgsp/master/docs/pgsp.png)


## Requires

go 1.16 or later
Expand All @@ -16,7 +15,7 @@ go 1.16 or later

### Download binary

[releases page](https://github.com/noborus/pgsp/releases/tag/v0.0.1).
[releases page](https://github.com/noborus/pgsp/releases/).

### Go install

Expand All @@ -43,11 +42,27 @@ pg_stat_progress_basebackup
█████████████████████████░░░░░░░░░░░░░░░░░░ 56%
```

It is also possible to specify one of the `analyze`, `basebackup`, `cluster`, `copy`, `createindex`, `vacuums` for monitoring.

```console
pgsp basebackup
```

```console
Monitors PostgreSQL's pg_stat_progress_*.

Usage:
pgsp [flags]
pgsp [command]

Available Commands:
analyze analyze
basebackup basebackup
cluster cluster
copy copy
createindex createindex
help Help about any command
vacuum vacuum

Flags:
-a, --AfterCompletion int Time to display after completion(Seconds) (default 10)
Expand All @@ -58,4 +73,6 @@ Flags:
-h, --help help for pgsp
-t, --toggle Help message for toggle
-v, --version display version information
```

Use "pgsp [command] --help" for more information about a command.
```
20 changes: 20 additions & 0 deletions cmd/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cmd

import (
"github.com/noborus/pgsp/tui"
"github.com/spf13/cobra"
)

// copyCmd represents the vacuum command
var copyCmd = &cobra.Command{
Use: "copy",
Short: "copy",
Long: `pg_stat_progress_copy.`,
Run: func(cmd *cobra.Command, args []string) {
Progress(tui.Copy)
},
}

func init() {
rootCmd.AddCommand(copyCmd)
}
140 changes: 140 additions & 0 deletions copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package pgsp

import (
"bytes"
"context"
"database/sql"
"log"
"strconv"

_ "github.com/lib/pq"
"github.com/noborus/pgsp/vertical"
"github.com/olekukonko/tablewriter"
)

// pg_stat_progress_copy
type Copy struct {
PID int `db:"pid"`
DATID int `db:"datid"`
DATNAME string `db:"datname"`
RELID int `db:"relid"`
COMMAND string `db:"command"`
CTYPE string `db:"type"`
BYTESProcessed int64 `db:"bytes_processed"`
BYTESTotal int64 `db:"bytes_total"`
TUPLESProcessed int64 `db:"tuples_processed"`
TUPLESExcluded int64 `db:"tuples_excluded"`
}

var CopyColumns = []string{
"pid",
"datid",
"datname",
"relid",
"command",
"type",
"bytes_processed",
"bytes_total",
"tuples_processed",
"tuples_excluded",
}

var CopyTableName = "pg_stat_progress_copy"

func GetCopy(ctx context.Context, db *sql.DB) ([]Copy, error) {
query := buildQuery(CopyTableName, CopyColumns)
return selectCopy(ctx, db, query)
}

func selectCopy(ctx context.Context, db *sql.DB, query string) ([]Copy, error) {
rows, err := db.QueryContext(ctx, query)
if err != nil {
log.Println(err)
return nil, err
}
defer rows.Close()

var as []Copy
for rows.Next() {
var row Copy
err = rows.Scan(
&row.PID,
&row.DATID,
&row.DATNAME,
&row.RELID,
&row.COMMAND,
&row.CTYPE,
&row.BYTESProcessed,
&row.BYTESTotal,
&row.TUPLESProcessed,
&row.TUPLESExcluded,
)
if err != nil {
return nil, err
}
as = append(as, row)
}
return as, nil
}

func (v Copy) Name() string {
return CopyTableName
}

func (v Copy) Pid() int {
return v.PID
}

func (v Copy) Table() string {
value := []string{
strconv.Itoa(v.PID),
strconv.Itoa(v.DATID),
v.DATNAME,
strconv.Itoa(v.RELID),
v.COMMAND,
v.CTYPE,
strconv.FormatInt(v.BYTESProcessed, 10),
strconv.FormatInt(v.BYTESTotal, 10),
strconv.FormatInt(v.TUPLESProcessed, 10),
strconv.FormatInt(v.TUPLESExcluded, 10),
}

buff := new(bytes.Buffer)
t := tablewriter.NewWriter(buff)
t.SetHeader(CopyColumns[0:7])
t.Append(value[0:7])
t.Render()

t2 := tablewriter.NewWriter(buff)
t2.SetHeader(CopyColumns[7:])
t2.Append(value[7:])
t2.Render()
return buff.String()
}

func (v Copy) Vertical() string {
buff := new(bytes.Buffer)
vt := vertical.NewWriter(buff)
vt.SetHeader(CopyColumns)
vt.Append([]interface{}{
v.PID,
v.DATID,
v.DATNAME,
v.COMMAND,
v.RELID,
v.CTYPE,
v.BYTESProcessed,
v.BYTESTotal,
v.TUPLESProcessed,
v.TUPLESExcluded,
})
vt.Render()
return buff.String()
}

func (v Copy) Progress() float64 {
if v.BYTESTotal == 0 {
return float64(0.5)
}
return float64(v.BYTESProcessed) / float64(v.BYTESTotal)
}
26 changes: 26 additions & 0 deletions tui/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Model struct {
Analyze bool
Cluster bool
BaseBackup bool
Copy bool
}

const (
Expand All @@ -55,6 +56,7 @@ const (
Vacuum
Cluster
BaseBackup
Copy
)

var colorTables map[string][]string = map[string][]string{
Expand All @@ -63,6 +65,7 @@ var colorTables map[string][]string = map[string][]string{
"pg_stat_progress_vacuum": {"#5A56E0", "#FF7CCB"},
"pg_stat_progress_cluster": {"#5A56E0", "#EE6FF8"},
"pg_stat_progress_basebackup": {"#FDFF8C", "#FF7CCB"},
"pg_stat_progress_copy": {"#5AF6FF", "#7CFFCB"},
}

var spin []string = []string{"|", "/", "-", "\\"}
Expand All @@ -81,6 +84,7 @@ func NewModel(db *sql.DB) Model {
Vacuum: true,
Cluster: true,
BaseBackup: true,
Copy: true,
}
return model
}
Expand All @@ -92,6 +96,7 @@ func Targets(model *Model, t int) *Model {
model.Vacuum = false
model.Cluster = false
model.BaseBackup = false
model.Copy = false
if t == Analyze {
model.Analyze = true
}
Expand All @@ -107,6 +112,9 @@ func Targets(model *Model, t int) *Model {
if t == BaseBackup {
model.BaseBackup = true
}
if t == Copy {
model.Copy = true
}
}
return model
}
Expand Down Expand Up @@ -245,6 +253,17 @@ func (m *Model) addBaseBackup(ctx context.Context) error {
return nil
}

func (m *Model) addCopy(ctx context.Context) error {
copy, err := pgsp.GetCopy(ctx, m.DB)
if err != nil {
return err
}
for _, v := range copy {
m.pgrss = m.addProgress(m.pgrss, v)
}
return nil
}

func (m *Model) updateProgress(ctx context.Context, db *sql.DB) error {
if m.CreateIndex {
if err := m.addCreateIndex(ctx); err != nil {
Expand Down Expand Up @@ -281,6 +300,13 @@ func (m *Model) updateProgress(ctx context.Context, db *sql.DB) error {
}
}

if m.Copy {
if err := m.addCopy(ctx); err != nil {
log.Println(err)
m.Copy = false
}
}

pgrss := make([]pgrs, 0, len(m.pgrss))
for _, pgrs := range m.pgrss {
if time.Since(pgrs.time) < time.Second*AfterCompletion {
Expand Down

0 comments on commit 4f55073

Please sign in to comment.