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