github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/db/replay.go (about)

     1  // Copyright 2022 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 db
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    22  	"github.com/matrixorigin/matrixone/pkg/container/types"
    23  	"github.com/matrixorigin/matrixone/pkg/logutil"
    24  	"github.com/matrixorigin/matrixone/pkg/objectio"
    25  
    26  	"sync"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnimpl"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal"
    35  )
    36  
    37  type Replayer struct {
    38  	DataFactory   *tables.DataFactory
    39  	db            *DB
    40  	maxTs         types.TS
    41  	once          sync.Once
    42  	ckpedTS       types.TS
    43  	wg            sync.WaitGroup
    44  	applyDuration time.Duration
    45  	txnCmdChan    chan *txnbase.TxnCmd
    46  	readCount     int
    47  	applyCount    int
    48  
    49  	lsn            uint64
    50  	enableLSNCheck bool
    51  }
    52  
    53  func newReplayer(dataFactory *tables.DataFactory, db *DB, ckpedTS types.TS, lsn uint64, enableLSNCheck bool) *Replayer {
    54  	return &Replayer{
    55  		DataFactory: dataFactory,
    56  		db:          db,
    57  		ckpedTS:     ckpedTS,
    58  		lsn:         lsn,
    59  		// for ckp version less than 7, lsn is always 0 and lsnCheck is disable
    60  		enableLSNCheck: enableLSNCheck,
    61  		wg:             sync.WaitGroup{},
    62  		txnCmdChan:     make(chan *txnbase.TxnCmd, 100),
    63  	}
    64  }
    65  
    66  func (replayer *Replayer) PreReplayWal() {
    67  	processor := new(catalog.LoopProcessor)
    68  	processor.ObjectFn = func(entry *catalog.ObjectEntry) (err error) {
    69  		if entry.GetTable().IsVirtual() {
    70  			return moerr.GetOkStopCurrRecur()
    71  		}
    72  		dropCommit := entry.TreeMaxDropCommitEntry()
    73  		if dropCommit != nil && dropCommit.DeleteBeforeLocked(replayer.ckpedTS) {
    74  			return moerr.GetOkStopCurrRecur()
    75  		}
    76  		entry.InitData(replayer.DataFactory)
    77  		return
    78  	}
    79  	if err := replayer.db.Catalog.RecurLoop(processor); err != nil {
    80  		if !moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
    81  			panic(err)
    82  		}
    83  	}
    84  }
    85  
    86  func (replayer *Replayer) postReplayWal() {
    87  	processor := new(catalog.LoopProcessor)
    88  	processor.ObjectFn = func(entry *catalog.ObjectEntry) (err error) {
    89  		if entry.InMemoryDeletesExisted() {
    90  			entry.GetTable().DeletedDirties = append(entry.GetTable().DeletedDirties, entry)
    91  		}
    92  		return
    93  	}
    94  	if err := replayer.db.Catalog.RecurLoop(processor); err != nil {
    95  		panic(err)
    96  	}
    97  }
    98  func (replayer *Replayer) Replay() {
    99  	replayer.wg.Add(1)
   100  	go replayer.applyTxnCmds()
   101  	if err := replayer.db.Wal.Replay(replayer.OnReplayEntry); err != nil {
   102  		panic(err)
   103  	}
   104  	replayer.txnCmdChan <- txnbase.NewLastTxnCmd()
   105  	close(replayer.txnCmdChan)
   106  	replayer.wg.Wait()
   107  	replayer.postReplayWal()
   108  	logutil.Info("open-tae", common.OperationField("replay"),
   109  		common.OperandField("wal"),
   110  		common.AnyField("apply logentries cost", replayer.applyDuration),
   111  		common.AnyField("read count", replayer.readCount),
   112  		common.AnyField("apply count", replayer.applyCount))
   113  }
   114  
   115  func (replayer *Replayer) OnReplayEntry(group uint32, lsn uint64, payload []byte, typ uint16, info any) {
   116  	replayer.once.Do(replayer.PreReplayWal)
   117  	if group != wal.GroupPrepare && group != wal.GroupC {
   118  		return
   119  	}
   120  	if !replayer.checkLSN(lsn) {
   121  		return
   122  	}
   123  	head := objectio.DecodeIOEntryHeader(payload)
   124  	codec := objectio.GetIOEntryCodec(*head)
   125  	entry, err := codec.Decode(payload[4:])
   126  	txnCmd := entry.(*txnbase.TxnCmd)
   127  	txnCmd.Lsn = lsn
   128  	if err != nil {
   129  		panic(err)
   130  	}
   131  	replayer.txnCmdChan <- txnCmd
   132  }
   133  func (replayer *Replayer) applyTxnCmds() {
   134  	defer replayer.wg.Done()
   135  	for {
   136  		txnCmd := <-replayer.txnCmdChan
   137  		if txnCmd.IsLastCmd() {
   138  			break
   139  		}
   140  		t0 := time.Now()
   141  		replayer.OnReplayTxn(txnCmd, txnCmd.Lsn)
   142  		txnCmd.Close()
   143  		replayer.applyDuration += time.Since(t0)
   144  
   145  	}
   146  }
   147  func (replayer *Replayer) GetMaxTS() types.TS {
   148  	return replayer.maxTs
   149  }
   150  
   151  func (replayer *Replayer) OnTimeStamp(ts types.TS) {
   152  	if ts.Greater(&replayer.maxTs) {
   153  		replayer.maxTs = ts
   154  	}
   155  }
   156  func (replayer *Replayer) checkLSN(lsn uint64) (needReplay bool) {
   157  	if !replayer.enableLSNCheck {
   158  		return true
   159  	}
   160  	if lsn <= replayer.lsn {
   161  		return false
   162  	}
   163  	if lsn == replayer.lsn+1 {
   164  		replayer.lsn++
   165  		return true
   166  	}
   167  	panic(fmt.Sprintf("invalid lsn %d, current lsn %d", lsn, replayer.lsn))
   168  }
   169  func (replayer *Replayer) OnReplayTxn(cmd txnif.TxnCmd, lsn uint64) {
   170  	var err error
   171  	replayer.readCount++
   172  	txnCmd := cmd.(*txnbase.TxnCmd)
   173  	// If WAL entry splits, they share same prepareTS
   174  	if txnCmd.PrepareTS.Less(&replayer.maxTs) {
   175  		return
   176  	}
   177  	replayer.applyCount++
   178  	txn := txnimpl.MakeReplayTxn(replayer.db.Runtime.Options.Ctx, replayer.db.TxnMgr, txnCmd.TxnCtx, lsn,
   179  		txnCmd, replayer, replayer.db.Catalog, replayer.DataFactory, replayer.db.Wal)
   180  	if err = replayer.db.TxnMgr.OnReplayTxn(txn); err != nil {
   181  		panic(err)
   182  	}
   183  	if txn.Is2PC() {
   184  		if _, err = txn.Prepare(replayer.db.Opts.Ctx); err != nil {
   185  			panic(err)
   186  		}
   187  	} else {
   188  		if err = txn.Commit(replayer.db.Opts.Ctx); err != nil {
   189  			panic(err)
   190  		}
   191  	}
   192  }