@@ -19,18 +19,24 @@ import (
1919 "encoding/json"
2020 "fmt"
2121 "slices"
22+ "strconv"
23+ "strings"
2224
25+ "github.com/pingcap/tidb/pkg/config/kerneltype"
2326 "github.com/pingcap/tidb/pkg/parser/ast"
2427 "github.com/pingcap/tidb/pkg/tablecodec"
2528 "github.com/pingcap/tidb/pkg/util/codec"
29+ "github.com/tikv/client-go/v2/tikv"
2630 pd "github.com/tikv/pd/client/http"
2731 "gopkg.in/yaml.v2"
2832)
2933
3034const (
3135 // IDPrefix is the prefix for label rule ID.
3236 IDPrefix = "schema"
33- ruleType = "key-range"
37+ // KeyspacePrefix is the prefix for keyspace in label rule ID.
38+ KeyspacePrefix = "keyspace"
39+ ruleType = "key-range"
3440)
3541
3642const (
@@ -94,20 +100,55 @@ func (r *Rule) Clone() *Rule {
94100 return newRule
95101}
96102
97- // Reset will reset the label rule for a table/partition with a given ID and names.
98- func (r * Rule ) Reset (dbName , tableName , partName string , ids ... int64 ) * Rule {
103+ // UseKeyspaceAwareRules returns true when table attribute label rules should be
104+ // scoped by keyspace in NextGen deployments.
105+ func UseKeyspaceAwareRules (tikvCodec tikv.Codec ) bool {
106+ return kerneltype .IsNextGen () && tikvCodec != nil && tikvCodec .GetKeyspaceMeta () != nil
107+ }
108+
109+ // NewRuleID generates a new rule ID for a table or partition.
110+ func NewRuleID (tikvCodec tikv.Codec , dbName , tableName , partName string ) string {
111+ var id string
99112 isPartition := partName != ""
100113 if isPartition {
101- r . ID = fmt .Sprintf (PartitionIDFormat , IDPrefix , dbName , tableName , partName )
114+ id = fmt .Sprintf (PartitionIDFormat , IDPrefix , dbName , tableName , partName )
102115 } else {
103- r .ID = fmt .Sprintf (TableIDFormat , IDPrefix , dbName , tableName )
116+ id = fmt .Sprintf (TableIDFormat , IDPrefix , dbName , tableName )
117+ }
118+ if UseKeyspaceAwareRules (tikvCodec ) {
119+ id = fmt .Sprintf ("%s/%d/%s" , KeyspacePrefix , tikvCodec .GetKeyspaceID (), id )
120+ }
121+ return id
122+ }
123+
124+ // RestoreRuleID converts an internal label rule ID to the user-visible form.
125+ func RestoreRuleID (ruleID string ) string {
126+ if ! kerneltype .IsNextGen () {
127+ return ruleID
128+ }
129+ parts := strings .Split (ruleID , "/" )
130+ if len (parts ) >= 3 && parts [0 ] == KeyspacePrefix && parts [2 ] == IDPrefix {
131+ return strings .Join (parts [2 :], "/" )
104132 }
133+ return ruleID
134+ }
135+
136+ // Reset will reset the label rule for a table/partition with a given ID and names.
137+ func (r * Rule ) Reset (tikvCodec tikv.Codec , dbName , tableName , partName string , ids ... int64 ) * Rule {
138+ isPartition := partName != ""
139+ useKeyspace := UseKeyspaceAwareRules (tikvCodec )
140+ r .ID = NewRuleID (tikvCodec , dbName , tableName , partName )
105141 if len (r .Labels ) == 0 {
106142 return r
107143 }
108- var hasDBKey , hasTableKey , hasPartitionKey bool
144+ var hasKeyspaceKey , hasDBKey , hasTableKey , hasPartitionKey bool
109145 for i := range r .Labels {
110146 switch r .Labels [i ].Key {
147+ case keyspaceKey :
148+ if useKeyspace {
149+ r .Labels [i ].Value = strconv .FormatInt (int64 (tikvCodec .GetKeyspaceID ()), 10 )
150+ hasKeyspaceKey = true
151+ }
111152 case dbKey :
112153 r .Labels [i ].Value = dbName
113154 hasDBKey = true
@@ -123,6 +164,10 @@ func (r *Rule) Reset(dbName, tableName, partName string, ids ...int64) *Rule {
123164 }
124165 }
125166
167+ if useKeyspace && ! hasKeyspaceKey {
168+ r .Labels = append (r .Labels , pd.RegionLabel {Key : keyspaceKey , Value : strconv .FormatInt (int64 (tikvCodec .GetKeyspaceID ()), 10 )})
169+ }
170+
126171 if ! hasDBKey {
127172 r .Labels = append (r .Labels , pd.RegionLabel {Key : dbKey , Value : dbName })
128173 }
@@ -138,9 +183,16 @@ func (r *Rule) Reset(dbName, tableName, partName string, ids ...int64) *Rule {
138183 dataSlice := make ([]any , 0 , len (ids ))
139184 slices .Sort (ids )
140185 for i := range ids {
186+ startKey := codec .EncodeBytes (nil , tablecodec .GenTablePrefix (ids [i ]))
187+ endKey := codec .EncodeBytes (nil , tablecodec .GenTablePrefix (ids [i ]+ 1 ))
188+ if useKeyspace {
189+ // Label rules are consumed as region boundary keys, so V2 must encode
190+ // the whole outer key instead of prefixing a mem-encoded table key.
191+ startKey , endKey = tikvCodec .EncodeRegionRange (tablecodec .GenTablePrefix (ids [i ]), tablecodec .GenTablePrefix (ids [i ]+ 1 ))
192+ }
141193 data := map [string ]string {
142- "start_key" : hex .EncodeToString (codec . EncodeBytes ( nil , tablecodec . GenTablePrefix ( ids [ i ])) ),
143- "end_key" : hex .EncodeToString (codec . EncodeBytes ( nil , tablecodec . GenTablePrefix ( ids [ i ] + 1 )) ),
194+ "start_key" : hex .EncodeToString (startKey ),
195+ "end_key" : hex .EncodeToString (endKey ),
144196 }
145197 dataSlice = append (dataSlice , data )
146198 }
0 commit comments