github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/catalog/catalog.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  	"context"
    20  	"fmt"
    21  	"sync"
    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  // +--------+---------+----------+----------+------------+
    33  // |   ID   |  Name   | CreateAt | DeleteAt | CommitInfo |
    34  // +--------+---------+----------+----------+------------+
    35  // |(uint64)|(varchar)| (uint64) | (uint64) |  (varchar) |
    36  // +--------+---------+----------+----------+------------+
    37  const (
    38  	SnapshotAttr_TID            = "table_id"
    39  	SnapshotAttr_DBID           = "db_id"
    40  	ObjectAttr_ID               = "id"
    41  	ObjectAttr_CreateAt         = "create_at"
    42  	ObjectAttr_SegNode          = "seg_node"
    43  	SnapshotAttr_BlockMaxRow    = "block_max_row"
    44  	SnapshotAttr_ObjectMaxBlock = "Object_max_block"
    45  	SnapshotAttr_SchemaExtra    = "schema_extra"
    46  	AccountIDDbNameTblName      = "account_id_db_name_tbl_name"
    47  	AccountIDDbName             = "account_id_db_name"
    48  	ObjectAttr_ObjectStats      = "object_stats"
    49  	ObjectAttr_State            = "state"
    50  	ObjectAttr_Sorted           = "sorted"
    51  	EntryNode_CreateAt          = "create_at"
    52  	EntryNode_DeleteAt          = "delete_at"
    53  )
    54  
    55  type DataFactory interface {
    56  	MakeTableFactory() TableDataFactory
    57  	MakeObjectFactory() ObjectDataFactory
    58  	MakeTombstoneFactory() TombstoneFactory
    59  }
    60  
    61  type Catalog struct {
    62  	*IDAlloctor
    63  	*sync.RWMutex
    64  
    65  	usageMemo any
    66  	entries   map[uint64]*common.GenericDLNode[*DBEntry]
    67  	nameNodes map[string]*nodeList[*DBEntry]
    68  	link      *common.GenericSortedDList[*DBEntry]
    69  	nodesMu   sync.RWMutex
    70  }
    71  
    72  func MockCatalog() *Catalog {
    73  	catalog := &Catalog{
    74  		RWMutex:    new(sync.RWMutex),
    75  		IDAlloctor: NewIDAllocator(),
    76  		entries:    make(map[uint64]*common.GenericDLNode[*DBEntry]),
    77  		nameNodes:  make(map[string]*nodeList[*DBEntry]),
    78  		link:       common.NewGenericSortedDList((*DBEntry).Less),
    79  	}
    80  	catalog.InitSystemDB()
    81  	return catalog
    82  }
    83  
    84  func OpenCatalog(usageMemo any) (*Catalog, error) {
    85  	catalog := &Catalog{
    86  		RWMutex:    new(sync.RWMutex),
    87  		IDAlloctor: NewIDAllocator(),
    88  		entries:    make(map[uint64]*common.GenericDLNode[*DBEntry]),
    89  		nameNodes:  make(map[string]*nodeList[*DBEntry]),
    90  		link:       common.NewGenericSortedDList((*DBEntry).Less),
    91  		usageMemo:  usageMemo,
    92  	}
    93  	catalog.InitSystemDB()
    94  	return catalog, nil
    95  }
    96  
    97  //#region Catalog Manipulation
    98  
    99  func genDBFullName(tenantID uint32, name string) string {
   100  	if name == pkgcatalog.MO_CATALOG {
   101  		tenantID = 0
   102  	}
   103  	return fmt.Sprintf("%d-%s", tenantID, name)
   104  }
   105  
   106  func (catalog *Catalog) SetUsageMemo(memo any) {
   107  	catalog.usageMemo = memo
   108  }
   109  
   110  func (catalog *Catalog) GetUsageMemo() any {
   111  	return catalog.usageMemo
   112  }
   113  
   114  func (catalog *Catalog) InitSystemDB() {
   115  	sysDB := NewSystemDBEntry(catalog)
   116  	dbTables := NewSystemTableEntry(sysDB, pkgcatalog.MO_DATABASE_ID, SystemDBSchema)
   117  	tableTables := NewSystemTableEntry(sysDB, pkgcatalog.MO_TABLES_ID, SystemTableSchema)
   118  	columnTables := NewSystemTableEntry(sysDB, pkgcatalog.MO_COLUMNS_ID, SystemColumnSchema)
   119  	err := sysDB.AddEntryLocked(dbTables, nil, false)
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  	if err = sysDB.AddEntryLocked(tableTables, nil, false); err != nil {
   124  		panic(err)
   125  	}
   126  	if err = sysDB.AddEntryLocked(columnTables, nil, false); err != nil {
   127  		panic(err)
   128  	}
   129  	if err = catalog.AddEntryLocked(sysDB, nil, false); err != nil {
   130  		panic(err)
   131  	}
   132  }
   133  
   134  func (catalog *Catalog) GCByTS(ctx context.Context, ts types.TS) {
   135  	logutil.Infof("GC Catalog %v", ts.ToString())
   136  	processor := LoopProcessor{}
   137  	processor.DatabaseFn = func(d *DBEntry) error {
   138  		needGC := d.DeleteBefore(ts)
   139  		if needGC {
   140  			catalog.RemoveDBEntry(d)
   141  		}
   142  		return nil
   143  	}
   144  	processor.TableFn = func(te *TableEntry) error {
   145  		needGC := te.DeleteBefore(ts)
   146  		if needGC {
   147  			db := te.db
   148  			db.RemoveEntry(te)
   149  		}
   150  		return nil
   151  	}
   152  	processor.ObjectFn = func(se *ObjectEntry) error {
   153  		se.RLock()
   154  		needGC := se.DeleteBeforeLocked(ts) && !se.InMemoryDeletesExisted()
   155  		se.RUnlock()
   156  		if needGC {
   157  			tbl := se.table
   158  			tbl.RemoveEntry(se)
   159  		}
   160  		return nil
   161  	}
   162  	processor.TombstoneFn = func(t data.Tombstone) error {
   163  		obj := t.GetObject().(*ObjectEntry)
   164  		obj.RLock()
   165  		needGC := obj.DeleteBeforeLocked(ts) && !obj.InMemoryDeletesExisted()
   166  		obj.RUnlock()
   167  		if needGC {
   168  			tbl := obj.table
   169  			tbl.GCTombstone(obj.ID)
   170  		}
   171  		return nil
   172  	}
   173  	err := catalog.RecurLoop(&processor)
   174  	if err != nil {
   175  		panic(err)
   176  	}
   177  }
   178  
   179  func (catalog *Catalog) Close() error {
   180  	return nil
   181  }
   182  
   183  func (catalog *Catalog) GetItemNodeByIDLocked(id uint64) *common.GenericDLNode[*DBEntry] {
   184  	return catalog.entries[id]
   185  }
   186  
   187  func (catalog *Catalog) GetDatabaseByID(id uint64) (db *DBEntry, err error) {
   188  	catalog.RLock()
   189  	defer catalog.RUnlock()
   190  	node := catalog.entries[id]
   191  	if node == nil {
   192  		err = moerr.GetOkExpectedEOB()
   193  		return
   194  	}
   195  	db = node.GetPayload()
   196  	return
   197  }
   198  
   199  func (catalog *Catalog) AddEntryLocked(database *DBEntry, txn txnif.TxnReader, skipDedup bool) error {
   200  	nn := catalog.nameNodes[database.GetFullName()]
   201  	if nn == nil {
   202  		n := catalog.link.Insert(database)
   203  		catalog.entries[database.ID] = n
   204  
   205  		nn := newNodeList(catalog.GetItemNodeByIDLocked,
   206  			dbVisibilityFn[*DBEntry],
   207  			&catalog.nodesMu,
   208  			database.name)
   209  		catalog.nameNodes[database.GetFullName()] = nn
   210  
   211  		nn.CreateNode(database.ID)
   212  	} else {
   213  		node := nn.GetNode()
   214  		if !skipDedup {
   215  			record := node.GetPayload()
   216  			err := record.PrepareAdd(txn)
   217  			if err != nil {
   218  				return err
   219  			}
   220  		}
   221  		n := catalog.link.Insert(database)
   222  		catalog.entries[database.ID] = n
   223  		nn.CreateNode(database.ID)
   224  	}
   225  	return nil
   226  }
   227  
   228  func (catalog *Catalog) TxnGetDBEntryByName(name string, txn txnif.AsyncTxn) (*DBEntry, error) {
   229  	catalog.RLock()
   230  	defer catalog.RUnlock()
   231  	fullName := genDBFullName(txn.GetTenantID(), name)
   232  	node := catalog.nameNodes[fullName]
   233  	if node == nil {
   234  		return nil, moerr.NewBadDBNoCtx(name)
   235  	}
   236  	n, err := node.TxnGetNodeLocked(txn, "")
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  	return n.GetPayload(), nil
   241  }
   242  
   243  func (catalog *Catalog) TxnGetDBEntryByID(id uint64, txn txnif.AsyncTxn) (*DBEntry, error) {
   244  	dbEntry, err := catalog.GetDatabaseByID(id)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  	visiable, dropped := dbEntry.GetVisibility(txn)
   249  	if !visiable || dropped {
   250  		return nil, moerr.GetOkExpectedEOB()
   251  	}
   252  	return dbEntry, nil
   253  }
   254  
   255  // RemoveDBEntry removes a database entry from the catalog physically, triggered by GC Task
   256  func (catalog *Catalog) RemoveDBEntry(database *DBEntry) error {
   257  	if database.IsSystemDB() {
   258  		logutil.Warnf("system db cannot be removed")
   259  		return moerr.NewTAEErrorNoCtx("not permitted")
   260  	}
   261  	logutil.Info("[Catalog]", common.OperationField("remove"),
   262  		common.OperandField(database.String()))
   263  	catalog.Lock()
   264  	defer catalog.Unlock()
   265  	if n, ok := catalog.entries[database.ID]; !ok {
   266  		return moerr.NewBadDBNoCtx(database.GetName())
   267  	} else {
   268  		nn := catalog.nameNodes[database.GetFullName()]
   269  		nn.DeleteNode(database.ID)
   270  		catalog.link.Delete(n)
   271  		if nn.Length() == 0 {
   272  			delete(catalog.nameNodes, database.GetFullName())
   273  		}
   274  		delete(catalog.entries, database.ID)
   275  	}
   276  	return nil
   277  }
   278  
   279  // DropDBEntry attach a drop mvvc node the entry.
   280  func (catalog *Catalog) DropDBEntry(entry *DBEntry, txn txnif.AsyncTxn) (isNewMVCCNode bool, err error) {
   281  	if entry.IsSystemDB() {
   282  		return false, moerr.NewTAEErrorNoCtx("not permitted")
   283  	}
   284  	entry.Lock()
   285  	defer entry.Unlock()
   286  	isNewMVCCNode, err = entry.DropEntryLocked(txn)
   287  	return
   288  }
   289  
   290  func (catalog *Catalog) DropDBEntryByName(
   291  	name string,
   292  	txn txnif.AsyncTxn) (isNewMVCCNode bool, deleted *DBEntry, err error) {
   293  	deleted, err = catalog.TxnGetDBEntryByName(name, txn)
   294  	if err != nil {
   295  		return
   296  	}
   297  	isNewMVCCNode, err = catalog.DropDBEntry(deleted, txn)
   298  	return
   299  }
   300  
   301  func (catalog *Catalog) DropDBEntryByID(id uint64, txn txnif.AsyncTxn) (isNewMVCCNode bool, deleted *DBEntry, err error) {
   302  	deleted, err = catalog.TxnGetDBEntryByID(id, txn)
   303  	if err != nil {
   304  		return
   305  	}
   306  	isNewMVCCNode, err = catalog.DropDBEntry(deleted, txn)
   307  	return
   308  }
   309  
   310  func (catalog *Catalog) CreateDBEntry(name, createSql, datTyp string, txn txnif.AsyncTxn) (*DBEntry, error) {
   311  	id := catalog.NextDB()
   312  	return catalog.CreateDBEntryWithID(name, createSql, datTyp, id, txn)
   313  }
   314  
   315  func (catalog *Catalog) CreateDBEntryWithID(name, createSql, datTyp string, id uint64, txn txnif.AsyncTxn) (*DBEntry, error) {
   316  	var err error
   317  	catalog.Lock()
   318  	defer catalog.Unlock()
   319  	if _, exist := catalog.entries[id]; exist {
   320  		return nil, moerr.GetOkExpectedDup()
   321  	}
   322  	entry := NewDBEntryWithID(catalog, name, createSql, datTyp, id, txn)
   323  	err = catalog.AddEntryLocked(entry, txn, false)
   324  
   325  	return entry, err
   326  }
   327  
   328  //#endregion
   329  
   330  //#region - Utils for Catalog
   331  
   332  func (catalog *Catalog) MakeDBIt(reverse bool) *common.GenericSortedDListIt[*DBEntry] {
   333  	catalog.RLock()
   334  	defer catalog.RUnlock()
   335  	return common.NewGenericSortedDListIt(catalog.RWMutex, catalog.link, reverse)
   336  }
   337  
   338  func (catalog *Catalog) SimplePPString(level common.PPLevel) string {
   339  	return catalog.PPString(level, 0, "")
   340  }
   341  
   342  func (catalog *Catalog) PPString(level common.PPLevel, depth int, prefix string) string {
   343  	var w bytes.Buffer
   344  	cnt := 0
   345  	it := catalog.MakeDBIt(true)
   346  	for ; it.Valid(); it.Next() {
   347  		cnt++
   348  		entry := it.Get().GetPayload()
   349  		_ = w.WriteByte('\n')
   350  		_, _ = w.WriteString(entry.PPString(level, depth+1, ""))
   351  	}
   352  
   353  	var w2 bytes.Buffer
   354  	_, _ = w2.WriteString(fmt.Sprintf("CATALOG[CNT=%d]", cnt))
   355  	_, _ = w2.WriteString(w.String())
   356  	return w2.String()
   357  }
   358  
   359  func (catalog *Catalog) RecurLoop(processor Processor) (err error) {
   360  	dbIt := catalog.MakeDBIt(true)
   361  	for ; dbIt.Valid(); dbIt.Next() {
   362  		dbEntry := dbIt.Get().GetPayload()
   363  		if err = processor.OnDatabase(dbEntry); err != nil {
   364  			if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   365  				err = nil
   366  				continue
   367  			}
   368  			break
   369  		}
   370  		if err = dbEntry.RecurLoop(processor); err != nil {
   371  			return
   372  		}
   373  		if err = processor.OnPostDatabase(dbEntry); err != nil {
   374  			break
   375  		}
   376  	}
   377  	if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   378  		err = nil
   379  	}
   380  	return err
   381  }
   382  
   383  //#endregion