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

Remove Progress.is_learner #119

Merged
merged 12 commits into from
Oct 22, 2018
Merged

Remove Progress.is_learner #119

merged 12 commits into from
Oct 22, 2018

Conversation

Hoverbear
Copy link
Contributor

@Hoverbear Hoverbear commented Sep 7, 2018

Remove the is_learner value from Progress.

Rationale

In the process of Joint Consensus (#101) we will have two different Configuration sets during some points in operation.

In #108 we made Progress a single set (instead of having separate sets for voters and learners). Progress still held an is_learner value, which meant we had two ways to determine if a node was a learner (via the ProgressSet.has_learner() and Progress.is_learner). This is not necessary.

We can use ProgressSet.has_learner(id) and ProgressSet.has_voter(id) exclusively.

Benefits

Doing this helps minimize complexity, and reduces places we keep track of voter status.

Future Work

In the future we may be in a joint consensus state, meaning that the Progress.is_learner value could be incorrect (If you promoted a learner, then the old configuration still has it has a non-voter).

This internalizes the concept of the is_learner() so we can minimize possible bug surface.

@Hoverbear Hoverbear added Enhancement An improvement to existing code. learner Anything related to learner mechanism. labels Sep 7, 2018
@Hoverbear Hoverbear added this to the 0.4.0 milestone Sep 7, 2018
@Hoverbear Hoverbear self-assigned this Sep 7, 2018
@Hoverbear Hoverbear added the Feature Related to a major feature. label Sep 7, 2018
@Hoverbear Hoverbear modified the milestones: 0.4.0, 0.5.0 Sep 11, 2018
@Hoverbear Hoverbear force-pushed the remove_is_learner branch 3 times, most recently from 2810600 to 4dd2e63 Compare September 12, 2018 00:03
@Hoverbear Hoverbear added this to To do in Joint Consensus Sep 12, 2018
@Hoverbear Hoverbear moved this from To do to Needs review in Joint Consensus Sep 12, 2018
@Hoverbear Hoverbear force-pushed the remove_is_learner branch 5 times, most recently from d861453 to f8f30f5 Compare September 19, 2018 00:11
@Hoverbear Hoverbear force-pushed the remove_is_learner branch 2 times, most recently from c468ee8 to a744827 Compare September 25, 2018 17:35
b.iter(|| ProgressSet::new());
};

c.bench_function(&format!("ProgressSet::new"), bench);
Copy link
Member

Choose a reason for hiding this comment

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

How about c.bench_function("ProgressSet::new", bench)?

