github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/kv/matcher.go (about) 1 // Copyright 2020 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 kv 15 16 import ( 17 "github.com/pingcap/kvproto/pkg/cdcpb" 18 "github.com/pingcap/log" 19 "go.uber.org/zap" 20 ) 21 22 type matcher struct { 23 // TODO : clear the single prewrite 24 unmatchedValue map[matchKey]*cdcpb.Event_Row 25 cachedCommit []*cdcpb.Event_Row 26 cachedRollback []*cdcpb.Event_Row 27 } 28 29 type matchKey struct { 30 startTs uint64 31 key string 32 } 33 34 func newMatchKey(row *cdcpb.Event_Row) matchKey { 35 return matchKey{startTs: row.GetStartTs(), key: string(row.GetKey())} 36 } 37 38 func newMatcher() *matcher { 39 return &matcher{ 40 unmatchedValue: make(map[matchKey]*cdcpb.Event_Row), 41 } 42 } 43 44 func (m *matcher) putPrewriteRow(row *cdcpb.Event_Row) { 45 key := newMatchKey(row) 46 // tikv may send a fake prewrite event with empty value caused by txn heartbeat. 47 // here we need to avoid the fake prewrite event overwrite the prewrite value. 48 49 // when the old-value is disabled, the value of the fake prewrite event is empty. 50 // when the old-value is enabled, the value of the fake prewrite event is also empty, 51 // but the old value of the fake prewrite event is not empty. 52 // We can distinguish fake prewrite events by whether the value is empty, 53 // no matter the old-value is enable or disabled 54 if _, exist := m.unmatchedValue[key]; exist && len(row.GetValue()) == 0 { 55 return 56 } 57 m.unmatchedValue[key] = row 58 } 59 60 // matchRow matches the commit event with the cached prewrite event 61 // the Value and OldValue will be assigned if a matched prewrite event exists. 62 func (m *matcher) matchRow(row *cdcpb.Event_Row, initialized bool) bool { 63 if value, exist := m.unmatchedValue[newMatchKey(row)]; exist { 64 // TiKV may send a fake prewrite event with empty value caused by txn heartbeat. 65 // 66 // We need to skip match if the region is not initialized, 67 // as prewrite events may be sent out of order. 68 if !initialized && len(value.GetValue()) == 0 { 69 return false 70 } 71 row.Value = value.GetValue() 72 row.OldValue = value.GetOldValue() 73 delete(m.unmatchedValue, newMatchKey(row)) 74 return true 75 } 76 return false 77 } 78 79 func (m *matcher) cacheCommitRow(row *cdcpb.Event_Row) { 80 m.cachedCommit = append(m.cachedCommit, row) 81 } 82 83 func (m *matcher) matchCachedRow(initialized bool) []*cdcpb.Event_Row { 84 if !initialized { 85 log.Panic("must be initialized before match cahced rows") 86 } 87 cachedCommit := m.cachedCommit 88 m.cachedCommit = nil 89 top := 0 90 for i := 0; i < len(cachedCommit); i++ { 91 cacheEntry := cachedCommit[i] 92 ok := m.matchRow(cacheEntry, true) 93 if !ok { 94 // when cdc receives a commit log without a corresponding 95 // prewrite log before initialized, a committed log with 96 // the same key and start-ts must have been received. 97 log.Info("ignore commit event without prewrite", 98 zap.Binary("key", cacheEntry.GetKey()), 99 zap.Uint64("ts", cacheEntry.GetStartTs())) 100 continue 101 } 102 cachedCommit[top] = cacheEntry 103 top++ 104 } 105 return cachedCommit[:top] 106 } 107 108 func (m *matcher) rollbackRow(row *cdcpb.Event_Row) { 109 delete(m.unmatchedValue, newMatchKey(row)) 110 } 111 112 func (m *matcher) cacheRollbackRow(row *cdcpb.Event_Row) { 113 m.cachedRollback = append(m.cachedRollback, row) 114 } 115 116 func (m *matcher) matchCachedRollbackRow(initialized bool) { 117 if !initialized { 118 log.Panic("must be initialized before match cahced rollback rows") 119 } 120 rollback := m.cachedRollback 121 m.cachedRollback = nil 122 for i := 0; i < len(rollback); i++ { 123 cacheEntry := rollback[i] 124 m.rollbackRow(cacheEntry) 125 } 126 }