Update Red Hat Copyright Notices
[nbdkit.git] / tests / test-blocksize-sharding.sh
blob9ce32829660be0163293f7f34834c5a382fadb94
1 #!/usr/bin/env bash
2 # nbdkit
3 # Copyright Red Hat
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # * Neither the name of Red Hat nor the names of its contributors may be
17 # used to endorse or promote products derived from this software without
18 # specific prior written permission.
20 # THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # SUCH DAMAGE.
33 # Demonstrate a fix for a bug where blocksize could lose aligned writes
34 # run in parallel with unaligned writes
36 source ./functions.sh
37 set -e
38 set -x
40 requires_plugin eval
41 requires_nbdsh_uri
42 requires dd oflag=seek_bytes </dev/null
44 files='blocksize-sharding.img blocksize-sharding.tmp'
45 rm -f $files
46 cleanup_fn rm -f $files
48 # Script a server that requires 16-byte aligned requests, and which delays
49 # 4s after reads if a witness file exists. Couple it with the delay filter
50 # that delays 2s before writes. If an unaligned and aligned write overlap,
51 # and can execute in parallel, we would have this timeline:
53 # T1 aligned write 1's to 0/16 T2 unaligned write 2's to 4/12
54 #t=0 blocksize: next->pwrite(0, 16) blocksize: next->pread(0, 16)
55 # delay: wait 2s delay: next->pread(0, 16)
56 # ... eval: read 0's, wait 4s
57 #t=2 delay: next->pwrite(0, 16) ...
58 # eval: write 1's ...
59 # return ...
60 #t=4 return 0's (now stale)
61 # blocksize: next->pwrite(0, 16)
62 # delay: wait 2s
63 #t=6 delay: next->pwrite(0, 16)
64 # eval: write stale RMW buffer
66 # leaving us with a sharded 0000222222222222 (T1's write is lost).
67 # But as long as the blocksize filter detects the overlap, we should end
68 # up with either 1111222222222222 (aligned write completed first), or with
69 # 1111111111111111 (unaligned write completed first), either taking 8s,
70 # but with no sharding.
72 # We also need an nbdsh script that kicks off parallel writes.
73 export script='
74 import os
75 import time
77 witness = os.getenv("witness")
79 def touch(path):
80 open(path, "a").close()
82 # First pass: check that two aligned operations work in parallel
83 # Total time should be closer to 2 seconds, rather than 4 if serialized
84 print("sanity check")
85 ba1 = bytearray(b"1"*16)
86 ba2 = bytearray(b"2"*16)
87 buf1 = nbd.Buffer.from_bytearray(ba1)
88 buf2 = nbd.Buffer.from_bytearray(ba2)
89 touch(witness)
90 start_t = time.time()
91 h.aio_pwrite(buf1, 0)
92 h.aio_pwrite(buf2, 0)
94 while h.aio_in_flight() > 0:
95 h.poll(-1)
96 end_t = time.time()
97 os.unlink(witness)
99 out = h.pread(16,0)
100 print(out)
101 t = end_t - start_t
102 print(t)
103 assert out in [b"1"*16, b"2"*16]
104 assert t >= 2 and t <= 3
106 # Next pass: try to kick off unaligned first
107 print("unaligned first")
108 h.zero(16, 0)
109 ba3 = bytearray(b"3"*12)
110 ba4 = bytearray(b"4"*16)
111 buf3 = nbd.Buffer.from_bytearray(ba3)
112 buf4 = nbd.Buffer.from_bytearray(ba4)
113 touch(witness)
114 start_t = time.time()
115 h.aio_pwrite(buf3, 4)
116 h.aio_pwrite(buf4, 0)
118 while h.aio_in_flight() > 0:
119 h.poll(-1)
120 end_t = time.time()
121 os.unlink(witness)
123 out = h.pread(16,0)
124 print(out)
125 t = end_t - start_t
126 print(t)
127 assert out in [b"4"*4 + b"3"*12, b"4"*16]
128 assert t >= 8
130 # Next pass: try to kick off aligned first
131 print("aligned first")
132 ba5 = bytearray(b"5"*16)
133 ba6 = bytearray(b"6"*12)
134 buf5 = nbd.Buffer.from_bytearray(ba5)
135 buf6 = nbd.Buffer.from_bytearray(ba6)
136 h.zero(16, 0)
137 touch(witness)
138 start_t = time.time()
139 h.aio_pwrite(buf5, 0)
140 h.aio_pwrite(buf6, 4)
142 while h.aio_in_flight() > 0:
143 h.poll(-1)
144 end_t = time.time()
145 os.unlink(witness)
147 out = h.pread(16,0)
148 print(out)
149 t = end_t - start_t
150 print(t)
151 assert out in [b"5"*4 + b"6"*12, b"5"*16]
152 assert t >= 8
155 # Now run everything
156 $TRUNCATE -s 16 blocksize-sharding.img
157 export witness="$PWD/blocksize-sharding.tmp"
158 nbdkit -U - --filter=blocksize --filter=delay eval delay-write=2 \
159 config='ln -sf "$(realpath "$3")" $tmpdir/$2' \
160 img="$PWD/blocksize-sharding.img" tmp="$PWD/blocksize-sharding.tmp" \
161 get_size='echo 16' block_size='echo 16 64K 1M' \
162 thread_model='echo parallel' \
163 zero='dd if=/dev/zero of=$tmpdir/img skip=$4 count=$3 \
164 iflag=count_bytes,skip_bytes' \
165 pread='
166 dd if=$tmpdir/img skip=$4 count=$3 iflag=count_bytes,skip_bytes
167 if [ -f $tmpdir/tmp ]; then sleep 4; fi ' \
168 pwrite='dd of=$tmpdir/img seek=$4 conv=notrunc oflag=seek_bytes' \
169 --run 'nbdsh -u "$uri" -c "$script"'