github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/txn/txnimpl/replaystore.go (about) 1 // Copyright 2021 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 txnimpl 16 17 import ( 18 "bytes" 19 20 "github.com/matrixorigin/matrixone/pkg/common/moerr" 21 "github.com/matrixorigin/matrixone/pkg/logutil" 22 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 23 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/updates" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal" 30 ) 31 32 type replayTxnStore struct { 33 txnbase.NoopTxnStore 34 Cmd *txnbase.TxnCmd 35 Observer wal.ReplayObserver 36 catalog *catalog.Catalog 37 dataFactory *tables.DataFactory 38 wal wal.Driver 39 } 40 41 func MakeReplayTxn( 42 mgr *txnbase.TxnManager, 43 ctx *txnbase.TxnCtx, 44 lsn uint64, 45 cmd *txnbase.TxnCmd, 46 observer wal.ReplayObserver, 47 catalog *catalog.Catalog, 48 dataFactory *tables.DataFactory, 49 wal wal.Driver) *txnbase.Txn { 50 store := &replayTxnStore{ 51 Cmd: cmd, 52 Observer: observer, 53 catalog: catalog, 54 dataFactory: dataFactory, 55 wal: wal, 56 } 57 txn := txnbase.NewPersistedTxn( 58 mgr, 59 ctx, 60 store, 61 lsn, 62 store.prepareCommit, 63 store.prepareRollback, 64 store.applyCommit, 65 store.applyRollback) 66 return txn 67 } 68 69 func (store *replayTxnStore) IsReadonly() bool { return false } 70 71 func (store *replayTxnStore) prepareCommit(txn txnif.AsyncTxn) (err error) { 72 // PrepareCommit all commands 73 // Check idempotent of each command 74 // Record all idempotent error commands and skip apply|rollback later 75 idxCtx := &wal.Index{LSN: txn.GetLSN()} 76 idxCtx.Size = store.Cmd.CmdSize 77 internalCnt := uint32(0) 78 store.Observer.OnTimeStamp(txn.GetPrepareTS()) 79 for i, command := range store.Cmd.Cmds { 80 command.SetReplayTxn(txn) 81 if command.GetType() == CmdAppend { 82 internalCnt++ 83 store.prepareCmd(command, nil) 84 } else { 85 idx := idxCtx.Clone() 86 idx.CSN = uint32(i) - internalCnt 87 store.prepareCmd(command, idx) 88 } 89 } 90 return 91 } 92 93 func (store *replayTxnStore) applyCommit(txn txnif.AsyncTxn) (err error) { 94 store.Cmd.ApplyCommit() 95 return 96 } 97 98 func (store *replayTxnStore) applyRollback(txn txnif.AsyncTxn) (err error) { 99 store.Cmd.ApplyRollback() 100 return 101 } 102 103 func (store *replayTxnStore) prepareRollback(txn txnif.AsyncTxn) (err error) { 104 panic(moerr.NewInternalErrorNoCtx("cannot prepareRollback rollback replay txn: %s", 105 txn.String())) 106 } 107 108 func (store *replayTxnStore) prepareCmd(txncmd txnif.TxnCmd, idxCtx *wal.Index) { 109 if idxCtx != nil && idxCtx.Size > 0 { 110 logutil.Debug("", common.OperationField("replay-cmd"), 111 common.OperandField(txncmd.Desc()), 112 common.AnyField("index", idxCtx.String())) 113 } 114 var err error 115 switch cmd := txncmd.(type) { 116 case *catalog.EntryCommand: 117 store.catalog.ReplayCmd(txncmd, store.dataFactory, idxCtx, store.Observer) 118 case *AppendCmd: 119 store.replayAppendData(cmd, store.Observer) 120 case *updates.UpdateCmd: 121 store.replayDataCmds(cmd, idxCtx, store.Observer) 122 } 123 if err != nil { 124 panic(err) 125 } 126 } 127 128 func (store *replayTxnStore) replayAppendData(cmd *AppendCmd, observer wal.ReplayObserver) { 129 hasActive := false 130 for _, info := range cmd.Infos { 131 database, err := store.catalog.GetDatabaseByID(info.GetDBID()) 132 if err != nil { 133 panic(err) 134 } 135 id := info.GetDest() 136 blk, err := database.GetBlockEntryByID(id) 137 if err != nil { 138 panic(err) 139 } 140 if !blk.IsActive() { 141 continue 142 } 143 if blk.GetMetaLoc() != "" { 144 continue 145 } 146 hasActive = true 147 } 148 149 if !hasActive { 150 return 151 } 152 153 var data *containers.Batch 154 155 for _, subTxnCmd := range cmd.Cmds { 156 switch subCmd := subTxnCmd.(type) { 157 case *txnbase.BatchCmd: 158 data = subCmd.Bat 159 case *txnbase.PointerCmd: 160 batEntry, err := store.wal.LoadEntry(subCmd.Group, subCmd.Lsn) 161 if err != nil { 162 panic(err) 163 } 164 r := bytes.NewBuffer(batEntry.GetPayload()) 165 txnCmd, _, err := txnbase.BuildCommandFrom(r) 166 if err != nil { 167 panic(err) 168 } 169 data = txnCmd.(*txnbase.BatchCmd).Bat 170 batEntry.Free() 171 } 172 } 173 if data != nil { 174 defer data.Close() 175 } 176 177 for _, info := range cmd.Infos { 178 database, err := store.catalog.GetDatabaseByID(info.GetDBID()) 179 if err != nil { 180 panic(err) 181 } 182 id := info.GetDest() 183 blk, err := database.GetBlockEntryByID(id) 184 if err != nil { 185 panic(err) 186 } 187 if !blk.IsActive() { 188 continue 189 } 190 if blk.GetMetaLoc() != "" { 191 continue 192 } 193 start := info.GetSrcOff() 194 bat := data.CloneWindow(int(start), int(info.GetSrcLen())) 195 bat.Compact() 196 defer bat.Close() 197 if err = blk.GetBlockData().OnReplayAppendPayload(bat); err != nil { 198 panic(err) 199 } 200 } 201 } 202 203 func (store *replayTxnStore) replayDataCmds(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) { 204 switch cmd.GetType() { 205 case txnbase.CmdAppend: 206 store.replayAppend(cmd, idxCtx, observer) 207 case txnbase.CmdDelete: 208 store.replayDelete(cmd, idxCtx, observer) 209 } 210 } 211 212 func (store *replayTxnStore) replayDelete(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) { 213 database, err := store.catalog.GetDatabaseByID(cmd.GetDBID()) 214 if err != nil { 215 panic(err) 216 } 217 deleteNode := cmd.GetDeleteNode() 218 deleteNode.SetLogIndex(idxCtx) 219 if deleteNode.Is1PC() { 220 if _, err := deleteNode.TxnMVCCNode.ApplyCommit(nil); err != nil { 221 panic(err) 222 } 223 } 224 id := deleteNode.GetID() 225 blk, err := database.GetBlockEntryByID(id) 226 if err != nil { 227 panic(err) 228 } 229 if !blk.IsActive() { 230 observer.OnStaleIndex(idxCtx) 231 return 232 } 233 blkData := blk.GetBlockData() 234 err = blkData.OnReplayDelete(deleteNode) 235 if err != nil { 236 panic(err) 237 } 238 239 } 240 241 func (store *replayTxnStore) replayAppend(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) { 242 database, err := store.catalog.GetDatabaseByID(cmd.GetDBID()) 243 if err != nil { 244 panic(err) 245 } 246 appendNode := cmd.GetAppendNode() 247 appendNode.SetLogIndex(idxCtx) 248 if appendNode.Is1PC() { 249 if _, err := appendNode.TxnMVCCNode.ApplyCommit(nil); err != nil { 250 panic(err) 251 } 252 } 253 id := appendNode.GetID() 254 blk, err := database.GetBlockEntryByID(id) 255 if err != nil { 256 panic(err) 257 } 258 if !blk.IsActive() { 259 observer.OnStaleIndex(idxCtx) 260 return 261 } 262 if blk.GetMetaLoc() != "" { 263 observer.OnStaleIndex(idxCtx) 264 return 265 } 266 if err = blk.GetBlockData().OnReplayAppend(appendNode); err != nil { 267 panic(err) 268 } 269 }