Estimate snapshot send size
This commit is contained in:
parent
6b01056691
commit
6d3dff30aa
103
sendrecv.go
103
sendrecv.go
|
@ -5,13 +5,18 @@ package zfs
|
||||||
// #include "common.h"
|
// #include "common.h"
|
||||||
// #include "zpool.h"
|
// #include "zpool.h"
|
||||||
// #include "zfs.h"
|
// #include "zfs.h"
|
||||||
|
// #include <memory.h>
|
||||||
|
// #include <string.h>
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,11 +28,11 @@ type SendFlags struct {
|
||||||
Dedup bool
|
Dedup bool
|
||||||
Props bool
|
Props bool
|
||||||
DryRun bool
|
DryRun bool
|
||||||
// Parsable bool
|
Parsable bool
|
||||||
// Progress bool
|
Progress bool
|
||||||
LargeBlock bool
|
LargeBlock bool
|
||||||
EmbedData bool
|
EmbedData bool
|
||||||
// Compress bool
|
Compress bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecvFlags struct {
|
type RecvFlags struct {
|
||||||
|
@ -58,11 +63,11 @@ func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
|
||||||
cflags.dedup = to_boolean_t(flags.Dedup)
|
cflags.dedup = to_boolean_t(flags.Dedup)
|
||||||
cflags.props = to_boolean_t(flags.Props)
|
cflags.props = to_boolean_t(flags.Props)
|
||||||
cflags.dryrun = to_boolean_t(flags.DryRun)
|
cflags.dryrun = to_boolean_t(flags.DryRun)
|
||||||
// cflags.parsable = to_boolean_t(flags.Parsable)
|
cflags.parsable = to_boolean_t(flags.Parsable)
|
||||||
// cflags.progress = to_boolean_t(flags.Progress)
|
cflags.progress = to_boolean_t(flags.Progress)
|
||||||
cflags.largeblock = to_boolean_t(flags.LargeBlock)
|
cflags.largeblock = to_boolean_t(flags.LargeBlock)
|
||||||
cflags.embed_data = to_boolean_t(flags.EmbedData)
|
cflags.embed_data = to_boolean_t(flags.EmbedData)
|
||||||
// cflags.compress = to_boolean_t(flags.Compress)
|
cflags.compress = to_boolean_t(flags.Compress)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,53 +204,61 @@ func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size uint64, err error) {
|
// SendSize - estimate snapshot size to transfer
|
||||||
var porigin Property
|
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size int64, err error) {
|
||||||
var from Dataset
|
var r, w *os.File
|
||||||
var dpath string
|
errch := make(chan error)
|
||||||
if dpath, err = d.Path(); err != nil {
|
defer func() {
|
||||||
|
select {
|
||||||
|
case <-errch:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
close(errch)
|
||||||
|
}()
|
||||||
|
flags.DryRun = true
|
||||||
|
flags.Verbose = true
|
||||||
|
flags.Progress = true
|
||||||
|
flags.Parsable = true
|
||||||
|
if r, w, err = os.Pipe(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
zc := C.new_zfs_cmd()
|
defer r.Close()
|
||||||
defer C.free(unsafe.Pointer(zc))
|
go func() {
|
||||||
dpath = strings.Split(dpath, "@")[0]
|
var tmpe error
|
||||||
if len(FromName) > 0 {
|
saveOut := C.dup(C.fileno(C.stdout))
|
||||||
|
if res := C.dup2(C.int(w.Fd()), C.fileno(C.stdout)); res < 0 {
|
||||||
if FromName[0] == '#' || FromName[0] == '@' {
|
tmpe = fmt.Errorf("Redirection of zfslib stdout failed %d", res)
|
||||||
FromName = dpath + FromName
|
|
||||||
}
|
|
||||||
porigin, _ = d.GetProperty(DatasetPropOrigin)
|
|
||||||
if len(porigin.Value) > 0 && porigin.Value == FromName {
|
|
||||||
FromName = ""
|
|
||||||
flags.FromOrigin = true
|
|
||||||
}
|
|
||||||
if from, err = DatasetOpen(FromName); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
zc.zc_fromobj = C.zfs_prop_get_int(from.list.zh, C.ZFS_PROP_OBJSETID)
|
|
||||||
from.Close()
|
|
||||||
} else {
|
} else {
|
||||||
zc.zc_fromobj = 0
|
tmpe = d.send(FromName, w, &flags)
|
||||||
}
|
C.fflush(C.stdout)
|
||||||
zc.zc_obj = C.uint64_t(to_boolean_t(flags.FromOrigin))
|
C.dup2(saveOut, C.fileno(C.stdout))
|
||||||
zc.zc_sendobj = C.zfs_prop_get_int(d.list.zh, C.ZFS_PROP_OBJSETID)
|
|
||||||
zc.zc_guid = 1
|
|
||||||
zc.zc_flags = 0
|
|
||||||
if flags.LargeBlock {
|
|
||||||
zc.zc_flags |= C.LZC_SEND_FLAG_LARGE_BLOCK
|
|
||||||
}
|
|
||||||
if flags.EmbedData {
|
|
||||||
zc.zc_flags |= C.LZC_SEND_FLAG_EMBED_DATA
|
|
||||||
}
|
}
|
||||||
|
w.Close()
|
||||||
|
errch <- tmpe
|
||||||
|
}()
|
||||||
|
|
||||||
// C.estimate_ioctl(d.list.zhp, prevsnap_obj, to_boolean_t(flags.FromOrigin), lzc_send_flags, unsafe.Pointer(&size))
|
r.SetReadDeadline(time.Now().Add(15 * time.Second))
|
||||||
if ec, e := C.estimate_send_size(zc); ec != 0 {
|
var data []byte
|
||||||
err = fmt.Errorf("Failed to estimate send size. %s %d", e.Error(), e.(syscall.Errno))
|
if data, err = ioutil.ReadAll(r); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
size = uint64(zc.zc_objset_type)
|
// parse size
|
||||||
|
var sizeRe *regexp.Regexp
|
||||||
|
if sizeRe, err = regexp.Compile("size[ \t]*([0-9]+)"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
matches := sizeRe.FindAllSubmatch(data, 3)
|
||||||
|
if len(matches) > 0 && len(matches[0]) > 1 {
|
||||||
|
if size, err = strconv.ParseInt(
|
||||||
|
string(matches[0][1]), 10, 64); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = <-errch
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Receive - receive snapshot stream
|
||||||
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
|
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
|
||||||
var dpath string
|
var dpath string
|
||||||
if dpath, err = d.Path(); err != nil {
|
if dpath, err = d.Path(); err != nil {
|
||||||
|
|
6
zfs.c
6
zfs.c
|
@ -256,6 +256,10 @@ struct zfs_cmd *new_zfs_cmd(){
|
||||||
}
|
}
|
||||||
|
|
||||||
int estimate_send_size(struct zfs_cmd *zc) {
|
int estimate_send_size(struct zfs_cmd *zc) {
|
||||||
return zfs_ioctl(libzfsHandle, ZFS_IOC_SEND, zc);
|
int rc = zfs_ioctl(libzfsHandle, ZFS_IOC_SEND, zc);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = errno;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue