github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/sink/dmlsink/mq/dispatcher/partition/index_value.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package partition 15 16 import ( 17 "strconv" 18 "sync" 19 20 "github.com/pingcap/log" 21 "github.com/pingcap/tiflow/cdc/model" 22 "github.com/pingcap/tiflow/pkg/errors" 23 "github.com/pingcap/tiflow/pkg/hash" 24 "go.uber.org/zap" 25 ) 26 27 // IndexValueDispatcher is a partition dispatcher which dispatches events based on the index value. 28 type IndexValueDispatcher struct { 29 hasher *hash.PositionInertia 30 lock sync.Mutex 31 32 IndexName string 33 } 34 35 // NewIndexValueDispatcher creates a IndexValueDispatcher. 36 func NewIndexValueDispatcher(indexName string) *IndexValueDispatcher { 37 return &IndexValueDispatcher{ 38 hasher: hash.NewPositionInertia(), 39 IndexName: indexName, 40 } 41 } 42 43 // DispatchRowChangedEvent returns the target partition to which 44 // a row changed event should be dispatched. 45 func (r *IndexValueDispatcher) DispatchRowChangedEvent(row *model.RowChangedEvent, partitionNum int32) (int32, string, error) { 46 r.lock.Lock() 47 defer r.lock.Unlock() 48 r.hasher.Reset() 49 r.hasher.Write([]byte(row.TableInfo.GetSchemaName()), []byte(row.TableInfo.GetTableName())) 50 51 dispatchCols := row.Columns 52 if len(row.Columns) == 0 { 53 dispatchCols = row.PreColumns 54 } 55 56 // the most normal case, index-name is not set, use the handle key columns. 57 if r.IndexName == "" { 58 tableInfo := row.TableInfo 59 for _, col := range dispatchCols { 60 if col == nil { 61 continue 62 } 63 if tableInfo.ForceGetColumnFlagType(col.ColumnID).IsHandleKey() { 64 r.hasher.Write([]byte(tableInfo.ForceGetColumnName(col.ColumnID)), []byte(model.ColumnValueString(col.Value))) 65 } 66 } 67 } else { 68 names, offsets, ok := row.TableInfo.IndexByName(r.IndexName) 69 if !ok { 70 log.Error("index not found when dispatch event", 71 zap.Any("tableName", row.TableInfo.GetTableName()), 72 zap.String("indexName", r.IndexName)) 73 return 0, "", errors.ErrDispatcherFailed.GenWithStack( 74 "index not found when dispatch event, table: %v, index: %s", row.TableInfo.GetTableName(), r.IndexName) 75 } 76 for idx := 0; idx < len(names); idx++ { 77 col := dispatchCols[offsets[idx]] 78 if col == nil { 79 continue 80 } 81 r.hasher.Write([]byte(names[idx]), []byte(model.ColumnValueString(col.Value))) 82 } 83 } 84 85 sum32 := r.hasher.Sum32() 86 return int32(sum32 % uint32(partitionNum)), strconv.FormatInt(int64(sum32), 10), nil 87 }