-
Notifications
You must be signed in to change notification settings - Fork 15
[PDS-403847] [III] Part 3: Accept Nodes Presenting Plausible-Evolution IDs Even If Not In Quorum #6768
Conversation
…db into jkong/403847-group-flames
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks fine, although one flag about hard failures
import org.immutables.value.Value; | ||
|
||
@Value.Immutable | ||
public interface IdSupportingHostIdResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a confusing name, imo, but I don't have a good one offhand (it reads as if the host id supports IDs which is... odd, even though, from the exception message in check, I gathered that you mean that this includes results from a host that supports returning host ids)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline: Let's go with NonSoftFailureHostIdResult
. Your inference is correct, but we should make it explicit.
return newServersWithoutSoftFailures.keySet(); | ||
} | ||
ConsistentClusterTopologies newNodesAgreedTopologies = maybeTopologies.get(); | ||
.filterValues(result -> result.result().type() == HostIdResult.Type.SUCCESS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider: consider having IdSupporting... have derived type and result fields so you don't have result.result().type() e.t.c?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah let's do this! I thought about it - was a bit hesitant to include the Type field because it was on HostIdResult, but these are pretty coupled anyway
.filterValues(result -> result.result().type() == HostIdResult.Type.SUCCESS | ||
&& pastTopologies.sharesAtLeastOneHostId( | ||
result.result().hostIds())) | ||
.toMap(); | ||
ConsistentClusterTopologies pastTopologySnapshot = pastConsistentTopologies.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is now unnecessary (replaced with a hoist to L243)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
womp - bad merge conflict resolution on my part. Thanks
@Value.Check | ||
default void check() { | ||
Preconditions.checkArgument( | ||
result().type() != HostIdResult.Type.SOFT_FAILURE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to exclude hard failures too? Since they too will have an empty set of hostIds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed: this was more NonSoftFailureHostIdResult
as opposed to a host ID result with IDs, so hard failures are allowed here. We could extract another class for the Success case, but given that that's pretty much just before we extract the host IDs and manipulate the Set<String>
I think the marginal value is a bit lower (whereas the "we got rid of soft failures" spans a bigger section of the code).
// connected by non-empty intersections. | ||
return false; | ||
} | ||
Preconditions.checkArgument(!sets.contains(ImmutableSet.of()), "Empty sets of host ids are not allowed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-actionable: The existence of a type NonemptySet would be nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it would :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@Value.Check | ||
default void check() { | ||
Preconditions.checkArgument( | ||
result().type() != HostIdResult.Type.SOFT_FAILURE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the nittiest of nits, and I don't really care if you don't action this: you can just use type!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gah! this is my fault for not pushing changes all the way down
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and, as per recent discussions, you can be very sure this will be actioned 😉
@@ -389,8 +389,8 @@ public void returnsAllNewHostsIfNoConsensusOnNewHostsWhenNoQuorumAndCurrentServe | |||
assertThat(hostsOffline).hasSizeGreaterThanOrEqualTo((ALL_HOSTS.size() + 1) / 2); | |||
assertThat(validator.getNewHostsWithInconsistentTopologies( | |||
mapToTokenRangeOrigin(newCassandraServers), allHosts)) | |||
.as("rejects all servers when no quorum from all hosts and no quorum on new hosts") | |||
.containsExactlyInAnyOrderElementsOf(newCassandraServers); | |||
.as("accepts servers with plausible evolution when no quorum from all hosts and no quorum on new hosts") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the test name doesn't match the tested behaviour anymore
@@ -537,8 +537,9 @@ public void returnsAllNewHostsIfNoConsensusOnConfigHostsWhenNoQuorumAndNoCurrent | |||
splitHostOriginBetweenLastKnownAndConfig( | |||
oldCassandraServers, Sets.difference(allCassandraServers, oldCassandraServers)), | |||
allHosts)) | |||
.as("rejects all servers when no quorum from all hosts and no quorum on available hosts") | |||
.containsExactlyInAnyOrderElementsOf(allCassandraServers); | |||
.as("accepts new servers with a plausible evolution when no quorum from all hosts and no quorum on" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likewise here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catches! Will fix.
Released 0.954.0 |
General
Before this PR:
Suppose we discover three new nodes in a Cassandra cluster when a quorum is not available. We currently attempt to get a quorum from them and then check if the topology they agree on is a plausible evolution of what the cluster has agreed on in the past - if so, we admit the nodes in the cluster that provided one of the topologies agreed upon by the quorum of new nodes. But this is unnecessary: we should not need a quorum of new nodes to be up if they agree with what we already have.
After this PR:
==COMMIT_MSG==
We now admit new nodes that match the existing topology even in the absence of a quorum of new nodes.
==COMMIT_MSG==
Priority: P2
Concerns / possible downsides (what feedback would you like?):
Is documentation needed?: No
Compatibility
Does this PR create any API breaks (e.g. at the Java or HTTP layers) - if so, do we have compatibility?: No
Does this PR change the persisted format of any data - if so, do we have forward and backward compatibility?: No
The code in this PR may be part of a blue-green deploy. Can upgrades from previous versions safely coexist? (Consider restarts of blue or green nodes.): Yes
Does this PR rely on statements being true about other products at a deployment - if so, do we have correct product dependencies on these products (or other ways of verifying that these statements are true)?: No
Does this PR need a schema migration? No
Testing and Correctness
What, if any, assumptions are made about the current state of the world? If they change over time, how will we find out?: Nothing much
What was existing testing like? What have you done to improve it?: Added new tests
If this PR contains complex concurrent or asynchronous code, is it correct? The onus is on the PR writer to demonstrate this.: Rollback
If this PR involves acquiring locks or other shared resources, how do we ensure that these are always released?: No
Execution
How would I tell this PR works in production? (Metrics, logs, etc.): Migrations work
Has the safety of all log arguments been decided correctly?: I believe so.
Will this change significantly affect our spending on metrics or logs?: No. There's a small risk in that we've noted before that logging CassandraServer is expensive, but we do it only once per refresh.
How would I tell that this PR does not work in production? (monitors, etc.): Migrations don't work
If this PR does not work as expected, how do I fix that state? Would rollback be straightforward?: Rollback
If the above plan is more complex than “recall and rollback”, please tag the support PoC here (if it is the end of the week, tag both the current and next PoC):
Scale
Would this PR be expected to pose a risk at scale? Think of the shopping product at our largest stack.: No
Would this PR be expected to perform a large number of database calls, and/or expensive database calls (e.g., row range scans, concurrent CAS)?: No
Would this PR ever, with time and scale, become the wrong thing to do - and if so, how would we know that we need to do something differently?: Don't think so
Development Process
Where should we start reviewing?: CTV
If this PR is in excess of 500 lines excluding versions lock-files, why does it not make sense to split it?:
Please tag any other people who should be aware of this PR:
@jeremyk-91
@sverma30
@raiju