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  }