@@ -36,6 +36,7 @@ import (
3636 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/logstore"
3737 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/rafttrace"
3838 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/rangefeed"
39+ "github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset"
3940 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/split"
4041 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/tenantrate"
4142 "github.com/cockroachdb/cockroach/pkg/raft"
@@ -2984,3 +2985,66 @@ func (r *Replica) SendStreamStats(stats *rac2.RangeSendStreamStats) {
29842985 r .flowControlV2 .SendStreamStats (stats )
29852986 }
29862987}
2988+
2989+ // overlapsUnreplicatedRangeIDLocalKeys checks if the provided span overlaps
2990+ // with any unreplicated rangeID local keys.
2991+ // Note that we could receive the span with a nil startKey, which has a special
2992+ // meaning that the span represents: [endKey.Prev(), endKey).
2993+ func overlapsUnreplicatedRangeIDLocalKeys (span spanset.TrickySpan ) error {
2994+ fullRangeIDLocalSpans := roachpb.Span {
2995+ Key : keys .LocalRangeIDPrefix .AsRawKey (),
2996+ EndKey : keys .LocalRangeIDPrefix .AsRawKey ().PrefixEnd (),
2997+ }
2998+
2999+ // If the provided span is completely outside the rangeID local spans for any
3000+ // rangeID, then there is no overlap with any rangeID local keys.
3001+ if ! spanset .Overlaps (fullRangeIDLocalSpans , span ) {
3002+ return nil
3003+ }
3004+
3005+ // At this point, we know that we overlap with fullRangeIDLocalSpans. If we
3006+ // are not completely within fullRangeIDLocalSpans, return an error as we
3007+ // make an assumption that spans should respect the local RangeID tree
3008+ // structure, and that spans that partially overlaps with
3009+ // fullRangeIDLocalSpans don't make logical sense.
3010+ if ! spanset .Contains (fullRangeIDLocalSpans , span ) {
3011+ return errors .Errorf ("overlapping an unreplicated rangeID key" )
3012+ }
3013+
3014+ // If the span in inside fullRangeIDLocalSpans, we expect that both start and
3015+ // end keys should be in the same rangeID.
3016+ rangeIDKey := span .Key
3017+ if rangeIDKey == nil {
3018+ rangeIDKey = span .EndKey
3019+ }
3020+ rangeID , err := keys .DecodeRangeIDPrefix (rangeIDKey )
3021+ if err != nil {
3022+ return errors .NewAssertionErrorWithWrappedErrf (err ,
3023+ "could not decode range ID for span: %s" , span )
3024+ }
3025+ if spanset .Overlaps (roachpb.Span {
3026+ Key : keys .MakeRangeIDUnreplicatedPrefix (rangeID ),
3027+ EndKey : keys .MakeRangeIDUnreplicatedPrefix (rangeID ).PrefixEnd (),
3028+ }, span ) {
3029+ return errors .Errorf ("overlapping an unreplicated rangeID span" )
3030+ }
3031+
3032+ return nil
3033+ }
3034+
3035+ // overlapsStoreLocalKeys returns an error if the provided span overlaps
3036+ // with any store local keys.
3037+ // Note that we could receive the span with a nil startKey, which has a special
3038+ // meaning that the span represents: [endKey.Prev(), endKey).
3039+ func overlapsStoreLocalKeys (span spanset.TrickySpan ) error {
3040+ localStoreSpan := roachpb.Span {
3041+ Key : keys .LocalStorePrefix ,
3042+ EndKey : keys .LocalStoreMax ,
3043+ }
3044+
3045+ if spanset .Overlaps (localStoreSpan , span ) {
3046+ return errors .Errorf ("overlaps with store local keys" )
3047+ }
3048+
3049+ return nil
3050+ }
0 commit comments