github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/rpc/handle.go (about)

     1  // Copyright 2021 - 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 rpc
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"os"
    22  	"sync"
    23  	"syscall"
    24  	"time"
    25  
    26  	"github.com/google/shlex"
    27  	"github.com/matrixorigin/matrixone/pkg/catalog"
    28  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    29  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    30  	"github.com/matrixorigin/matrixone/pkg/container/types"
    31  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    32  	"github.com/matrixorigin/matrixone/pkg/defines"
    33  	"github.com/matrixorigin/matrixone/pkg/logutil"
    34  	apipb "github.com/matrixorigin/matrixone/pkg/pb/api"
    35  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    36  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    37  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    38  	catalog2 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    39  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    40  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    41  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/dataio/blockio"
    42  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db"
    43  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/rpchandle"
    44  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/logtail"
    45  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/moengine"
    46  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/options"
    47  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks"
    48  
    49  	"go.uber.org/zap"
    50  )
    51  
    52  // TODO::GC the abandoned txn.
    53  type Handle struct {
    54  	eng moengine.TxnEngine
    55  	mu  struct {
    56  		sync.RWMutex
    57  		//map txn id to txnContext.
    58  		txnCtxs map[string]*txnContext
    59  	}
    60  	jobScheduler tasks.JobScheduler
    61  }
    62  
    63  var _ rpchandle.Handler = (*Handle)(nil)
    64  
    65  type txnContext struct {
    66  	//createAt is used to GC the abandoned txn.
    67  	createAt time.Time
    68  	meta     txn.TxnMeta
    69  	reqs     []any
    70  	//the table to create by this txn.
    71  	toCreate map[uint64]*catalog2.Schema
    72  }
    73  
    74  func (h *Handle) GetTxnEngine() moengine.TxnEngine {
    75  	return h.eng
    76  }
    77  
    78  func NewTAEHandle(path string, opt *options.Options) *Handle {
    79  	if path == "" {
    80  		path = "./store"
    81  	}
    82  	tae, err := openTAE(path, opt)
    83  	if err != nil {
    84  		panic(err)
    85  	}
    86  
    87  	h := &Handle{
    88  		eng:          moengine.NewEngine(tae),
    89  		jobScheduler: tasks.NewParallelJobScheduler(100),
    90  	}
    91  	h.mu.txnCtxs = make(map[string]*txnContext)
    92  	return h
    93  }
    94  
    95  func (h *Handle) HandleCommit(
    96  	ctx context.Context,
    97  	meta txn.TxnMeta) (err error) {
    98  	h.mu.RLock()
    99  	txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())]
   100  	h.mu.RUnlock()
   101  	//Handle precommit-write command for 1PC
   102  	var txn moengine.Txn
   103  	if ok {
   104  		for _, e := range txnCtx.reqs {
   105  			switch req := e.(type) {
   106  			case *db.CreateDatabaseReq:
   107  				err = h.HandleCreateDatabase(
   108  					ctx,
   109  					meta,
   110  					req,
   111  					&db.CreateDatabaseResp{},
   112  				)
   113  			case *db.CreateRelationReq:
   114  				err = h.HandleCreateRelation(
   115  					ctx,
   116  					meta,
   117  					req,
   118  					&db.CreateRelationResp{},
   119  				)
   120  			case *db.DropDatabaseReq:
   121  				err = h.HandleDropDatabase(
   122  					ctx,
   123  					meta,
   124  					req,
   125  					&db.DropDatabaseResp{},
   126  				)
   127  			case *db.DropOrTruncateRelationReq:
   128  				err = h.HandleDropOrTruncateRelation(
   129  					ctx,
   130  					meta,
   131  					req,
   132  					&db.DropOrTruncateRelationResp{},
   133  				)
   134  			case *db.UpdateConstraintReq:
   135  				err = h.HandleUpdateConstraint(
   136  					ctx,
   137  					meta,
   138  					req,
   139  					&db.UpdateConstraintResp{},
   140  				)
   141  			case *db.WriteReq:
   142  				err = h.HandleWrite(
   143  					ctx,
   144  					meta,
   145  					req,
   146  					&db.WriteResp{},
   147  				)
   148  			default:
   149  				panic(moerr.NewNYI(ctx, "Pls implement me"))
   150  			}
   151  			//Need to roll back the txn.
   152  			if err != nil {
   153  				txn, _ = h.eng.GetTxnByID(meta.GetID())
   154  				txn.Rollback()
   155  				return
   156  			}
   157  		}
   158  	}
   159  	txn, err = h.eng.GetTxnByID(meta.GetID())
   160  	if err != nil {
   161  		return
   162  	}
   163  	//if txn is 2PC ,need to set commit timestamp passed by coordinator.
   164  	if txn.Is2PC() {
   165  		txn.SetCommitTS(types.TimestampToTS(meta.GetCommitTS()))
   166  	}
   167  	err = txn.Commit()
   168  
   169  	//delete the txn's context.
   170  	h.mu.Lock()
   171  	delete(h.mu.txnCtxs, string(meta.GetID()))
   172  	h.mu.Unlock()
   173  	return
   174  }
   175  
   176  func (h *Handle) HandleRollback(
   177  	ctx context.Context,
   178  	meta txn.TxnMeta) (err error) {
   179  	h.mu.Lock()
   180  	_, ok := h.mu.txnCtxs[string(meta.GetID())]
   181  	delete(h.mu.txnCtxs, string(meta.GetID()))
   182  	h.mu.Unlock()
   183  	//Rollback after pre-commit write.
   184  	if ok {
   185  		return
   186  	}
   187  	var txn moengine.Txn
   188  	txn, err = h.eng.GetTxnByID(meta.GetID())
   189  
   190  	if err != nil {
   191  		return err
   192  	}
   193  	err = txn.Rollback()
   194  	return
   195  }
   196  
   197  func (h *Handle) HandleCommitting(
   198  	ctx context.Context,
   199  	meta txn.TxnMeta) (err error) {
   200  	var txn moengine.Txn
   201  	txn, err = h.eng.GetTxnByID(meta.GetID())
   202  	if err != nil {
   203  		return err
   204  	}
   205  	txn.SetCommitTS(types.TimestampToTS(meta.GetCommitTS()))
   206  	err = txn.Committing()
   207  	return
   208  }
   209  
   210  func (h *Handle) HandlePrepare(
   211  	ctx context.Context,
   212  	meta txn.TxnMeta) (pts timestamp.Timestamp, err error) {
   213  	h.mu.RLock()
   214  	txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())]
   215  	h.mu.RUnlock()
   216  	var txn moengine.Txn
   217  	if ok {
   218  		//handle pre-commit write for 2PC
   219  		for _, e := range txnCtx.reqs {
   220  			switch req := e.(type) {
   221  			case *db.CreateDatabaseReq:
   222  				err = h.HandleCreateDatabase(
   223  					ctx,
   224  					meta,
   225  					req,
   226  					&db.CreateDatabaseResp{},
   227  				)
   228  			case *db.CreateRelationReq:
   229  				err = h.HandleCreateRelation(
   230  					ctx,
   231  					meta,
   232  					req,
   233  					&db.CreateRelationResp{},
   234  				)
   235  			case *db.DropDatabaseReq:
   236  				err = h.HandleDropDatabase(
   237  					ctx,
   238  					meta,
   239  					req,
   240  					&db.DropDatabaseResp{},
   241  				)
   242  			case *db.DropOrTruncateRelationReq:
   243  				err = h.HandleDropOrTruncateRelation(
   244  					ctx,
   245  					meta,
   246  					req,
   247  					&db.DropOrTruncateRelationResp{},
   248  				)
   249  			case *db.UpdateConstraintReq:
   250  				err = h.HandleUpdateConstraint(
   251  					ctx,
   252  					meta,
   253  					req,
   254  					&db.UpdateConstraintResp{},
   255  				)
   256  			case *db.WriteReq:
   257  				err = h.HandleWrite(
   258  					ctx,
   259  					meta,
   260  					req,
   261  					&db.WriteResp{},
   262  				)
   263  			default:
   264  				panic(moerr.NewNYI(ctx, "Pls implement me"))
   265  			}
   266  			//need to rollback the txn
   267  			if err != nil {
   268  				txn, _ = h.eng.GetTxnByID(meta.GetID())
   269  				txn.Rollback()
   270  				return
   271  			}
   272  		}
   273  	}
   274  	txn, err = h.eng.GetTxnByID(meta.GetID())
   275  	if err != nil {
   276  		return timestamp.Timestamp{}, err
   277  	}
   278  	participants := make([]uint64, 0, len(meta.GetDNShards()))
   279  	for _, shard := range meta.GetDNShards() {
   280  		participants = append(participants, shard.GetShardID())
   281  	}
   282  	txn.SetParticipants(participants)
   283  	var ts types.TS
   284  	ts, err = txn.Prepare()
   285  	pts = ts.ToTimestamp()
   286  	//delete the txn's context.
   287  	h.mu.Lock()
   288  	delete(h.mu.txnCtxs, string(meta.GetID()))
   289  	h.mu.Unlock()
   290  	return
   291  }
   292  
   293  func (h *Handle) HandleStartRecovery(
   294  	ctx context.Context,
   295  	ch chan txn.TxnMeta) {
   296  	//panic(moerr.NewNYI("HandleStartRecovery is not implemented yet"))
   297  	//TODO:: 1.  Get the 2PC transactions which be in prepared or
   298  	//           committing state from txn engine's recovery.
   299  	//       2.  Feed these transaction into ch.
   300  	close(ch)
   301  }
   302  
   303  func (h *Handle) HandleClose(ctx context.Context) (err error) {
   304  	//FIXME::should wait txn request's job done?
   305  	h.jobScheduler.Stop()
   306  	return h.eng.Close()
   307  }
   308  
   309  func (h *Handle) HandleDestroy(ctx context.Context) (err error) {
   310  	//FIXME::should wait txn request's job done?
   311  	h.jobScheduler.Stop()
   312  	return h.eng.Destroy()
   313  }
   314  
   315  func (h *Handle) HandleGetLogTail(
   316  	ctx context.Context,
   317  	meta txn.TxnMeta,
   318  	req apipb.SyncLogTailReq,
   319  	resp *apipb.SyncLogTailResp) (err error) {
   320  	tae := h.eng.GetTAE(context.Background())
   321  	res, err := logtail.HandleSyncLogTailReq(
   322  		ctx,
   323  		tae.BGCheckpointRunner,
   324  		tae.LogtailMgr,
   325  		tae.Catalog,
   326  		req,
   327  		true)
   328  	if err != nil {
   329  		return err
   330  	}
   331  	*resp = res
   332  	return nil
   333  }
   334  
   335  func (h *Handle) HandleFlushTable(
   336  	ctx context.Context,
   337  	meta txn.TxnMeta,
   338  	req db.FlushTable,
   339  	resp *apipb.SyncLogTailResp) (err error) {
   340  
   341  	// We use current TS instead of transaction ts.
   342  	// Here, the point of this handle function is to trigger a flush
   343  	// via mo_ctl.  We mimic the behaviour of a real background flush
   344  	// currTs := types.TimestampToTS(meta.GetSnapshotTS())
   345  	currTs := types.BuildTS(time.Now().UTC().UnixNano(), 0)
   346  
   347  	err = h.eng.FlushTable(ctx,
   348  		req.AccessInfo.AccountID,
   349  		req.DatabaseID,
   350  		req.TableID,
   351  		currTs)
   352  	return err
   353  }
   354  
   355  func (h *Handle) HandleForceCheckpoint(
   356  	ctx context.Context,
   357  	meta txn.TxnMeta,
   358  	req db.Checkpoint,
   359  	resp *apipb.SyncLogTailResp) (err error) {
   360  
   361  	timeout := req.FlushDuration
   362  
   363  	currTs := types.BuildTS(time.Now().UTC().UnixNano(), 0)
   364  
   365  	err = h.eng.ForceCheckpoint(ctx,
   366  		currTs, timeout)
   367  	return err
   368  }
   369  
   370  func (h *Handle) HandleInspectDN(
   371  	ctx context.Context,
   372  	meta txn.TxnMeta,
   373  	req db.InspectDN,
   374  	resp *db.InspectResp) (err error) {
   375  	tae := h.eng.GetTAE(context.Background())
   376  	args, _ := shlex.Split(req.Operation)
   377  	logutil.Info("Inspect", zap.Strings("args", args))
   378  	b := &bytes.Buffer{}
   379  
   380  	inspectCtx := &inspectContext{
   381  		db:     tae,
   382  		acinfo: &req.AccessInfo,
   383  		args:   args,
   384  		out:    b,
   385  		resp:   resp,
   386  	}
   387  	RunInspect(inspectCtx)
   388  	resp.Message = b.String()
   389  	return nil
   390  }
   391  
   392  func (h *Handle) startLoadJobs(
   393  	ctx context.Context,
   394  	meta txn.TxnMeta,
   395  	req *db.WriteReq,
   396  ) (err error) {
   397  	var locations []string
   398  	var columnTypes []types.Type
   399  	var columnNames []string
   400  	var isNull []bool
   401  	var jobIds []string
   402  	var columnIdx int
   403  	if req.Type == db.EntryInsert {
   404  		//for loading primary keys of blocks
   405  		locations = append(locations, req.MetaLocs...)
   406  		columnTypes = append(columnTypes, req.Schema.GetSingleSortKey().Type)
   407  		columnNames = append(columnNames, req.Schema.GetSingleSortKey().Name)
   408  		columnIdx = req.Schema.GetSingleSortKeyIdx()
   409  		isNull = append(isNull, false)
   410  		req.Jobs = make([]*tasks.Job, len(req.MetaLocs))
   411  		req.JobRes = make([]*tasks.JobResult, len(req.Jobs))
   412  		for i := range req.MetaLocs {
   413  			jobIds = append(jobIds,
   414  				fmt.Sprintf("load-primarykey-%s", req.MetaLocs[i]))
   415  		}
   416  	} else {
   417  		//for loading deleted rowid.
   418  		locations = append(locations, req.DeltaLocs...)
   419  		columnTypes = append(columnTypes, types.T_Rowid.ToType())
   420  		columnIdx = 0
   421  		columnNames = append(columnNames, catalog.Row_ID)
   422  		isNull = append(isNull, false)
   423  		req.Jobs = make([]*tasks.Job, len(req.DeltaLocs))
   424  		req.JobRes = make([]*tasks.JobResult, len(req.Jobs))
   425  		for i := range req.DeltaLocs {
   426  			jobIds = append(jobIds,
   427  				fmt.Sprintf("load-deleted-rowid-%s", req.DeltaLocs[i]))
   428  		}
   429  	}
   430  	//start loading jobs asynchronously,should create a new root context.
   431  	nctx := context.Background()
   432  	if deadline, ok := ctx.Deadline(); ok {
   433  		nctx, req.Cancel = context.WithTimeout(nctx, time.Until(deadline))
   434  	}
   435  	for i, v := range locations {
   436  		nctx = context.WithValue(nctx, db.LocationKey{}, v)
   437  		req.Jobs[i] = tasks.NewJob(
   438  			jobIds[i],
   439  			nctx,
   440  			func(ctx context.Context) (jobR *tasks.JobResult) {
   441  				jobR = &tasks.JobResult{}
   442  				loc, ok := ctx.Value(db.LocationKey{}).(string)
   443  				if !ok {
   444  					panic(moerr.NewInternalErrorNoCtx("Miss Location"))
   445  				}
   446  				//reader, err := blockio.NewReader(ctx,
   447  				//	h.eng.GetTAE(ctx).Fs, req.MetaLocs[i])
   448  				reader, err := blockio.NewReader(ctx,
   449  					h.eng.GetTAE(ctx).Fs, loc)
   450  				if err != nil {
   451  					jobR.Err = err
   452  					return
   453  				}
   454  				meta, err := reader.ReadMeta(nil)
   455  				if err != nil {
   456  					jobR.Err = err
   457  					return
   458  				}
   459  				bat, err := reader.LoadBlkColumnsByMetaAndIdx(
   460  					columnTypes,
   461  					columnNames,
   462  					isNull,
   463  					meta,
   464  					columnIdx,
   465  				)
   466  				if err != nil {
   467  					jobR.Err = err
   468  					return
   469  				}
   470  				jobR.Res = bat.Vecs[0]
   471  				return
   472  			},
   473  		)
   474  		if err = h.jobScheduler.Schedule(req.Jobs[i]); err != nil {
   475  			return err
   476  		}
   477  	}
   478  	return
   479  }
   480  
   481  // EvaluateTxnRequest only evaluate the request ,do not change the state machine of TxnEngine.
   482  func (h *Handle) EvaluateTxnRequest(
   483  	ctx context.Context,
   484  	meta txn.TxnMeta,
   485  ) (err error) {
   486  	h.mu.RLock()
   487  	txnCtx := h.mu.txnCtxs[string(meta.GetID())]
   488  	h.mu.RUnlock()
   489  	for _, e := range txnCtx.reqs {
   490  		if r, ok := e.(*db.WriteReq); ok {
   491  			if r.FileName != "" {
   492  				if r.Type == db.EntryInsert {
   493  					v, ok := txnCtx.toCreate[r.TableID]
   494  					if !ok {
   495  						txn, err := h.eng.GetOrCreateTxnWithMeta(
   496  							nil,
   497  							meta.GetID(),
   498  							types.TimestampToTS(meta.GetSnapshotTS()))
   499  						if err != nil {
   500  							return err
   501  						}
   502  						dbase, err := h.eng.GetDatabaseByID(ctx, r.DatabaseId, txn)
   503  						if err != nil {
   504  							return err
   505  						}
   506  						tb, err := dbase.GetRelationByID(ctx, r.TableID)
   507  						if err != nil {
   508  							return err
   509  						}
   510  						r.Schema = tb.GetSchema(ctx)
   511  					} else {
   512  						r.Schema = v
   513  					}
   514  					if r.Schema.HasPK() {
   515  						//start to load primary keys
   516  						err = h.startLoadJobs(ctx, meta, r)
   517  						if err != nil {
   518  							return
   519  						}
   520  					}
   521  					continue
   522  				}
   523  				//start to load deleted row ids
   524  				err = h.startLoadJobs(ctx, meta, r)
   525  				if err != nil {
   526  					return
   527  				}
   528  
   529  			}
   530  		}
   531  	}
   532  	return
   533  }
   534  
   535  func (h *Handle) CacheTxnRequest(
   536  	ctx context.Context,
   537  	meta txn.TxnMeta,
   538  	req any,
   539  	rsp any) (err error) {
   540  	h.mu.Lock()
   541  	txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())]
   542  	if !ok {
   543  		txnCtx = &txnContext{
   544  			createAt: time.Now(),
   545  			meta:     meta,
   546  			toCreate: make(map[uint64]*catalog2.Schema),
   547  		}
   548  		h.mu.txnCtxs[string(meta.GetID())] = txnCtx
   549  	}
   550  	h.mu.Unlock()
   551  	txnCtx.reqs = append(txnCtx.reqs, req)
   552  	if r, ok := req.(*db.CreateRelationReq); ok {
   553  		// Does this place need
   554  		schema, err := moengine.DefsToSchema(r.Name, r.Defs)
   555  		if err != nil {
   556  			return err
   557  		}
   558  		txnCtx.toCreate[r.RelationId] = schema
   559  	}
   560  	return nil
   561  }
   562  
   563  func (h *Handle) HandlePreCommitWrite(
   564  	ctx context.Context,
   565  	meta txn.TxnMeta,
   566  	req apipb.PrecommitWriteCmd,
   567  	resp *apipb.SyncLogTailResp) (err error) {
   568  	var e any
   569  
   570  	es := req.EntryList
   571  
   572  	for len(es) > 0 {
   573  		e, es, err = catalog.ParseEntryList(es)
   574  		if err != nil {
   575  			return err
   576  		}
   577  		switch cmds := e.(type) {
   578  		case []catalog.CreateDatabase:
   579  			for _, cmd := range cmds {
   580  				req := &db.CreateDatabaseReq{
   581  					Name:       cmd.Name,
   582  					CreateSql:  cmd.CreateSql,
   583  					DatabaseId: cmd.DatabaseId,
   584  					AccessInfo: db.AccessInfo{
   585  						UserID:    cmd.Creator,
   586  						RoleID:    cmd.Owner,
   587  						AccountID: cmd.AccountId,
   588  					},
   589  				}
   590  				if err = h.CacheTxnRequest(ctx, meta, req,
   591  					new(db.CreateDatabaseResp)); err != nil {
   592  					return err
   593  				}
   594  			}
   595  		case []catalog.CreateTable:
   596  			for _, cmd := range cmds {
   597  				req := &db.CreateRelationReq{
   598  					AccessInfo: db.AccessInfo{
   599  						UserID:    cmd.Creator,
   600  						RoleID:    cmd.Owner,
   601  						AccountID: cmd.AccountId,
   602  					},
   603  					Name:         cmd.Name,
   604  					RelationId:   cmd.TableId,
   605  					DatabaseName: cmd.DatabaseName,
   606  					DatabaseID:   cmd.DatabaseId,
   607  					Defs:         cmd.Defs,
   608  				}
   609  				if err = h.CacheTxnRequest(ctx, meta, req,
   610  					new(db.CreateRelationResp)); err != nil {
   611  					return err
   612  				}
   613  			}
   614  		case []catalog.UpdateConstraint:
   615  			for _, cmd := range cmds {
   616  				req := &db.UpdateConstraintReq{
   617  					TableName:    cmd.TableName,
   618  					TableId:      cmd.TableId,
   619  					DatabaseName: cmd.DatabaseName,
   620  					DatabaseId:   cmd.DatabaseId,
   621  					Constraint:   cmd.Constraint,
   622  				}
   623  				if err = h.CacheTxnRequest(ctx, meta, req,
   624  					new(db.UpdateConstraintResp)); err != nil {
   625  					return err
   626  				}
   627  			}
   628  		case []catalog.DropDatabase:
   629  			for _, cmd := range cmds {
   630  				req := &db.DropDatabaseReq{
   631  					Name: cmd.Name,
   632  					ID:   cmd.Id,
   633  				}
   634  				if err = h.CacheTxnRequest(ctx, meta, req,
   635  					new(db.DropDatabaseResp)); err != nil {
   636  					return err
   637  				}
   638  			}
   639  		case []catalog.DropOrTruncateTable:
   640  			for _, cmd := range cmds {
   641  				req := &db.DropOrTruncateRelationReq{
   642  					IsDrop:       cmd.IsDrop,
   643  					Name:         cmd.Name,
   644  					ID:           cmd.Id,
   645  					NewId:        cmd.NewId,
   646  					DatabaseName: cmd.DatabaseName,
   647  					DatabaseID:   cmd.DatabaseId,
   648  				}
   649  				if err = h.CacheTxnRequest(ctx, meta, req,
   650  					new(db.DropOrTruncateRelationResp)); err != nil {
   651  					return err
   652  				}
   653  			}
   654  		case *apipb.Entry:
   655  			//Handle DML
   656  			pe := e.(*apipb.Entry)
   657  			moBat, err := batch.ProtoBatchToBatch(pe.GetBat())
   658  			if err != nil {
   659  				panic(err)
   660  			}
   661  			req := &db.WriteReq{
   662  				Type:         db.EntryType(pe.EntryType),
   663  				DatabaseId:   pe.GetDatabaseId(),
   664  				TableID:      pe.GetTableId(),
   665  				DatabaseName: pe.GetDatabaseName(),
   666  				TableName:    pe.GetTableName(),
   667  				FileName:     pe.GetFileName(),
   668  				Batch:        moBat,
   669  			}
   670  			if req.FileName != "" {
   671  				rows := catalog.GenRows(req.Batch)
   672  				for _, row := range rows {
   673  					if req.Type == db.EntryInsert {
   674  						//req.Blks[i] = row[catalog.BLOCKMETA_ID_ON_FS_IDX].(uint64)
   675  						//req.MetaLocs[i] = string(row[catalog.BLOCKMETA_METALOC_ON_FS_IDX].([]byte))
   676  						req.MetaLocs = append(req.MetaLocs,
   677  							string(row[0].([]byte)))
   678  					} else {
   679  						//req.DeltaLocs[i] = string(row[0].([]byte))
   680  						req.DeltaLocs = append(req.DeltaLocs,
   681  							string(row[0].([]byte)))
   682  					}
   683  				}
   684  			}
   685  			if err = h.CacheTxnRequest(ctx, meta, req,
   686  				new(db.WriteResp)); err != nil {
   687  				return err
   688  			}
   689  		default:
   690  			panic(moerr.NewNYI(ctx, ""))
   691  		}
   692  	}
   693  	//evaluate all the txn requests.
   694  	return h.EvaluateTxnRequest(ctx, meta)
   695  }
   696  
   697  //Handle DDL commands.
   698  
   699  func (h *Handle) HandleCreateDatabase(
   700  	ctx context.Context,
   701  	meta txn.TxnMeta,
   702  	req *db.CreateDatabaseReq,
   703  	resp *db.CreateDatabaseResp) (err error) {
   704  	_, span := trace.Start(ctx, "HandleCreateDatabase")
   705  	defer span.End()
   706  
   707  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   708  		types.TimestampToTS(meta.GetSnapshotTS()))
   709  	if err != nil {
   710  		return err
   711  	}
   712  
   713  	logutil.Infof("[precommit] create database: %+v\n txn: %s\n", req, txn.String())
   714  	defer func() {
   715  		logutil.Infof("[precommit] create database end txn: %s\n", txn.String())
   716  	}()
   717  
   718  	ctx = context.WithValue(ctx, defines.TenantIDKey{}, req.AccessInfo.AccountID)
   719  	ctx = context.WithValue(ctx, defines.UserIDKey{}, req.AccessInfo.UserID)
   720  	ctx = context.WithValue(ctx, defines.RoleIDKey{}, req.AccessInfo.RoleID)
   721  	err = h.eng.CreateDatabaseWithID(ctx, req.Name, req.CreateSql, req.DatabaseId, txn)
   722  	if err != nil {
   723  		return
   724  	}
   725  	resp.ID = req.DatabaseId
   726  	return
   727  }
   728  
   729  func (h *Handle) HandleDropDatabase(
   730  	ctx context.Context,
   731  	meta txn.TxnMeta,
   732  	req *db.DropDatabaseReq,
   733  	resp *db.DropDatabaseResp) (err error) {
   734  
   735  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   736  		types.TimestampToTS(meta.GetSnapshotTS()))
   737  	if err != nil {
   738  		return err
   739  	}
   740  
   741  	logutil.Infof("[precommit] drop database: %+v\n txn: %s\n", req, txn.String())
   742  	defer func() {
   743  		logutil.Infof("[precommit] drop database end: %s\n", txn.String())
   744  	}()
   745  
   746  	if err = h.eng.DropDatabaseByID(ctx, req.ID, txn); err != nil {
   747  		return
   748  	}
   749  	resp.ID = req.ID
   750  	return
   751  }
   752  
   753  func (h *Handle) HandleCreateRelation(
   754  	ctx context.Context,
   755  	meta txn.TxnMeta,
   756  	req *db.CreateRelationReq,
   757  	resp *db.CreateRelationResp) (err error) {
   758  
   759  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   760  		types.TimestampToTS(meta.GetSnapshotTS()))
   761  	if err != nil {
   762  		return
   763  	}
   764  
   765  	logutil.Infof("[precommit] create relation: %+v\n txn: %s\n", req, txn.String())
   766  	defer func() {
   767  		logutil.Infof("[precommit] create relation end txn: %s\n", txn.String())
   768  	}()
   769  
   770  	ctx = context.WithValue(ctx, defines.TenantIDKey{}, req.AccessInfo.AccountID)
   771  	ctx = context.WithValue(ctx, defines.UserIDKey{}, req.AccessInfo.UserID)
   772  	ctx = context.WithValue(ctx, defines.RoleIDKey{}, req.AccessInfo.RoleID)
   773  	db, err := h.eng.GetDatabase(ctx, req.DatabaseName, txn)
   774  	if err != nil {
   775  		return
   776  	}
   777  
   778  	err = db.CreateRelationWithID(ctx, req.Name, req.RelationId, req.Defs)
   779  	if err != nil {
   780  		return
   781  	}
   782  
   783  	resp.ID = req.RelationId
   784  	return
   785  }
   786  
   787  func (h *Handle) HandleDropOrTruncateRelation(
   788  	ctx context.Context,
   789  	meta txn.TxnMeta,
   790  	req *db.DropOrTruncateRelationReq,
   791  	resp *db.DropOrTruncateRelationResp) (err error) {
   792  
   793  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   794  		types.TimestampToTS(meta.GetSnapshotTS()))
   795  	if err != nil {
   796  		return
   797  	}
   798  
   799  	logutil.Infof("[precommit] drop/truncate relation: %+v\n txn: %s\n", req, txn.String())
   800  	defer func() {
   801  		logutil.Infof("[precommit] drop/truncate relation end txn: %s\n", txn.String())
   802  	}()
   803  
   804  	db, err := h.eng.GetDatabaseByID(ctx, req.DatabaseID, txn)
   805  	if err != nil {
   806  		return
   807  	}
   808  
   809  	if req.IsDrop {
   810  		err = db.DropRelationByID(ctx, req.ID)
   811  		if err != nil {
   812  			return
   813  		}
   814  		return
   815  	}
   816  	err = db.TruncateRelationByID(ctx, req.ID, req.NewId)
   817  	return err
   818  }
   819  
   820  // HandleWrite Handle DML commands
   821  func (h *Handle) HandleWrite(
   822  	ctx context.Context,
   823  	meta txn.TxnMeta,
   824  	req *db.WriteReq,
   825  	resp *db.WriteResp) (err error) {
   826  	defer func() {
   827  		if req.Cancel != nil {
   828  			req.Cancel()
   829  		}
   830  	}()
   831  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   832  		types.TimestampToTS(meta.GetSnapshotTS()))
   833  	if err != nil {
   834  		return
   835  	}
   836  
   837  	logutil.Infof("[precommit] handle write typ: %v, %d-%s, %d-%s\n txn: %s\n",
   838  		req.Type, req.TableID,
   839  		req.TableName, req.DatabaseId, req.DatabaseName,
   840  		txn.String(),
   841  	)
   842  	logutil.Debugf("[precommit] write batch: %s\n", debugMoBatch(req.Batch))
   843  	defer func() {
   844  		logutil.Infof("[precommit] handle write end txn: %s\n", txn.String())
   845  	}()
   846  
   847  	dbase, err := h.eng.GetDatabaseByID(ctx, req.DatabaseId, txn)
   848  	if err != nil {
   849  		return
   850  	}
   851  
   852  	tb, err := dbase.GetRelationByID(ctx, req.TableID)
   853  	if err != nil {
   854  		return
   855  	}
   856  
   857  	if req.Type == db.EntryInsert {
   858  		//Add blocks which had been bulk-loaded into S3 into table.
   859  		if req.FileName != "" {
   860  			//wait for loading primary key done.
   861  			var pkVecs []containers.Vector
   862  			for i, job := range req.Jobs {
   863  				req.JobRes[i] = job.WaitDone()
   864  				if req.JobRes[i].Err != nil {
   865  					return req.JobRes[i].Err
   866  				}
   867  				pkVecs = append(
   868  					pkVecs,
   869  					req.JobRes[i].Res.(containers.Vector))
   870  			}
   871  			err = tb.AddBlksWithMetaLoc(
   872  				ctx,
   873  				pkVecs,
   874  				req.FileName,
   875  				req.MetaLocs,
   876  				0)
   877  			return
   878  		}
   879  		//Appends a batch of data into table.
   880  		err = tb.Write(ctx, req.Batch)
   881  		return
   882  	}
   883  	//handle delete
   884  	if req.FileName != "" {
   885  		//wait for loading deleted row-id done.
   886  		for i, job := range req.Jobs {
   887  			req.JobRes[i] = job.WaitDone()
   888  			if req.JobRes[i].Err != nil {
   889  				return req.JobRes[i].Err
   890  			}
   891  			rowidVec := req.JobRes[i].Res.(containers.Vector)
   892  			//FIXME::??
   893  			//defer taeVec.Close()
   894  			//TODO::check whether rowid is generated by DN in debug mode.
   895  			// IsGeneratedByDN(rowidVec)
   896  			tb.DeleteByPhyAddrKeys(ctx, containers.UnmarshalToMoVec(rowidVec))
   897  		}
   898  		return
   899  	}
   900  	err = tb.DeleteByPhyAddrKeys(ctx, req.Batch.GetVector(0))
   901  	return
   902  }
   903  
   904  func (h *Handle) HandleUpdateConstraint(
   905  	ctx context.Context,
   906  	meta txn.TxnMeta,
   907  	req *db.UpdateConstraintReq,
   908  	resp *db.UpdateConstraintResp) (err error) {
   909  	txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(),
   910  		types.TimestampToTS(meta.GetSnapshotTS()))
   911  	if err != nil {
   912  		return err
   913  	}
   914  
   915  	cstr := req.Constraint
   916  	req.Constraint = nil
   917  	logutil.Infof("[precommit] update cstr: %+v cstr %d bytes\n txn: %s\n", req, len(cstr), txn.String())
   918  
   919  	dbase, err := h.eng.GetDatabaseByID(ctx, req.DatabaseId, txn)
   920  	if err != nil {
   921  		return
   922  	}
   923  
   924  	tbl, err := dbase.GetRelationByID(ctx, req.TableId)
   925  	if err != nil {
   926  		return
   927  	}
   928  
   929  	tbl.UpdateConstraintWithBin(ctx, cstr)
   930  
   931  	return nil
   932  }
   933  
   934  func vec2Str[T any](vec []T, v *vector.Vector) string {
   935  	var w bytes.Buffer
   936  	_, _ = w.WriteString(fmt.Sprintf("[%d]: ", v.Length()))
   937  	first := true
   938  	for i := 0; i < len(vec); i++ {
   939  		if !first {
   940  			_ = w.WriteByte(',')
   941  		}
   942  		if v.Nsp.Contains(uint64(i)) {
   943  			_, _ = w.WriteString(common.TypeStringValue(v.Typ, types.Null{}))
   944  		} else {
   945  			_, _ = w.WriteString(common.TypeStringValue(v.Typ, vec[i]))
   946  		}
   947  		first = false
   948  	}
   949  	return w.String()
   950  }
   951  
   952  func moVec2String(v *vector.Vector, printN int) string {
   953  	switch v.Typ.Oid {
   954  	case types.T_bool:
   955  		return vec2Str(vector.MustTCols[bool](v)[:printN], v)
   956  	case types.T_int8:
   957  		return vec2Str(vector.MustTCols[int8](v)[:printN], v)
   958  	case types.T_int16:
   959  		return vec2Str(vector.MustTCols[int16](v)[:printN], v)
   960  	case types.T_int32:
   961  		return vec2Str(vector.MustTCols[int32](v)[:printN], v)
   962  	case types.T_int64:
   963  		return vec2Str(vector.MustTCols[int64](v)[:printN], v)
   964  	case types.T_uint8:
   965  		return vec2Str(vector.MustTCols[uint8](v)[:printN], v)
   966  	case types.T_uint16:
   967  		return vec2Str(vector.MustTCols[uint16](v)[:printN], v)
   968  	case types.T_uint32:
   969  		return vec2Str(vector.MustTCols[uint32](v)[:printN], v)
   970  	case types.T_uint64:
   971  		return vec2Str(vector.MustTCols[uint64](v)[:printN], v)
   972  	case types.T_float32:
   973  		return vec2Str(vector.MustTCols[float32](v)[:printN], v)
   974  	case types.T_float64:
   975  		return vec2Str(vector.MustTCols[float64](v)[:printN], v)
   976  	case types.T_date:
   977  		return vec2Str(vector.MustTCols[types.Date](v)[:printN], v)
   978  	case types.T_datetime:
   979  		return vec2Str(vector.MustTCols[types.Datetime](v)[:printN], v)
   980  	case types.T_time:
   981  		return vec2Str(vector.MustTCols[types.Time](v)[:printN], v)
   982  	case types.T_timestamp:
   983  		return vec2Str(vector.MustTCols[types.Timestamp](v)[:printN], v)
   984  	case types.T_decimal64:
   985  		return vec2Str(vector.MustTCols[types.Decimal64](v)[:printN], v)
   986  	case types.T_decimal128:
   987  		return vec2Str(vector.MustTCols[types.Decimal128](v)[:printN], v)
   988  	case types.T_uuid:
   989  		return vec2Str(vector.MustTCols[types.Uuid](v)[:printN], v)
   990  	case types.T_TS:
   991  		return vec2Str(vector.MustTCols[types.TS](v)[:printN], v)
   992  	case types.T_Rowid:
   993  		return vec2Str(vector.MustTCols[types.Rowid](v)[:printN], v)
   994  	}
   995  	if v.Typ.IsVarlen() {
   996  		return vec2Str(vector.MustBytesCols(v)[:printN], v)
   997  	}
   998  	return fmt.Sprintf("unkown type vec... %v", v.Typ)
   999  }
  1000  
  1001  func debugMoBatch(moBat *batch.Batch) string {
  1002  	if !logutil.GetSkip1Logger().Core().Enabled(zap.DebugLevel) {
  1003  		return "not debug level"
  1004  	}
  1005  	printN := moBat.Length()
  1006  	if printN > logtail.PrintN {
  1007  		printN = logtail.PrintN
  1008  	}
  1009  	buf := new(bytes.Buffer)
  1010  	for i, vec := range moBat.Vecs {
  1011  		fmt.Fprintf(buf, "[%v] = %v\n", moBat.Attrs[i], moVec2String(vec, printN))
  1012  	}
  1013  	return buf.String()
  1014  }
  1015  
  1016  func openTAE(targetDir string, opt *options.Options) (tae *db.DB, err error) {
  1017  
  1018  	if targetDir != "" {
  1019  		mask := syscall.Umask(0)
  1020  		if err := os.MkdirAll(targetDir, os.FileMode(0755)); err != nil {
  1021  			syscall.Umask(mask)
  1022  			logutil.Infof("Recreate dir error:%v\n", err)
  1023  			return nil, err
  1024  		}
  1025  		syscall.Umask(mask)
  1026  		tae, err = db.Open(targetDir+"/tae", opt)
  1027  		if err != nil {
  1028  			logutil.Infof("Open tae failed. error:%v", err)
  1029  			return nil, err
  1030  		}
  1031  		return tae, nil
  1032  	}
  1033  
  1034  	tae, err = db.Open(targetDir, opt)
  1035  	if err != nil {
  1036  		logutil.Infof("Open tae failed. error:%v", err)
  1037  		return nil, err
  1038  	}
  1039  	return
  1040  }