github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/txn/txnbase/txnctx.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 txnbase 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 "sync" 21 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/container/types" 24 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 26 ) 27 28 func IDToIDCtx(id uint64) []byte { 29 ctx := make([]byte, 8) 30 binary.BigEndian.PutUint64(ctx, id) 31 return ctx 32 } 33 34 func IDCtxToID(buf []byte) string { 35 return string(buf) 36 } 37 38 type TxnCtx struct { 39 sync.RWMutex 40 sync.WaitGroup 41 DoneCond sync.Cond 42 ID string 43 IDCtx []byte 44 StartTS, CommitTS, PrepareTS types.TS 45 Info []byte 46 State txnif.TxnState 47 Participants []uint64 48 49 // Memo is not thread-safe 50 // It will be readonly when txn state is not txnif.TxnStateActive 51 Memo *txnif.TxnMemo 52 } 53 54 func NewTxnCtx(id []byte, start types.TS, info []byte) *TxnCtx { 55 ctx := &TxnCtx{ 56 ID: string(id), 57 IDCtx: id, 58 StartTS: start, 59 PrepareTS: txnif.UncommitTS, 60 CommitTS: txnif.UncommitTS, 61 Info: info, 62 Memo: txnif.NewTxnMemo(), 63 } 64 ctx.DoneCond = *sync.NewCond(ctx) 65 return ctx 66 } 67 68 func NewEmptyTxnCtx() *TxnCtx { 69 ctx := &TxnCtx{ 70 Memo: txnif.NewTxnMemo(), 71 } 72 ctx.DoneCond = *sync.NewCond(ctx) 73 return ctx 74 } 75 76 func (ctx *TxnCtx) IsReplay() bool { return false } 77 func (ctx *TxnCtx) GetMemo() *txnif.TxnMemo { 78 return ctx.Memo 79 } 80 81 func (ctx *TxnCtx) Is2PC() bool { return len(ctx.Participants) > 1 } 82 83 func (ctx *TxnCtx) GetCtx() []byte { 84 return ctx.IDCtx 85 } 86 87 func (ctx *TxnCtx) Repr() string { 88 ctx.RLock() 89 defer ctx.RUnlock() 90 repr := fmt.Sprintf( 91 "ctx[%X][%s->%s->%s][%s]", 92 ctx.ID, 93 ctx.StartTS.ToString(), 94 ctx.PrepareTS.ToString(), 95 ctx.CommitTS.ToString(), 96 txnif.TxnStrState(ctx.State), 97 ) 98 return repr 99 } 100 101 func (ctx *TxnCtx) SameTxn(startTs types.TS) bool { return ctx.StartTS.Equal(startTs) } 102 func (ctx *TxnCtx) CommitBefore(startTs types.TS) bool { 103 return ctx.GetCommitTS().Less(startTs) 104 } 105 func (ctx *TxnCtx) CommitAfter(startTs types.TS) bool { 106 return ctx.GetCommitTS().Greater(startTs) 107 } 108 109 func (ctx *TxnCtx) String() string { return ctx.Repr() } 110 func (ctx *TxnCtx) GetID() string { return ctx.ID } 111 func (ctx *TxnCtx) GetInfo() []byte { return ctx.Info } 112 func (ctx *TxnCtx) GetStartTS() types.TS { return ctx.StartTS } 113 func (ctx *TxnCtx) GetCommitTS() types.TS { 114 ctx.RLock() 115 defer ctx.RUnlock() 116 return ctx.CommitTS 117 } 118 119 func (ctx *TxnCtx) SetCommitTS(cts types.TS) (err error) { 120 ctx.RLock() 121 defer ctx.RUnlock() 122 ctx.CommitTS = cts 123 return 124 } 125 126 func (ctx *TxnCtx) GetParticipants() []uint64 { 127 ctx.RLock() 128 defer ctx.RUnlock() 129 return ctx.Participants 130 } 131 132 func (ctx *TxnCtx) SetParticipants(ids []uint64) (err error) { 133 ctx.RLock() 134 defer ctx.RUnlock() 135 ctx.Participants = ids 136 return 137 } 138 139 func (ctx *TxnCtx) GetPrepareTS() types.TS { 140 ctx.RLock() 141 defer ctx.RUnlock() 142 return ctx.PrepareTS 143 } 144 145 // Atomically returns the current txn state 146 func (ctx *TxnCtx) getTxnState() txnif.TxnState { 147 ctx.RLock() 148 defer ctx.RUnlock() 149 return ctx.State 150 } 151 152 // Wait txn state to be rollbacked or committed 153 func (ctx *TxnCtx) resolveTxnState() txnif.TxnState { 154 ctx.DoneCond.L.Lock() 155 defer ctx.DoneCond.L.Unlock() 156 state := ctx.State 157 //if state != txnif.TxnStatePreparing { 158 if state == txnif.TxnStateActive || 159 state == txnif.TxnStateRollbacked || 160 state == txnif.TxnStateCommitted { 161 return state 162 } 163 ctx.DoneCond.Wait() 164 return ctx.State 165 } 166 167 // False when atomically get the current txn state 168 // 169 // True when the txn state is committing, wait it to be committed or rollbacked. It 170 // is used during snapshot reads. If TxnStateActive is currently returned, this value will 171 // definitely not be used, because even if it becomes TxnStatePreparing later, the timestamp 172 // would be larger than the current read timestamp. 173 func (ctx *TxnCtx) GetTxnState(waitIfCommitting bool) (state txnif.TxnState) { 174 // Quick get the current txn state 175 // If waitIfCommitting is false, return the state 176 // If state is not txnif.TxnStatePreparing, return the state 177 178 //if state = ctx.getTxnState(); !waitIfCommitting || state != txnif.TxnStatePreparing { 179 if state = ctx.getTxnState(); !waitIfCommitting || 180 state == txnif.TxnStateActive || 181 state == txnif.TxnStateCommitted || 182 state == txnif.TxnStateRollbacked { 183 return state 184 } 185 186 // Wait the committing txn to be committed or rollbacked 187 state = ctx.resolveTxnState() 188 return 189 } 190 191 func (ctx *TxnCtx) IsVisible(o txnif.TxnReader) bool { 192 ostart := o.GetStartTS() 193 ctx.RLock() 194 defer ctx.RUnlock() 195 return ostart.LessEq(ctx.StartTS) 196 } 197 198 func (ctx *TxnCtx) IsActiveLocked() bool { 199 return ctx.CommitTS == txnif.UncommitTS 200 } 201 202 func (ctx *TxnCtx) ToPreparingLocked(ts types.TS) error { 203 if ts.LessEq(ctx.StartTS) { 204 panic(fmt.Sprintf("start ts %d should be less than commit ts %d", ctx.StartTS, ts)) 205 } 206 // if !ctx.CommitTS.Equal(txnif.UncommitTS) { 207 // return moerr.NewTxnNotActive("") 208 // } 209 ctx.PrepareTS = ts 210 ctx.CommitTS = ts 211 ctx.State = txnif.TxnStatePreparing 212 return nil 213 } 214 215 func (ctx *TxnCtx) ToPrepared() (err error) { 216 ctx.Lock() 217 defer ctx.Unlock() 218 return ctx.ToPreparedLocked() 219 } 220 221 func (ctx *TxnCtx) ToPreparedLocked() (err error) { 222 if ctx.State != txnif.TxnStatePreparing { 223 err = moerr.NewTAEPrepareNoCtx("ToPreparedLocked: state is not preparing") 224 return 225 } 226 ctx.State = txnif.TxnStatePrepared 227 return 228 } 229 230 func (ctx *TxnCtx) ToCommittingFinished() (err error) { 231 ctx.Lock() 232 defer ctx.Unlock() 233 return ctx.ToCommittingFinishedLocked() 234 } 235 236 func (ctx *TxnCtx) ToCommittingFinishedLocked() (err error) { 237 if ctx.State != txnif.TxnStatePrepared { 238 err = moerr.NewTAECommitNoCtx("ToCommittingFinishedLocked: state is not prepared") 239 return 240 } 241 ctx.State = txnif.TxnStateCommittingFinished 242 return 243 } 244 245 func (ctx *TxnCtx) ToCommittedLocked() error { 246 if ctx.Is2PC() { 247 if ctx.State != txnif.TxnStateCommittingFinished && 248 ctx.State != txnif.TxnStatePrepared { 249 return moerr.NewTAECommitNoCtx("ToCommittedLocked: 2PC txn's state " + 250 "is not Prepared or CommittingFinished") 251 } 252 ctx.State = txnif.TxnStateCommitted 253 return nil 254 } 255 if ctx.State != txnif.TxnStatePreparing { 256 return moerr.NewTAECommitNoCtx("ToCommittedLocked: 1PC txn's state is not preparing") 257 } 258 ctx.State = txnif.TxnStateCommitted 259 return nil 260 } 261 262 func (ctx *TxnCtx) ToRollbacking(ts types.TS) error { 263 ctx.Lock() 264 defer ctx.Unlock() 265 return ctx.ToRollbackingLocked(ts) 266 } 267 268 func (ctx *TxnCtx) ToRollbackingLocked(ts types.TS) error { 269 if ts.Less(ctx.StartTS) { 270 panic(fmt.Sprintf("commit ts %d should not be less than start ts %d", ts, ctx.StartTS)) 271 } 272 if (ctx.State != txnif.TxnStateActive) && (ctx.State != txnif.TxnStatePreparing) { 273 return moerr.NewTAERollbackNoCtx("ToRollbackingLocked: state is not active or preparing") 274 } 275 ctx.CommitTS = ts 276 ctx.PrepareTS = ts 277 ctx.State = txnif.TxnStateRollbacking 278 return nil 279 } 280 281 func (ctx *TxnCtx) ToRollbackedLocked() error { 282 if ctx.Is2PC() { 283 if ctx.State != txnif.TxnStatePrepared && 284 ctx.State != txnif.TxnStateRollbacking { 285 return moerr.NewTAERollbackNoCtx("state %s", txnif.TxnStrState(ctx.State)) 286 } 287 ctx.State = txnif.TxnStateRollbacked 288 return nil 289 } 290 if ctx.State != txnif.TxnStateRollbacking { 291 return moerr.NewTAERollbackNoCtx("state %s", txnif.TxnStrState(ctx.State)) 292 } 293 ctx.State = txnif.TxnStateRollbacked 294 return nil 295 } 296 297 func (ctx *TxnCtx) ToUnknownLocked() { 298 ctx.State = txnif.TxnStateUnknown 299 }