Improve iSCSI device detection speed
Current iSCSI device detection checks for the presence of devices based on the scan time, so it checks for presence, sleeps, scans, and checks again. This means that if the device becomes available while we sleep to send another scan we won't detect the device. This patch changes this, making the searching and the rescanning independent operations operating at different cadences. Checking for the device will happen every seconds, and the rescans will happen after 4, 9, and 16 seconds. Change-Id: I716a3ea8583e289819cc37b6b5dd9730dd59406b
This commit is contained in:
parent
716ca5e5f1
commit
aecf9c968b
|
@ -618,8 +618,16 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
device = hctl = None
|
||||
portal = props['target_portal']
|
||||
session, manual_scan = self._connect_to_iscsi_portal(props)
|
||||
do_scans = rescans > 0
|
||||
retry = 1
|
||||
do_scans = rescans > 0 or manual_scan
|
||||
# Scan is sent on connect by iscsid, but we must do it manually on
|
||||
# manual scan mode. This scan cannot count towards total rescans.
|
||||
if manual_scan:
|
||||
num_rescans = -1
|
||||
seconds_next_scan = 0
|
||||
else:
|
||||
num_rescans = 0
|
||||
seconds_next_scan = 4
|
||||
|
||||
if session:
|
||||
data['num_logins'] += 1
|
||||
LOG.debug('Connected to %s', portal)
|
||||
|
@ -628,11 +636,12 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
if not hctl:
|
||||
hctl = self._linuxscsi.get_hctl(session,
|
||||
props['target_lun'])
|
||||
# Scan is sent on connect by iscsid, so skip first rescan
|
||||
# but on manual scan mode we have to do it ourselves.
|
||||
if hctl:
|
||||
if retry > 1 or manual_scan:
|
||||
if seconds_next_scan <= 0:
|
||||
num_rescans += 1
|
||||
self._linuxscsi.scan_iscsi(*hctl)
|
||||
# 4 seconds on 1st rescan, 9s on 2nd, 16s on 3rd
|
||||
seconds_next_scan = (num_rescans + 2) ** 2
|
||||
|
||||
device = self._linuxscsi.device_name_by_hctl(session,
|
||||
hctl)
|
||||
|
@ -642,11 +651,12 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
except Exception:
|
||||
LOG.exception('Exception scanning %s', portal)
|
||||
pass
|
||||
retry += 1
|
||||
do_scans = (retry <= rescans and
|
||||
do_scans = (num_rescans <= rescans and
|
||||
not (device or data['stop_connecting']))
|
||||
if do_scans:
|
||||
time.sleep(retry ** 2)
|
||||
time.sleep(1)
|
||||
seconds_next_scan -= 1
|
||||
|
||||
if device:
|
||||
LOG.debug('Connected to %s using %s', device,
|
||||
strutils.mask_password(props))
|
||||
|
|
|
@ -1291,12 +1291,13 @@ Setting up iSCSI targets: unused
|
|||
find_dm_mock.assert_not_called()
|
||||
self.assertEqual(12, connect_mock.call_count)
|
||||
|
||||
@mock.patch('time.sleep', mock.Mock())
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
|
||||
return_value='sda')
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
|
||||
def test_connect_vol(self, connect_mock, dev_name_mock, scan_mock):
|
||||
def test_connect_vol(self, connect_mock, dev_name_mock, scan_mock,
|
||||
sleep_mock):
|
||||
lscsi = self.connector._linuxscsi
|
||||
data = self._get_connect_vol_data()
|
||||
hctl = [mock.sentinel.host, mock.sentinel.channel,
|
||||
|
@ -1319,8 +1320,72 @@ Setting up iSCSI targets: unused
|
|||
mock.call(mock.sentinel.session,
|
||||
self.CON_PROPS['target_lun'])])
|
||||
|
||||
scan_mock.assert_called_once_with(*hctl)
|
||||
scan_mock.assert_not_called()
|
||||
dev_name_mock.assert_called_once_with(mock.sentinel.session, hctl)
|
||||
sleep_mock.assert_called_once_with(1)
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
|
||||
side_effect=(None, None, None, None, 'sda'))
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
|
||||
def test_connect_vol_rescan(self, connect_mock, dev_name_mock, scan_mock,
|
||||
sleep_mock):
|
||||
lscsi = self.connector._linuxscsi
|
||||
data = self._get_connect_vol_data()
|
||||
hctl = [mock.sentinel.host, mock.sentinel.channel,
|
||||
mock.sentinel.target, mock.sentinel.lun]
|
||||
|
||||
connect_mock.return_value = (mock.sentinel.session, False)
|
||||
|
||||
with mock.patch.object(lscsi, 'get_hctl',
|
||||
return_value=hctl) as hctl_mock:
|
||||
self.connector._connect_vol(3, self.CON_PROPS, data)
|
||||
|
||||
expected = self._get_connect_vol_data()
|
||||
expected.update(num_logins=1, stopped_threads=1,
|
||||
found_devices=['sda'], just_added_devices=['sda'])
|
||||
self.assertDictEqual(expected, data)
|
||||
|
||||
connect_mock.assert_called_once_with(self.CON_PROPS)
|
||||
hctl_mock.assert_called_once_with(mock.sentinel.session,
|
||||
self.CON_PROPS['target_lun'])
|
||||
|
||||
scan_mock.assert_called_once_with(*hctl)
|
||||
self.assertEqual(5, dev_name_mock.call_count)
|
||||
self.assertEqual(4, sleep_mock.call_count)
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
|
||||
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
|
||||
side_effect=(None, None, None, None, 'sda'))
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
|
||||
def test_connect_vol_manual(self, connect_mock, dev_name_mock, scan_mock,
|
||||
sleep_mock):
|
||||
lscsi = self.connector._linuxscsi
|
||||
data = self._get_connect_vol_data()
|
||||
hctl = [mock.sentinel.host, mock.sentinel.channel,
|
||||
mock.sentinel.target, mock.sentinel.lun]
|
||||
|
||||
# Simulate manual scan
|
||||
connect_mock.return_value = (mock.sentinel.session, True)
|
||||
|
||||
with mock.patch.object(lscsi, 'get_hctl',
|
||||
return_value=hctl) as hctl_mock:
|
||||
self.connector._connect_vol(3, self.CON_PROPS, data)
|
||||
|
||||
expected = self._get_connect_vol_data()
|
||||
expected.update(num_logins=1, stopped_threads=1,
|
||||
found_devices=['sda'], just_added_devices=['sda'])
|
||||
self.assertDictEqual(expected, data)
|
||||
|
||||
connect_mock.assert_called_once_with(self.CON_PROPS)
|
||||
hctl_mock.assert_called_once_with(mock.sentinel.session,
|
||||
self.CON_PROPS['target_lun'])
|
||||
|
||||
self.assertEqual(2, scan_mock.call_count)
|
||||
self.assertEqual(5, dev_name_mock.call_count)
|
||||
self.assertEqual(4, sleep_mock.call_count)
|
||||
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal',
|
||||
return_value=(None, False))
|
||||
|
|
Loading…
Reference in New Issue