mirror of
https://github.com/zrepl/zrepl.git
synced 2024-12-22 23:20:51 +01:00
client/status: current bytes/second + spinning progress bar
This commit is contained in:
parent
0b8c19c620
commit
2889a5d5ff
@ -22,6 +22,41 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type bytesProgressHistory struct {
|
||||||
|
changeCounter int
|
||||||
|
lastChangeAt time.Time
|
||||||
|
last int64
|
||||||
|
bpsIncreaseExpAvg float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bytesProgressHistory) Update(currentVal int64) (bytesPerSecondAvg int64, changeCount int) {
|
||||||
|
if currentVal < p.last {
|
||||||
|
*p = bytesProgressHistory{
|
||||||
|
last: currentVal,
|
||||||
|
lastChangeAt: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
p.last = currentVal
|
||||||
|
}()
|
||||||
|
if time.Now().Sub(p.lastChangeAt) > 3 *time.Second { // FIXME depends on refresh frequency
|
||||||
|
p.changeCounter = 0
|
||||||
|
p.bpsIncreaseExpAvg = 0
|
||||||
|
}
|
||||||
|
if currentVal != p.last {
|
||||||
|
p.changeCounter++
|
||||||
|
p.lastChangeAt = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
byteIncrease := float64(currentVal - p.last)
|
||||||
|
if byteIncrease < 0 {
|
||||||
|
byteIncrease = 0
|
||||||
|
}
|
||||||
|
const factor = 0.1
|
||||||
|
p.bpsIncreaseExpAvg = (1-factor) * p.bpsIncreaseExpAvg + factor *byteIncrease
|
||||||
|
return int64(p.bpsIncreaseExpAvg), p.changeCounter
|
||||||
|
}
|
||||||
|
|
||||||
type tui struct {
|
type tui struct {
|
||||||
x, y int
|
x, y int
|
||||||
indent int
|
indent int
|
||||||
@ -29,10 +64,14 @@ type tui struct {
|
|||||||
lock sync.Mutex //For report and error
|
lock sync.Mutex //For report and error
|
||||||
report map[string]job.Status
|
report map[string]job.Status
|
||||||
err error
|
err error
|
||||||
|
|
||||||
|
replicationProgress map[string]*bytesProgressHistory // by job name
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTui() tui {
|
func newTui() tui {
|
||||||
return tui{}
|
return tui{
|
||||||
|
replicationProgress: make(map[string]*bytesProgressHistory, 0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tui) moveCursor(x, y int) {
|
func (t *tui) moveCursor(x, y int) {
|
||||||
@ -204,6 +243,15 @@ loop:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tui) getReplicationProgresHistory(jobName string) *bytesProgressHistory {
|
||||||
|
p, ok := t.replicationProgress[jobName]
|
||||||
|
if !ok {
|
||||||
|
p = &bytesProgressHistory{}
|
||||||
|
t.replicationProgress[jobName] = p
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tui) draw() {
|
func (t *tui) draw() {
|
||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
defer t.lock.Unlock()
|
defer t.lock.Unlock()
|
||||||
@ -263,7 +311,7 @@ func (t *tui) draw() {
|
|||||||
t.printf("Replication:")
|
t.printf("Replication:")
|
||||||
t.newline()
|
t.newline()
|
||||||
t.addIndent(1)
|
t.addIndent(1)
|
||||||
t.renderReplicationReport(pushStatus.Replication)
|
t.renderReplicationReport(pushStatus.Replication, t.getReplicationProgresHistory(k))
|
||||||
t.addIndent(-1)
|
t.addIndent(-1)
|
||||||
|
|
||||||
t.printf("Pruning Sender:")
|
t.printf("Pruning Sender:")
|
||||||
@ -283,7 +331,7 @@ func (t *tui) draw() {
|
|||||||
termbox.Flush()
|
termbox.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tui) renderReplicationReport(rep *replication.Report) {
|
func (t *tui) renderReplicationReport(rep *replication.Report, history *bytesProgressHistory) {
|
||||||
if rep == nil {
|
if rep == nil {
|
||||||
t.printf("...\n")
|
t.printf("...\n")
|
||||||
return
|
return
|
||||||
@ -335,9 +383,10 @@ func (t *tui) renderReplicationReport(rep *replication.Report) {
|
|||||||
transferred += fstx
|
transferred += fstx
|
||||||
total += fstotal
|
total += fstotal
|
||||||
}
|
}
|
||||||
|
rate, changeCount := history.Update(transferred)
|
||||||
t.write("Progress: ")
|
t.write("Progress: ")
|
||||||
t.drawBar(80, transferred, total)
|
t.drawBar(50, transferred, total, changeCount)
|
||||||
t.write(fmt.Sprintf(" %s / %s", ByteCountBinary(transferred), ByteCountBinary(total)))
|
t.write(fmt.Sprintf(" %s / %s @ %s/s", ByteCountBinary(transferred), ByteCountBinary(total), ByteCountBinary(rate)))
|
||||||
t.newline()
|
t.newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +543,10 @@ func leftPad(str string, length int, pad string) string {
|
|||||||
return times(pad, length-len(str)) + str
|
return times(pad, length-len(str)) + str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tui) drawBar(length int, bytes, totalBytes int64) {
|
var arrowPositions = `>\|/`
|
||||||
|
|
||||||
|
// changeCount = 0 indicates stall / no progresss
|
||||||
|
func (t *tui) drawBar(length int, bytes, totalBytes int64, changeCount int) {
|
||||||
var completedLength int
|
var completedLength int
|
||||||
if totalBytes > 0 {
|
if totalBytes > 0 {
|
||||||
completedLength = int(int64(length) * bytes / totalBytes)
|
completedLength = int(int64(length) * bytes / totalBytes)
|
||||||
@ -507,7 +559,7 @@ func (t *tui) drawBar(length int, bytes, totalBytes int64) {
|
|||||||
|
|
||||||
t.write("[")
|
t.write("[")
|
||||||
t.write(times("=", completedLength))
|
t.write(times("=", completedLength))
|
||||||
t.write(">")
|
t.write( string(arrowPositions[changeCount%len(arrowPositions)]))
|
||||||
t.write(times("-", length-completedLength))
|
t.write(times("-", length-completedLength))
|
||||||
t.write("]")
|
t.write("]")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user