github.com/matrixorigin/matrixone@v1.2.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  	"context"
    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/iface/txnif"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/updates"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal"
    29  )
    30  
    31  type replayTxnStore struct {
    32  	txnbase.NoopTxnStore
    33  	Cmd         *txnbase.TxnCmd
    34  	Observer    wal.ReplayObserver
    35  	catalog     *catalog.Catalog
    36  	dataFactory *tables.DataFactory
    37  	wal         wal.Driver
    38  	ctx         context.Context
    39  }
    40  
    41  func MakeReplayTxn(
    42  	ctx context.Context,
    43  	mgr *txnbase.TxnManager,
    44  	txnCtx *txnbase.TxnCtx,
    45  	lsn uint64,
    46  	cmd *txnbase.TxnCmd,
    47  	observer wal.ReplayObserver,
    48  	catalog *catalog.Catalog,
    49  	dataFactory *tables.DataFactory,
    50  	wal wal.Driver) *txnbase.Txn {
    51  	store := &replayTxnStore{
    52  		Cmd:         cmd,
    53  		Observer:    observer,
    54  		catalog:     catalog,
    55  		dataFactory: dataFactory,
    56  		wal:         wal,
    57  		ctx:         ctx,
    58  	}
    59  	txn := txnbase.NewPersistedTxn(
    60  		mgr,
    61  		txnCtx,
    62  		store,
    63  		lsn,
    64  		store.prepareCommit,
    65  		store.prepareRollback,
    66  		store.applyCommit,
    67  		store.applyRollback)
    68  	return txn
    69  }
    70  func (store *replayTxnStore) GetContext() context.Context {
    71  	return store.ctx
    72  }
    73  func (store *replayTxnStore) IsReadonly() bool { return false }
    74  
    75  func (store *replayTxnStore) prepareCommit(txn txnif.AsyncTxn) (err error) {
    76  	// PrepareCommit all commands
    77  	// Check idempotent of each command
    78  	// Record all idempotent error commands and skip apply|rollback later
    79  	store.Observer.OnTimeStamp(txn.GetPrepareTS())
    80  	for _, command := range store.Cmd.Cmds {
    81  		command.SetReplayTxn(txn)
    82  		store.prepareCmd(command)
    83  	}
    84  	return
    85  }
    86  
    87  func (store *replayTxnStore) applyCommit(txn txnif.AsyncTxn) (err error) {
    88  	store.Cmd.ApplyCommit()
    89  	return
    90  }
    91  
    92  func (store *replayTxnStore) applyRollback(txn txnif.AsyncTxn) (err error) {
    93  	store.Cmd.ApplyRollback()
    94  	return
    95  }
    96  
    97  func (store *replayTxnStore) prepareRollback(txn txnif.AsyncTxn) (err error) {
    98  	panic(moerr.NewInternalErrorNoCtx("cannot prepareRollback rollback replay txn: %s",
    99  		txn.String()))
   100  }
   101  
   102  func (store *replayTxnStore) prepareCmd(txncmd txnif.TxnCmd) {
   103  	if txncmd.GetType() != txnbase.IOET_WALTxnEntry {
   104  		logutil.Debug("", common.OperationField("replay-cmd"),
   105  			common.OperandField(txncmd.Desc()))
   106  	}
   107  	var err error
   108  	switch cmd := txncmd.(type) {
   109  	case *catalog.EntryCommand[*catalog.EmptyMVCCNode, *catalog.DBNode],
   110  		*catalog.EntryCommand[*catalog.TableMVCCNode, *catalog.TableNode],
   111  		*catalog.EntryCommand[*catalog.MetadataMVCCNode, *catalog.ObjectNode],
   112  		*catalog.EntryCommand[*catalog.ObjectMVCCNode, *catalog.ObjectNode],
   113  		*catalog.EntryCommand[*catalog.MetadataMVCCNode, *catalog.BlockNode]:
   114  		store.catalog.ReplayCmd(txncmd, store.dataFactory, store.Observer)
   115  	case *AppendCmd:
   116  		store.replayAppendData(cmd, store.Observer)
   117  	case *updates.UpdateCmd:
   118  		store.replayDataCmds(cmd, store.Observer)
   119  	}
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  }
   124  
   125  func (store *replayTxnStore) replayAppendData(cmd *AppendCmd, observer wal.ReplayObserver) {
   126  	hasActive := false
   127  	for _, info := range cmd.Infos {
   128  		id := info.GetDest()
   129  		database, err := store.catalog.GetDatabaseByID(id.DbID)
   130  		if err != nil {
   131  			panic(err)
   132  		}
   133  		blk, err := database.GetBlockEntryByID(id)
   134  		if err != nil {
   135  			panic(err)
   136  		}
   137  		if !blk.IsActive() {
   138  			continue
   139  		}
   140  		if blk.ObjectPersisted() {
   141  			continue
   142  		}
   143  		hasActive = true
   144  	}
   145  
   146  	if !hasActive {
   147  		return
   148  	}
   149  
   150  	data := cmd.Data
   151  	if data != nil {
   152  		defer data.Close()
   153  	}
   154  
   155  	for _, info := range cmd.Infos {
   156  		id := info.GetDest()
   157  		database, err := store.catalog.GetDatabaseByID(id.DbID)
   158  		if err != nil {
   159  			panic(err)
   160  		}
   161  		blk, err := database.GetBlockEntryByID(id)
   162  		if err != nil {
   163  			panic(err)
   164  		}
   165  		if !blk.IsActive() {
   166  			continue
   167  		}
   168  		if blk.ObjectPersisted() {
   169  			continue
   170  		}
   171  		start := info.GetSrcOff()
   172  		bat := data.CloneWindow(int(start), int(info.GetSrcLen()))
   173  		bat.Compact()
   174  		defer bat.Close()
   175  		if err = blk.GetObjectData().OnReplayAppendPayload(bat); err != nil {
   176  			panic(err)
   177  		}
   178  	}
   179  }
   180  
   181  func (store *replayTxnStore) replayDataCmds(cmd *updates.UpdateCmd, observer wal.ReplayObserver) {
   182  	switch cmd.GetType() {
   183  	case updates.IOET_WALTxnCommand_AppendNode:
   184  		store.replayAppend(cmd, observer)
   185  	case updates.IOET_WALTxnCommand_DeleteNode, updates.IOET_WALTxnCommand_PersistedDeleteNode:
   186  		store.replayDelete(cmd, observer)
   187  	}
   188  }
   189  
   190  func (store *replayTxnStore) replayDelete(cmd *updates.UpdateCmd, observer wal.ReplayObserver) {
   191  	deleteNode := cmd.GetDeleteNode()
   192  	if deleteNode.Is1PC() {
   193  		if _, err := deleteNode.TxnMVCCNode.ApplyCommit(); err != nil {
   194  			panic(err)
   195  		}
   196  	}
   197  	id := deleteNode.GetID()
   198  	database, err := store.catalog.GetDatabaseByID(id.DbID)
   199  	if err != nil {
   200  		panic(err)
   201  	}
   202  	blk, err := database.GetBlockEntryByID(id)
   203  	if err != nil {
   204  		panic(err)
   205  	}
   206  	if !blk.IsActive() {
   207  		return
   208  	}
   209  	blkData := blk.GetObjectData()
   210  	_, blkOffset := id.BlockID.Offsets()
   211  	err = blkData.OnReplayDelete(blkOffset, deleteNode)
   212  	if err != nil {
   213  		panic(err)
   214  	}
   215  
   216  }
   217  
   218  func (store *replayTxnStore) replayAppend(cmd *updates.UpdateCmd, observer wal.ReplayObserver) {
   219  	appendNode := cmd.GetAppendNode()
   220  	if appendNode.Is1PC() {
   221  		if _, err := appendNode.TxnMVCCNode.ApplyCommit(); err != nil {
   222  			panic(err)
   223  		}
   224  	}
   225  	id := appendNode.GetID()
   226  	database, err := store.catalog.GetDatabaseByID(id.DbID)
   227  	if err != nil {
   228  		panic(err)
   229  	}
   230  	blk, err := database.GetBlockEntryByID(id)
   231  	if err != nil {
   232  		panic(err)
   233  	}
   234  	if !blk.IsActive() {
   235  		return
   236  	}
   237  	if blk.ObjectPersisted() {
   238  		return
   239  	}
   240  	if err = blk.GetObjectData().OnReplayAppend(appendNode); err != nil {
   241  		panic(err)
   242  	}
   243  }