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