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

raftlog: don't embed raftpb.Entry in Entry #97349

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/kv/kvserver/debug_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func tryRaftLogEntry(kv storage.MVCCKeyValue) (string, error) {
defer e.Release()

if len(e.Data) == 0 {
return fmt.Sprintf("%s: EMPTY\n", &e.Entry), nil
return fmt.Sprintf("%s: EMPTY\n", (*raftpb.Entry)(&e.RaftEntry)), nil
}
e.Data = nil
cmd := e.Cmd
Expand All @@ -366,7 +366,7 @@ func tryRaftLogEntry(kv storage.MVCCKeyValue) (string, error) {
}
cmd.WriteBatch = nil

return fmt.Sprintf("%s (ID %s) by %s\n%s\nwrite batch:\n%s", &e.Entry, e.ID, leaseStr, &cmd, wbStr), nil
return fmt.Sprintf("%s (ID %s) by %s\n%s\nwrite batch:\n%s", (*raftpb.Entry)(&e.RaftEntry), e.ID, leaseStr, &cmd, wbStr), nil
}

func tryTxn(kv storage.MVCCKeyValue) (string, error) {
Expand Down
1 change: 1 addition & 0 deletions pkg/kv/kvserver/raftlog/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ go_library(
go_test(
name = "raftlog_test",
srcs = [
"command_test.go",
"encoding_test.go",
"entry_bench_test.go",
"entry_test.go",
Expand Down
28 changes: 28 additions & 0 deletions pkg/kv/kvserver/raftlog/command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 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 (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

// TestReplicatedCmdString checks that ReplicatedCmd does not implement
// fmt.Stringer. It is fine to implement this in the future, however previously
// at one point it "accidentally" implemented fmt.Stringer via embedding, which
// could hide information.
func TestReplicatedCmdString(t *testing.T) {
var cmd interface{} = (*ReplicatedCmd)(nil)
_, ok := cmd.(fmt.Stringer)
require.False(t, ok)
}
2 changes: 1 addition & 1 deletion pkg/kv/kvserver/raftlog/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func BenchmarkRaftAdmissionMetaOverhead(b *testing.B) {

encodingBuf := make([]byte, RaftCommandPrefixLen+raftAdmissionMeta.Size()+len(marshaledRaftCmd))
raftEnt := Entry{
Entry: raftpb.Entry{
RaftEntry: RaftEntry{
Term: 1,
Index: 1,
Type: raftpb.EntryNormal,
Expand Down
22 changes: 14 additions & 8 deletions pkg/kv/kvserver/raftlog/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,17 @@ func DecomposeRaftEncodingStandardOrSideloaded(data []byte) (kvserverbase.CmdIDK
return kvserverbase.CmdIDKey(data[1 : 1+RaftCommandIDLen]), data[1+RaftCommandIDLen:]
}

// RaftEntry is structurally identical to raftpb.Entry but does not implement any
// of its methods (and in particular fmt.Stringer). This avoids leaking the String
// method into structs that embed an Entry, where it would produce poor results
// since it wouldn't reflect any additional fields.
type RaftEntry raftpb.Entry

// Entry contains data related to a raft log entry. This is the raftpb.Entry
// itself but also all encapsulated data relevant for command application and
// admission control.
type Entry struct {
raftpb.Entry
RaftEntry
ID kvserverbase.CmdIDKey // may be empty for zero Entry
Cmd kvserverpb.RaftCommand
ConfChangeV1 *raftpb.ConfChange // only set for config change
Expand All @@ -92,7 +98,7 @@ var entryPool = sync.Pool{
// NewEntry populates an Entry from the provided raftpb.Entry.
func NewEntry(ent raftpb.Entry) (*Entry, error) {
e := entryPool.Get().(*Entry)
*e = Entry{Entry: ent}
*e = Entry{RaftEntry: RaftEntry(ent)}
if err := e.load(); err != nil {
return nil, err
}
Expand All @@ -109,7 +115,7 @@ func NewEntryFromRawValue(b []byte) (*Entry, error) {

e := entryPool.Get().(*Entry)

if err := storage.MakeValue(meta).GetProto(&e.Entry); err != nil {
if err := storage.MakeValue(meta).GetProto((*raftpb.Entry)(&e.RaftEntry)); err != nil {
return nil, errors.Wrap(err, "unmarshalling raft Entry")
}

Expand Down Expand Up @@ -137,7 +143,7 @@ func raftEntryFromRawValue(b []byte) (raftpb.Entry, error) {
}

func (e *Entry) load() error {
typ, err := EncodingOf(e.Entry)
typ, err := EncodingOf(raftpb.Entry(e.RaftEntry))
if err != nil {
return err
}
Expand All @@ -154,10 +160,10 @@ func (e *Entry) load() error {
}
switch typ {
case EntryEncodingStandardWithAC, EntryEncodingSideloadedWithAC:
e.ID, raftCmdBytes = DecomposeRaftEncodingStandardOrSideloaded(e.Entry.Data)
e.ID, raftCmdBytes = DecomposeRaftEncodingStandardOrSideloaded(e.RaftEntry.Data)
e.ApplyAdmissionControl = true
case EntryEncodingStandardWithoutAC, EntryEncodingSideloadedWithoutAC:
e.ID, raftCmdBytes = DecomposeRaftEncodingStandardOrSideloaded(e.Entry.Data)
e.ID, raftCmdBytes = DecomposeRaftEncodingStandardOrSideloaded(e.RaftEntry.Data)
case EntryEncodingEmpty:
// Nothing to load, the empty raftpb.Entry is represented by a trivial
// Entry.
Expand All @@ -174,7 +180,7 @@ func (e *Entry) load() error {

if ccTarget != nil {
// Conf change - more unmarshaling to do.
if err := protoutil.Unmarshal(e.Entry.Data, ccTarget); err != nil {
if err := protoutil.Unmarshal(e.RaftEntry.Data, ccTarget); err != nil {
return errors.Wrap(err, "unmarshalling ConfChange")
}
e.ConfChangeContext = &kvserverpb.ConfChangeContext{}
Expand Down Expand Up @@ -207,7 +213,7 @@ func (e *Entry) ConfChange() raftpb.ConfChangeI {
// log, i.e. it is the inverse to NewEntryFromRawBytes.
func (e *Entry) ToRawBytes() ([]byte, error) {
var value roachpb.Value
if err := value.SetProto(&e.Entry); err != nil {
if err := value.SetProto((*raftpb.Entry)(&e.RaftEntry)); err != nil {
return nil, err
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/kv/kvserver/replica_application_state_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func TestReplicaStateMachineChangeReplicas(t *testing.T) {

// Stage a command with the ChangeReplicas trigger.
ent := &raftlog.Entry{
Entry: raftpb.Entry{
RaftEntry: raftlog.RaftEntry{
Index: r.mu.state.RaftAppliedIndex + 1,
Type: raftpb.EntryConfChange,
},
Expand Down Expand Up @@ -197,7 +197,7 @@ func TestReplicaStateMachineRaftLogTruncationStronglyCoupled(t *testing.T) {
// Stage a command that truncates one raft log entry which we pretend has a
// byte size of 1.
ent := &raftlog.Entry{
Entry: raftpb.Entry{
RaftEntry: raftlog.RaftEntry{
Index: raftAppliedIndex + 1,
Type: raftpb.EntryNormal,
},
Expand Down Expand Up @@ -316,7 +316,7 @@ func TestReplicaStateMachineRaftLogTruncationLooselyCoupled(t *testing.T) {
// Stage a command that truncates one raft log entry which we pretend has a
// byte size of 1.
ent := &raftlog.Entry{
Entry: raftpb.Entry{
RaftEntry: raftlog.RaftEntry{
Index: raftAppliedIndex + 1,
Type: raftpb.EntryNormal,
},
Expand Down Expand Up @@ -447,7 +447,7 @@ func TestReplicaStateMachineEphemeralAppBatchRejection(t *testing.T) {
for _, s := range []string{"earlier", "later"} {
req, repr := descWriteRepr(s)
ent := &raftlog.Entry{
Entry: raftpb.Entry{
RaftEntry: raftlog.RaftEntry{
Index: raftAppliedIndex + 1,
Type: raftpb.EntryNormal,
},
Expand Down