Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug in DCAwareRoundRobinPolicy #351

Open
dkropachev opened this issue Aug 3, 2024 · 2 comments
Open

Possible bug in DCAwareRoundRobinPolicy #351

dkropachev opened this issue Aug 3, 2024 · 2 comments
Assignees

Comments

@dkropachev
Copy link
Collaborator

dkropachev commented Aug 3, 2024

Code under question is in the DCAwareRoundRobinPolicy.distance:

dc_hosts = self._dc_live_hosts.get(dc)
if not dc_hosts:
return HostDistance.IGNORED
if host in list(dc_hosts)[:self.used_hosts_per_remote_dc]:
return HostDistance.REMOTE
else:
return HostDistance.IGNORED

This peace of the code creates a split in DCAwareRoundRobinPolicy.distance behavior for case when used_hosts_per_remote_dc is not empty:

  1. if node was added to the policy and remote dc bucket does not contain more than used_hosts_per_remote_dc it will return HostDistance.REMOTE
  2. Otherwise it will return HostDistance.IGNORE

Which means that if code uses .distance before on_add it will yield wrong result if this node fits into used_hosts_per_remote_dc.
Now you should always consider it when using lbp.distance.

Just one exampe that I managed to eyeball is in Cluster.on_add:

def on_add(self, host, refresh_nodes=True):
if self.is_shutdown:
return
log.debug("Handling new host %r and notifying listeners", host)
distance = self.profile_manager.distance(host)
if distance != HostDistance.IGNORED:
self._prepare_all_queries(host)
log.debug("Done preparing queries for new host %r", host)
self.profile_manager.on_add(host)
self.control_connection.on_add(host, refresh_nodes)
if distance == HostDistance.IGNORED:
log.debug("Not adding connection pool for new host %r because the "
"load balancing policy has marked it as IGNORED", host)
self._finalize_add(host, set_up=False)
return
futures_lock = Lock()
futures_results = []
futures = set()

So it won't finalize properly for node from remote dc and won't run self._prepare_all_queries(host) for it.
Just becase it is doing:

        distance = self.profile_manager.distance(host)
        if distance != HostDistance.IGNORED:
            self._prepare_all_queries(host)
            log.debug("Done preparing queries for new host %r", host)

        self.profile_manager.on_add(host)

Instead of

        self.profile_manager.on_add(host)
        distance = self.profile_manager.distance(host)
        if distance != HostDistance.IGNORED:
            self._prepare_all_queries(host)
            log.debug("Done preparing queries for new host %r", host)
@dkropachev
Copy link
Collaborator Author

As I understand it was done to signal upper logic to connect only to a certain number of remote dc nodes.

My proposal, instead of going around the code and fixing distance usage to make sure that everywhere it is used to decide whether node is worth of connecting to or not, to delegate this functionality to another method on lbp like should_connect(host):bool and use it there for that purpose, removing self._dc_live_hosts from distance calculation.

@Lorak-mmk
Copy link

Hmm... by looking at the code it looks like you are right.
But if that were the case, then the driver would never connect to nodes outside the current DC, right?
I don't think that's the case, so maybe we are somehow misunderstanding the code - or it is the case and somehow no one noticed and no test checked this?
We should check if that really is the case or if we misunderstood something before trying to fix it.

If we were to fix this: I'd be strongly against other method. There should be only one (or maybe a few, but a low number) paths were nodes are added to policy. Those should be fixed (which will improve the driver and possibly uncover other bugs by reading code) instead of complicating code.

@dkropachev dkropachev self-assigned this Aug 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants