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

feat: targetServerType=preferPrimary connection parameter #2483

Merged
merged 5 commits into from
May 2, 2022

Conversation

mitya555
Copy link
Contributor

@mitya555 mitya555 commented Apr 6, 2022

@davecramer - this PR is a cleaner copy of the PR#1430 as we discussed here: https://www.postgresql.org/message-id/CADK3HHJBQJje9Etd29HY6_1S1kRdR4KEviPev-vjtrQp-dZ%2BFQ%40mail.gmail.com

Below is the original PR#1430 Description:

Allows a new preferMaster value for targetServerType parameter, which forces the driver to preferably connect to a master host. The behaiviour is basically the inverse of preferSecondary value and the usecases are described in the mailing list: https://www.postgresql.org/message-id/VI1PR05MB5295AE43EF9525EACC9E57ECBC750%40VI1PR05MB5295.eurprd05.prod.outlook.com

Also updated the documentation and readme for the parameter.

All Submissions:

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

New Feature Submissions:

  1. Does your submission pass tests?
  2. Does ./gradlew autostyleCheck checkstyleAll pass ?
  3. Have you added your new test classes to an existing test suite in alphabetical order? (Added tests to an existing test class in alphabetical order)

Changes to Existing Features:

  • Does this break existing behaviour? If so please explain.
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully run tests with your changes locally?

return any.iterator();
}

if (any.isEmpty()) {
return secondaries.iterator();
return preferred.iterator();
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the logic here ?

if preferred is empty fails and any is empty is true, then it's going to return an empty iterator ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If preferred is not empty, then neither can any be.

I'm guessing a static analysis would flag the any.get(0) without checking as a bug.
An assert !any.isEmpty() should suffice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the logic here ?

if preferred is empty fails and any is empty is true, then it's going to return an empty iterator ?

if preferred-is-empty fails (i.e. "preferred" iterator is not empty) and any-is-empty is true (i.e. "any" iterator is empty), then it's going to return "preferred" iterator, which is not empty. It follows exactly same logic for the "preferred" iterator that was here before for the "secondaries" iterator.

I agree with @OrangeDog though that if "preferred" is not empty, then "any" cannot be empty either, which means that "any-is-empty is true" branch will never be entered

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way this code seems difficult to follow. Can someone suggest a simplification?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the checks are actually necessary:

List<CandidateHost> preferred = getCandidateHosts(preferredServerType);
List<CandidateHost> any = getCandidateHosts(HostRequirement.any);

any.removeAll(preferred);
return append(preferred, any).iterator();

May need a different function call if the lists aren't mutable. Or skip removeAll and don't worry about repeated attempts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way this code seems difficult to follow. Can someone suggest a simplification?

Pushed 404efd1 commit that simplifies MultiHostChooser.candidateIterator() code and fixes condition for the optimization inside this method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way this code seems difficult to follow. Can someone suggest a simplification?

Pushed 404efd1 commit that simplifies MultiHostChooser.candidateIterator() code and fixes condition for the optimization inside this method

@davecramer - can I do anything else to address your concern that the code in question is difficult to follow and your request for its simplification?

@davecramer davecramer changed the title New targetServerType=preferMaster parameter value New targetServerType=preferPrimary parameter value Apr 19, 2022
// Note: this is only an optimization
secondaries = rtrim(1, secondaries);
preferred = rtrim(1, preferred);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any.removeAll(preferred) would avoid duplicate attempts even more effectively, and not require explanation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I just tried to keep the changes minimal and keep the logic as close as possible to the original logic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any.removeAll(preferred) would avoid duplicate attempts even more effectively, and not require explanation

After further consideration I think that any.removeAll(preferred) won't work with CandidateHost class instances because it won't find a match in any for any instance from preferred and, even if implemented properly (i.e. against HostSpec instances instead of CandidateHost), then it will break the logic implemented here originally for the host selection.

None of the checks are actually necessary:

List<CandidateHost> preferred = getCandidateHosts(preferredServerType);
List<CandidateHost> any = getCandidateHosts(HostRequirement.any);

any.removeAll(preferred);
return append(preferred, any).iterator();

May need a different function call if the lists aren't mutable. Or skip removeAll and don't worry about repeated attempts.

Those repeated attempts are actually important here since they are made for different HostRequirements

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't work with CandidateHost class instances

Ah yes. I missed the .hostSpec in the original. Removing all of them would need a bit more code.

Those repeated attempts are actually important

Then why is it removing one of them as an optimisation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why is it removing one of them as an optimisation?

It is removing just this one for optimization because it would check this host two times in a row, first time for a narrower requirement/condition (e.g. secondary) and, if the first check fails, it checks it right away for the broader any requirement/condition. These two checks in a row don't make too much sense so it removes the check for the narrower condition and makes just one check for the broader any condition

Copy link
Contributor Author

@mitya555 mitya555 Apr 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's important that the HostSpecs' order in each part of the returned List<CandidateHost> result (i.e. the first preferred part and the last any part) is the same as the order of host specs in the jdbc url. What's also important is that those preferred and any parts are shuffled independently, when loadBalanceHosts=true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. The previous logic with trimming secondaries was invalid.

@vlsi
Copy link
Member

vlsi commented Apr 30, 2022

I fully support preferPrimary option, however, it looks like host chooser should be reworked as follows:

  1. candidateIterator should always call getCandidateHosts(targetServerType). In other words, it should always retrieve all the hosts with matching state
  2. Then it should shuffle the list if required
  3. Then it should move "preferred" servers to the left of the list. That is a single for loop when we check if a given server is preferred, and, if so, it could be swapped with the position of the first non-preferred.
  4. CandidateHost does not seem to add value, so we can just remove it
  5. withReqStatus, append, rtrim should be removed as well

@davecramer , @mitya555 , WDYT?

@OrangeDog
Copy link
Contributor

@vlsi no, that doesn't make much sense. It already always gets all the matching hosts, and already always puts them first.
Shuffling them together and then unshuffling them again is pointless.

Copy link
Member

@vlsi vlsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vlsi vlsi changed the title New targetServerType=preferPrimary parameter value feat: targetServerType=preferPrimary connection parameter Apr 30, 2022
@davecramer davecramer merged commit 8444ed6 into pgjdbc:master May 2, 2022
@OrangeDog
Copy link
Contributor

Not sure how the changelog is managed, but this ended up in "Fixed" instead of "Added".

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

Successfully merging this pull request may close these issues.

None yet

4 participants