Skip to content

Commit

Permalink
Merge pull request #46 from markusressel/feature/list-snapshot-size
Browse files Browse the repository at this point in the history
add "Used" column to snapshot browser
  • Loading branch information
markusressel authored Nov 3, 2024
2 parents f418fed + a20f849 commit 1c17cc8
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 96 deletions.
12 changes: 11 additions & 1 deletion internal/ui/snapshot_browser/snapshot_browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package snapshot_browser

import (
"fmt"
"github.com/dustin/go-humanize"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"golang.org/x/exp/slices"
Expand Down Expand Up @@ -59,8 +60,13 @@ var (
Title: "Diff",
Alignment: tview.AlignCenter,
}
columnUsed = &table.Column{
Id: 3,
Title: "Used",
Alignment: tview.AlignCenter,
}
tableColumns = []*table.Column{
columnName, columnDate, columnDiff,
columnName, columnDate, columnDiff, columnUsed,
}
)

Expand Down Expand Up @@ -109,6 +115,8 @@ func (snapshotBrowser *SnapshotBrowserComponent) createLayout() *tview.Pages {
cellText = "N/A"
cellColor = theme.Colors.SnapshotBrowser.Table.State.Unknown
}
} else if column == columnUsed {
cellText = humanize.IBytes(entry.Snapshot.GetUsed())
}
cell := tview.NewTableCell(cellText).
SetTextColor(cellColor).SetAlign(cellAlign)
Expand All @@ -129,6 +137,8 @@ func (snapshotBrowser *SnapshotBrowserComponent) createLayout() *tview.Pages {
result = a.Snapshot.Date.Compare(*b.Snapshot.Date)
} else if columnToSortBy == columnDiff {
result = int(b.DiffState - a.DiffState)
} else if columnToSortBy == columnUsed {
result = int(b.Snapshot.GetUsed() - a.Snapshot.GetUsed())
}
if inverted {
result *= -1
Expand Down
63 changes: 0 additions & 63 deletions internal/util/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ package util
import (
"fmt"
"golang.org/x/exp/constraints"
"sort"
"strconv"
"zfs-file-history/internal/logging"
)

const (
InterpolationTypeLinear = "linear"
)

// Coerce returns a value that is at least min and at most max, otherwise value
func Coerce[T constraints.Ordered](value T, min T, max T) T {
if value > max {
Expand Down Expand Up @@ -51,64 +46,6 @@ func Ratio(target float64, rangeMin float64, rangeMax float64) float64 {
return (target - rangeMin) / (rangeMax - rangeMin)
}

// UpdateSimpleMovingAvg calculates the new moving average, based on an existing average and buffer size
func UpdateSimpleMovingAvg(oldAvg float64, n int, newValue float64) float64 {
return oldAvg + (1/float64(n))*(newValue-oldAvg)
}

// InterpolateLinearly takes the given mapping and adds interpolated values in [start;stop].
func InterpolateLinearly(data *map[int]float64, start int, stop int) map[int]float64 {
interpolated := map[int]float64{}
for i := start; i <= stop; i++ {
interpolatedValue := CalculateInterpolatedCurveValue(*data, InterpolationTypeLinear, float64(i))
interpolated[i] = interpolatedValue
}
return interpolated
}

// CalculateInterpolatedCurveValue creates an interpolated function from the given map of x-values -> y-values
// as specified by the interpolationType and returns the y-value for the given input
func CalculateInterpolatedCurveValue(steps map[int]float64, interpolationType string, input float64) float64 {
xValues := make([]int, 0, len(steps))
for x := range steps {
xValues = append(xValues, x)
}
// sort them increasing
sort.Ints(xValues)

// find value closest to input
for i := 0; i < len(xValues)-1; i++ {
currentX := xValues[i]
nextX := xValues[i+1]

if input <= float64(currentX) && i == 0 {
// input is below the smallest given step, so
// we fall back to the value of the smallest step
return steps[currentX]
}

if input >= float64(nextX) {
continue
}

if input == float64(currentX) {
return steps[currentX]
} else {
// input is somewhere in between currentX and nextX
currentY := steps[currentX]
nextY := steps[nextX]

ratio := Ratio(input, float64(currentX), float64(nextX))
interpolation := currentY + ratio*(nextY-currentY)
return interpolation
}
}

// input is above (or equal to) the largest given
// step, so we fall back to the value of the largest step
return steps[xValues[len(xValues)-1]]
}

// FindClosest finds the closest value to target in options.
func FindClosest(target int, arr []int) int {
n := len(arr)
Expand Down
26 changes: 0 additions & 26 deletions internal/util/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,6 @@ import (
"testing"
)

func TestCalculateInterpolatedCurveValue(t *testing.T) {
// GIVEN
expectedInputOutput := map[float64]float64{
//-100.0: 0.0,
0: 0.0,
100.0: 100.0,
500.0: 500.0,
1000.0: 1000.0,
2000.0: 1000.0,
}
steps := map[int]float64{
0: 0,
100: 100,
1000: 1000,
}
interpolationType := InterpolationTypeLinear

for input, output := range expectedInputOutput {
// WHEN
result := CalculateInterpolatedCurveValue(steps, interpolationType, input)

// THEN
assert.Equal(t, output, result)
}
}

func TestRatio(t *testing.T) {
// GIVEN
a := 0.0
Expand Down
2 changes: 1 addition & 1 deletion internal/zfs/dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (dataset *Dataset) GetSnapshots() ([]*Snapshot, error) {
logging.Warning("Could not find snapshot %s on dataset %s", name, dataset.GetName())
}

result = append(result, NewSnapshot(name, file, dataset, &creationDate))
result = append(result, NewSnapshot(name, file, dataset, &creationDate, s))
}

return result, nil
Expand Down
24 changes: 19 additions & 5 deletions internal/zfs/snapshot.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package zfs

import (
golibzfs "github.com/kraudcloud/go-libzfs"
"io"
"os"
path2 "path"
"strconv"
"strings"
"syscall"
"time"
Expand All @@ -17,18 +19,21 @@ type Snapshot struct {
Path string
ParentDataset *Dataset
Date *time.Time

internalSnapshot *golibzfs.Dataset
}

func (s *Snapshot) Equal(e Snapshot) bool {
return s.Name == e.Name && s.Path == e.Path
}

func NewSnapshot(name string, path string, parentDataset *Dataset, date *time.Time) *Snapshot {
func NewSnapshot(name string, path string, parentDataset *Dataset, date *time.Time, s *golibzfs.Dataset) *Snapshot {
snapshot := &Snapshot{
Name: name,
Path: path,
ParentDataset: parentDataset,
Date: date,
Name: name,
Path: path,
ParentDataset: parentDataset,
Date: date,
internalSnapshot: s,
}

return snapshot
Expand Down Expand Up @@ -300,6 +305,15 @@ func (s *Snapshot) DestroyRecursive() error {
return ds.DestroySnapshot(s.Name, true)
}

func (s *Snapshot) GetUsed() uint64 {
used, err := strconv.ParseUint(s.internalSnapshot.Properties[golibzfs.DatasetPropUsed].Value, 10, 64)
if err != nil {
logging.Error("Could not parse used property: %s", err.Error())
return 0
}
return used
}

func syncFileProperties(dstPath string, stat os.FileInfo) error {
err := os.Chmod(dstPath, stat.Mode())
if err != nil {
Expand Down

0 comments on commit 1c17cc8

Please sign in to comment.