You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: replica_gc_queue.go
    path of file: ./repos/cockroach/pkg/kv/kvserver
    
    the code of the file until where you have to start completion: // Copyright 2015 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 kvserver

import (
	"context"
	"time"

	"github.com/cockroachdb/cockroach/pkg/kv"
	"github.com/cockroachdb/cockroach/pkg/kv/kvpb"
	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase"
	"github.com/cockroachdb/cockroach/pkg/roachpb"
	"github.com/cockroachdb/cockroach/pkg/spanconfig"
	"github.com/cockroachdb/cockroach/pkg/util/hlc"
	"github.com/cockroachdb/cockroach/pkg/util/log"
	"github.com/cockroachdb/cockroach/pkg/util/log/logcrash"
	"github.com/cockroachdb/cockroach/pkg/util/metric"
	"github.com/cockroachdb/errors"
	"go.etcd.io/raft/v3"
)

const (
	// replicaGCQueueTimerDuration is the duration between GCs of queued replicas.
	replicaGCQueueTimerDuration = 100 * time.Millisecond

	// ReplicaGCQueueCheckInterval is the inactivity duration after which
	// a range will be considered for garbage collection. Exported for testing.
	ReplicaGCQueueCheckInterval = 12 * time.Hour
	// ReplicaGCQueueSuspectCheckInterval is the duration after which a Replica
	// which is suspected to be removed should be considered for garbage
	// collection. See replicaIsSuspect() for details on what makes a replica
	// suspect.
	ReplicaGCQueueSuspectCheckInterval = 3 * time.Second
)

// Priorities for the replica GC queue.
const (
	replicaGCPriorityDefault = 0.0

	// Replicas that have been removed from the range spend a lot of
	// time in the candidate state, so treat them as higher priority.
	// Learner replicas which have been removed never enter the candidate state
	// but in the common case a replica should not be a learner for long so
	// treat it the same as a candidate.
	replicaGCPrioritySuspect = 1.0

	// The highest priority is used when we have definite evidence
	// (external to replicaGCQueue) that the replica has been removed.
	replicaGCPriorityRemoved = 2.0
)

var (
	metaReplic
    
func replicaIsSuspect(repl *Replica) bool {
	// It is critical to think of the replica as suspect if it is a learner as
	// it both shouldn't be a learner for long but will never become a candidate.
	// It is less critical to consider joint configuration members as suspect
	// but in cases where a replica is removed but only ever hears about the
	// command which sets it to VOTER_OUTGOING we would conservatively wait
	// 12 hours before removing the node. Finally we consider replicas which are
	// VOTER_INCOMING as suspect because no replica should stay in that state for
	// too long and being conservative here doesn't seem worthwhile.
	replDesc, ok := repl.Desc().GetReplicaDescriptor(repl.store.StoreID())
	if !ok {
		return true
	}
	if t := replDesc.Type; t != roachpb.VOTER_FULL && t != roachpb.NON_VOTER {
		return true
	}

	// NodeLiveness can be nil in tests/benchmarks.
	if repl.store.cfg.NodeLiveness == nil {
		return false
	}

	// If a replica doesn't have an active raft group, we should check whether
	// or not the node is active. If not, we should consider the replica suspect
	// because it has probably already been removed from its raft group but
	// doesn't know it. Without this, node decommissioning can stall on such
	// dormant ranges.
	raftStatus := repl.RaftStatus()
	if raftStatus == nil {
		liveness, ok := repl.store.cfg.NodeLiveness.Self()
		return ok && !liveness.Membership.Active()
	}

	livenessMap := repl.store.cfg.NodeLiveness.GetIsLiveMap()
	switch raftStatus.SoftState.RaftState {
	// If a replica is a candidate, then by definition it has lost contact with
	// its leader and possibly the rest of the Raft group, so consider it suspect.
	case raft.StateCandidate, raft.StatePreCandidate:
		return true

	// If the replica is a follower, check that the leader is in our range
	// descriptor and that we're still in touch with it. This handles e.g. a
	// non-voting replica which has lost its leader. It also attempts to handle
	// a quiesced follower which was partitioned away from the Raft group during
	// its own removal from the range -- this case is vulnerable to race
	// conditions, but if it fails it will be GCed within 12 hours anyway.
	case raft.StateFollower:
		leadDesc, ok := repl.Desc().GetReplicaDescriptorByID(roachpb.ReplicaID(raftStatus.Lead))
		if !ok || !livenessMap[leadDesc.NodeID].IsLive {
			return true
		}

	// If the replica is a leader, check that it has a quorum. This handles e.g.
	// a stuck leader with a lost quorum being replaced via Node.ResetQuorum,
	// which must cause the stale leader to relinquish its lease and GC itself.
	case raft.StateLeader:
		if !repl.Desc().Replicas().CanMakeProgress(func(d roachpb.ReplicaDescriptor) bool {
			return livenessMap[d.NodeID].IsLive
		}) {
			return true
		}
	}

	return false
}