diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 59a8926b73..f3a3ec4d35 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -672,37 +672,12 @@ class ComputeManager(manager.Manager): self._syncs_in_progress_lock = threading.Lock() self.send_instance_updates = ( CONF.filter_scheduler.track_instance_changes) - if CONF.max_concurrent_builds != 0: - self._build_semaphore = threading.Semaphore( - CONF.max_concurrent_builds) - else: - self._build_semaphore = compute_utils.UnlimitedSemaphore() - if CONF.max_concurrent_snapshots > 0: - self._snapshot_semaphore = threading.Semaphore( - CONF.max_concurrent_snapshots) - else: - self._snapshot_semaphore = compute_utils.UnlimitedSemaphore() - if CONF.max_concurrent_live_migrations > 0: - self._live_migration_executor = nova.utils.create_executor( - max_workers=CONF.max_concurrent_live_migrations) - else: - # setting CONF.max_concurrent_live_migrations to 0 (unlimited) - # is deprecated but still supported, so we need to use a sane - # default values for each threading mode - LOG.warning("Nova compute deprecated the support of unlimited " - "parallel live migration so " - "[DEFAULT]max_concurrent_live_migrations configured " - "with value 0 is deprecated and will not be supported " - "in future releases. Please set an explicit positive" - "value to this config option instead.") - if utils.concurrency_mode_threading(): - self._live_migration_executor = nova.utils.create_executor( - max_workers=5) - else: - # In eventlet mode we need to keep backward compatibility and - # 1000 greenthreads to emulate unlimited. - self._live_migration_executor = nova.utils.create_executor( - max_workers=1000) + self._build_semaphore = threading.Semaphore( + self._get_max_concurrent_builds()) + self._snapshot_semaphore = threading.Semaphore( + self._get_max_concurrent_snapshots()) + self._live_migration_executor = nova.utils.create_executor( + max_workers=self._get_max_concurrent_live_migrations()) # This is a dict, keyed by instance uuid, to a two-item tuple of # migration object and Future for the queued live migration. @@ -722,6 +697,68 @@ class ComputeManager(manager.Manager): self.rt = resource_tracker.ResourceTracker( self.host, self.driver, reportclient=self.reportclient) + def _get_max_concurrent_builds(self): + if CONF.max_concurrent_builds > 0: + return CONF.max_concurrent_builds + + # setting CONF.max_concurrent_builds to 0 (unlimited) + # is deprecated but still supported, so we need to use a sane + # default values for each threading mode + LOG.warning("Nova compute deprecated the support of unlimited " + "parallel instance builds so " + "[DEFAULT]max_concurrent_builds configured " + "with value 0 is deprecated and will not be supported " + "in future releases. Please set an explicit positive " + "value to this config option instead.") + if utils.concurrency_mode_threading(): + # Fall back to the default of the config + return 10 + else: + # In eventlet mode we need to keep backward compatibility, and + # we use 1000 to emulate unlimited + return 1000 + + def _get_max_concurrent_snapshots(self): + if CONF.max_concurrent_snapshots > 0: + return CONF.max_concurrent_snapshots + + # setting CONF.max_concurrent_snapshots to 0 (unlimited) + # is deprecated but still supported, so we need to use a sane + # default values for each threading mode + LOG.warning("Nova compute deprecated the support of unlimited " + "parallel instance snapshots so " + "[DEFAULT]max_concurrent_snapshots configured " + "with value 0 is deprecated and will not be supported " + "in future releases. Please set an explicit positive " + "value to this config option instead.") + if utils.concurrency_mode_threading(): + # Fall back to the default of the config + return 5 + else: + # In eventlet mode we need to keep backward compatibility, and + # we use 1000 to emulate unlimited + return 1000 + + def _get_max_concurrent_live_migrations(self): + if CONF.max_concurrent_live_migrations > 0: + return CONF.max_concurrent_live_migrations + + # setting CONF.max_concurrent_live_migrations to 0 (unlimited) + # is deprecated but still supported, so we need to use a sane + # default values for each threading mode + LOG.warning("Nova compute deprecated the support of unlimited " + "parallel live migration so " + "[DEFAULT]max_concurrent_live_migrations configured " + "with value 0 is deprecated and will not be supported " + "in future releases. Please set an explicit positive" + "value to this config option instead.") + if utils.concurrency_mode_threading(): + return 5 + else: + # In eventlet mode we need to keep backward compatibility and + # 1000 greenthreads to emulate unlimited + return 1000 + @contextlib.contextmanager def syncs_in_progress(self) -> Iterator[set[str]]: with self._syncs_in_progress_lock: diff --git a/nova/conf/compute.py b/nova/conf/compute.py index 076060857b..4f58e89cd0 100644 --- a/nova/conf/compute.py +++ b/nova/conf/compute.py @@ -666,7 +666,11 @@ per compute node. Possible Values: -* 0 : treated as unlimited. +* ``0``: Deprecated since 33.0.0 (2026.1 Gazpacho). This value was previously + documented as meaning unlimited. Since this release, the implementation keeps + using 1000 as the real limit in eventlet mode and will use 10 in native + threading mode. In the future release when eventlet support is removed, 0 as + a valid value will also be removed. * Any positive integer representing maximum concurrent builds. """), cfg.IntOpt('max_concurrent_snapshots', @@ -680,7 +684,11 @@ compute node. Possible Values: -* 0 : treated as unlimited. +* ``0``: Deprecated since 33.0.0 (2026.1 Gazpacho). This value was previously + documented as meaning unlimited. Since this release, the implementation keeps + using 1000 as the real limit in eventlet mode and will use 5 in native + threading mode. In the future release when eventlet support is removed, 0 as + a valid value will also be removed. * Any positive integer representing maximum concurrent snapshots. """), cfg.IntOpt('max_concurrent_live_migrations', diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index aba391af3a..1cf6e07336 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -979,9 +979,10 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, def test_max_concurrent_builds_semaphore_unlimited(self): self.flags(max_concurrent_builds=0) compute = manager.ComputeManager() - self.assertEqual(0, compute._build_semaphore.balance) - self.assertIsInstance(compute._build_semaphore, - compute_utils.UnlimitedSemaphore) + if utils.concurrency_mode_threading(): + self.assertEqual(10, compute._build_semaphore._value) + else: + self.assertEqual(1000, compute._build_semaphore._value) @mock.patch('nova.objects.Instance.save') @mock.patch('nova.compute.manager.ComputeManager.' @@ -1013,9 +1014,10 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase, def test_max_concurrent_snapshots_semaphore_unlimited(self): self.flags(max_concurrent_snapshots=0) compute = manager.ComputeManager() - self.assertEqual(0, compute._snapshot_semaphore.balance) - self.assertIsInstance(compute._snapshot_semaphore, - compute_utils.UnlimitedSemaphore) + if utils.concurrency_mode_threading(): + self.assertEqual(5, compute._snapshot_semaphore._value) + else: + self.assertEqual(1000, compute._snapshot_semaphore._value) def test_nil_out_inst_obj_host_and_node_sets_nil(self): instance = fake_instance.fake_instance_obj(self.context, diff --git a/releasenotes/notes/deprecate-unlimited-max_concurrent_live_migrations-29c54c7eeb77041c.yaml b/releasenotes/notes/deprecate-unlimited-max_concurrent_live_migrations-29c54c7eeb77041c.yaml index fc37edecda..e7276853fb 100644 --- a/releasenotes/notes/deprecate-unlimited-max_concurrent_live_migrations-29c54c7eeb77041c.yaml +++ b/releasenotes/notes/deprecate-unlimited-max_concurrent_live_migrations-29c54c7eeb77041c.yaml @@ -18,6 +18,24 @@ upgrade: higher value explicitly before the upgrade. Please read the `concurrency `__ guide for more details. + - | + The meaning of the 0 value of the config option + ``[DEFAULT]max_concurrent_builds`` has been changed. In the past + it meant "unlimited" but actually it was limited by the oslo.messaging's + ``executor_thread_pool_size`` config option. For eventlet mode "unlimited" + now means 1000 concurrent builds. For the native threading mode it is + now reduced to 10 native threads. Please also read the `concurrency + `__ + guide for more details. + - | + The meaning of the 0 value of the config option + ``[DEFAULT]max_concurrent_snapshots`` has been changed. In the past + it meant "unlimited" but actually it was limited by the oslo.messaging's + ``executor_thread_pool_size`` config option. For eventlet mode "unlimited" + now means 1000 concurrent snapshots. For the native threading mode it is + now reduced to 5 native threads. Please also read the `concurrency + `__ + guide for more details. deprecations: - | The possible 0 value of the configuration option @@ -26,3 +44,11 @@ deprecations: default value, 1, of this config option. If more performant live migration is needed, use the ``live_migration_parallel_connections`` config option instead. + - | + The possible 0 value of the configuration option + ``[DEFAULT]max_concurrent_builds`` is deprecated and will be + removed in a future release. + - | + The possible 0 value of the configuration option + ``[DEFAULT]max_concurrent_snapshots`` is deprecated and will be + removed in a future release.