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
(cherry picked from commit aecf9c968b
)
This commit is contained in:
parent
ab5d9a1d83
commit
21a22664bb
|
@ -617,8 +617,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)
|
||||
|
@ -627,11 +635,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)
|
||||
|
@ -641,11 +650,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))
|
||||
|
|
|
@ -1327,12 +1327,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,
|
||||
|
@ -1355,8 +1356,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