github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/database.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  	"encoding/binary"
    20  	"fmt"
    21  	"io"
    22  	"sync"
    23  
    24  	pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog"
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/logutil"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    30  )
    31  
    32  type accessInfo struct {
    33  	TenantID, UserID, RoleID uint32
    34  	CreateAt                 types.Timestamp
    35  }
    36  
    37  func (ai *accessInfo) WriteTo(w io.Writer) (n int64, err error) {
    38  	for _, id := range []uint32{ai.TenantID, ai.UserID, ai.RoleID} {
    39  		if err = binary.Write(w, binary.BigEndian, id); err != nil {
    40  			return
    41  		}
    42  	}
    43  	if err = binary.Write(w, binary.BigEndian, int64(ai.CreateAt)); err != nil {
    44  		return
    45  	}
    46  	return 20, nil
    47  }
    48  
    49  func (ai *accessInfo) ReadFrom(r io.Reader) (n int64, err error) {
    50  	for _, idPtr := range []*uint32{&ai.TenantID, &ai.UserID, &ai.RoleID} {
    51  		if err = binary.Read(r, binary.BigEndian, idPtr); err != nil {
    52  			return
    53  		}
    54  	}
    55  	at := int64(0)
    56  	if err = binary.Read(r, binary.BigEndian, &at); err != nil {
    57  		return
    58  	}
    59  	ai.CreateAt = types.Timestamp(at)
    60  	return 20, nil
    61  }
    62  
    63  func dbVisibilityFn[T *DBEntry](n *common.GenericDLNode[*DBEntry], ts types.TS) (visible, dropped bool) {
    64  	db := n.GetPayload()
    65  	visible, dropped = db.GetVisibility(ts)
    66  	return
    67  }
    68  
    69  type DBEntry struct {
    70  	*DBBaseEntry
    71  	catalog   *Catalog
    72  	acInfo    accessInfo
    73  	name      string
    74  	createSql string
    75  	fullName  string
    76  	isSys     bool
    77  
    78  	entries   map[uint64]*common.GenericDLNode[*TableEntry]
    79  	nameNodes map[string]*nodeList[*TableEntry]
    80  	link      *common.GenericSortedDList[*TableEntry]
    81  
    82  	nodesMu sync.RWMutex
    83  }
    84  
    85  func compareTableFn(a, b *TableEntry) int {
    86  	return a.TableBaseEntry.DoCompre(b.TableBaseEntry)
    87  }
    88  
    89  func NewDBEntryWithID(catalog *Catalog, name string, createSql string, id uint64, txn txnif.AsyncTxn) *DBEntry {
    90  	//id := catalog.NextDB()
    91  
    92  	e := &DBEntry{
    93  		DBBaseEntry: NewDBBaseEntry(id),
    94  		catalog:     catalog,
    95  		name:        name,
    96  		createSql:   createSql,
    97  		entries:     make(map[uint64]*common.GenericDLNode[*TableEntry]),
    98  		nameNodes:   make(map[string]*nodeList[*TableEntry]),
    99  		link:        common.NewGenericSortedDList(compareTableFn),
   100  	}
   101  	if txn != nil {
   102  		// Only in unit test, txn can be nil
   103  		e.acInfo.TenantID = txn.GetTenantID()
   104  		e.acInfo.UserID, e.acInfo.RoleID = txn.GetUserAndRoleID()
   105  	}
   106  	e.CreateWithTxn(txn)
   107  	e.acInfo.CreateAt = types.CurrentTimestamp()
   108  	return e
   109  }
   110  
   111  func NewDBEntry(catalog *Catalog, name, createSql string, txn txnif.AsyncTxn) *DBEntry {
   112  	id := catalog.NextDB()
   113  
   114  	e := &DBEntry{
   115  		DBBaseEntry: NewDBBaseEntry(id),
   116  		catalog:     catalog,
   117  		name:        name,
   118  		createSql:   createSql,
   119  		entries:     make(map[uint64]*common.GenericDLNode[*TableEntry]),
   120  		nameNodes:   make(map[string]*nodeList[*TableEntry]),
   121  		link:        common.NewGenericSortedDList(compareTableFn),
   122  	}
   123  	if txn != nil {
   124  		// Only in unit test, txn can be nil
   125  		e.acInfo.TenantID = txn.GetTenantID()
   126  		e.acInfo.UserID, e.acInfo.RoleID = txn.GetUserAndRoleID()
   127  	}
   128  	e.CreateWithTxn(txn)
   129  	e.acInfo.CreateAt = types.CurrentTimestamp()
   130  	return e
   131  }
   132  
   133  func NewDBEntryByTS(catalog *Catalog, name string, ts types.TS) *DBEntry {
   134  	id := catalog.NextDB()
   135  
   136  	e := &DBEntry{
   137  		DBBaseEntry: NewDBBaseEntry(id),
   138  		catalog:     catalog,
   139  		name:        name,
   140  		entries:     make(map[uint64]*common.GenericDLNode[*TableEntry]),
   141  		nameNodes:   make(map[string]*nodeList[*TableEntry]),
   142  		link:        common.NewGenericSortedDList(compareTableFn),
   143  	}
   144  	e.CreateWithTS(ts)
   145  	e.acInfo.CreateAt = types.CurrentTimestamp()
   146  	return e
   147  }
   148  
   149  func NewSystemDBEntry(catalog *Catalog) *DBEntry {
   150  	entry := &DBEntry{
   151  		DBBaseEntry: NewDBBaseEntry(pkgcatalog.MO_CATALOG_ID),
   152  		catalog:     catalog,
   153  		name:        pkgcatalog.MO_CATALOG,
   154  		createSql:   "create database " + pkgcatalog.MO_CATALOG,
   155  		entries:     make(map[uint64]*common.GenericDLNode[*TableEntry]),
   156  		nameNodes:   make(map[string]*nodeList[*TableEntry]),
   157  		link:        common.NewGenericSortedDList(compareTableFn),
   158  		isSys:       true,
   159  	}
   160  	entry.CreateWithTS(types.SystemDBTS)
   161  	return entry
   162  }
   163  
   164  func NewReplayDBEntry() *DBEntry {
   165  	entry := &DBEntry{
   166  		DBBaseEntry: NewReplayDBBaseEntry(),
   167  		entries:     make(map[uint64]*common.GenericDLNode[*TableEntry]),
   168  		nameNodes:   make(map[string]*nodeList[*TableEntry]),
   169  		link:        common.NewGenericSortedDList(compareTableFn),
   170  	}
   171  	return entry
   172  }
   173  
   174  func (e *DBEntry) IsSystemDB() bool { return e.isSys }
   175  func (e *DBEntry) CoarseTableCnt() int {
   176  	e.RLock()
   177  	defer e.RUnlock()
   178  	return len(e.entries)
   179  }
   180  
   181  func (e *DBEntry) GetTenantID() uint32          { return e.acInfo.TenantID }
   182  func (e *DBEntry) GetUserID() uint32            { return e.acInfo.UserID }
   183  func (e *DBEntry) GetRoleID() uint32            { return e.acInfo.RoleID }
   184  func (e *DBEntry) GetCreateAt() types.Timestamp { return e.acInfo.CreateAt }
   185  func (e *DBEntry) GetName() string              { return e.name }
   186  func (e *DBEntry) GetCreateSql() string         { return e.createSql }
   187  func (e *DBEntry) GetFullName() string {
   188  	if len(e.fullName) == 0 {
   189  		e.fullName = genDBFullName(e.acInfo.TenantID, e.name)
   190  	}
   191  	return e.fullName
   192  }
   193  
   194  func (e *DBEntry) String() string {
   195  	e.RLock()
   196  	defer e.RUnlock()
   197  	return e.StringLocked()
   198  }
   199  
   200  func (e *DBEntry) StringLocked() string {
   201  	return e.StringWithlevelLocked(common.PPL1)
   202  }
   203  func (e *DBEntry) StringWithLevel(level common.PPLevel) string {
   204  	e.RLock()
   205  	defer e.RUnlock()
   206  	return e.StringWithlevelLocked(level)
   207  }
   208  
   209  func (e *DBEntry) StringWithlevelLocked(level common.PPLevel) string {
   210  	if level <= common.PPL1 {
   211  		return fmt.Sprintf("DB[%d][name=%s][C@%s,D@%s]",
   212  			e.DBBaseEntry.ID, e.GetFullName(), e.GetCreatedAt().ToString(), e.GetDeleteAt().ToString())
   213  	}
   214  	return fmt.Sprintf("DB%s[name=%s]", e.DBBaseEntry.StringLocked(), e.GetFullName())
   215  }
   216  
   217  func (e *DBEntry) MakeTableIt(reverse bool) *common.GenericSortedDListIt[*TableEntry] {
   218  	e.RLock()
   219  	defer e.RUnlock()
   220  	return common.NewGenericSortedDListIt(e.RWMutex, e.link, reverse)
   221  }
   222  
   223  func (e *DBEntry) 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, e.StringWithLevel(level)))
   226  	if level == common.PPL0 {
   227  		return w.String()
   228  	}
   229  	it := e.MakeTableIt(true)
   230  	for it.Valid() {
   231  		table := it.Get().GetPayload()
   232  		_ = w.WriteByte('\n')
   233  		_, _ = w.WriteString(table.PPString(level, depth+1, ""))
   234  		it.Next()
   235  	}
   236  	return w.String()
   237  }
   238  
   239  func (e *DBEntry) GetBlockEntryByID(id *common.ID) (blk *BlockEntry, err error) {
   240  	e.RLock()
   241  	table, err := e.GetTableEntryByID(id.TableID)
   242  	e.RUnlock()
   243  	if err != nil {
   244  		return
   245  	}
   246  	seg, err := table.GetSegmentByID(id.SegmentID)
   247  	if err != nil {
   248  		return
   249  	}
   250  	blk, err = seg.GetBlockEntryByID(id.BlockID)
   251  	return
   252  }
   253  
   254  func (e *DBEntry) GetItemNodeByIDLocked(id uint64) *common.GenericDLNode[*TableEntry] {
   255  	return e.entries[id]
   256  }
   257  
   258  func (e *DBEntry) GetTableEntryByID(id uint64) (table *TableEntry, err error) {
   259  	e.RLock()
   260  	defer e.RUnlock()
   261  	node := e.entries[id]
   262  	if node == nil {
   263  		return nil, moerr.GetOkExpectedEOB()
   264  	}
   265  	table = node.GetPayload()
   266  	return
   267  }
   268  
   269  func (e *DBEntry) txnGetNodeByName(
   270  	tenantID uint32,
   271  	name string,
   272  	ts types.TS) (*common.GenericDLNode[*TableEntry], error) {
   273  	e.RLock()
   274  	defer e.RUnlock()
   275  	fullName := genTblFullName(tenantID, name)
   276  	node := e.nameNodes[fullName]
   277  	if node == nil {
   278  		return nil, moerr.GetOkExpectedEOB()
   279  	}
   280  	return node.TxnGetNodeLocked(ts)
   281  }
   282  
   283  func (e *DBEntry) TxnGetTableEntryByName(name string, txn txnif.AsyncTxn) (entry *TableEntry, err error) {
   284  	n, err := e.txnGetNodeByName(txn.GetTenantID(), name, txn.GetStartTS())
   285  	if err != nil {
   286  		return
   287  	}
   288  	entry = n.GetPayload()
   289  	return
   290  }
   291  
   292  func (e *DBEntry) GetTableEntryByName(
   293  	tenantID uint32,
   294  	name string,
   295  	ts types.TS) (entry *TableEntry, err error) {
   296  	n, err := e.txnGetNodeByName(tenantID, name, ts)
   297  	if err != nil {
   298  		return
   299  	}
   300  	entry = n.GetPayload()
   301  	return
   302  }
   303  
   304  func (e *DBEntry) TxnGetTableEntryByID(id uint64, txn txnif.AsyncTxn) (entry *TableEntry, err error) {
   305  	entry, err = e.GetTableEntryByID(id)
   306  	if err != nil {
   307  		return
   308  	}
   309  	//check whether visible and dropped.
   310  	visible, dropped := entry.GetVisibility(txn.GetStartTS())
   311  	if !visible || dropped {
   312  		return nil, moerr.GetOkExpectedEOB()
   313  	}
   314  	return
   315  }
   316  
   317  // Catalog entry is dropped in following steps:
   318  // 1. Locate the record by timestamp
   319  // 2. Check conflication.
   320  // 2.1 Wait for the related txn if need.
   321  // 2.2 w-w conflict when 1. there's an active txn; or
   322  //  2. the CommitTS of the latest related txn is larger than StartTS of write txn
   323  //
   324  // 3. Check duplicate/not found.
   325  // If the entry has already been dropped, return ErrNotFound.
   326  func (e *DBEntry) DropTableEntry(name string, txn txnif.AsyncTxn) (newEntry bool, deleted *TableEntry, err error) {
   327  	dn, err := e.txnGetNodeByName(txn.GetTenantID(), name, txn.GetStartTS())
   328  	if err != nil {
   329  		return
   330  	}
   331  	entry := dn.GetPayload()
   332  	entry.Lock()
   333  	defer entry.Unlock()
   334  	newEntry, err = entry.DropEntryLocked(txn)
   335  	if err == nil {
   336  		deleted = entry
   337  	}
   338  	return
   339  }
   340  
   341  func (e *DBEntry) DropTableEntryByID(id uint64, txn txnif.AsyncTxn) (newEntry bool, deleted *TableEntry, err error) {
   342  	entry, err := e.GetTableEntryByID(id)
   343  	if err != nil {
   344  		return
   345  	}
   346  
   347  	entry.Lock()
   348  	defer entry.Unlock()
   349  	newEntry, err = entry.DropEntryLocked(txn)
   350  	if err == nil {
   351  		deleted = entry
   352  	}
   353  	return
   354  }
   355  
   356  func (e *DBEntry) CreateTableEntry(schema *Schema, txn txnif.AsyncTxn, dataFactory TableDataFactory) (created *TableEntry, err error) {
   357  	e.Lock()
   358  	created = NewTableEntry(e, schema, txn, dataFactory)
   359  	err = e.AddEntryLocked(created, txn, false)
   360  	e.Unlock()
   361  
   362  	return created, err
   363  }
   364  
   365  func (e *DBEntry) CreateTableEntryWithTableId(schema *Schema, txn txnif.AsyncTxn, dataFactory TableDataFactory, tableId uint64) (created *TableEntry, err error) {
   366  	e.Lock()
   367  	//Deduplicate for tableId
   368  	if _, exist := e.entries[tableId]; exist {
   369  		return nil, moerr.GetOkExpectedDup()
   370  	}
   371  	created = NewTableEntryWithTableId(e, schema, txn, dataFactory, tableId)
   372  	err = e.AddEntryLocked(created, txn, false)
   373  	e.Unlock()
   374  
   375  	return created, err
   376  }
   377  
   378  func (e *DBEntry) RemoveEntry(table *TableEntry) (err error) {
   379  	defer func() {
   380  		if err == nil {
   381  			e.catalog.AddTableCnt(-1)
   382  			e.catalog.AddColumnCnt(-1 * len(table.schema.ColDefs))
   383  		}
   384  	}()
   385  	// table.Close()
   386  	logutil.Info("[Catalog]", common.OperationField("remove"),
   387  		common.OperandField(table.String()))
   388  	e.Lock()
   389  	defer e.Unlock()
   390  	if n, ok := e.entries[table.GetID()]; !ok {
   391  		return moerr.GetOkExpectedEOB()
   392  	} else {
   393  		nn := e.nameNodes[table.GetFullName()]
   394  		nn.DeleteNode(table.GetID())
   395  		e.link.Delete(n)
   396  		if nn.Length() == 0 {
   397  			delete(e.nameNodes, table.GetFullName())
   398  		}
   399  		delete(e.entries, table.GetID())
   400  	}
   401  	return
   402  }
   403  
   404  func (e *DBEntry) Close() {
   405  	tbls := e.getAllTablesLocked()
   406  	for _, tbl := range tbls {
   407  		err := e.RemoveEntry(tbl)
   408  		if err != nil {
   409  			panic(err)
   410  		}
   411  	}
   412  }
   413  
   414  func (e *DBEntry) getAllTablesLocked() []*TableEntry {
   415  	tbls := make([]*TableEntry, 0)
   416  	it := e.MakeTableIt(false)
   417  	for it.Valid() {
   418  		tbls = append(tbls, it.Get().GetPayload())
   419  		it.Next()
   420  	}
   421  	return tbls
   422  }
   423  
   424  // Catalog entry is created in following steps:
   425  // 1. Locate the record. Creating always gets the latest DBEntry.
   426  // 2.1 If there doesn't exist a DBEntry, add new entry and return.
   427  // 2.2 If there exists a DBEntry:
   428  // 2.2.1 Check conflication.
   429  //  1. Wait for the related txn if need.
   430  //  2. w-w conflict when: there's an active txn; or
   431  //     he CommitTS of the latest related txn is larger than StartTS of write txn
   432  //
   433  // 2.2.2 Check duplicate/not found.
   434  // If the entry hasn't been dropped, return ErrDuplicate.
   435  func (e *DBEntry) AddEntryLocked(table *TableEntry, txn txnif.TxnReader, skipDedup bool) (err error) {
   436  	defer func() {
   437  		if err == nil {
   438  			e.catalog.AddTableCnt(1)
   439  			e.catalog.AddColumnCnt(len(table.schema.ColDefs))
   440  		}
   441  	}()
   442  	fullName := table.GetFullName()
   443  	nn := e.nameNodes[fullName]
   444  	if nn == nil {
   445  		n := e.link.Insert(table)
   446  		e.entries[table.GetID()] = n
   447  
   448  		nn := newNodeList(e.GetItemNodeByIDLocked,
   449  			tableVisibilityFn[*TableEntry],
   450  			&e.nodesMu,
   451  			fullName)
   452  		e.nameNodes[fullName] = nn
   453  
   454  		nn.CreateNode(table.GetID())
   455  	} else {
   456  		node := nn.GetNode()
   457  		if !skipDedup {
   458  			record := node.GetPayload()
   459  			err = record.PrepareAdd(txn)
   460  			if err != nil {
   461  				return
   462  			}
   463  		}
   464  		n := e.link.Insert(table)
   465  		e.entries[table.GetID()] = n
   466  		nn.CreateNode(table.GetID())
   467  	}
   468  	return
   469  }
   470  
   471  func (e *DBEntry) MakeCommand(id uint32) (txnif.TxnCmd, error) {
   472  	cmdType := CmdUpdateDatabase
   473  	e.RLock()
   474  	defer e.RUnlock()
   475  	return newDBCmd(id, cmdType, e), nil
   476  }
   477  
   478  func (e *DBEntry) Set1PC() {
   479  	e.GetLatestNodeLocked().Set1PC()
   480  }
   481  func (e *DBEntry) Is1PC() bool {
   482  	return e.GetLatestNodeLocked().Is1PC()
   483  }
   484  func (e *DBEntry) GetCatalog() *Catalog { return e.catalog }
   485  
   486  func (e *DBEntry) RecurLoop(processor Processor) (err error) {
   487  	tableIt := e.MakeTableIt(true)
   488  	for tableIt.Valid() {
   489  		table := tableIt.Get().GetPayload()
   490  		if err = processor.OnTable(table); err != nil {
   491  			if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   492  				err = nil
   493  				tableIt.Next()
   494  				continue
   495  			}
   496  			break
   497  		}
   498  		if err = table.RecurLoop(processor); err != nil {
   499  			return
   500  		}
   501  		tableIt.Next()
   502  	}
   503  	if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) {
   504  		err = nil
   505  	}
   506  	return err
   507  }
   508  
   509  func (e *DBEntry) PrepareRollback() (err error) {
   510  	var isEmpty bool
   511  	if isEmpty, err = e.DBBaseEntry.PrepareRollback(); err != nil {
   512  		return
   513  	}
   514  	if isEmpty {
   515  		if err = e.catalog.RemoveEntry(e); err != nil {
   516  			return
   517  		}
   518  	}
   519  	return
   520  }
   521  
   522  func (e *DBEntry) WriteTo(w io.Writer) (n int64, err error) {
   523  	if n, err = e.DBBaseEntry.WriteAllTo(w); err != nil {
   524  		return
   525  	}
   526  	x, err := e.acInfo.WriteTo(w)
   527  	if err != nil {
   528  		return
   529  	}
   530  	n += x
   531  	if err = binary.Write(w, binary.BigEndian, uint16(len(e.name))); err != nil {
   532  		return
   533  	}
   534  	var sn int
   535  	sn, err = w.Write([]byte(e.name))
   536  	if err != nil {
   537  		return
   538  	}
   539  	n += int64(sn) + 2
   540  	if err = binary.Write(w, binary.BigEndian, uint16(len(e.createSql))); err != nil {
   541  		return
   542  	}
   543  	sn, err = w.Write([]byte(e.createSql))
   544  	n += int64(sn) + 2
   545  	return
   546  }
   547  
   548  func (e *DBEntry) ReadFrom(r io.Reader) (n int64, err error) {
   549  	if n, err = e.DBBaseEntry.ReadAllFrom(r); err != nil {
   550  		return
   551  	}
   552  	x, err := e.acInfo.ReadFrom(r)
   553  	if err != nil {
   554  		return
   555  	}
   556  	n += x
   557  	size := uint16(0)
   558  	if err = binary.Read(r, binary.BigEndian, &size); err != nil {
   559  		return
   560  	}
   561  	n += 2
   562  	buf := make([]byte, size)
   563  	if _, err = r.Read(buf); err != nil {
   564  		return
   565  	}
   566  	n += int64(size)
   567  	e.name = string(buf)
   568  
   569  	if err = binary.Read(r, binary.BigEndian, &size); err != nil {
   570  		return
   571  	}
   572  	n += 2
   573  	buf = make([]byte, size)
   574  	if _, err = r.Read(buf); err != nil {
   575  		return
   576  	}
   577  	n += int64(size)
   578  	e.createSql = string(buf)
   579  	return
   580  }
   581  
   582  // IsActive is coarse API: no consistency check
   583  func (e *DBEntry) IsActive() bool {
   584  	return !e.HasDropCommitted()
   585  }