github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/cdclog/buffer.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 cdclog 15 16 import ( 17 "time" 18 19 "github.com/pingcap/errors" 20 "github.com/pingcap/log" 21 "github.com/pingcap/tidb/meta/autoid" 22 "github.com/pingcap/tidb/table" 23 "github.com/pingcap/tidb/types" 24 "go.uber.org/zap" 25 26 "github.com/pingcap/br/pkg/kv" 27 ) 28 29 // TableBuffer represents the kv buffer of this table. 30 // we restore one tableBuffer in one goroutine. 31 // this is the concurrent unit of log restore. 32 type TableBuffer struct { 33 KvPairs []kv.Row 34 count int 35 size int64 36 37 KvEncoder kv.Encoder 38 tableInfo table.Table 39 allocator autoid.Allocators 40 41 flushKVSize int64 42 flushKVPairs int 43 44 colNames []string 45 colPerm []int 46 } 47 48 func newKVEncoder(allocators autoid.Allocators, tbl table.Table) (kv.Encoder, error) { 49 encTable, err := table.TableFromMeta(allocators, tbl.Meta()) 50 if err != nil { 51 return nil, errors.Trace(err) 52 } 53 return kv.NewTableKVEncoder(encTable, &kv.SessionOptions{ 54 Timestamp: time.Now().Unix(), 55 // TODO get the version from TiDB cluster 56 // currently TiDB only support v1 and v2, and since 4.0 57 // the default RowFormatVersion is 2, so I think 58 // we can implement the row version retrieve from cluster in the future 59 // when TiDB decide to support v3 RowFormatVersion. 60 RowFormatVersion: "2", 61 }), nil 62 } 63 64 // NewTableBuffer creates TableBuffer. 65 func NewTableBuffer(tbl table.Table, allocators autoid.Allocators, flushKVPairs int, flushKVSize int64) *TableBuffer { 66 tb := &TableBuffer{ 67 KvPairs: make([]kv.Row, 0, flushKVPairs), 68 flushKVPairs: flushKVPairs, 69 flushKVSize: flushKVSize, 70 } 71 if tbl != nil { 72 tb.ReloadMeta(tbl, allocators) 73 } 74 return tb 75 } 76 77 // ResetTableInfo set tableInfo to nil for next reload. 78 func (t *TableBuffer) ResetTableInfo() { 79 t.tableInfo = nil 80 } 81 82 // TableInfo returns the table info of this buffer. 83 func (t *TableBuffer) TableInfo() table.Table { 84 return t.tableInfo 85 } 86 87 // TableID returns the table id of this buffer. 88 func (t *TableBuffer) TableID() int64 { 89 if t.tableInfo != nil { 90 return t.tableInfo.Meta().ID 91 } 92 return 0 93 } 94 95 // ReloadMeta reload columns after 96 // 1. table buffer created. 97 // 2. every ddl executed. 98 func (t *TableBuffer) ReloadMeta(tbl table.Table, allocator autoid.Allocators) { 99 columns := tbl.Meta().Cols() 100 colNames := make([]string, 0, len(columns)) 101 colPerm := make([]int, 0, len(columns)+1) 102 103 for i, col := range columns { 104 colNames = append(colNames, col.Name.String()) 105 colPerm = append(colPerm, i) 106 } 107 if kv.TableHasAutoRowID(tbl.Meta()) { 108 colPerm = append(colPerm, -1) 109 } 110 if t.allocator == nil { 111 t.allocator = allocator 112 } 113 t.tableInfo = tbl 114 t.colNames = colNames 115 t.colPerm = colPerm 116 // reset kv encoder after meta changed 117 t.KvEncoder = nil 118 } 119 120 func (t *TableBuffer) translateToDatum(row map[string]Column) ([]types.Datum, error) { 121 cols := make([]types.Datum, 0, len(row)) 122 for _, col := range t.colNames { 123 val, err := row[col].ToDatum() 124 if err != nil { 125 return nil, errors.Trace(err) 126 } 127 cols = append(cols, val) 128 } 129 return cols, nil 130 } 131 132 func (t *TableBuffer) appendRow( 133 row map[string]Column, 134 item *SortItem, 135 encodeFn func(row []types.Datum, 136 rowID int64, 137 columnPermutation []int) (kv.Row, int, error), 138 ) error { 139 cols, err := t.translateToDatum(row) 140 if err != nil { 141 return errors.Trace(err) 142 } 143 pair, size, err := encodeFn(cols, item.RowID, t.colPerm) 144 if err != nil { 145 return errors.Trace(err) 146 } 147 t.KvPairs = append(t.KvPairs, pair) 148 t.size += int64(size) 149 t.count++ 150 return nil 151 } 152 153 // Append appends the item to this buffer. 154 func (t *TableBuffer) Append(item *SortItem) error { 155 var err error 156 log.Debug("Append item to buffer", 157 zap.Stringer("table", t.tableInfo.Meta().Name), 158 zap.Any("item", item), 159 ) 160 row := item.Data.(*MessageRow) 161 162 if t.KvEncoder == nil { 163 // lazy create kv encoder 164 log.Debug("create kv encoder lazily", 165 zap.Any("alloc", t.allocator), zap.Any("tbl", t.tableInfo)) 166 t.KvEncoder, err = newKVEncoder(t.allocator, t.tableInfo) 167 if err != nil { 168 return errors.Trace(err) 169 } 170 } 171 172 if row.PreColumns != nil { 173 // remove old keys 174 log.Debug("process update event", zap.Any("row", row)) 175 err := t.appendRow(row.PreColumns, item, t.KvEncoder.RemoveRecord) 176 if err != nil { 177 return errors.Trace(err) 178 } 179 } 180 if row.Update != nil { 181 // Add new columns 182 if row.PreColumns == nil { 183 log.Debug("process insert event", zap.Any("row", row)) 184 } 185 err := t.appendRow(row.Update, item, t.KvEncoder.AddRecord) 186 if err != nil { 187 return errors.Trace(err) 188 } 189 } 190 if row.Delete != nil { 191 // Remove current columns 192 log.Debug("process delete event", zap.Any("row", row)) 193 err := t.appendRow(row.Delete, item, t.KvEncoder.RemoveRecord) 194 if err != nil { 195 return errors.Trace(err) 196 } 197 } 198 return nil 199 } 200 201 // ShouldApply tells whether we should flush memory kv buffer to storage. 202 func (t *TableBuffer) ShouldApply() bool { 203 // flush when reached flush kv len or flush size 204 return t.size >= t.flushKVSize || t.count >= t.flushKVPairs 205 } 206 207 // IsEmpty tells buffer is empty. 208 func (t *TableBuffer) IsEmpty() bool { 209 return t.size == 0 210 } 211 212 // Clear reset the buffer. 213 func (t *TableBuffer) Clear() { 214 t.KvPairs = t.KvPairs[:0] 215 t.count = 0 216 t.size = 0 217 }