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

storage: correctly handle empty forwarded proposals #31066

Open
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
5 participants
@tschottdorf
Member

tschottdorf commented Oct 8, 2018

The code assumed that an empty proposal would be a command ID with empty
data, but it's really the empty slice (command IDs+data is our encoding;
Raft itself emits an entry with completely blank data).

Fixes #31050.

Release note: None

storage: correctly handle empty forwarded proposals
The code assumed that an empty proposal would be a command ID with empty
data, but it's really the empty slice (command IDs+data is our encoding;
Raft itself emits an entry with completely blank data).

Fixes #31050.

Release note: None

@tschottdorf tschottdorf requested a review from cockroachdb/core-prs as a code owner Oct 8, 2018

@cockroach-teamcity

This comment has been minimized.

Show comment
Hide comment
@cockroach-teamcity

cockroach-teamcity Oct 8, 2018

Member

This change is Reviewable

Member

cockroach-teamcity commented Oct 8, 2018

This change is Reviewable

@tschottdorf

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained


pkg/storage/replica.go, line 4107 at r1 (raw file):

	}

	if rg.Status().RaftState != raft.StateLeader {

Isn't this not enough though? We might think we're the leader but we're not. Wouldn't that result in us tracking something that may never actually get committed, and rejecting reproposals based on that?

@tschottdorf tschottdorf requested a review from nvanbenschoten Oct 8, 2018

@petermattis

:lgtm: for the protection against processing empty proposals.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale)


pkg/storage/replica.go, line 4107 at r1 (raw file):

We might think we're the leader but we're not.

How could that happen? This method is called immediately after raftGroup.Step which should have an up to date view of leadership. One problem that could happen is that we're not the leader for part of Message, but one of the Entries steps the state machine causing us to become the leader.

@tschottdorf

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/storage/replica.go, line 4107 at r1 (raw file):

Previously, petermattis (Peter Mattis) wrote…

We might think we're the leader but we're not.

How could that happen? This method is called immediately after raftGroup.Step which should have an up to date view of leadership. One problem that could happen is that we're not the leader for part of Message, but one of the Entries steps the state machine causing us to become the leader.

That's just the local view of leadership, the rest of the replica set could've moved on to a new leader under a higher term.
I think this is OK though, for then the next reproposal would reach a new leader.

Good point though about obtaining leadership. Aren't we in the clear though? We Step the whole message into the Raft group before checking the leadership.

@petermattis

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/storage/replica.go, line 4107 at r1 (raw file):

Good point though about obtaining leadership. Aren't we in the clear though? We Step the whole message into the Raft group before checking the leadership.

I think you're correct. We step the whole message, but ErrProposalDropped will be returned if we're not the leader at the start of processing Message.Entries and see MsgProp.

@bdarnell

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/storage/replica.go, line 4119 at r1 (raw file):

		switch e.Type {
		case raftpb.EntryNormal:
			if len(e.Data) == 0 {

Both kinds of "empty" proposals exist. Raft itself generates log entries with len(e.Data) == 0 for a couple of reasons (new leaders and concurrent config changes), and we generate the "command id with empty data" ones when waking the leader. I think we still need the guard here for empty data after decoding the command id, in addition to the guard for completely empty entries.

I also don't understand how a raft-generated empty entry would ever get forwarded. These entries are only generated on leaders and become MsgApp immediately, never MsgProp.

@nvanbenschoten

:lgtm_cancel:

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/storage/replica.go, line 4107 at r1 (raw file):

I think this is OK though, for then the next reproposal would reach a new leader.

Yes, that's the rationale that's being used to justify this. However, I'm really starting to doubt our ability to figure out what's going to end up in the Raft log and what's not. I'd like to discuss #30064 (comment) as an alternative to all of this.


pkg/storage/replica_test.go, line 8575 at r1 (raw file):

			},
			expDrop:             false,
			expRemotePropsAfter: 2,

Hold on, we don't want to make this change. This was the cause of a memory leak before which was fixed in #29618.

@tschottdorf

This comment has been minimized.

Show comment
Hide comment
@tschottdorf

tschottdorf Oct 9, 2018

Member
Member

tschottdorf commented Oct 9, 2018

@tschottdorf

This comment has been minimized.

Show comment
Hide comment
@tschottdorf

tschottdorf Oct 9, 2018

Member

Closing. @nvanbenschoten will rip all of this out.

Member

tschottdorf commented Oct 9, 2018

Closing. @nvanbenschoten will rip all of this out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment