github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/txn/txnimpl/localseg.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 txnimpl
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    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/data"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    28  )
    29  
    30  const (
    31  	// Note: Do not edit this id!!!
    32  	LocalSegmentStartID uint64 = 1 << 47
    33  )
    34  
    35  var localSegmentIdAlloc *common.IdAlloctor
    36  
    37  func init() {
    38  	localSegmentIdAlloc = common.NewIdAlloctor(LocalSegmentStartID)
    39  }
    40  
    41  func isLocalSegment(id *common.ID) bool {
    42  	return id.SegmentID >= LocalSegmentStartID
    43  }
    44  
    45  func isLocalSegmentByID(id uint64) bool {
    46  	return id >= LocalSegmentStartID
    47  }
    48  
    49  type localSegment struct {
    50  	entry      *catalog.SegmentEntry
    51  	appendable InsertNode
    52  	//index for primary key
    53  	index TableIndex
    54  	//nodes contains anode and node.
    55  	nodes       []InsertNode
    56  	table       *txnTable
    57  	rows        uint32
    58  	appends     []*appendCtx
    59  	tableHandle data.TableHandle
    60  	nseg        handle.Segment
    61  	//sched  tasks.TaskScheduler
    62  }
    63  
    64  func newLocalSegment(table *txnTable) *localSegment {
    65  	entry := catalog.NewStandaloneSegment(
    66  		table.entry,
    67  		localSegmentIdAlloc.Alloc(),
    68  		table.store.txn.GetStartTS())
    69  	return &localSegment{
    70  		entry:   entry,
    71  		nodes:   make([]InsertNode, 0),
    72  		index:   NewSimpleTableIndex(),
    73  		appends: make([]*appendCtx, 0),
    74  		table:   table,
    75  	}
    76  }
    77  
    78  func (seg *localSegment) GetLocalPhysicalAxis(row uint32) (int, uint32) {
    79  	var sum uint32
    80  	for i, node := range seg.nodes {
    81  		sum += node.Rows()
    82  		if row <= sum-1 {
    83  			return i, node.Rows() - (sum - (row + 1)) - 1
    84  		}
    85  	}
    86  	panic("Invalid row ")
    87  }
    88  
    89  // register a non-appendable insertNode.
    90  func (seg *localSegment) registerNode(metaLoc string, deltaLoc string) {
    91  	meta := catalog.NewStandaloneBlockWithLoc(
    92  		seg.entry,
    93  		uint64(len(seg.nodes)),
    94  		seg.table.store.txn.GetStartTS(),
    95  		metaLoc,
    96  		deltaLoc)
    97  	seg.entry.AddEntryLocked(meta)
    98  	n := NewNode(
    99  		seg.table,
   100  		seg.table.store.dataFactory.Fs,
   101  		seg.table.store.nodesMgr,
   102  		seg.table.store.dataFactory.Scheduler,
   103  		meta,
   104  	)
   105  	seg.nodes = append(seg.nodes, n)
   106  
   107  }
   108  
   109  // register an appendable insertNode.
   110  func (seg *localSegment) registerANode() {
   111  	meta := catalog.NewStandaloneBlock(
   112  		seg.entry,
   113  		uint64(len(seg.nodes)),
   114  		seg.table.store.txn.GetStartTS())
   115  	seg.entry.AddEntryLocked(meta)
   116  	n := NewANode(
   117  		seg.table,
   118  		seg.table.store.dataFactory.Fs,
   119  		seg.table.store.nodesMgr,
   120  		seg.table.store.dataFactory.Scheduler,
   121  		meta,
   122  	)
   123  	seg.appendable = n
   124  	seg.nodes = append(seg.nodes, n)
   125  	//TODO::if appendable insertNode >= 2, start to flush it into S3/FS.
   126  	//seg.sched.Scheduler()
   127  }
   128  
   129  // ApplyAppend applies all the anodes into appendable blocks
   130  // and un-reference the appendable blocks which had been referenced when PrepareApply.
   131  func (seg *localSegment) ApplyAppend() (err error) {
   132  	var destOff int
   133  	defer func() {
   134  		// Close All unclosed Appends:un-reference the appendable block.
   135  		seg.CloseAppends()
   136  	}()
   137  	for _, ctx := range seg.appends {
   138  		bat, _ := ctx.node.Window(ctx.start, ctx.start+ctx.count)
   139  		defer bat.Close()
   140  		if destOff, err = ctx.driver.ApplyAppend(
   141  			bat,
   142  			seg.table.store.txn); err != nil {
   143  			return
   144  		}
   145  		id := ctx.driver.GetID()
   146  		ctx.node.AddApplyInfo(
   147  			ctx.start,
   148  			ctx.count,
   149  			uint32(destOff),
   150  			ctx.count,
   151  			seg.table.entry.GetDB().ID, id)
   152  	}
   153  	if seg.tableHandle != nil {
   154  		seg.table.entry.GetTableData().ApplyHandle(seg.tableHandle)
   155  	}
   156  	return
   157  }
   158  
   159  func (seg *localSegment) PrepareApply() (err error) {
   160  	defer func() {
   161  		if err != nil {
   162  			// Close All unclosed Appends: un-reference all the appendable blocks.
   163  			seg.CloseAppends()
   164  		}
   165  	}()
   166  	for _, node := range seg.nodes {
   167  		if err = seg.prepareApplyNode(node); err != nil {
   168  			return
   169  		}
   170  	}
   171  	return
   172  }
   173  
   174  func (seg *localSegment) prepareApplyNode(node InsertNode) (err error) {
   175  	if !node.IsPersisted() {
   176  		tableData := seg.table.entry.GetTableData()
   177  		if seg.tableHandle == nil {
   178  			seg.tableHandle = tableData.GetHandle()
   179  		}
   180  		appended := uint32(0)
   181  		for appended < node.RowsWithoutDeletes() {
   182  			appender, err := seg.tableHandle.GetAppender()
   183  			if moerr.IsMoErrCode(err, moerr.ErrAppendableSegmentNotFound) {
   184  				segH, err := seg.table.CreateSegment(true)
   185  				if err != nil {
   186  					return err
   187  				}
   188  				blk, err := segH.CreateBlock(true)
   189  				if err != nil {
   190  					return err
   191  				}
   192  				appender = seg.tableHandle.SetAppender(blk.Fingerprint())
   193  			} else if moerr.IsMoErrCode(err, moerr.ErrAppendableBlockNotFound) {
   194  				id := appender.GetID()
   195  				blk, err := seg.table.CreateBlock(id.SegmentID, true)
   196  				if err != nil {
   197  					return err
   198  				}
   199  				appender = seg.tableHandle.SetAppender(blk.Fingerprint())
   200  			}
   201  			//PrepareAppend: It is very important that appending a AppendNode into
   202  			// block's MVCCHandle before applying data into block.
   203  			anode, created, toAppend, err := appender.PrepareAppend(
   204  				node.RowsWithoutDeletes()-appended,
   205  				seg.table.store.txn)
   206  			if err != nil {
   207  				return err
   208  			}
   209  			toAppendWithDeletes := node.LengthWithDeletes(appended, toAppend)
   210  			ctx := &appendCtx{
   211  				driver: appender,
   212  				node:   node,
   213  				anode:  anode,
   214  				start:  node.OffsetWithDeletes(appended),
   215  				count:  toAppendWithDeletes,
   216  			}
   217  			if created {
   218  				seg.table.store.IncreateWriteCnt()
   219  				seg.table.txnEntries.Append(anode)
   220  			}
   221  			id := appender.GetID()
   222  			seg.table.store.warChecker.Insert(appender.GetMeta().(*catalog.BlockEntry))
   223  			seg.table.store.txn.GetMemo().AddBlock(seg.table.entry.GetDB().ID,
   224  				id.TableID, id.SegmentID, id.BlockID)
   225  			seg.appends = append(seg.appends, ctx)
   226  			logutil.Debugf("%s: toAppend %d, appended %d, blks=%d",
   227  				id.String(), toAppend, appended, len(seg.appends))
   228  			appended += toAppend
   229  			if appended == node.Rows() {
   230  				break
   231  			}
   232  		}
   233  		return
   234  	}
   235  	//handle persisted insertNode.
   236  	if seg.nseg == nil ||
   237  		seg.nseg.GetMeta().(*catalog.SegmentEntry).BlockCnt() ==
   238  			int(seg.nseg.GetMeta().(*catalog.SegmentEntry).GetTable().
   239  				GetSchema().SegmentMaxBlocks) {
   240  		seg.nseg, err = seg.table.CreateNonAppendableSegment(true)
   241  		if err != nil {
   242  			return
   243  		}
   244  	}
   245  	_, err = seg.nseg.CreateNonAppendableBlockWithMeta(node.GetPersistedLoc())
   246  	if err != nil {
   247  		return
   248  	}
   249  	return
   250  }
   251  
   252  // CloseAppends un-reference the appendable blocks
   253  func (seg *localSegment) CloseAppends() {
   254  	for _, ctx := range seg.appends {
   255  		ctx.driver.Close()
   256  	}
   257  }
   258  
   259  // Append appends batch of data into anode.
   260  func (seg *localSegment) Append(data *containers.Batch) (err error) {
   261  	if seg.appendable == nil {
   262  		seg.registerANode()
   263  	}
   264  	appended := uint32(0)
   265  	offset := uint32(0)
   266  	length := uint32(data.Length())
   267  	for {
   268  		h := seg.appendable
   269  		space := h.GetSpace()
   270  		if space == 0 {
   271  			seg.registerANode()
   272  			h = seg.appendable
   273  		}
   274  		appended, err = h.Append(data, offset)
   275  		if err != nil {
   276  			return
   277  		}
   278  		if seg.table.schema.HasPK() {
   279  			if err = seg.index.BatchInsert(
   280  				data.Attrs[seg.table.schema.GetSingleSortKeyIdx()],
   281  				data.Vecs[seg.table.schema.GetSingleSortKeyIdx()],
   282  				int(offset),
   283  				int(appended),
   284  				seg.rows,
   285  				false); err != nil {
   286  				break
   287  			}
   288  		}
   289  		offset += appended
   290  		seg.rows += appended
   291  		if offset >= length {
   292  			break
   293  		}
   294  	}
   295  	return
   296  }
   297  
   298  // AddBlksWithMetaLoc transfers blocks with meta location into non-appendable nodes
   299  func (seg *localSegment) AddBlksWithMetaLoc(
   300  	pkVecs []containers.Vector,
   301  	file string,
   302  	metaLocs []string,
   303  ) (err error) {
   304  	for i, metaLoc := range metaLocs {
   305  		seg.registerNode(metaLoc, "")
   306  		//insert primary keys into seg.index
   307  		if pkVecs != nil {
   308  			if err = seg.index.BatchInsert(
   309  				seg.table.schema.GetSingleSortKey().Name,
   310  				pkVecs[i],
   311  				0,
   312  				pkVecs[i].Length(),
   313  				seg.rows,
   314  				false,
   315  			); err != nil {
   316  				return
   317  			}
   318  			seg.rows += uint32(pkVecs[i].Length())
   319  		}
   320  	}
   321  	return nil
   322  }
   323  
   324  func (seg *localSegment) DeleteFromIndex(from, to uint32, node InsertNode) (err error) {
   325  	for i := from; i <= to; i++ {
   326  		v, err := node.GetValue(seg.table.schema.GetSingleSortKeyIdx(), i)
   327  		if err != nil {
   328  			return err
   329  		}
   330  		if err = seg.index.Delete(v); err != nil {
   331  			return err
   332  		}
   333  	}
   334  	return
   335  }
   336  
   337  // RangeDelete delete rows : [start, end]
   338  func (seg *localSegment) RangeDelete(start, end uint32) error {
   339  	first, firstOffset := seg.GetLocalPhysicalAxis(start)
   340  	last, lastOffset := seg.GetLocalPhysicalAxis(end)
   341  	var err error
   342  	if last == first {
   343  		node := seg.nodes[first]
   344  		err = node.RangeDelete(firstOffset, lastOffset)
   345  		if err != nil {
   346  			return err
   347  		}
   348  		if !seg.table.schema.HasPK() {
   349  			// If no pk defined
   350  			return err
   351  		}
   352  		err = seg.DeleteFromIndex(firstOffset, lastOffset, node)
   353  		return err
   354  	}
   355  
   356  	node := seg.nodes[first]
   357  	if err = node.RangeDelete(firstOffset, node.Rows()-1); err != nil {
   358  
   359  		return err
   360  	}
   361  	if err = seg.DeleteFromIndex(firstOffset, node.Rows()-1, node); err != nil {
   362  		return err
   363  	}
   364  	node = seg.nodes[last]
   365  	if err = node.RangeDelete(0, lastOffset); err != nil {
   366  		return err
   367  	}
   368  	if err = seg.DeleteFromIndex(0, lastOffset, node); err != nil {
   369  		return err
   370  	}
   371  	if last > first+1 {
   372  		for i := first + 1; i < last; i++ {
   373  			node = seg.nodes[i]
   374  			if err = node.RangeDelete(0, node.Rows()-1); err != nil {
   375  				break
   376  			}
   377  			if err = seg.DeleteFromIndex(0, node.Rows()-1, node); err != nil {
   378  				break
   379  			}
   380  		}
   381  	}
   382  	return err
   383  }
   384  
   385  // CollectCmd collect txnCmd for anode whose data resides in memory.
   386  func (seg *localSegment) CollectCmd(cmdMgr *commandManager) (err error) {
   387  	for _, node := range seg.nodes {
   388  		csn := uint32(0xffff) // Special cmd
   389  		cmd, err := node.MakeCommand(csn)
   390  		if err != nil {
   391  			panic(err)
   392  		}
   393  		if cmd != nil {
   394  			cmdMgr.AddInternalCmd(cmd)
   395  		}
   396  	}
   397  	return
   398  }
   399  
   400  func (seg *localSegment) DeletesToString() string {
   401  	var s string
   402  	for i, n := range seg.nodes {
   403  		s = fmt.Sprintf("%s\t<INode-%d>: %s\n", s, i, n.PrintDeletes())
   404  	}
   405  	return s
   406  }
   407  
   408  func (seg *localSegment) IsDeleted(row uint32) bool {
   409  	npos, noffset := seg.GetLocalPhysicalAxis(row)
   410  	n := seg.nodes[npos]
   411  	return n.IsRowDeleted(noffset)
   412  }
   413  
   414  func (seg *localSegment) Rows() (n uint32) {
   415  	for _, node := range seg.nodes {
   416  		n += node.Rows()
   417  	}
   418  	return
   419  }
   420  
   421  func (seg *localSegment) GetByFilter(filter *handle.Filter) (id *common.ID, offset uint32, err error) {
   422  	id = seg.entry.AsCommonID()
   423  	if !seg.table.schema.HasPK() {
   424  		_, _, offset = model.DecodePhyAddrKeyFromValue(filter.Val)
   425  		return
   426  	}
   427  	if v, ok := filter.Val.([]byte); ok {
   428  		offset, err = seg.index.Search(string(v))
   429  	} else {
   430  		offset, err = seg.index.Search(filter.Val)
   431  	}
   432  	return
   433  }
   434  
   435  func (seg *localSegment) GetPKColumn() containers.Vector {
   436  	schema := seg.table.entry.GetSchema()
   437  	return seg.index.KeyToVector(schema.GetSingleSortKeyType())
   438  }
   439  
   440  func (seg *localSegment) GetPKVecs() []containers.Vector {
   441  	schema := seg.table.entry.GetSchema()
   442  	return seg.index.KeyToVectors(schema.GetSingleSortKeyType())
   443  }
   444  
   445  func (seg *localSegment) BatchDedup(key containers.Vector) error {
   446  	return seg.index.BatchDedup(seg.table.GetSchema().GetSingleSortKey().Name, key)
   447  }
   448  
   449  func (seg *localSegment) GetColumnDataByIds(
   450  	blk *catalog.BlockEntry,
   451  	colIdxes []int,
   452  	buffers []*bytes.Buffer) (view *model.BlockView, err error) {
   453  	npos := int(blk.ID)
   454  	n := seg.nodes[npos]
   455  	return n.GetColumnDataByIds(colIdxes, buffers)
   456  }
   457  
   458  func (seg *localSegment) GetColumnDataById(
   459  	blk *catalog.BlockEntry,
   460  	colIdx int,
   461  	buffer *bytes.Buffer) (view *model.ColumnView, err error) {
   462  	npos := int(blk.ID)
   463  	n := seg.nodes[npos]
   464  	return n.GetColumnDataById(colIdx, buffer)
   465  }
   466  
   467  func (seg *localSegment) GetBlockRows(blk *catalog.BlockEntry) int {
   468  	npos := int(blk.ID)
   469  	n := seg.nodes[npos]
   470  	return int(n.Rows())
   471  }
   472  
   473  func (seg *localSegment) GetValue(row uint32, col uint16) (any, error) {
   474  	npos, noffset := seg.GetLocalPhysicalAxis(row)
   475  	n := seg.nodes[npos]
   476  	return n.GetValue(int(col), noffset)
   477  }
   478  
   479  // Close free the resource when transaction commits.
   480  func (seg *localSegment) Close() (err error) {
   481  	for _, node := range seg.nodes {
   482  		if err = node.Close(); err != nil {
   483  			return
   484  		}
   485  	}
   486  	seg.index.Close()
   487  	seg.index = nil
   488  	seg.nodes = nil
   489  	seg.appendable = nil
   490  	return
   491  }