Skip to content

Commit e26c4b1

Browse files
committed
session: discard stale replacement-host pools
1 parent 3309e8f commit e26c4b1

2 files changed

Lines changed: 60 additions & 17 deletions

File tree

cassandra/cluster.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,24 +4095,39 @@ def callback(pool, errors):
40954095
metadata_host = self.cluster.metadata.get_host_by_host_id(host.host_id)
40964096

40974097
target_host = metadata_host if metadata_host is not None else host
4098-
target_host_matches = False
4099-
for pool_host in tuple(retained_pools):
4100-
if pool_host is target_host:
4101-
target_host_matches = True
4102-
elif pool_host == target_host:
4103-
previous_pools.append(retained_pools.pop(pool_host))
4104-
4105-
if target_host_matches:
4106-
reuse_existing_pool = True
4098+
target_endpoint_changed = False
4099+
if target_host is not host:
4100+
with target_host.lock:
4101+
target_endpoint_changed = not self._endpoints_match(
4102+
target_host.endpoint, creation_endpoint)
4103+
4104+
if target_endpoint_changed:
4105+
log.debug(
4106+
"Discarding stale connection pool for host %s; "
4107+
"metadata host endpoint changed from %s",
4108+
host, creation_endpoint)
4109+
self._invalidate_pool_creation(
4110+
host, expected_endpoint=creation_endpoint)
4111+
discard_pool = True
41074112
else:
4108-
source_host = new_pool.host
4109-
if (source_host is not target_host and
4110-
target_host.sharding_info is None):
4111-
target_host.sharding_info = source_host.sharding_info
4112-
new_pool.host = target_host
4113-
retained_pools[target_host] = new_pool
4114-
self._pools = retained_pools
4115-
self._clear_pool_creation(host, creation_epoch)
4113+
target_host_matches = False
4114+
for pool_host in tuple(retained_pools):
4115+
if pool_host is target_host:
4116+
target_host_matches = True
4117+
elif pool_host == target_host:
4118+
previous_pools.append(retained_pools.pop(pool_host))
4119+
4120+
if target_host_matches:
4121+
reuse_existing_pool = True
4122+
else:
4123+
source_host = new_pool.host
4124+
if (source_host is not target_host and
4125+
target_host.sharding_info is None):
4126+
target_host.sharding_info = source_host.sharding_info
4127+
new_pool.host = target_host
4128+
retained_pools[target_host] = new_pool
4129+
self._pools = retained_pools
4130+
self._clear_pool_creation(host, creation_epoch)
41164131

41174132
if reuse_existing_pool:
41184133
log.debug("Reusing existing connection pool for host %s", host)

tests/unit/test_cluster.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from cassandra.cluster import _Scheduler, Session, Cluster, default_lbp_factory, \
2727
ExecutionProfile, _ConfigMode, EXEC_PROFILE_DEFAULT
2828
from cassandra.connection import ClientRoutesEndPoint, ConnectionException, DefaultEndPoint, SniEndPoint
29+
from cassandra.metadata import Metadata
2930
from cassandra.pool import Host, HostConnection, _HostReconnectionHandler
3031
from cassandra.policies import HostDistance, RetryPolicy, RoundRobinPolicy, DowngradingConsistencyRetryPolicy, SimpleConvictionPolicy
3132
from cassandra.query import SimpleStatement, named_tuple_factory, tuple_factory
@@ -664,6 +665,33 @@ def make_pool(host, distance, pool_session, endpoint=None):
664665
assert session._pools == {}
665666
created_pools[0].shutdown.assert_called_once_with()
666667

668+
def test_stale_host_pool_creation_does_not_publish_to_replacement_host(self):
669+
host_id = uuid.uuid4()
670+
stale_host = Host(DefaultEndPoint("127.0.0.1"), SimpleConvictionPolicy,
671+
host_id=host_id)
672+
replacement_host = Host(DefaultEndPoint("127.0.0.2"),
673+
SimpleConvictionPolicy, host_id=host_id)
674+
cluster, session, executor = self._make_cluster_and_session(
675+
[replacement_host])
676+
cluster.metadata = Metadata()
677+
cluster.metadata.add_or_return_host(replacement_host)
678+
created_pools = []
679+
680+
def make_pool(host, distance, pool_session, endpoint=None):
681+
pool = self._make_pool(host, distance, pool_session, endpoint)
682+
created_pools.append(pool)
683+
return pool
684+
685+
with patch("cassandra.cluster.HostConnection", side_effect=make_pool):
686+
future = session.add_or_renew_pool(
687+
stale_host, is_host_addition=False)
688+
689+
executor.run_next()
690+
691+
assert future.result() is False
692+
assert session._pools == {}
693+
created_pools[0].shutdown.assert_called_once_with()
694+
667695
def test_remove_pool_expected_host_mismatch_invalidates_stale_creation(self):
668696
stale_host = self._make_host("127.0.0.1")
669697
replacement_host = self._make_host("127.0.0.1")

0 commit comments

Comments
 (0)