zfs: use channel as iterator for ZFSList results

The old approach with ZFSList would keep the two-dimensional array of
lines and their fields in memory (for a short time), which could easily
consume 100s of MiB with > 10000 snapshots / bookmarks (see #34)

fixes #61
This commit is contained in:
Christian Schwarz
2018-02-18 13:28:46 +01:00
parent aa92261ea7
commit 3ba3648f0f
4 changed files with 95 additions and 13 deletions

View File

@@ -2,6 +2,7 @@ package zfs
import (
"bytes"
"context"
"errors"
"fmt"
"strconv"
@@ -61,17 +62,23 @@ type FilesystemVersionFilter interface {
}
func ZFSListFilesystemVersions(fs *DatasetPath, filter FilesystemVersionFilter) (res []FilesystemVersion, err error) {
var fieldLines [][]string
fieldLines, err = ZFSList(
listResults := make(chan ZFSListResult)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go ZFSListChan(ctx, listResults,
[]string{"name", "guid", "createtxg", "creation"},
"-r", "-d", "1",
"-t", "bookmark,snapshot",
"-s", "createtxg", fs.ToString())
if err != nil {
return
}
res = make([]FilesystemVersion, 0, len(fieldLines))
for _, line := range fieldLines {
res = make([]FilesystemVersion, 0)
for listResult := range listResults {
if listResult.err != nil {
return nil, listResult.err
}
line := listResult.fields
if len(line[0]) < 3 {
err = errors.New(fmt.Sprintf("snapshot or bookmark name implausibly short: %s", line[0]))