github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/txn/txnimpl/replaystore.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 txnimpl
    16  
    17  import (
    18  	"bytes"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    21  	"github.com/matrixorigin/matrixone/pkg/logutil"
    22  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/updates"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal"
    30  )
    31  
    32  type replayTxnStore struct {
    33  	txnbase.NoopTxnStore
    34  	Cmd         *txnbase.TxnCmd
    35  	Observer    wal.ReplayObserver
    36  	catalog     *catalog.Catalog
    37  	dataFactory *tables.DataFactory
    38  	wal         wal.Driver
    39  }
    40  
    41  func MakeReplayTxn(
    42  	mgr *txnbase.TxnManager,
    43  	ctx *txnbase.TxnCtx,
    44  	lsn uint64,
    45  	cmd *txnbase.TxnCmd,
    46  	observer wal.ReplayObserver,
    47  	catalog *catalog.Catalog,
    48  	dataFactory *tables.DataFactory,
    49  	wal wal.Driver) *txnbase.Txn {
    50  	store := &replayTxnStore{
    51  		Cmd:         cmd,
    52  		Observer:    observer,
    53  		catalog:     catalog,
    54  		dataFactory: dataFactory,
    55  		wal:         wal,
    56  	}
    57  	txn := txnbase.NewPersistedTxn(
    58  		mgr,
    59  		ctx,
    60  		store,
    61  		lsn,
    62  		store.prepareCommit,
    63  		store.prepareRollback,
    64  		store.applyCommit,
    65  		store.applyRollback)
    66  	return txn
    67  }
    68  
    69  func (store *replayTxnStore) IsReadonly() bool { return false }
    70  
    71  func (store *replayTxnStore) prepareCommit(txn txnif.AsyncTxn) (err error) {
    72  	// PrepareCommit all commands
    73  	// Check idempotent of each command
    74  	// Record all idempotent error commands and skip apply|rollback later
    75  	idxCtx := &wal.Index{LSN: txn.GetLSN()}
    76  	idxCtx.Size = store.Cmd.CmdSize
    77  	internalCnt := uint32(0)
    78  	store.Observer.OnTimeStamp(txn.GetPrepareTS())
    79  	for i, command := range store.Cmd.Cmds {
    80  		command.SetReplayTxn(txn)
    81  		if command.GetType() == CmdAppend {
    82  			internalCnt++
    83  			store.prepareCmd(command, nil)
    84  		} else {
    85  			idx := idxCtx.Clone()
    86  			idx.CSN = uint32(i) - internalCnt
    87  			store.prepareCmd(command, idx)
    88  		}
    89  	}
    90  	return
    91  }
    92  
    93  func (store *replayTxnStore) applyCommit(txn txnif.AsyncTxn) (err error) {
    94  	store.Cmd.ApplyCommit()
    95  	return
    96  }
    97  
    98  func (store *replayTxnStore) applyRollback(txn txnif.AsyncTxn) (err error) {
    99  	store.Cmd.ApplyRollback()
   100  	return
   101  }
   102  
   103  func (store *replayTxnStore) prepareRollback(txn txnif.AsyncTxn) (err error) {
   104  	panic(moerr.NewInternalErrorNoCtx("cannot prepareRollback rollback replay txn: %s",
   105  		txn.String()))
   106  }
   107  
   108  func (store *replayTxnStore) prepareCmd(txncmd txnif.TxnCmd, idxCtx *wal.Index) {
   109  	if idxCtx != nil && idxCtx.Size > 0 {
   110  		logutil.Debug("", common.OperationField("replay-cmd"),
   111  			common.OperandField(txncmd.Desc()),
   112  			common.AnyField("index", idxCtx.String()))
   113  	}
   114  	var err error
   115  	switch cmd := txncmd.(type) {
   116  	case *catalog.EntryCommand:
   117  		store.catalog.ReplayCmd(txncmd, store.dataFactory, idxCtx, store.Observer)
   118  	case *AppendCmd:
   119  		store.replayAppendData(cmd, store.Observer)
   120  	case *updates.UpdateCmd:
   121  		store.replayDataCmds(cmd, idxCtx, store.Observer)
   122  	}
   123  	if err != nil {
   124  		panic(err)
   125  	}
   126  }
   127  
   128  func (store *replayTxnStore) replayAppendData(cmd *AppendCmd, observer wal.ReplayObserver) {
   129  	hasActive := false
   130  	for _, info := range cmd.Infos {
   131  		database, err := store.catalog.GetDatabaseByID(info.GetDBID())
   132  		if err != nil {
   133  			panic(err)
   134  		}
   135  		id := info.GetDest()
   136  		blk, err := database.GetBlockEntryByID(id)
   137  		if err != nil {
   138  			panic(err)
   139  		}
   140  		if !blk.IsActive() {
   141  			continue
   142  		}
   143  		if blk.GetMetaLoc() != "" {
   144  			continue
   145  		}
   146  		hasActive = true
   147  	}
   148  
   149  	if !hasActive {
   150  		return
   151  	}
   152  
   153  	var data *containers.Batch
   154  
   155  	for _, subTxnCmd := range cmd.Cmds {
   156  		switch subCmd := subTxnCmd.(type) {
   157  		case *txnbase.BatchCmd:
   158  			data = subCmd.Bat
   159  		case *txnbase.PointerCmd:
   160  			batEntry, err := store.wal.LoadEntry(subCmd.Group, subCmd.Lsn)
   161  			if err != nil {
   162  				panic(err)
   163  			}
   164  			r := bytes.NewBuffer(batEntry.GetPayload())
   165  			txnCmd, _, err := txnbase.BuildCommandFrom(r)
   166  			if err != nil {
   167  				panic(err)
   168  			}
   169  			data = txnCmd.(*txnbase.BatchCmd).Bat
   170  			batEntry.Free()
   171  		}
   172  	}
   173  	if data != nil {
   174  		defer data.Close()
   175  	}
   176  
   177  	for _, info := range cmd.Infos {
   178  		database, err := store.catalog.GetDatabaseByID(info.GetDBID())
   179  		if err != nil {
   180  			panic(err)
   181  		}
   182  		id := info.GetDest()
   183  		blk, err := database.GetBlockEntryByID(id)
   184  		if err != nil {
   185  			panic(err)
   186  		}
   187  		if !blk.IsActive() {
   188  			continue
   189  		}
   190  		if blk.GetMetaLoc() != "" {
   191  			continue
   192  		}
   193  		start := info.GetSrcOff()
   194  		bat := data.CloneWindow(int(start), int(info.GetSrcLen()))
   195  		bat.Compact()
   196  		defer bat.Close()
   197  		if err = blk.GetBlockData().OnReplayAppendPayload(bat); err != nil {
   198  			panic(err)
   199  		}
   200  	}
   201  }
   202  
   203  func (store *replayTxnStore) replayDataCmds(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) {
   204  	switch cmd.GetType() {
   205  	case txnbase.CmdAppend:
   206  		store.replayAppend(cmd, idxCtx, observer)
   207  	case txnbase.CmdDelete:
   208  		store.replayDelete(cmd, idxCtx, observer)
   209  	}
   210  }
   211  
   212  func (store *replayTxnStore) replayDelete(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) {
   213  	database, err := store.catalog.GetDatabaseByID(cmd.GetDBID())
   214  	if err != nil {
   215  		panic(err)
   216  	}
   217  	deleteNode := cmd.GetDeleteNode()
   218  	deleteNode.SetLogIndex(idxCtx)
   219  	if deleteNode.Is1PC() {
   220  		if _, err := deleteNode.TxnMVCCNode.ApplyCommit(nil); err != nil {
   221  			panic(err)
   222  		}
   223  	}
   224  	id := deleteNode.GetID()
   225  	blk, err := database.GetBlockEntryByID(id)
   226  	if err != nil {
   227  		panic(err)
   228  	}
   229  	if !blk.IsActive() {
   230  		observer.OnStaleIndex(idxCtx)
   231  		return
   232  	}
   233  	blkData := blk.GetBlockData()
   234  	err = blkData.OnReplayDelete(deleteNode)
   235  	if err != nil {
   236  		panic(err)
   237  	}
   238  
   239  }
   240  
   241  func (store *replayTxnStore) replayAppend(cmd *updates.UpdateCmd, idxCtx *wal.Index, observer wal.ReplayObserver) {
   242  	database, err := store.catalog.GetDatabaseByID(cmd.GetDBID())
   243  	if err != nil {
   244  		panic(err)
   245  	}
   246  	appendNode := cmd.GetAppendNode()
   247  	appendNode.SetLogIndex(idxCtx)
   248  	if appendNode.Is1PC() {
   249  		if _, err := appendNode.TxnMVCCNode.ApplyCommit(nil); err != nil {
   250  			panic(err)
   251  		}
   252  	}
   253  	id := appendNode.GetID()
   254  	blk, err := database.GetBlockEntryByID(id)
   255  	if err != nil {
   256  		panic(err)
   257  	}
   258  	if !blk.IsActive() {
   259  		observer.OnStaleIndex(idxCtx)
   260  		return
   261  	}
   262  	if blk.GetMetaLoc() != "" {
   263  		observer.OnStaleIndex(idxCtx)
   264  		return
   265  	}
   266  	if err = blk.GetBlockData().OnReplayAppend(appendNode); err != nil {
   267  		panic(err)
   268  	}
   269  }