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