1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 29dd003a9SVladimir Sementsov-Ogievskiy# group: rw 3e38da020SMax Reitz# 4e38da020SMax Reitz# Tests for active mirroring 5e38da020SMax Reitz# 6e38da020SMax Reitz# Copyright (C) 2018 Red Hat, Inc. 7e38da020SMax Reitz# 8e38da020SMax Reitz# This program is free software; you can redistribute it and/or modify 9e38da020SMax Reitz# it under the terms of the GNU General Public License as published by 10e38da020SMax Reitz# the Free Software Foundation; either version 2 of the License, or 11e38da020SMax Reitz# (at your option) any later version. 12e38da020SMax Reitz# 13e38da020SMax Reitz# This program is distributed in the hope that it will be useful, 14e38da020SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 15e38da020SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16e38da020SMax Reitz# GNU General Public License for more details. 17e38da020SMax Reitz# 18e38da020SMax Reitz# You should have received a copy of the GNU General Public License 19e38da020SMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 20e38da020SMax Reitz# 21e38da020SMax Reitz 2238591290SHanna Reitzimport math 23e38da020SMax Reitzimport os 2438591290SHanna Reitzimport subprocess 257b5929c7SHanna Reitzimport time 267b5929c7SHanna Reitzfrom typing import List, Optional 27e38da020SMax Reitzimport iotests 28e38da020SMax Reitzfrom iotests import qemu_img 29e38da020SMax Reitz 30e38da020SMax Reitzsource_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt) 31e38da020SMax Reitztarget_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt) 32e38da020SMax Reitz 33e38da020SMax Reitzclass TestActiveMirror(iotests.QMPTestCase): 34e38da020SMax Reitz image_len = 128 * 1024 * 1024 # MB 35e38da020SMax Reitz potential_writes_in_flight = True 36e38da020SMax Reitz 37e38da020SMax Reitz def setUp(self): 38e38da020SMax Reitz qemu_img('create', '-f', iotests.imgfmt, source_img, '128M') 39e38da020SMax Reitz qemu_img('create', '-f', iotests.imgfmt, target_img, '128M') 40e38da020SMax Reitz 41e38da020SMax Reitz blk_source = {'id': 'source', 42e38da020SMax Reitz 'if': 'none', 43e38da020SMax Reitz 'node-name': 'source-node', 44e38da020SMax Reitz 'driver': iotests.imgfmt, 45e0f69d83SVladimir Sementsov-Ogievskiy 'file': {'driver': 'blkdebug', 46e0f69d83SVladimir Sementsov-Ogievskiy 'image': {'driver': 'file', 47e0f69d83SVladimir Sementsov-Ogievskiy 'filename': source_img}}} 48e38da020SMax Reitz 49e38da020SMax Reitz blk_target = {'node-name': 'target-node', 50e38da020SMax Reitz 'driver': iotests.imgfmt, 51e38da020SMax Reitz 'file': {'driver': 'file', 52e38da020SMax Reitz 'filename': target_img}} 53e38da020SMax Reitz 54e38da020SMax Reitz self.vm = iotests.VM() 55e38da020SMax Reitz self.vm.add_drive_raw(self.vm.qmp_to_opts(blk_source)) 56e38da020SMax Reitz self.vm.add_blockdev(self.vm.qmp_to_opts(blk_target)) 5738591290SHanna Reitz self.vm.add_device('virtio-blk,id=vblk,drive=source') 58e38da020SMax Reitz self.vm.launch() 59e38da020SMax Reitz 60e38da020SMax Reitz def tearDown(self): 61e38da020SMax Reitz self.vm.shutdown() 62e38da020SMax Reitz 63e38da020SMax Reitz if not self.potential_writes_in_flight: 64e38da020SMax Reitz self.assertTrue(iotests.compare_images(source_img, target_img), 65e38da020SMax Reitz 'mirror target does not match source') 66e38da020SMax Reitz 67e38da020SMax Reitz os.remove(source_img) 68e38da020SMax Reitz os.remove(target_img) 69e38da020SMax Reitz 70e38da020SMax Reitz def doActiveIO(self, sync_source_and_target): 71e38da020SMax Reitz # Fill the source image 72e38da020SMax Reitz self.vm.hmp_qemu_io('source', 73e38da020SMax Reitz 'write -P 1 0 %i' % self.image_len); 74e38da020SMax Reitz 75e38da020SMax Reitz # Start some background requests 769a3a9a63SMax Reitz for offset in range(1 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024): 77e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -P 2 %i 1M' % offset) 789a3a9a63SMax Reitz for offset in range(2 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024): 79e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset) 80e38da020SMax Reitz 81e38da020SMax Reitz # Start the block job 82*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-mirror', 83e38da020SMax Reitz job_id='mirror', 84e38da020SMax Reitz filter_node_name='mirror-node', 85e38da020SMax Reitz device='source-node', 86e38da020SMax Reitz target='target-node', 87e38da020SMax Reitz sync='full', 88e38da020SMax Reitz copy_mode='write-blocking') 89e38da020SMax Reitz 90e38da020SMax Reitz # Start some more requests 919a3a9a63SMax Reitz for offset in range(3 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024): 92e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset) 939a3a9a63SMax Reitz for offset in range(4 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024): 94e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset) 95e38da020SMax Reitz 96e38da020SMax Reitz # Wait for the READY event 97e38da020SMax Reitz self.wait_ready(drive='mirror') 98e38da020SMax Reitz 99e38da020SMax Reitz # Now start some final requests; all of these (which land on 100e38da020SMax Reitz # the source) should be settled using the active mechanism. 101e38da020SMax Reitz # The mirror code itself asserts that the source BDS's dirty 102e38da020SMax Reitz # bitmap will stay clean between READY and COMPLETED. 1039a3a9a63SMax Reitz for offset in range(5 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024): 104e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset) 1059a3a9a63SMax Reitz for offset in range(6 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024): 106e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset) 107e38da020SMax Reitz 108e38da020SMax Reitz if sync_source_and_target: 109e38da020SMax Reitz # If source and target should be in sync after the mirror, 110e38da020SMax Reitz # we have to flush before completion 111e38da020SMax Reitz self.vm.hmp_qemu_io('source', 'aio_flush') 112e38da020SMax Reitz self.potential_writes_in_flight = False 113e38da020SMax Reitz 114e38da020SMax Reitz self.complete_and_wait(drive='mirror', wait_ready=False) 115e38da020SMax Reitz 116e38da020SMax Reitz def testActiveIO(self): 117e38da020SMax Reitz self.doActiveIO(False) 118e38da020SMax Reitz 119e38da020SMax Reitz def testActiveIOFlushed(self): 120e38da020SMax Reitz self.doActiveIO(True) 121e38da020SMax Reitz 12219ba4651SMax Reitz def testUnalignedActiveIO(self): 12319ba4651SMax Reitz # Fill the source image 12419ba4651SMax Reitz result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') 12519ba4651SMax Reitz 12619ba4651SMax Reitz # Start the block job (very slowly) 127*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-mirror', 12819ba4651SMax Reitz job_id='mirror', 12919ba4651SMax Reitz filter_node_name='mirror-node', 13019ba4651SMax Reitz device='source-node', 13119ba4651SMax Reitz target='target-node', 13219ba4651SMax Reitz sync='full', 13319ba4651SMax Reitz copy_mode='write-blocking', 13419ba4651SMax Reitz buf_size=(1048576 // 4), 13519ba4651SMax Reitz speed=1) 13619ba4651SMax Reitz 13719ba4651SMax Reitz # Start an unaligned request to a dirty area 13819ba4651SMax Reitz result = self.vm.hmp_qemu_io('source', 'write -P 2 %i 1' % (1048576 + 42)) 13919ba4651SMax Reitz 14019ba4651SMax Reitz # Let the job finish 141*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('block-job-set-speed', device='mirror', speed=0) 14219ba4651SMax Reitz self.complete_and_wait(drive='mirror') 14319ba4651SMax Reitz 14419ba4651SMax Reitz self.potential_writes_in_flight = False 145e38da020SMax Reitz 146e0f69d83SVladimir Sementsov-Ogievskiy def testIntersectingActiveIO(self): 147e0f69d83SVladimir Sementsov-Ogievskiy # Fill the source image 148e0f69d83SVladimir Sementsov-Ogievskiy result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M') 149e0f69d83SVladimir Sementsov-Ogievskiy 150e0f69d83SVladimir Sementsov-Ogievskiy # Start the block job (very slowly) 151*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-mirror', 152e0f69d83SVladimir Sementsov-Ogievskiy job_id='mirror', 153e0f69d83SVladimir Sementsov-Ogievskiy filter_node_name='mirror-node', 154e0f69d83SVladimir Sementsov-Ogievskiy device='source-node', 155e0f69d83SVladimir Sementsov-Ogievskiy target='target-node', 156e0f69d83SVladimir Sementsov-Ogievskiy sync='full', 157e0f69d83SVladimir Sementsov-Ogievskiy copy_mode='write-blocking', 158e0f69d83SVladimir Sementsov-Ogievskiy speed=1) 159e0f69d83SVladimir Sementsov-Ogievskiy 160e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'break write_aio A') 161e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'aio_write 0 1M') # 1 162e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'wait_break A') 163e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 2 164e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'aio_write 0 2M') # 3 165e0f69d83SVladimir Sementsov-Ogievskiy 166e0f69d83SVladimir Sementsov-Ogievskiy # Now 2 and 3 are in mirror_wait_on_conflicts, waiting for 1 167e0f69d83SVladimir Sementsov-Ogievskiy 168e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'break write_aio B') 169e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'aio_write 1M 2M') # 4 170e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'wait_break B') 171e0f69d83SVladimir Sementsov-Ogievskiy 172e0f69d83SVladimir Sementsov-Ogievskiy # 4 doesn't wait for 2 and 3, because they didn't yet set 173e0f69d83SVladimir Sementsov-Ogievskiy # in_flight_bitmap. So, nothing prevents 4 to go except for our 174e0f69d83SVladimir Sementsov-Ogievskiy # break-point B. 175e0f69d83SVladimir Sementsov-Ogievskiy 176e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'resume A') 177e0f69d83SVladimir Sementsov-Ogievskiy 178e0f69d83SVladimir Sementsov-Ogievskiy # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop 179e0f69d83SVladimir Sementsov-Ogievskiy # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty 180d44dae1aSVladimir Sementsov-Ogievskiy # due to request 4. 181d44dae1aSVladimir Sementsov-Ogievskiy # In the past at that point 2 and 3 would wait for each other producing 182d44dae1aSVladimir Sementsov-Ogievskiy # a dead-lock. Now this is fixed and they will wait for request 4. 183e0f69d83SVladimir Sementsov-Ogievskiy 184e0f69d83SVladimir Sementsov-Ogievskiy self.vm.hmp_qemu_io('source', 'resume B') 185e0f69d83SVladimir Sementsov-Ogievskiy 186d44dae1aSVladimir Sementsov-Ogievskiy # After resuming 4, one of 2 and 3 goes first and set in_flight_bitmap, 187d44dae1aSVladimir Sementsov-Ogievskiy # so the other will wait for it. 188e0f69d83SVladimir Sementsov-Ogievskiy 189*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('block-job-set-speed', device='mirror', speed=0) 190e0f69d83SVladimir Sementsov-Ogievskiy self.complete_and_wait(drive='mirror') 191e0f69d83SVladimir Sementsov-Ogievskiy 192e0f69d83SVladimir Sementsov-Ogievskiy self.potential_writes_in_flight = False 193e0f69d83SVladimir Sementsov-Ogievskiy 194e38da020SMax Reitz 1957b5929c7SHanna Reitzclass TestThrottledWithNbdExportBase(iotests.QMPTestCase): 19638591290SHanna Reitz image_len = 128 * 1024 * 1024 # MB 1977b5929c7SHanna Reitz iops: Optional[int] = None 19838591290SHanna Reitz background_processes: List['subprocess.Popen[str]'] = [] 19938591290SHanna Reitz 20038591290SHanna Reitz def setUp(self): 2017b5929c7SHanna Reitz # Must be set by subclasses 2027b5929c7SHanna Reitz self.assertIsNotNone(self.iops) 2037b5929c7SHanna Reitz 20438591290SHanna Reitz qemu_img('create', '-f', iotests.imgfmt, source_img, '128M') 20538591290SHanna Reitz qemu_img('create', '-f', iotests.imgfmt, target_img, '128M') 20638591290SHanna Reitz 20738591290SHanna Reitz self.vm = iotests.VM() 20838591290SHanna Reitz self.vm.launch() 20938591290SHanna Reitz 210*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('object-add', **{ 21138591290SHanna Reitz 'qom-type': 'throttle-group', 21238591290SHanna Reitz 'id': 'thrgr', 21338591290SHanna Reitz 'limits': { 21438591290SHanna Reitz 'iops-total': self.iops, 21538591290SHanna Reitz 'iops-total-max': self.iops 21638591290SHanna Reitz } 21738591290SHanna Reitz }) 21838591290SHanna Reitz 219*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-add', **{ 22038591290SHanna Reitz 'node-name': 'source-node', 22138591290SHanna Reitz 'driver': 'throttle', 22238591290SHanna Reitz 'throttle-group': 'thrgr', 22338591290SHanna Reitz 'file': { 22438591290SHanna Reitz 'driver': iotests.imgfmt, 22538591290SHanna Reitz 'file': { 22638591290SHanna Reitz 'driver': 'file', 22738591290SHanna Reitz 'filename': source_img 22838591290SHanna Reitz } 22938591290SHanna Reitz } 23038591290SHanna Reitz }) 23138591290SHanna Reitz 232*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-add', **{ 23338591290SHanna Reitz 'node-name': 'target-node', 23438591290SHanna Reitz 'driver': iotests.imgfmt, 23538591290SHanna Reitz 'file': { 23638591290SHanna Reitz 'driver': 'file', 23738591290SHanna Reitz 'filename': target_img 23838591290SHanna Reitz } 23938591290SHanna Reitz }) 24038591290SHanna Reitz 24138591290SHanna Reitz self.nbd_sock = iotests.file_path('nbd.sock', 24238591290SHanna Reitz base_dir=iotests.sock_dir) 24338591290SHanna Reitz self.nbd_url = f'nbd+unix:///source-node?socket={self.nbd_sock}' 24438591290SHanna Reitz 245*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('nbd-server-start', addr={ 24638591290SHanna Reitz 'type': 'unix', 24738591290SHanna Reitz 'data': { 24838591290SHanna Reitz 'path': self.nbd_sock 24938591290SHanna Reitz } 25038591290SHanna Reitz }) 25138591290SHanna Reitz 252*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('block-export-add', id='exp0', type='nbd', 25338591290SHanna Reitz node_name='source-node', writable=True) 25438591290SHanna Reitz 25538591290SHanna Reitz def tearDown(self): 25638591290SHanna Reitz # Wait for background requests to settle 25738591290SHanna Reitz try: 25838591290SHanna Reitz while True: 25938591290SHanna Reitz p = self.background_processes.pop() 26038591290SHanna Reitz while True: 26138591290SHanna Reitz try: 26238591290SHanna Reitz p.wait(timeout=0.0) 26338591290SHanna Reitz break 26438591290SHanna Reitz except subprocess.TimeoutExpired: 26538591290SHanna Reitz self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') 26638591290SHanna Reitz except IndexError: 26738591290SHanna Reitz pass 26838591290SHanna Reitz 26938591290SHanna Reitz # Cancel ongoing block jobs 27038591290SHanna Reitz for job in self.vm.qmp('query-jobs')['return']: 27138591290SHanna Reitz self.vm.qmp('block-job-cancel', device=job['id'], force=True) 27238591290SHanna Reitz 27338591290SHanna Reitz while True: 27438591290SHanna Reitz self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') 27538591290SHanna Reitz if len(self.vm.qmp('query-jobs')['return']) == 0: 27638591290SHanna Reitz break 27738591290SHanna Reitz 27838591290SHanna Reitz self.vm.shutdown() 27938591290SHanna Reitz os.remove(source_img) 28038591290SHanna Reitz os.remove(target_img) 28138591290SHanna Reitz 2827b5929c7SHanna Reitz 2837b5929c7SHanna Reitzclass TestLowThrottledWithNbdExport(TestThrottledWithNbdExportBase): 2847b5929c7SHanna Reitz iops = 16 2857b5929c7SHanna Reitz 28638591290SHanna Reitz def testUnderLoad(self): 28738591290SHanna Reitz ''' 28838591290SHanna Reitz Throttle the source node, then issue a whole bunch of external requests 28938591290SHanna Reitz while the mirror job (in write-blocking mode) is running. We want to 29038591290SHanna Reitz see background requests being issued even while the source is under 29138591290SHanna Reitz full load by active writes, so that progress can be made towards READY. 29238591290SHanna Reitz ''' 29338591290SHanna Reitz 29438591290SHanna Reitz # Fill the first half of the source image; do not fill the second half, 29538591290SHanna Reitz # that is where we will have active requests occur. This ensures that 29638591290SHanna Reitz # active mirroring itself will not directly contribute to the job's 29738591290SHanna Reitz # progress (because when the job was started, those areas were not 29838591290SHanna Reitz # intended to be copied, so active mirroring will only lead to not 29938591290SHanna Reitz # losing progress, but also not making any). 30038591290SHanna Reitz self.vm.hmp_qemu_io('source-node', 30138591290SHanna Reitz f'aio_write -P 1 0 {self.image_len // 2}') 30238591290SHanna Reitz self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') 30338591290SHanna Reitz 30438591290SHanna Reitz # Launch the mirror job 30538591290SHanna Reitz mirror_buf_size = 65536 306*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-mirror', 30738591290SHanna Reitz job_id='mirror', 30838591290SHanna Reitz filter_node_name='mirror-node', 30938591290SHanna Reitz device='source-node', 31038591290SHanna Reitz target='target-node', 31138591290SHanna Reitz sync='full', 31238591290SHanna Reitz copy_mode='write-blocking', 31338591290SHanna Reitz buf_size=mirror_buf_size) 31438591290SHanna Reitz 31538591290SHanna Reitz # We create the external requests via qemu-io processes on the NBD 31638591290SHanna Reitz # server. Have their offset start in the middle of the image so they 31738591290SHanna Reitz # do not overlap with the background requests (which start from the 31838591290SHanna Reitz # beginning). 31938591290SHanna Reitz active_request_offset = self.image_len // 2 32038591290SHanna Reitz active_request_len = 4096 32138591290SHanna Reitz 32238591290SHanna Reitz # Create enough requests to saturate the node for 5 seconds 32338591290SHanna Reitz for _ in range(0, 5 * self.iops): 32438591290SHanna Reitz req = f'write -P 42 {active_request_offset} {active_request_len}' 32538591290SHanna Reitz active_request_offset += active_request_len 32638591290SHanna Reitz p = iotests.qemu_io_popen('-f', 'nbd', self.nbd_url, '-c', req) 32738591290SHanna Reitz self.background_processes += [p] 32838591290SHanna Reitz 32938591290SHanna Reitz # Now advance the clock one I/O operation at a time by the 4 seconds 33038591290SHanna Reitz # (i.e. one less than 5). We expect the mirror job to issue background 33138591290SHanna Reitz # operations here, even though active requests are still in flight. 33238591290SHanna Reitz # The active requests will take precedence, however, because they have 33338591290SHanna Reitz # been issued earlier than mirror's background requests. 33438591290SHanna Reitz # Once the active requests we have started above are done (i.e. after 5 33538591290SHanna Reitz # virtual seconds), we expect those background requests to be worked 33638591290SHanna Reitz # on. We only advance 4 seconds here to avoid race conditions. 33738591290SHanna Reitz for _ in range(0, 4 * self.iops): 33838591290SHanna Reitz step = math.ceil(1 * 1000 * 1000 * 1000 / self.iops) 33938591290SHanna Reitz self.vm.qtest(f'clock_step {step}') 34038591290SHanna Reitz 34138591290SHanna Reitz # Note how much remains to be done until the mirror job is finished 34238591290SHanna Reitz job_status = self.vm.qmp('query-jobs')['return'][0] 34338591290SHanna Reitz start_remaining = job_status['total-progress'] - \ 34438591290SHanna Reitz job_status['current-progress'] 34538591290SHanna Reitz 34638591290SHanna Reitz # Create a whole bunch of more active requests 34738591290SHanna Reitz for _ in range(0, 10 * self.iops): 34838591290SHanna Reitz req = f'write -P 42 {active_request_offset} {active_request_len}' 34938591290SHanna Reitz active_request_offset += active_request_len 35038591290SHanna Reitz p = iotests.qemu_io_popen('-f', 'nbd', self.nbd_url, '-c', req) 35138591290SHanna Reitz self.background_processes += [p] 35238591290SHanna Reitz 35338591290SHanna Reitz # Let the clock advance more. After 1 second, as noted above, we 35438591290SHanna Reitz # expect the background requests to be worked on. Give them a couple 35538591290SHanna Reitz # of seconds (specifically 4) to see their impact. 35638591290SHanna Reitz for _ in range(0, 5 * self.iops): 35738591290SHanna Reitz step = math.ceil(1 * 1000 * 1000 * 1000 / self.iops) 35838591290SHanna Reitz self.vm.qtest(f'clock_step {step}') 35938591290SHanna Reitz 36038591290SHanna Reitz # Note how much remains to be done now. We expect this number to be 36138591290SHanna Reitz # reduced thanks to those background requests. 36238591290SHanna Reitz job_status = self.vm.qmp('query-jobs')['return'][0] 36338591290SHanna Reitz end_remaining = job_status['total-progress'] - \ 36438591290SHanna Reitz job_status['current-progress'] 36538591290SHanna Reitz 36638591290SHanna Reitz # See that indeed progress was being made on the job, even while the 36738591290SHanna Reitz # node was saturated with active requests 36838591290SHanna Reitz self.assertGreater(start_remaining - end_remaining, 0) 36938591290SHanna Reitz 37038591290SHanna Reitz 3717b5929c7SHanna Reitzclass TestHighThrottledWithNbdExport(TestThrottledWithNbdExportBase): 3727b5929c7SHanna Reitz iops = 1024 3737b5929c7SHanna Reitz 3747b5929c7SHanna Reitz def testActiveOnCreation(self): 3757b5929c7SHanna Reitz ''' 3767b5929c7SHanna Reitz Issue requests on the mirror source node right as the mirror is 3777b5929c7SHanna Reitz instated. It's possible that requests occur before the actual job is 3787b5929c7SHanna Reitz created, but after the node has been put into the graph. Write 3797b5929c7SHanna Reitz requests across the node must in that case be forwarded to the source 3807b5929c7SHanna Reitz node without attempting to mirror them (there is no job object yet, so 3817b5929c7SHanna Reitz attempting to access it would cause a segfault). 3827b5929c7SHanna Reitz We do this with a lightly throttled node (i.e. quite high IOPS limit). 3837b5929c7SHanna Reitz Using throttling seems to increase reproductivity, but if the limit is 3847b5929c7SHanna Reitz too low, all requests allowed per second will be submitted before 3857b5929c7SHanna Reitz mirror_start_job() gets to the problematic point. 3867b5929c7SHanna Reitz ''' 3877b5929c7SHanna Reitz 3887b5929c7SHanna Reitz # Let qemu-img bench create write requests (enough for two seconds on 3897b5929c7SHanna Reitz # the virtual clock) 3907b5929c7SHanna Reitz bench_args = ['bench', '-w', '-d', '1024', '-f', 'nbd', 3917b5929c7SHanna Reitz '-c', str(self.iops * 2), self.nbd_url] 3927b5929c7SHanna Reitz p = iotests.qemu_tool_popen(iotests.qemu_img_args + bench_args) 3937b5929c7SHanna Reitz self.background_processes += [p] 3947b5929c7SHanna Reitz 3957b5929c7SHanna Reitz # Give qemu-img bench time to start up and issue requests 3967b5929c7SHanna Reitz time.sleep(1.0) 3977b5929c7SHanna Reitz # Flush the request queue, so new requests can come in right as we 3987b5929c7SHanna Reitz # start blockdev-mirror 3997b5929c7SHanna Reitz self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}') 4007b5929c7SHanna Reitz 401*b6aed193SVladimir Sementsov-Ogievskiy self.vm.cmd('blockdev-mirror', 4027b5929c7SHanna Reitz job_id='mirror', 4037b5929c7SHanna Reitz device='source-node', 4047b5929c7SHanna Reitz target='target-node', 4057b5929c7SHanna Reitz sync='full', 4067b5929c7SHanna Reitz copy_mode='write-blocking') 4077b5929c7SHanna Reitz 4087b5929c7SHanna Reitz 409e38da020SMax Reitzif __name__ == '__main__': 410103cbc77SMax Reitz iotests.main(supported_fmts=['qcow2', 'raw'], 411103cbc77SMax Reitz supported_protocols=['file']) 412