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, 2018 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	log_must set_tunable32 OVERRIDE_ESTIMATE_RECORDSIZE 8192
40	for ds in $datasets; do
41                destroy_dataset $ds "-rf"
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	total_size=$(echo "$total_size" | awk '{print $NF}')
65	if [[ $options != *"P"* ]]; then
66		total_size=${total_size%M}
67		total_size=$(echo "$total_size * $block_count" | bc)
68	fi
69	echo $total_size
70
71}
72
73function verify_size_estimates
74{
75	typeset options=$1
76	typeset file_size=$2
77	typeset refer_diff=$(echo "$refer_size - $estimate_size" | bc)
78	refer_diff=$(echo "$refer_diff / 1" | bc)
79	refer_diff=$(echo "$refer_diff" | nawk '{print ($1 < 0) ? ($1 * -1): $1'})
80	typeset file_diff=$(echo "$file_size - $estimate_size" | bc)
81	file_diff=$(echo "$file_diff / 1" | bc)
82	file_diff=$(echo "$file_diff" | nawk '{print ($1 < 0) ? ($1 * -1):$1'})
83	typeset expected_diff=$(cal_percentage $refer_size)
84
85	[[ -z $refer_diff && -z $file_diff && -z $expected_diff ]] && \
86	    log_fail "zfs send $options failed"
87	[[ $refer_diff -le $expected_diff &&  \
88	    $file_diff -le $expected_diff ]] || \
89	    log_fail "zfs send $options gives wrong size estimates"
90}
91
92log_assert "Verify 'zfs send -nvP' generates valid stream estimates"
93log_onexit cleanup
94log_must set_tunable32 OVERRIDE_ESTIMATE_RECORDSIZE 0
95typeset -l block_count=0
96typeset -l block_size
97typeset -i PERCENT=1
98
99((block_count=1024*1024))
100
101# create dataset
102log_must zfs create $TESTPOOL/$TESTFS1
103
104# create multiple snapshot for the dataset with data
105for block_size in 64 128 256; do
106	log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS1/file$block_size \
107	    bs=1M count=$block_size
108	log_must zfs snapshot $TESTPOOL/$TESTFS1@snap$block_size
109	log_must zfs bookmark $TESTPOOL/$TESTFS1@snap$block_size \
110	    "$TESTPOOL/$TESTFS1#bmark$block_size"
111done
112
113full_snapshot="$TESTPOOL/$TESTFS1@snap64"
114incremental_snapshot="$TESTPOOL/$TESTFS1@snap256"
115full_bookmark="$TESTPOOL/$TESTFS1#bmark64"
116incremental_bookmark="$TESTPOOL/$TESTFS1#bmark256"
117
118full_size=$(zfs send $full_snapshot 2>&1 | wc -c)
119incremental_size=$(zfs send $incremental_snapshot 2>&1 | wc -c)
120incremental_send=$(zfs send -i $full_snapshot $incremental_snapshot 2>&1 | wc -c)
121
122log_note "verify zfs send -nv"
123options="-nv"
124refer_size=$(get_prop refer $full_snapshot)
125estimate_size=$(get_estimate_size $full_snapshot $options)
126log_must verify_size_estimates $options $full_size
127
128log_note "verify zfs send -Pnv"
129options="-Pnv"
130
131estimate_size=$(get_estimate_size $full_snapshot $options)
132log_must verify_size_estimates $options $full_size
133
134log_note "verify zfs send -nv for multiple snapshot send"
135options="-nv"
136refer_size=$(get_prop refer $incremental_snapshot)
137
138estimate_size=$(get_estimate_size $incremental_snapshot $options)
139log_must verify_size_estimates $options $incremental_size
140
141log_note "verify zfs send -vPn for multiple snapshot send"
142options="-vPn"
143
144estimate_size=$(get_estimate_size $incremental_snapshot $options)
145log_must verify_size_estimates $options $incremental_size
146
147log_note "verify zfs send -inv for incremental send"
148options="-nvi"
149refer_size=$(get_prop refer $incremental_snapshot)
150deduct_size=$(get_prop refer $full_snapshot)
151refer_size=$(echo "$refer_size - $deduct_size" | bc)
152
153estimate_size=$(get_estimate_size $incremental_snapshot $options $full_snapshot)
154log_must verify_size_estimates $options $incremental_send
155estimate_size=$(get_estimate_size $incremental_snapshot $options $full_bookmark)
156log_must verify_size_estimates $options $incremental_send
157
158log_note "verify zfs send -ivPn for incremental send"
159options="-vPni"
160
161estimate_size=$(get_estimate_size $incremental_snapshot $options $full_snapshot)
162log_must verify_size_estimates $options $incremental_send
163estimate_size=$(get_estimate_size $incremental_snapshot $options $full_bookmark)
164log_must verify_size_estimates $options $incremental_send
165
166log_must zfs destroy -r $TESTPOOL/$TESTFS1
167
168#setup_recursive_send
169datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
170    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
171# create nested datasets
172log_must zfs create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
173
174# verify dataset creation
175for ds in $datasets; do
176        datasetexists $ds || log_fail "Create $ds dataset fail."
177done
178for ds in $datasets; do
179	log_must dd if=/dev/urandom of=/$ds/file64 \
180	    bs=1M count=64
181done
182
183# create recursive nested snapshot
184log_must zfs snapshot -r $TESTPOOL/$TESTFS1@snap64
185for ds in $datasets; do
186        datasetexists $ds@snap64 || log_fail "Create $ds@snap64 snapshot fail."
187done
188recursive_size=$(zfs send -R $full_snapshot 2>&1 | wc -c)
189log_note "verify zfs send -Rnv for recursive send"
190options="-Rnv"
191refer_size=$(get_prop refer $full_snapshot)
192refer_size=$(echo "$refer_size * 3" | bc)
193
194estimate_size=$(get_estimate_size $full_snapshot $options)
195log_must verify_size_estimates $options $recursive_size
196
197log_note "verify zfs send -RvPn for recursive send"
198options="-RvPn"
199estimate_size=$(get_estimate_size $full_snapshot $options)
200log_must verify_size_estimates $options $recursive_size
201
202log_pass "'zfs send' prints the correct size estimates using '-n' and '-P' options."
203