github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/txn/txnbase/mvccnode.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 "io" 20 21 "github.com/matrixorigin/matrixone/pkg/common/moerr" 22 "github.com/matrixorigin/matrixone/pkg/container/types" 23 "github.com/matrixorigin/matrixone/pkg/container/vector" 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 26 ) 27 28 type TxnMVCCNode struct { 29 Start, Prepare, End types.TS 30 Txn txnif.TxnReader 31 Aborted bool 32 is1PC bool // for subTxn 33 } 34 35 var ( 36 SnapshotAttr_StartTS = "start_ts" 37 SnapshotAttr_PrepareTS = "prepare_ts" 38 SnapshotAttr_CommitTS = "commit_ts" 39 SnapshotAttr_LogIndex_LSN = "log_index_lsn" 40 SnapshotAttr_LogIndex_CSN = "log_index_csn" 41 SnapshotAttr_LogIndex_Size = "log_index_size" 42 ) 43 44 func NewTxnMVCCNodeWithTxn(txn txnif.TxnReader) *TxnMVCCNode { 45 var ts types.TS 46 if txn != nil { 47 ts = txn.GetStartTS() 48 } 49 return &TxnMVCCNode{ 50 Start: ts, 51 Prepare: txnif.UncommitTS, 52 End: txnif.UncommitTS, 53 Txn: txn, 54 } 55 } 56 func NewTxnMVCCNodeWithTS(ts types.TS) *TxnMVCCNode { 57 return &TxnMVCCNode{ 58 Start: ts, 59 Prepare: ts, 60 End: ts, 61 } 62 } 63 func NewTxnMVCCNodeWithStartEnd(start, end types.TS) *TxnMVCCNode { 64 return &TxnMVCCNode{ 65 Start: start, 66 Prepare: end, 67 End: end, 68 } 69 } 70 func (un *TxnMVCCNode) IsAborted() bool { 71 return un.Aborted 72 } 73 func (un *TxnMVCCNode) Is1PC() bool { 74 return un.is1PC 75 } 76 func (un *TxnMVCCNode) Set1PC() { 77 un.is1PC = true 78 } 79 80 // Check w-w confilct 81 func (un *TxnMVCCNode) CheckConflict(txn txnif.TxnReader) error { 82 // If node is held by a active txn 83 if !un.IsCommitted() { 84 // No conflict if it is the same txn 85 if un.IsSameTxn(txn) { 86 return nil 87 } 88 return txnif.ErrTxnWWConflict 89 } 90 91 // For a committed node, it is w-w conflict if ts is lt the node commit ts 92 // -------+-------------+--------------------> 93 // ts CommitTs time 94 startTS := txn.GetStartTS() 95 if un.End.Greater(&startTS) { 96 return txnif.ErrTxnWWConflict 97 } 98 return nil 99 } 100 101 // Check whether is mvcc node is visible to ts 102 // Make sure all the relevant prepared txns should be committed|rollbacked 103 func (un *TxnMVCCNode) IsVisible(txn txnif.TxnReader) (visible bool) { 104 // Node is always visible to its born txn 105 if un.IsSameTxn(txn) { 106 return true 107 } 108 109 // The born txn of this node has not been commited|rollbacked 110 if un.IsActive() || un.IsCommitting() { 111 return false 112 } 113 114 // Node is visible if the commit ts is le ts 115 startTS := txn.GetStartTS() 116 if un.End.LessEq(&startTS) && !un.Aborted { 117 return true 118 } 119 120 // Node is not invisible if the commit ts is gt ts 121 return false 122 123 } 124 125 // Check whether is mvcc node is visible to ts 126 // Make sure all the relevant prepared txns should be committed|rollbacked 127 func (un *TxnMVCCNode) IsVisibleByTS(ts types.TS) (visible bool) { 128 // The born txn of this node has not been commited|rollbacked 129 if un.IsActive() || un.IsCommitting() { 130 return false 131 } 132 133 // Node is visible if the commit ts is le ts 134 if un.End.LessEq(&ts) && !un.Aborted { 135 return true 136 } 137 138 // Node is not invisible if the commit ts is gt ts 139 return false 140 141 } 142 func (un *TxnMVCCNode) GetPrepare() types.TS { 143 if un.Txn != nil { 144 return un.Txn.GetPrepareTS() 145 } 146 return un.Prepare 147 } 148 149 func (un *TxnMVCCNode) PreparedIn(minTS, maxTS types.TS) (in, before bool) { 150 // -------+----------+----------------+---------------> 151 // | | | Time 152 // MinTS MaxTs Prepare In future 153 // Created by other active txn 154 // false: not prepared in range 155 // false: not prepared before minTs 156 if un.Prepare.IsEmpty() { 157 return false, false 158 } 159 160 // -------+--------------+------------+---------------> 161 // | | | Time 162 // PrepareTs MinTs MaxTs 163 // Created by other committed txn 164 // false: not prepared in range 165 // true: prepared before minTs 166 if un.Prepare.Less(&minTS) { 167 return false, true 168 } 169 170 // -------+--------------+------------+---------------> 171 // | | | Time 172 // MinTs PrepareTs MaxTs 173 // Created by other committed txn 174 // true: prepared in range 175 // false: not prepared before minTs 176 if un.Prepare.GreaterEq(&minTS) && un.Prepare.LessEq(&maxTS) { 177 return true, false 178 } 179 180 // -------+--------------+------------+---------------> 181 // | | | Time 182 // MinTs MaxTs PrepareTs 183 // Created by other committed txn 184 // false: not prepared in range 185 // false: not prepared before minTs 186 return false, false 187 } 188 189 // in indicates whether this node is committed in between [minTs, maxTs] 190 // before indicates whether this node is committed before minTs 191 // NeedWaitCommitting should be called before to make sure all prepared active 192 // txns in between [minTs, maxTs] be committed or rollbacked 193 func (un *TxnMVCCNode) CommittedIn(minTS, maxTS types.TS) (in, before bool) { 194 // -------+----------+----------------+---------------> 195 // | | | Time 196 // MinTS MaxTs Commit In future 197 // Created by other active txn 198 // false: not committed in range 199 // false: not committed before minTs 200 if un.End.IsEmpty() { 201 return false, false 202 } 203 204 // -------+--------------+------------+---------------> 205 // | | | Time 206 // CommittedTS MinTs MaxTs 207 // Created by other committed txn 208 // false: not committed in range 209 // true: committed before minTs 210 if un.End.Less(&minTS) { 211 return false, true 212 } 213 214 // -------+--------------+------------+---------------> 215 // | | | Time 216 // MinTs CommittedTS MaxTs 217 // Created by other committed txn 218 // true: committed in range 219 // false: not committed before minTs 220 if un.End.GreaterEq(&minTS) && un.End.LessEq(&maxTS) { 221 return true, false 222 } 223 224 // -------+--------------+------------+---------------> 225 // | | | Time 226 // MinTs MaxTs CommittedTs 227 // Created by other committed txn 228 // false: not committed in range 229 // false: not committed before minTs 230 return false, false 231 } 232 233 // Check whether need to wait this mvcc node 234 func (un *TxnMVCCNode) NeedWaitCommitting(ts types.TS) (bool, txnif.TxnReader) { 235 // If this node is active, not to wait 236 // If this node is committed|rollbacked, not to wait 237 if !un.IsCommitting() { 238 return false, nil 239 } 240 241 // --------+----------------+------------------------> 242 // Ts PrepareTs Time 243 // If ts is before the prepare ts. not to wait 244 prepareTS := un.Txn.GetPrepareTS() 245 if prepareTS.GreaterEq(&ts) { 246 return false, nil 247 } 248 249 // --------+----------------+------------------------> 250 // PrepareTs Ts Time 251 // If ts is after the prepare ts. need to wait 252 return true, un.Txn 253 } 254 255 func (un *TxnMVCCNode) IsSameTxn(txn txnif.TxnReader) bool { 256 if un.Txn == nil { 257 return false 258 } 259 // for appendnode test 260 if txn == nil { 261 return false 262 } 263 return un.Txn.GetID() == txn.GetID() 264 } 265 266 func (un *TxnMVCCNode) IsActive() bool { 267 if un.Txn == nil { 268 return false 269 } 270 return un.Txn.GetTxnState(false) == txnif.TxnStateActive 271 } 272 273 func (un *TxnMVCCNode) IsCommitting() bool { 274 if un.Txn == nil { 275 return false 276 } 277 return un.Txn.GetTxnState(false) != txnif.TxnStateActive 278 } 279 280 func (un *TxnMVCCNode) IsCommitted() bool { 281 return un.Txn == nil 282 } 283 284 func (un *TxnMVCCNode) GetStart() types.TS { 285 return un.Start 286 } 287 288 func (un *TxnMVCCNode) GetEnd() types.TS { 289 return un.End 290 } 291 292 func (un *TxnMVCCNode) GetTxn() txnif.TxnReader { 293 return un.Txn 294 } 295 296 func (un *TxnMVCCNode) Compare(o *TxnMVCCNode) int { 297 if un.Start.Less(&o.Start) { 298 return -1 299 } 300 if un.Start.Equal(&o.Start) { 301 return 0 302 } 303 return 1 304 } 305 306 func (un *TxnMVCCNode) Compare2(o *TxnMVCCNode) int { 307 if un.Prepare.Less(&o.Prepare) { 308 return -1 309 } 310 if un.Prepare.Equal(&o.Prepare) { 311 return un.Compare(o) 312 } 313 return 1 314 } 315 316 func (un *TxnMVCCNode) ApplyCommit() (ts types.TS, err error) { 317 if un.Is1PC() { 318 un.End = un.Txn.GetPrepareTS() 319 } else { 320 un.End = un.Txn.GetCommitTS() 321 } 322 un.Txn = nil 323 ts = un.End 324 return 325 } 326 327 func (un *TxnMVCCNode) PrepareRollback() (err error) { 328 un.Aborted = true 329 return 330 } 331 332 func (un *TxnMVCCNode) ApplyRollback() (ts types.TS, err error) { 333 ts = un.Txn.GetCommitTS() 334 un.End = ts 335 un.Txn = nil 336 un.Aborted = true 337 return 338 } 339 340 func (un *TxnMVCCNode) WriteTo(w io.Writer) (n int64, err error) { 341 var sn1 int 342 if sn1, err = w.Write(un.Start[:]); err != nil { 343 return 344 } 345 n += int64(sn1) 346 if sn1, err = w.Write(un.Prepare[:]); err != nil { 347 return 348 } 349 n += int64(sn1) 350 if sn1, err = w.Write(un.End[:]); err != nil { 351 return 352 } 353 n += int64(sn1) 354 if sn1, err = w.Write(types.EncodeBool(&un.is1PC)); err != nil { 355 return 356 } 357 n += int64(sn1) 358 return 359 } 360 361 func (un *TxnMVCCNode) ReadFrom(r io.Reader) (n int64, err error) { 362 var sn int 363 if sn, err = r.Read(un.Start[:]); err != nil { 364 return 365 } 366 n += int64(sn) 367 if sn, err = r.Read(un.Prepare[:]); err != nil { 368 return 369 } 370 n += int64(sn) 371 if sn, err = r.Read(un.End[:]); err != nil { 372 return 373 } 374 n += int64(sn) 375 376 if sn, err = r.Read(types.EncodeBool(&un.is1PC)); err != nil { 377 return 378 } 379 n += int64(sn) 380 return 381 } 382 383 func CompareTxnMVCCNode(e, o *TxnMVCCNode) int { 384 return e.Compare(o) 385 } 386 387 func (un *TxnMVCCNode) Update(o *TxnMVCCNode) { 388 if !un.Start.Equal(&o.Start) { 389 panic(fmt.Sprintf("logic err, expect %s, start at %s", un.Start.ToString(), o.Start.ToString())) 390 } 391 if !un.Prepare.Equal(&o.Prepare) { 392 panic(fmt.Sprintf("logic err expect %s, prepare at %s", un.Prepare.ToString(), o.Prepare.ToString())) 393 } 394 } 395 396 func (un *TxnMVCCNode) CloneAll() *TxnMVCCNode { 397 n := &TxnMVCCNode{} 398 n.Start = un.Start 399 n.Prepare = un.Prepare 400 n.End = un.End 401 return n 402 } 403 404 func (un *TxnMVCCNode) String() string { 405 return fmt.Sprintf("[%s,%s]", 406 un.Start.ToString(), 407 un.End.ToString()) 408 } 409 410 func (un *TxnMVCCNode) PrepareCommit() (ts types.TS, err error) { 411 if un.Txn == nil { 412 err = moerr.NewTxnNotFoundNoCtx() 413 return 414 } 415 un.Prepare = un.Txn.GetPrepareTS() 416 ts = un.Prepare 417 return 418 } 419 420 func (un *TxnMVCCNode) AppendTuple(bat *containers.Batch) { 421 startTSVec := bat.GetVectorByName(SnapshotAttr_StartTS) 422 vector.AppendFixed( 423 startTSVec.GetDownstreamVector(), 424 un.Start, 425 false, 426 startTSVec.GetAllocator(), 427 ) 428 vector.AppendFixed( 429 bat.GetVectorByName(SnapshotAttr_PrepareTS).GetDownstreamVector(), 430 un.Prepare, 431 false, 432 startTSVec.GetAllocator(), 433 ) 434 vector.AppendFixed( 435 bat.GetVectorByName(SnapshotAttr_CommitTS).GetDownstreamVector(), 436 un.End, 437 false, 438 startTSVec.GetAllocator(), 439 ) 440 } 441 442 // In push model, logtail is prepared before committing txn, 443 // un.End is txnif.Uncommit 444 func (un *TxnMVCCNode) AppendTupleWithCommitTS(bat *containers.Batch, commitTS types.TS) { 445 startTSVec := bat.GetVectorByName(SnapshotAttr_StartTS) 446 vector.AppendFixed( 447 startTSVec.GetDownstreamVector(), 448 un.Start, 449 false, 450 startTSVec.GetAllocator(), 451 ) 452 vector.AppendFixed( 453 bat.GetVectorByName(SnapshotAttr_PrepareTS).GetDownstreamVector(), 454 un.Prepare, 455 false, 456 startTSVec.GetAllocator(), 457 ) 458 vector.AppendFixed( 459 bat.GetVectorByName(SnapshotAttr_CommitTS).GetDownstreamVector(), 460 commitTS, 461 false, 462 startTSVec.GetAllocator(), 463 ) 464 } 465 466 func (un *TxnMVCCNode) ReadTuple(bat *containers.Batch, offset int) { 467 // TODO 468 } 469 470 func ReadTuple(bat *containers.Batch, row int) (un *TxnMVCCNode) { 471 end := bat.GetVectorByName(SnapshotAttr_CommitTS).Get(row).(types.TS) 472 start := bat.GetVectorByName(SnapshotAttr_StartTS).Get(row).(types.TS) 473 prepare := bat.GetVectorByName(SnapshotAttr_PrepareTS).Get(row).(types.TS) 474 un = &TxnMVCCNode{ 475 Start: start, 476 Prepare: prepare, 477 End: end, 478 } 479 return 480 }