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

release-21.1: kv: remove dependency on ticks from maybeDropMsgApp #74205

Merged
Merged
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
3 changes: 3 additions & 0 deletions pkg/kv/kvserver/replica.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ type Replica struct {
// The writes to this key happen in Replica.setStartKeyLocked.
startKey roachpb.RKey

// creationTime is the time that the Replica struct was initially constructed.
creationTime time.Time

store *Store
abortSpan *abortspan.AbortSpan // Avoids anomalous reads after abort

Expand Down
1 change: 1 addition & 0 deletions pkg/kv/kvserver/replica_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func newUnloadedReplica(
r := &Replica{
AmbientContext: store.cfg.AmbientCtx,
RangeID: desc.RangeID,
creationTime: timeutil.Now(),
store: store,
abortSpan: abortspan.New(desc.RangeID),
concMgr: concurrency.NewManager(concurrency.Config{
Expand Down
31 changes: 18 additions & 13 deletions pkg/kv/kvserver/split_trigger_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,42 @@ package kvserver
import (
"context"
"fmt"
"time"

"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/util/log"
"github.com/cockroachdb/cockroach/pkg/util/timeutil"
"go.etcd.io/etcd/raft/v3/raftpb"
)

const maxDelaySplitTriggerTicks = 100
const maxDelaySplitTriggerDur = 20 * time.Second

type replicaMsgAppDropper Replica

func (rd *replicaMsgAppDropper) Args() (initialized bool, ticks int) {
func (rd *replicaMsgAppDropper) Args() (initialized bool, age time.Duration) {
r := (*Replica)(rd)
r.mu.RLock()
initialized = r.isInitializedRLocked()
ticks = r.mu.ticks
creationTime := r.creationTime
r.mu.RUnlock()
return initialized, ticks
age = timeutil.Since(creationTime)
return initialized, age
}

func (rd *replicaMsgAppDropper) ShouldDrop(startKey roachpb.RKey) (fmt.Stringer, bool) {
func (rd *replicaMsgAppDropper) ShouldDrop(
ctx context.Context, startKey roachpb.RKey,
) (fmt.Stringer, bool) {
lhsRepl := (*Replica)(rd).store.LookupReplica(startKey)
if lhsRepl == nil {
return nil, false
}
lhsRepl.store.replicaGCQueue.AddAsync(context.Background(), lhsRepl, replicaGCPriorityDefault)
lhsRepl.store.replicaGCQueue.AddAsync(ctx, lhsRepl, replicaGCPriorityDefault)
return lhsRepl, true
}

type msgAppDropper interface {
Args() (initialized bool, ticks int)
ShouldDrop(key roachpb.RKey) (fmt.Stringer, bool)
Args() (initialized bool, age time.Duration)
ShouldDrop(ctx context.Context, key roachpb.RKey) (fmt.Stringer, bool)
}

// maybeDropMsgApp returns true if the incoming Raft message should be dropped.
Expand All @@ -69,7 +74,7 @@ func maybeDropMsgApp(
// message via msg.Context. Check if this replica might be waiting for a
// split trigger. The first condition for that is not knowing the key
// bounds, i.e. not being initialized.
initialized, ticks := r.Args()
initialized, age := r.Args()

if initialized {
return false
Expand Down Expand Up @@ -130,24 +135,24 @@ func maybeDropMsgApp(

// NB: the caller is likely holding r.raftMu, but that's OK according to
// the lock order. We're not allowed to hold r.mu, but we don't.
lhsRepl, drop := r.ShouldDrop(startKey)
lhsRepl, drop := r.ShouldDrop(ctx, startKey)
if !drop {
return false
}

if verbose {
log.Infof(ctx, "start key is contained in replica %v", lhsRepl)
}
if ticks > maxDelaySplitTriggerTicks {
if age > maxDelaySplitTriggerDur {
// This is an escape hatch in case there are other scenarios (missed in
// the above analysis) in which a split trigger just isn't coming. If
// there are, the idea is that we notice this log message and improve
// the heuristics.
log.Warningf(
ctx,
"would have dropped incoming MsgApp to wait for split trigger, "+
"but allowing due to %d (>%d) ticks",
ticks, maxDelaySplitTriggerTicks)
"but allowing because uninitialized replica was created %s (>%s) ago",
age, maxDelaySplitTriggerDur)
return false
}
if verbose {
Expand Down
15 changes: 9 additions & 6 deletions pkg/kv/kvserver/split_trigger_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"context"
"fmt"
"testing"
"time"

"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/testutils"
Expand All @@ -26,17 +27,19 @@ import (

type testMsgAppDropper struct {
initialized bool
ticks int
age time.Duration
lhs bool

startKey string // set by ShouldDrop
}

func (td *testMsgAppDropper) Args() (initialized bool, ticks int) {
return td.initialized, td.ticks
func (td *testMsgAppDropper) Args() (initialized bool, age time.Duration) {
return td.initialized, td.age
}

func (td *testMsgAppDropper) ShouldDrop(startKey roachpb.RKey) (fmt.Stringer, bool) {
func (td *testMsgAppDropper) ShouldDrop(
ctx context.Context, startKey roachpb.RKey,
) (fmt.Stringer, bool) {
if len(startKey) == 0 {
panic("empty startKey")
}
Expand All @@ -56,9 +59,9 @@ func TestMaybeDropMsgApp(t *testing.T) {
// Drop message to wait for trigger.
{initialized: false, lhs: true}: true,
// Drop message to wait for trigger.
{initialized: false, lhs: true, ticks: maxDelaySplitTriggerTicks}: true,
{initialized: false, lhs: true, age: maxDelaySplitTriggerDur}: true,
// Escape hatch fires.
{initialized: false, lhs: true, ticks: maxDelaySplitTriggerTicks + 1}: false,
{initialized: false, lhs: true, age: maxDelaySplitTriggerDur + 1}: false,
}

msgHeartbeat := &raftpb.Message{
Expand Down