github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/db/replay.go (about) 1 // Copyright 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package db 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/matrixorigin/matrixone/pkg/common/moerr" 22 "github.com/matrixorigin/matrixone/pkg/container/types" 23 "github.com/matrixorigin/matrixone/pkg/logutil" 24 "github.com/matrixorigin/matrixone/pkg/objectio" 25 26 "sync" 27 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnimpl" 34 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal" 35 ) 36 37 type Replayer struct { 38 DataFactory *tables.DataFactory 39 db *DB 40 maxTs types.TS 41 once sync.Once 42 ckpedTS types.TS 43 wg sync.WaitGroup 44 applyDuration time.Duration 45 txnCmdChan chan *txnbase.TxnCmd 46 readCount int 47 applyCount int 48 49 lsn uint64 50 enableLSNCheck bool 51 } 52 53 func newReplayer(dataFactory *tables.DataFactory, db *DB, ckpedTS types.TS, lsn uint64, enableLSNCheck bool) *Replayer { 54 return &Replayer{ 55 DataFactory: dataFactory, 56 db: db, 57 ckpedTS: ckpedTS, 58 lsn: lsn, 59 // for ckp version less than 7, lsn is always 0 and lsnCheck is disable 60 enableLSNCheck: enableLSNCheck, 61 wg: sync.WaitGroup{}, 62 txnCmdChan: make(chan *txnbase.TxnCmd, 100), 63 } 64 } 65 66 func (replayer *Replayer) PreReplayWal() { 67 processor := new(catalog.LoopProcessor) 68 processor.ObjectFn = func(entry *catalog.ObjectEntry) (err error) { 69 if entry.GetTable().IsVirtual() { 70 return moerr.GetOkStopCurrRecur() 71 } 72 dropCommit := entry.TreeMaxDropCommitEntry() 73 if dropCommit != nil && dropCommit.DeleteBeforeLocked(replayer.ckpedTS) { 74 return moerr.GetOkStopCurrRecur() 75 } 76 entry.InitData(replayer.DataFactory) 77 return 78 } 79 if err := replayer.db.Catalog.RecurLoop(processor); err != nil { 80 if !moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 81 panic(err) 82 } 83 } 84 } 85 86 func (replayer *Replayer) postReplayWal() { 87 processor := new(catalog.LoopProcessor) 88 processor.ObjectFn = func(entry *catalog.ObjectEntry) (err error) { 89 if entry.InMemoryDeletesExisted() { 90 entry.GetTable().DeletedDirties = append(entry.GetTable().DeletedDirties, entry) 91 } 92 return 93 } 94 if err := replayer.db.Catalog.RecurLoop(processor); err != nil { 95 panic(err) 96 } 97 } 98 func (replayer *Replayer) Replay() { 99 replayer.wg.Add(1) 100 go replayer.applyTxnCmds() 101 if err := replayer.db.Wal.Replay(replayer.OnReplayEntry); err != nil { 102 panic(err) 103 } 104 replayer.txnCmdChan <- txnbase.NewLastTxnCmd() 105 close(replayer.txnCmdChan) 106 replayer.wg.Wait() 107 replayer.postReplayWal() 108 logutil.Info("open-tae", common.OperationField("replay"), 109 common.OperandField("wal"), 110 common.AnyField("apply logentries cost", replayer.applyDuration), 111 common.AnyField("read count", replayer.readCount), 112 common.AnyField("apply count", replayer.applyCount)) 113 } 114 115 func (replayer *Replayer) OnReplayEntry(group uint32, lsn uint64, payload []byte, typ uint16, info any) { 116 replayer.once.Do(replayer.PreReplayWal) 117 if group != wal.GroupPrepare && group != wal.GroupC { 118 return 119 } 120 if !replayer.checkLSN(lsn) { 121 return 122 } 123 head := objectio.DecodeIOEntryHeader(payload) 124 codec := objectio.GetIOEntryCodec(*head) 125 entry, err := codec.Decode(payload[4:]) 126 txnCmd := entry.(*txnbase.TxnCmd) 127 txnCmd.Lsn = lsn 128 if err != nil { 129 panic(err) 130 } 131 replayer.txnCmdChan <- txnCmd 132 } 133 func (replayer *Replayer) applyTxnCmds() { 134 defer replayer.wg.Done() 135 for { 136 txnCmd := <-replayer.txnCmdChan 137 if txnCmd.IsLastCmd() { 138 break 139 } 140 t0 := time.Now() 141 replayer.OnReplayTxn(txnCmd, txnCmd.Lsn) 142 txnCmd.Close() 143 replayer.applyDuration += time.Since(t0) 144 145 } 146 } 147 func (replayer *Replayer) GetMaxTS() types.TS { 148 return replayer.maxTs 149 } 150 151 func (replayer *Replayer) OnTimeStamp(ts types.TS) { 152 if ts.Greater(&replayer.maxTs) { 153 replayer.maxTs = ts 154 } 155 } 156 func (replayer *Replayer) checkLSN(lsn uint64) (needReplay bool) { 157 if !replayer.enableLSNCheck { 158 return true 159 } 160 if lsn <= replayer.lsn { 161 return false 162 } 163 if lsn == replayer.lsn+1 { 164 replayer.lsn++ 165 return true 166 } 167 panic(fmt.Sprintf("invalid lsn %d, current lsn %d", lsn, replayer.lsn)) 168 } 169 func (replayer *Replayer) OnReplayTxn(cmd txnif.TxnCmd, lsn uint64) { 170 var err error 171 replayer.readCount++ 172 txnCmd := cmd.(*txnbase.TxnCmd) 173 // If WAL entry splits, they share same prepareTS 174 if txnCmd.PrepareTS.Less(&replayer.maxTs) { 175 return 176 } 177 replayer.applyCount++ 178 txn := txnimpl.MakeReplayTxn(replayer.db.Runtime.Options.Ctx, replayer.db.TxnMgr, txnCmd.TxnCtx, lsn, 179 txnCmd, replayer, replayer.db.Catalog, replayer.DataFactory, replayer.db.Wal) 180 if err = replayer.db.TxnMgr.OnReplayTxn(txn); err != nil { 181 panic(err) 182 } 183 if txn.Is2PC() { 184 if _, err = txn.Prepare(replayer.db.Opts.Ctx); err != nil { 185 panic(err) 186 } 187 } else { 188 if err = txn.Commit(replayer.db.Opts.Ctx); err != nil { 189 panic(err) 190 } 191 } 192 }