@Hoverbear Hoverbear force-pushed the remove_is_learner branch 2 times, most recently from e250876 to 546b926 Compare September 26, 2018 17:17
src/raft.rs Outdated
@@ -1993,12 +1993,13 @@ impl<T: Storage> Raft<T> {
fn check_quorum_active(&mut self) -> bool {
let self_id = self.id;
let mut act = 0;
let learners = self.prs().learner_ids().clone();
Copy link
Contributor Author

@Hoverbear Hoverbear Sep 27, 2018

Choose a reason for hiding this comment

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

The clone here seems the best way, as much as I hate it. Since we use .mut_prs() and iterate we have a mutable borrow out for self.

We copy this HashSet<u64> which should only have learner _ids() in it, which should be not unreasonably large. An alternative is we can clone voter_ids() which should always be reasonable even if there are many learners. The downside being we always have the cost of the voters (3-7 usually).

Copy link
Member

Choose a reason for hiding this comment

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

You can use take_prs to get around the lifetime check just as other places already did.

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 always feel so dirty doing this. 🤣 But yes you're right.

src/raft.rs Outdated
if let Some(progress) = self.prs().get(id) {
// If progress.is_learner == learner, then it's already inserted as what it should be, return early to avoid error.
if progress.is_learner == learner {
if self.prs().get(id).is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not necessary any more.

Copy link
Member

Choose a reason for hiding this comment

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

Agree. insert_learner and similar functions do the check already. We can check the result to reflect errors.

Copy link
Contributor Author

@Hoverbear Hoverbear Oct 1, 2018

Choose a reason for hiding this comment

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

Ok. I will make this function (which is private) return a Result<()>. I would like to make the callers return a Result<()> in 0.5.0.

See #129.

@hicqu
Copy link
Contributor

hicqu commented Sep 29, 2018

rest LGTM. Nice work!

Joint Consensus automation moved this from Reviewer approved to Needs review Oct 10, 2018
@Hoverbear
Copy link
Contributor Author

@BusyJay Can you take another look?

Joint Consensus automation moved this from Needs review to Reviewer approved Oct 10, 2018
hicqu
hicqu previously approved these changes Oct 10, 2018
@hicqu
Copy link
Contributor

hicqu commented Oct 11, 2018

PTAL @BusyJay .

Joint Consensus automation moved this from Reviewer approved to Needs review Oct 17, 2018
@Hoverbear
Copy link
Contributor Author

@BusyJay Please take a look again, the test name is fixed.

Joint Consensus automation moved this from Needs review to Reviewer approved Oct 19, 2018
BusyJay
BusyJay previously approved these changes Oct 19, 2018
src/progress.rs Outdated Show resolved Hide resolved
siddontang
siddontang previously approved these changes Oct 20, 2018
Copy link
Contributor

@siddontang siddontang left a comment

Choose a reason for hiding this comment

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

Rest LGTM

@Hoverbear Hoverbear dismissed stale reviews from siddontang and BusyJay via 68f90e6 October 20, 2018 14:11
Joint Consensus automation moved this from Reviewer approved to Needs review Oct 20, 2018
@Hoverbear
Copy link
Contributor Author

@siddontang Resolved, PTAL. I think it's ready for merge.

Joint Consensus automation moved this from Needs review to Reviewer approved Oct 22, 2018
@Hoverbear Hoverbear merged commit dcba27f into master Oct 22, 2018
Joint Consensus automation moved this from Reviewer approved to Done Oct 22, 2018
@Hoverbear Hoverbear deleted the remove_is_learner branch October 22, 2018 14:26
bors bot added a commit that referenced this pull request Nov 21, 2018
121: Move poll & quorum functionality into ProgressSet r=Hoverbear a=Hoverbear

Based off #119. **You are seeing that change set as well here, so go review that, then this after merging it! :)**

Migrate poll and quorum related functionality inside `ProgressSet`.

These functions operated on the `ProgressSet` anyways, they were just scoped to the `Raft`.

# Rationale

With the introduction of Joint Consensus, the idea of a Quorum is no longer always a single value. (If the cluster is in a joint state it actually has two quorums. The old configuration and the new one.)

In the interest of isolating responsibility and dulling sharp edges, this PR migrates code the following functionality:

* `check_quorum_active`: Migrated, it was doing a mutable fold on the peers and resetting their recent active, then returning if there was enough for quorum. The `ProgressSet` can do this itself, and it means we can avoid having to return some enum of either `(quorum)` or `(new_quorum, old_quorum)`. The `Raft` module need not care.
* `poll`: Was split into a mutating vote-setter function, and a check function (non mutating). The check function returns a semantically meaningful enum now. This was a good idea since `poll(vote) >= quorum`, while still valid, may be comparing tuples or values. Internalizing this logic and instead returning a semantic value helps with understanding.
* `minimum_committed_index`: Since in a joint consensus state we need to check the minimum committed index of both old and new, we can internalize this check and just return a bool.

# Benefits

This PR essentially amounts to API cleaning. It doesn't change any behavior, but it's a change we should do to make future work easier.

# Future Work

When Joint Consensus (#101 ) lands it will change these new functions to be joint-aware and correctly return values regardless of the configuration state.

Co-authored-by: Hoverbear <andrew@hoverbear.org>
Co-authored-by: Hoverbear <operator@hoverbear.org>
Co-authored-by: A. Hobden <andrew@hoverbear.org>
Co-authored-by: A. Hobden <operator@hoverbear.org>
Co-authored-by: qupeng <onlyqupeng@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement An improvement to existing code. Feature Related to a major feature. learner Anything related to learner mechanism.
Projects
Development

Successfully merging this pull request may close these issues.

None yet

5 participants