1#!/bin/ksh
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
19#
20
21. $STF_SUITE/include/libtest.shlib
22#
23# DESCRIPTION:
24#	Verify 'zfs send' can generate valid streams with different options
25#
26# STRATEGY:
27#	1. Create datasets
28#	2. Write some data to the datasets
29#	3. Create a full send streams
30#	4. Receive the send stream
31#	5. Do a dry run with different options and verify the generated size
32#          estimate against the received stream
33#
34
35verify_runnable "both"
36
37function cleanup
38{
39	mdb_set_uint32 zfs_override_estimate_recordsize 8192
40	for ds in $datasets; do
41                datasetexists $ds && zfs destroy -rf $ds
42	done
43}
44
45function cal_percentage
46{
47	typeset value=$1
48	return=$(echo "$PERCENT * $value" | bc)
49	return=$(echo "$return / 100" | bc)
50	echo $return
51}
52
53function get_estimate_size
54{
55	typeset snapshot=$1
56	typeset option=$2
57	typeset base_snapshot=${3:-""}
58	if [[ -z $3 ]];then
59		typeset total_size=$(zfs send $option $snapshot 2>&1 | tail -1)
60	else
61		typeset total_size=$(zfs send $option $base_snapshot $snapshot \
62		     2>&1 | tail -1)
63	fi
64	if [[ $options == *"P"* ]]; then
65		total_size=$(echo "$total_size" | awk '{print $2}')
66	else
67		total_size=$(echo "$total_size" | awk '{print $5}')
68		total_size=${total_size%M}
69		total_size=$(echo "$total_size * $block_count" | bc)
70	fi
71	echo $total_size
72
73}
74
75function verify_size_estimates
76{
77	typeset options=$1
78	typeset file_size=$2
79	typeset refer_diff=$(echo "$refer_size - $estimate_size" | bc)
80	refer_diff=$(echo "$refer_diff / 1" | bc)
81	refer_diff=$(echo "$refer_diff" | nawk '{print ($1 < 0) ? ($1 * -1): $1'})
82	typeset file_diff=$(echo "$file_size - $estimate_size" | bc)
83	file_diff=$(echo "$file_diff / 1" | bc)
84	file_diff=$(echo "$file_diff" | nawk '{print ($1 < 0) ? ($1 * -1):$1'})
85	typeset expected_diff=$(cal_percentage $refer_size)
86
87	[[ -z $refer_diff && -z $file_diff && -z $expected_diff ]] && \
88	    log_fail "zfs send $options failed"
89	[[ $refer_diff -le $expected_diff &&  \
90	    $file_diff -le $expected_diff ]] || \
91	    log_fail "zfs send $options gives wrong size estimates"
92}
93
94log_assert "Verify 'zfs send -nvP' generates valid stream estimates"
95log_onexit cleanup
96mdb_set_uint32 zfs_override_estimate_recordsize 0
97typeset -l block_count=0
98typeset -l block_size
99typeset -i PERCENT=1
100
101((block_count=1024*1024))
102
103# create dataset
104log_must zfs create $TESTPOOL/$TESTFS1
105
106# create multiple snapshot for the dataset with data
107for block_size in 64 128 256; do
108	log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS1/file$block_size \
109	    bs=1M count=$block_size
110	log_must zfs snapshot $TESTPOOL/$TESTFS1@snap$block_size
111done
112
113full_snapshot="$TESTPOOL/$TESTFS1@snap64"
114increamental_snapshot="$TESTPOOL/$TESTFS1@snap256"
115
116full_size=$(zfs send $full_snapshot 2>&1 | wc -c)
117increamental_size=$(zfs send $increamental_snapshot 2>&1 | wc -c)
118increamental_send=$(zfs send -i $full_snapshot $increamental_snapshot 2>&1 | wc -c)
119
120log_note "verify zfs send -nv"
121options="-nv"
122refer_size=$(get_prop refer $full_snapshot)
123estimate_size=$(get_estimate_size $full_snapshot $options)
124log_must verify_size_estimates $options $full_size
125
126log_note "verify zfs send -Pnv"
127options="-Pnv"
128
129estimate_size=$(get_estimate_size $full_snapshot $options)
130log_must verify_size_estimates $options $full_size
131
132log_note "verify zfs send -nv for multiple snapshot send"
133options="-nv"
134refer_size=$(get_prop refer $increamental_snapshot)
135
136estimate_size=$(get_estimate_size $increamental_snapshot $options)
137log_must verify_size_estimates $options $increamental_size
138
139log_note "verify zfs send -vPn for multiple snapshot send"
140options="-vPn"
141
142estimate_size=$(get_estimate_size $increamental_snapshot $options)
143log_must verify_size_estimates $options $increamental_size
144
145log_note "verify zfs send -inv for increamental send"
146options="-nvi"
147refer_size=$(get_prop refer $increamental_snapshot)
148deduct_size=$(get_prop refer $full_snapshot)
149refer_size=$(echo "$refer_size - $deduct_size" | bc)
150
151estimate_size=$(get_estimate_size $increamental_snapshot $options $full_snapshot)
152log_must verify_size_estimates $options $increamental_send
153
154log_note "verify zfs send -ivPn for increamental send"
155options="-vPni"
156
157estimate_size=$(get_estimate_size $increamental_snapshot $options $full_snapshot)
158log_must verify_size_estimates $options $increamental_send
159
160log_must zfs destroy -r $TESTPOOL/$TESTFS1
161
162#setup_recursive_send
163datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
164    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
165# create nested datasets
166log_must zfs create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
167
168# verify dataset creation
169for ds in $datasets; do
170        datasetexists $ds || log_fail "Create $ds dataset fail."
171done
172for ds in $datasets; do
173	log_must dd if=/dev/urandom of=/$ds/file64 \
174	    bs=1M count=64
175done
176
177# create recursive nested snapshot
178log_must zfs snapshot -r $TESTPOOL/$TESTFS1@snap64
179for ds in $datasets; do
180        datasetexists $ds@snap64 || log_fail "Create $ds@snap64 snapshot fail."
181done
182recursive_size=$(zfs send -R $full_snapshot 2>&1 | wc -c)
183log_note "verify zfs send -Rnv for recursive send"
184options="-Rnv"
185refer_size=$(get_prop refer $full_snapshot)
186refer_size=$(echo "$refer_size * 3" | bc)
187
188estimate_size=$(get_estimate_size $full_snapshot $options)
189log_must verify_size_estimates $options $recursive_size
190
191log_note "verify zfs send -RvPn for recursive send"
192options="-RvPn"
193estimate_size=$(get_estimate_size $full_snapshot $options)
194log_must verify_size_estimates $options $recursive_size
195
196log_pass "'zfs send' prints the correct size estimates using '-n' and '-P' options."
197