github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/table.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 catalog
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"sync/atomic"
    22  
    23  	pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog"
    24  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    25  	"github.com/matrixorigin/matrixone/pkg/container/types"
    26  	"github.com/matrixorigin/matrixone/pkg/logutil"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    30  )
    31  
    32  type TableDataFactory = func(meta *TableEntry) data.Table
    33  
    34  func tableVisibilityFn[T *TableEntry](n *common.GenericDLNode[*TableEntry], ts types.TS) (visible, dropped bool) {
    35  	table := n.GetPayload()
    36  	visible, dropped = table.GetVisibility(ts)
    37  	return
    38  }
    39  
    40  type TableEntry struct {
    41  	*TableBaseEntry
    42  	db      *DBEntry
    43  	schema  *Schema
    44  	entries map[uint64]*common.GenericDLNode[*SegmentEntry]
    45  	//link.head and link.tail is nil when create tableEntry object.
    46  	link      *common.GenericSortedDList[*SegmentEntry]
    47  	tableData data.Table
    48  	rows      atomic.Uint64
    49  	// fullname is format as 'tenantID-tableName', the tenantID prefix is only used 'mo_catalog' database
    50  	fullName string
    51  }
    52  
    53  func genTblFullName(tenantID uint32, name string) string {
    54  	if name == pkgcatalog.MO_DATABASE || name == pkgcatalog.MO_TABLES || name == pkgcatalog.MO_COLUMNS {
    55  		tenantID = 0
    56  	}
    57  	return fmt.Sprintf("%d-%s", tenantID, name)
    58  }
    59  
    60  func NewTableEntry(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory) *TableEntry {
    61  	id := db.catalog.NextTable()
    62  	return NewTableEntryWithTableId(db, schema, txnCtx, dataFactory, id)
    63  }
    64  
    65  func NewTableEntryWithTableId(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory, tableId uint64) *TableEntry {
    66  	if txnCtx != nil {
    67  		// Only in unit test, txnCtx can be nil
    68  		schema.AcInfo.TenantID = txnCtx.GetTenantID()
    69  		schema.AcInfo.UserID, schema.AcInfo.RoleID = txnCtx.GetUserAndRoleID()
    70  	}
    71  	schema.AcInfo.CreateAt = types.CurrentTimestamp()
    72  	e := &TableEntry{
    73  		TableBaseEntry: NewTableBaseEntry(tableId),
    74  		db:             db,
    75  		schema:         schema,
    76  		link:           common.NewGenericSortedDList(compareSegmentFn),
    77  		entries:        make(map[uint64]*common.GenericDLNode[*SegmentEntry]),
    78  	}
    79  	if dataFactory != nil {
    80  		e.tableData = dataFactory(e)
    81  	}
    82  	e.CreateWithTxn(txnCtx, schema)
    83  	return e
    84  }
    85  
    86  func NewSystemTableEntry(db *DBEntry, id uint64, schema *Schema) *TableEntry {
    87  	e := &TableEntry{
    88  		TableBaseEntry: NewTableBaseEntry(id),
    89  		db:             db,
    90  		schema:         schema,
    91  		link:           common.NewGenericSortedDList(compareSegmentFn),
    92  		entries:        make(map[uint64]*common.GenericDLNode[*SegmentEntry]),
    93  	}
    94  	e.CreateWithTS(types.SystemDBTS)
    95  	var sid uint64
    96  	if schema.Name == SystemTableSchema.Name {
    97  		sid = SystemSegment_Table_ID
    98  	} else if schema.Name == SystemDBSchema.Name {
    99  		sid = SystemSegment_DB_ID
   100  	} else if schema.Name == SystemColumnSchema.Name {
   101  		sid = SystemSegment_Columns_ID
   102  	} else {
   103  		panic("not supported")
   104  	}
   105  	segment := NewSysSegmentEntry(e, sid)
   106  	e.AddEntryLocked(segment)
   107  	return e
   108  }
   109  
   110  func NewReplayTableEntry() *TableEntry {
   111  	e := &TableEntry{
   112  		TableBaseEntry: NewReplayTableBaseEntry(),
   113  		link:           common.NewGenericSortedDList(compareSegmentFn),
   114  		entries:        make(map[uint64]*common.GenericDLNode[*SegmentEntry]),
   115  	}
   116  	return e
   117  }
   118  
   119  func MockStaloneTableEntry(id uint64, schema *Schema) *TableEntry {
   120  	return &TableEntry{
   121  		TableBaseEntry: NewTableBaseEntry(id),
   122  		schema:         schema,
   123  		link:           common.NewGenericSortedDList(compareSegmentFn),
   124  		entries:        make(map[uint64]*common.GenericDLNode[*SegmentEntry]),
   125  	}
   126  }
   127  
   128  func (entry *TableEntry) IsVirtual() bool {
   129  	if !entry.db.IsSystemDB() {
   130  		return false
   131  	}
   132  	return entry.schema.Name == pkgcatalog.MO_DATABASE ||
   133  		entry.schema.Name == pkgcatalog.MO_TABLES ||
   134  		entry.schema.Name == pkgcatalog.MO_COLUMNS
   135  }
   136  
   137  func (entry *TableEntry) GetRows() uint64 {
   138  	return entry.rows.Load()
   139  }
   140  
   141  func (entry *TableEntry) AddRows(delta uint64) uint64 {
   142  	return entry.rows.Add(delta)
   143  }
   144  
   145  func (entry *TableEntry) RemoveRows(delta uint64) uint64 {
   146  	return entry.rows.Add(^(delta - 1))
   147  }
   148  
   149  func (entry *TableEntry) GetSegmentByID(id uint64) (seg *SegmentEntry, err error) {
   150  	entry.RLock()
   151  	defer entry.RUnlock()
   152  	node := entry.entries[id]
   153  	if node == nil {
   154  		return nil, moerr.GetOkExpectedEOB()
   155  	}
   156  	return node.GetPayload(), nil
   157  }
   158  
   159  func (entry *TableEntry) MakeSegmentIt(reverse bool) *common.GenericSortedDListIt[*SegmentEntry] {
   160  	entry.RLock()
   161  	defer entry.RUnlock()
   162  	return common.NewGenericSortedDListIt(entry.RWMutex, entry.link, reverse)
   163  }
   164  
   165  func (entry *TableEntry) CreateSegment(txn txnif.AsyncTxn, state EntryState, dataFactory SegmentDataFactory) (created *SegmentEntry, err error) {
   166  	entry.Lock()
   167  	defer entry.Unlock()
   168  	created = NewSegmentEntry(entry, txn, state, dataFactory)
   169  	entry.AddEntryLocked(created)
   170  	return
   171  }
   172  
   173  func (entry *TableEntry) MakeCommand(id uint32) (cmd txnif.TxnCmd, err error) {
   174  	cmdType := CmdUpdateTable
   175  	entry.RLock()
   176  	defer entry.RUnlock()
   177  	return newTableCmd(id, cmdType, entry), nil
   178  }
   179  
   180  func (entry *TableEntry) Set1PC() {
   181  	entry.GetLatestNodeLocked().Set1PC()
   182  }
   183  func (entry *TableEntry) Is1PC() bool {
   184  	return entry.GetLatestNodeLocked().Is1PC()
   185  }
   186  func (entry *TableEntry) AddEntryLocked(segment *SegmentEntry) {
   187  	n := entry.link.Insert(segment)
   188  	entry.entries[segment.GetID()] = n
   189  }
   190  
   191  func (entry *TableEntry) deleteEntryLocked(segment *SegmentEntry) error {
   192  	if n, ok := entry.entries[segment.GetID()]; !ok {
   193  		return moerr.GetOkExpectedEOB()
   194  	} else {
   195  		entry.link.Delete(n)
   196  		delete(entry.entries, segment.GetID())
   197  		segment.Close()
   198  	}
   199  	return nil
   200  }
   201  
   202  func (entry *TableEntry) GetSchema() *Schema {
   203  	return entry.schema
   204  }
   205  
   206  func (entry *TableEntry) GetColDefs() []*ColDef {
   207  	colDefs := entry.schema.ColDefs
   208  	colDefs = append(colDefs, entry.schema.PhyAddrKey)
   209  	return colDefs
   210  }
   211  
   212  func (entry *TableEntry) GetFullName() string {
   213  	if len(entry.fullName) == 0 {
   214  		entry.fullName = genTblFullName(entry.schema.AcInfo.TenantID, entry.schema.Name)
   215  	}
   216  	return entry.fullName
   217  }
   218  
   219  func (entry *TableEntry) GetDB() *DBEntry {
   220  	return entry.db
   221  }
   222  
   223  func (entry *TableEntry) PPString(level common.PPLevel, depth int, prefix string) string {
   224  	var w bytes.Buffer
   225  	_, _ = w.WriteString(fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, entry.StringWithLevel(level)))
   226  	if level == common.PPL0 {
   227  		return w.String()
   228  	}
   229  	it := entry.MakeSegmentIt(true)
   230  	for it.Valid() {
   231  		segment := it.Get().GetPayload()
   232  		_ = w.WriteByte('\n')
   233  		_, _ = w.WriteString(segment.PPString(level, depth+1, prefix))
   234  		it.Next()
   235  	}
   236  	return w.String()
   237  }
   238  
   239  func (entry *TableEntry) String() string {
   240  	entry.RLock()
   241  	defer entry.RUnlock()
   242  	return entry.StringLocked()
   243  }
   244  
   245  func (entry *TableEntry) StringWithLevel(level common.PPLevel) string {
   246  	entry.RLock()
   247  	defer entry.RUnlock()
   248  	return entry.StringLockedWithLevel(level)
   249  }
   250  func (entry *TableEntry) StringLockedWithLevel(level common.PPLevel) string {
   251  	if level <= common.PPL1 {
   252  		return fmt.Sprintf("TBL[%d][name=%s][C@%s,D@%s]",
   253  			entry.ID, entry.schema.Name, entry.GetCreatedAt().ToString(), entry.GetDeleteAt().ToString())
   254  	}
   255  	return fmt.Sprintf("TBL%s[name=%s]", entry.TableBaseEntry.StringLocked(), entry.schema.Name)
   256  }
   257  
   258  func (entry *TableEntry) StringLocked() string {
   259  	return entry.StringLockedWithLevel(common.PPL1)
   260  }
   261  
   262  func (entry *TableEntry) GetCatalog() *Catalog { return entry.db.catalog }
   263  
   264  func (entry *TableEntry) GetTableData() data.Table { return entry.tableData }
   265  
   266  func (entry *TableEntry) LastAppendableSegmemt() (seg *SegmentEntry) {
   267  	it := entry.MakeSegmentIt(false)
   268  	for it.Valid() {
   269  		itSeg := it.Get().GetPayload()
   270  		dropped := itSeg.HasDropCommitted()
   271  		if itSeg.IsAppendable() && !dropped {
   272  			seg = itSeg
   273  			break
   274  		}
   275  		it.Next()
   276  	}
   277  	return seg
   278  }
   279  
   280  func (entry *TableEntry) LastNonAppendableSegmemt() (seg *SegmentEntry) {
   281  	it := entry.MakeSegmentIt(false)
   282  	for it.Valid() {
   283  		itSeg := it.Get().GetPayload()
   284  		dropped := itSeg.HasDropCommitted()
   285  		if !itSeg.IsAppendable() && !dropped {
   286  			seg = itSeg
   287  			break
   288  		}
   289  		it.Next()
   290  	}
   291  	return seg
   292  }
   293  
   294  func (entry *TableEntry) AsCommonID() *common.ID {
   295  	return &common.ID{
   296  		TableID: entry.GetID(),
   297  	}
   298  }
   299  
   300  func (entry *TableEntry) RecurLoop(processor Processor) (err error) {
   301  	segIt := entry.MakeSegmentIt(true)
   302  	for segIt.Valid() {
   303  		segment := segIt.Get().GetPayload()
   304  		if err = processor.OnSegment(segment); err != nil {
   305  			if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   306  				err = nil
   307  				segIt.Next()
   308  				continue
   309  			}
   310  			break
   311  		}
   312  		blkIt := segment.MakeBlockIt(true)
   313  		for blkIt.Valid() {
   314  			block := blkIt.Get().GetPayload()
   315  			if err = processor.OnBlock(block); err != nil {
   316  				if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   317  					err = nil
   318  					blkIt.Next()
   319  					continue
   320  				}
   321  				break
   322  			}
   323  			blkIt.Next()
   324  		}
   325  		if err = processor.OnPostSegment(segment); err != nil {
   326  			break
   327  		}
   328  		segIt.Next()
   329  	}
   330  	if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   331  		err = nil
   332  	}
   333  	return err
   334  }
   335  
   336  func (entry *TableEntry) DropSegmentEntry(id uint64, txn txnif.AsyncTxn) (deleted *SegmentEntry, err error) {
   337  	seg, err := entry.GetSegmentByID(id)
   338  	if err != nil {
   339  		return
   340  	}
   341  	seg.Lock()
   342  	defer seg.Unlock()
   343  	needWait, waitTxn := seg.NeedWaitCommitting(txn.GetStartTS())
   344  	if needWait {
   345  		seg.Unlock()
   346  		waitTxn.GetTxnState(true)
   347  		seg.Lock()
   348  	}
   349  	var isNewNode bool
   350  	isNewNode, err = seg.DropEntryLocked(txn)
   351  	if err == nil && isNewNode {
   352  		deleted = seg
   353  	}
   354  	return
   355  }
   356  
   357  func (entry *TableEntry) RemoveEntry(segment *SegmentEntry) (err error) {
   358  	logutil.Info("[Catalog]", common.OperationField("remove"),
   359  		common.OperandField(segment.String()))
   360  	// segment.Close()
   361  	entry.Lock()
   362  	defer entry.Unlock()
   363  	return entry.deleteEntryLocked(segment)
   364  }
   365  
   366  func (entry *TableEntry) Close() {
   367  	segs := entry.getAllSegs()
   368  	entry.Lock()
   369  	defer entry.Unlock()
   370  	for _, seg := range segs {
   371  		err := entry.deleteEntryLocked(seg)
   372  		if err != nil {
   373  			panic(err)
   374  		}
   375  	}
   376  }
   377  
   378  func (entry *TableEntry) getAllSegs() []*SegmentEntry {
   379  	segs := make([]*SegmentEntry, 0)
   380  	it := entry.MakeSegmentIt(false)
   381  	for it.Valid() {
   382  		segs = append(segs, it.Get().GetPayload())
   383  		it.Next()
   384  	}
   385  	return segs
   386  }
   387  
   388  func (entry *TableEntry) PrepareRollback() (err error) {
   389  	var isEmpty bool
   390  	isEmpty, err = entry.TableBaseEntry.PrepareRollback()
   391  	if err != nil {
   392  		return
   393  	}
   394  	if isEmpty {
   395  		err = entry.GetDB().RemoveEntry(entry)
   396  		if err != nil {
   397  			return
   398  		}
   399  	}
   400  	return
   401  }
   402  
   403  func (entry *TableEntry) WriteTo(w io.Writer) (n int64, err error) {
   404  	if n, err = entry.TableBaseEntry.WriteAllTo(w); err != nil {
   405  		return
   406  	}
   407  	buf, err := entry.schema.Marshal()
   408  	if err != nil {
   409  		return
   410  	}
   411  	sn := int(0)
   412  	sn, err = w.Write(buf)
   413  	n += int64(sn)
   414  	return
   415  }
   416  
   417  func (entry *TableEntry) ReadFrom(r io.Reader) (n int64, err error) {
   418  	if n, err = entry.TableBaseEntry.ReadAllFrom(r); err != nil {
   419  		return
   420  	}
   421  	if entry.schema == nil {
   422  		entry.schema = NewEmptySchema("")
   423  	}
   424  	sn := int64(0)
   425  	sn, err = entry.schema.ReadFrom(r)
   426  	n += sn
   427  	return
   428  }
   429  
   430  // IsActive is coarse API: no consistency check
   431  func (entry *TableEntry) IsActive() bool {
   432  	db := entry.GetDB()
   433  	if !db.IsActive() {
   434  		return false
   435  	}
   436  	return !entry.HasDropCommitted()
   437  }
   438  
   439  // GetTerminationTS is coarse API: no consistency check
   440  func (entry *TableEntry) GetTerminationTS() (ts types.TS, terminated bool) {
   441  	dbEntry := entry.GetDB()
   442  
   443  	dbEntry.RLock()
   444  	terminated, ts = dbEntry.TryGetTerminatedTS(true)
   445  	dbEntry.RUnlock()
   446  
   447  	return
   448  }