forked from cockroachdb/cockroach
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
raftlog: introduce & use in loqrecovery, kvserver
This commit introduces a new package `raftlog`. Aspirationally, this will at some point become the de facto way of encapsulating the raft log encoding and may play a role in programmatically constructing and inspecting raft logs (e.g. for testing). For now, we introduce two concepts: - `raftlog.Entry`, which wraps a `raftpb.Entry` and all of the information derived from it, such as the command ID, the `kvserverpb.RaftCommand`, the configuration change (if any), etc. - `raftlog.Iterator`, a way to iterate over the raft log in terms of `raftlog.Entry` (as opposed to `raftpb.Entry` which requires lots of manual processing). Both are then applied across the codebase, concretely: - `loqrecovery` is simplified via `raftlog.Iterator` to pull commit triggers out of the raft log. - debug pretty-printing is simpler thanks to use of `raftlog.Entry`. - `decodedRaftEntry` is now structurally a `raftpb.Entry`, and again lots manual custom unmarshaling code evaporates. It's currently difficult to create "interesting" raft log entries if trying to stay away from manual population of large datastructures (which is prone to rotting), so there's zero unit testing of `raftlog.Iterator`. However, the code is not new, instead it was deduplicated from a few places, and is now tested through all of them; so I don't feel to bad about it. I still think it is a priority to be able to "comfortably" create at least "simple" raft logs, meaning we need to be able to string together `batcheval` and entry creation at least in a rudimentary fashion. I intend to look into this next and add comprehensive unit tests for `raftlog.{Entry,Iterator}`. Touches cockroachdb#75729. Release note: None
- Loading branch information
Showing
12 changed files
with
379 additions
and
318 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
|
||
go_library( | ||
name = "raftlog", | ||
srcs = [ | ||
"entry.go", | ||
"iterator.go", | ||
], | ||
importpath = "github.com/cockroachdb/cockroach/pkg/kv/kvserver/raftlog", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"//pkg/keys", | ||
"//pkg/kv/kvserver/kvserverbase", | ||
"//pkg/kv/kvserver/kvserverpb", | ||
"//pkg/roachpb:with-mocks", | ||
"//pkg/storage", | ||
"//pkg/storage/enginepb", | ||
"//pkg/util/protoutil", | ||
"@com_github_cockroachdb_errors//:errors", | ||
"@io_etcd_go_etcd_raft_v3//raftpb", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2022 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package raftlog | ||
|
||
import ( | ||
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase" | ||
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb" | ||
"github.com/cockroachdb/cockroach/pkg/storage" | ||
"github.com/cockroachdb/cockroach/pkg/storage/enginepb" | ||
"github.com/cockroachdb/cockroach/pkg/util/protoutil" | ||
"github.com/cockroachdb/errors" | ||
"go.etcd.io/etcd/raft/v3/raftpb" | ||
) | ||
|
||
// Entry contains data related to the current raft log entry. | ||
type Entry struct { | ||
Meta enginepb.MVCCMetadata // optional | ||
Ent raftpb.Entry | ||
ID kvserverbase.CmdIDKey | ||
CC1 *raftpb.ConfChange | ||
CC2 *raftpb.ConfChangeV2 | ||
CCC *kvserverpb.ConfChangeContext | ||
Cmd kvserverpb.RaftCommand | ||
} | ||
|
||
func (e *Entry) CC() raftpb.ConfChangeI { | ||
if e.CC1 != nil { | ||
return e.CC1 | ||
} | ||
if e.CC2 != nil { | ||
return e.CC2 | ||
} | ||
// NB: nil != interface{}(nil). | ||
return nil | ||
} | ||
|
||
func (e *Entry) LoadFromRawValue(b []byte) error { | ||
if err := protoutil.Unmarshal(b, &e.Meta); err != nil { | ||
return errors.Wrap(err, "decoding raft log MVCCMetadata") | ||
} | ||
|
||
if err := storage.MakeValue(e.Meta).GetProto(&e.Ent); err != nil { | ||
return errors.Wrap(err, "unmarshalling raft Entry") | ||
} | ||
|
||
return e.load() | ||
} | ||
|
||
func (e *Entry) Load() error { | ||
e.Meta = enginepb.MVCCMetadata{} | ||
return e.load() | ||
} | ||
|
||
func (e *Entry) load() error { | ||
if len(e.Ent.Data) == 0 { | ||
// Raft-proposed empty entry. | ||
return nil | ||
} | ||
|
||
var payload []byte | ||
switch e.Ent.Type { | ||
case raftpb.EntryNormal: | ||
e.ID, payload = kvserverbase.DecodeRaftCommand(e.Ent.Data) | ||
case raftpb.EntryConfChange: | ||
e.CC1 = &raftpb.ConfChange{} | ||
if err := protoutil.Unmarshal(e.Ent.Data, e.CC1); err != nil { | ||
return errors.Wrap(err, "unmarshalling ConfChange") | ||
} | ||
e.CCC = &kvserverpb.ConfChangeContext{} | ||
if err := protoutil.Unmarshal(e.CC1.Context, e.CCC); err != nil { | ||
return errors.Wrap(err, "unmarshalling ConfChangeContext") | ||
} | ||
payload = e.CCC.Payload | ||
e.ID = kvserverbase.CmdIDKey(e.CCC.CommandID) | ||
case raftpb.EntryConfChangeV2: | ||
e.CC2 = &raftpb.ConfChangeV2{} | ||
if err := protoutil.Unmarshal(e.Ent.Data, e.CC2); err != nil { | ||
return errors.Wrap(err, "unmarshalling ConfChangeV2") | ||
} | ||
e.CCC = &kvserverpb.ConfChangeContext{} | ||
if err := protoutil.Unmarshal(e.CC2.Context, e.CCC); err != nil { | ||
return errors.Wrap(err, "unmarshalling ConfChangeContext") | ||
} | ||
payload = e.CCC.Payload | ||
e.ID = kvserverbase.CmdIDKey(e.CCC.CommandID) | ||
default: | ||
return errors.AssertionFailedf("unknown entry type %d", e.Ent.Type) | ||
} | ||
|
||
// TODO(tbg): can len(payload)==0 if we propose an empty command to wake up leader? | ||
// If so, is that a problem here? | ||
return errors.Wrap(protoutil.Unmarshal(payload, &e.Cmd), "unmarshalling RaftCommand") | ||
} |
Oops, something went wrong.