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  }