Merge pull request #382 from Cerberus98/ncp1480_subnet_select
Don't lock when selecting v6 subnets
This commit is contained in:
@@ -597,10 +597,13 @@ def network_delete(context, network):
|
||||
context.session.delete(network)
|
||||
|
||||
|
||||
def subnet_find_ordered_by_most_full(context, net_id, **filters):
|
||||
def subnet_find_ordered_by_most_full(context, net_id, lock_subnets=True,
|
||||
**filters):
|
||||
count = sql_func.count(models.IPAddress.address).label("count")
|
||||
size = (models.Subnet.last_ip - models.Subnet.first_ip)
|
||||
query = context.session.query(models.Subnet, count).with_lockmode('update')
|
||||
query = context.session.query(models.Subnet, count)
|
||||
if lock_subnets:
|
||||
query = query.with_lockmode("update")
|
||||
query = query.filter_by(do_not_use=False)
|
||||
query = query.outerjoin(models.Subnet.generated_ips)
|
||||
query = query.group_by(models.Subnet.id)
|
||||
|
||||
@@ -59,7 +59,11 @@ quark_opts = [
|
||||
cfg.BoolOpt("ipam_use_synchronization",
|
||||
default=False,
|
||||
help=_("Configures whether or not to use the experimental"
|
||||
" semaphore logic around IPAM"))
|
||||
" semaphore logic around IPAM")),
|
||||
cfg.BoolOpt("ipam_select_subnet_v6_locking",
|
||||
default=True,
|
||||
help=_("Controls whether or not SELECT ... FOR UPDATE is used"
|
||||
" when retrieving v6 subnets explicitly."))
|
||||
]
|
||||
|
||||
CONF.register_opts(quark_opts, "QUARK")
|
||||
@@ -757,8 +761,20 @@ class QuarkIpam(object):
|
||||
ip_version=filters.get("ip_version"))))
|
||||
|
||||
with context.session.begin():
|
||||
# NCP-1480: Don't need to lock V6 subnets, since we don't use
|
||||
# next_auto_assign_ip for them. We already uniquely identified
|
||||
# the V6 we're going to get by generating a MAC in a previous step.
|
||||
# Also note that this only works under BOTH or BOTH_REQUIRED. ANY
|
||||
# does not pass an ip_version
|
||||
lock_subnets = True
|
||||
if (not CONF.QUARK.ipam_select_subnet_v6_locking and
|
||||
"ip_version" in filters and
|
||||
int(filters["ip_version"]) == 6):
|
||||
lock_subnets = False
|
||||
|
||||
subnets = db_api.subnet_find_ordered_by_most_full(
|
||||
context, net_id, segment_id=segment_id, scope=db_api.ALL,
|
||||
context, net_id, lock_subnets=lock_subnets,
|
||||
segment_id=segment_id, scope=db_api.ALL,
|
||||
subnet_id=subnet_ids, **filters)
|
||||
|
||||
if not subnets:
|
||||
|
||||
@@ -2073,6 +2073,64 @@ class QuarkIpamTestSelectSubnet(QuarkIpamBaseTest):
|
||||
self.assertEqual(subnets[0][0]["next_auto_assign_ip"], -1)
|
||||
|
||||
|
||||
class QuarkIpamTestSelectSubnetLocking(QuarkIpamBaseTest):
|
||||
@contextlib.contextmanager
|
||||
def _stubs(self, subnet, count, increments=True, marks_full=True):
|
||||
with contextlib.nested(
|
||||
mock.patch("quark.db.api.subnet_find_ordered_by_most_full"),
|
||||
mock.patch("quark.db.api.subnet_update_next_auto_assign_ip"),
|
||||
mock.patch("quark.db.api.subnet_update_set_full"),
|
||||
mock.patch("sqlalchemy.orm.session.Session.refresh"),
|
||||
) as (subnet_find, subnet_incr, subnet_set_full, refresh):
|
||||
sub_mods = []
|
||||
sub_mods.append((subnet_helper(subnet), count))
|
||||
|
||||
def subnet_increment(context, sub):
|
||||
if increments:
|
||||
sub["next_auto_assign_ip"] += 1
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_full_mock(context, sub):
|
||||
if marks_full:
|
||||
sub["next_auto_assign_ip"] = -1
|
||||
return True
|
||||
return False
|
||||
|
||||
subnet_find.return_value = sub_mods
|
||||
subnet_incr.side_effect = subnet_increment
|
||||
subnet_set_full.side_effect = set_full_mock
|
||||
cfg.CONF.set_override('ipam_select_subnet_v6_locking', False,
|
||||
'QUARK')
|
||||
yield subnet_find
|
||||
cfg.CONF.set_override('ipam_select_subnet_v6_locking', True,
|
||||
'QUARK')
|
||||
|
||||
def test_select_subnet_v6_does_not_lock(self):
|
||||
subnet = dict(id=1, first_ip=0, last_ip=18446744073709551615L,
|
||||
cidr="::0/64", ip_version=6,
|
||||
next_auto_assign_ip=1,
|
||||
ip_policy=None, network_id=1)
|
||||
with self._stubs(subnet, 1) as subnet_find:
|
||||
self.ipam.select_subnet(self.context, subnet["network_id"],
|
||||
None, None, ip_version=6)
|
||||
subnet_find.assert_called_with(self.context, 1, lock_subnets=False,
|
||||
subnet_id=None, scope="all",
|
||||
segment_id=None, ip_version=6)
|
||||
|
||||
def test_select_subnet_v4_locks(self):
|
||||
subnet = dict(id=1, first_ip=0, last_ip=255,
|
||||
cidr="0.0.0.0/24", ip_version=4,
|
||||
next_auto_assign_ip=1,
|
||||
ip_policy=None, network_id=1)
|
||||
with self._stubs(subnet, 1) as subnet_find:
|
||||
self.ipam.select_subnet(self.context, subnet["network_id"],
|
||||
None, None, ip_version=4)
|
||||
subnet_find.assert_called_with(self.context, 1, lock_subnets=True,
|
||||
subnet_id=None, scope="all",
|
||||
segment_id=None, ip_version=4)
|
||||
|
||||
|
||||
class QuarkIpamTestLog(test_base.TestBase):
|
||||
def test_ipam_log_entry_success_flagging(self):
|
||||
log = quark.ipam.QuarkIPAMLog()
|
||||
|
||||
Reference in New Issue
Block a user