github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/block.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  	"encoding/binary"
    19  	"fmt"
    20  	"io"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/container/types"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    27  )
    28  
    29  type BlockDataFactory = func(meta *BlockEntry) data.Block
    30  
    31  func compareBlockFn(a, b *BlockEntry) int {
    32  	return a.MetaBaseEntry.DoCompre(b.MetaBaseEntry)
    33  }
    34  
    35  type BlockEntry struct {
    36  	*MetaBaseEntry
    37  	segment *SegmentEntry
    38  	state   EntryState
    39  	blkData data.Block
    40  }
    41  
    42  func NewReplayBlockEntry() *BlockEntry {
    43  	return &BlockEntry{
    44  		MetaBaseEntry: NewReplayMetaBaseEntry(),
    45  	}
    46  }
    47  
    48  func NewBlockEntry(segment *SegmentEntry, txn txnif.AsyncTxn, state EntryState, dataFactory BlockDataFactory) *BlockEntry {
    49  	id := segment.GetTable().GetDB().catalog.NextBlock()
    50  	e := &BlockEntry{
    51  		MetaBaseEntry: NewMetaBaseEntry(id),
    52  		segment:       segment,
    53  		state:         state,
    54  	}
    55  	if dataFactory != nil {
    56  		e.blkData = dataFactory(e)
    57  	}
    58  	e.MetaBaseEntry.CreateWithTxn(txn)
    59  	return e
    60  }
    61  
    62  func NewBlockEntryWithMeta(
    63  	segment *SegmentEntry,
    64  	txn txnif.AsyncTxn,
    65  	state EntryState,
    66  	dataFactory BlockDataFactory,
    67  	metaLoc string,
    68  	deltaLoc string) *BlockEntry {
    69  	id := segment.GetTable().GetDB().catalog.NextBlock()
    70  	e := &BlockEntry{
    71  		MetaBaseEntry: NewMetaBaseEntry(id),
    72  		segment:       segment,
    73  		state:         state,
    74  	}
    75  	e.MetaBaseEntry.CreateWithTxnAndMeta(txn, metaLoc, deltaLoc)
    76  	if dataFactory != nil {
    77  		e.blkData = dataFactory(e)
    78  	}
    79  	return e
    80  }
    81  
    82  func NewStandaloneBlock(segment *SegmentEntry, id uint64, ts types.TS) *BlockEntry {
    83  	e := &BlockEntry{
    84  		MetaBaseEntry: NewMetaBaseEntry(id),
    85  		segment:       segment,
    86  		state:         ES_Appendable,
    87  	}
    88  	e.MetaBaseEntry.CreateWithTS(ts)
    89  	return e
    90  }
    91  
    92  func NewStandaloneBlockWithLoc(
    93  	segment *SegmentEntry,
    94  	id uint64,
    95  	ts types.TS,
    96  	metaLoc string,
    97  	delLoc string) *BlockEntry {
    98  	e := &BlockEntry{
    99  		MetaBaseEntry: NewMetaBaseEntry(id),
   100  		segment:       segment,
   101  		state:         ES_NotAppendable,
   102  	}
   103  	e.MetaBaseEntry.CreateWithLoc(ts, metaLoc, delLoc)
   104  	return e
   105  }
   106  
   107  func NewSysBlockEntry(segment *SegmentEntry, id uint64) *BlockEntry {
   108  	e := &BlockEntry{
   109  		MetaBaseEntry: NewMetaBaseEntry(id),
   110  		segment:       segment,
   111  		state:         ES_Appendable,
   112  	}
   113  	e.MetaBaseEntry.CreateWithTS(types.SystemDBTS)
   114  	return e
   115  }
   116  
   117  func (entry *BlockEntry) GetCatalog() *Catalog { return entry.segment.table.db.catalog }
   118  
   119  func (entry *BlockEntry) IsAppendable() bool {
   120  	return entry.state == ES_Appendable
   121  }
   122  
   123  func (entry *BlockEntry) GetSegment() *SegmentEntry {
   124  	return entry.segment
   125  }
   126  
   127  func (entry *BlockEntry) MakeCommand(id uint32) (cmd txnif.TxnCmd, err error) {
   128  	cmdType := CmdUpdateBlock
   129  	entry.RLock()
   130  	defer entry.RUnlock()
   131  	return newBlockCmd(id, cmdType, entry), nil
   132  }
   133  
   134  func (entry *BlockEntry) Set1PC() {
   135  	entry.GetLatestNodeLocked().Set1PC()
   136  }
   137  func (entry *BlockEntry) Is1PC() bool {
   138  	return entry.GetLatestNodeLocked().Is1PC()
   139  }
   140  func (entry *BlockEntry) PPString(level common.PPLevel, depth int, prefix string) string {
   141  	s := fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, entry.StringWithLevelLocked(level))
   142  	return s
   143  }
   144  
   145  func (entry *BlockEntry) Repr() string {
   146  	id := entry.AsCommonID()
   147  	return fmt.Sprintf("[%s]BLK[%s]", entry.state.Repr(), id.String())
   148  }
   149  
   150  func (entry *BlockEntry) String() string {
   151  	entry.RLock()
   152  	defer entry.RUnlock()
   153  	return entry.StringLocked()
   154  }
   155  
   156  func (entry *BlockEntry) StringLocked() string {
   157  	return fmt.Sprintf("[%s]BLK%s", entry.state.Repr(), entry.MetaBaseEntry.StringLocked())
   158  }
   159  
   160  func (entry *BlockEntry) StringWithLevel(level common.PPLevel) string {
   161  	entry.RLock()
   162  	defer entry.RUnlock()
   163  	return entry.StringWithLevelLocked(level)
   164  }
   165  
   166  func (entry *BlockEntry) StringWithLevelLocked(level common.PPLevel) string {
   167  	if level <= common.PPL1 {
   168  		return fmt.Sprintf("[%s]BLK[%d][C@%s,D@%s]",
   169  			entry.state.Repr(), entry.ID, entry.GetCreatedAt().ToString(), entry.GetDeleteAt().ToString())
   170  	}
   171  	return fmt.Sprintf("[%s]BLK%s", entry.state.Repr(), entry.MetaBaseEntry.StringLocked())
   172  }
   173  
   174  func (entry *BlockEntry) AsCommonID() *common.ID {
   175  	return &common.ID{
   176  		TableID:   entry.GetSegment().GetTable().GetID(),
   177  		SegmentID: entry.GetSegment().GetID(),
   178  		BlockID:   entry.GetID(),
   179  	}
   180  }
   181  
   182  func (entry *BlockEntry) InitData(factory DataFactory) {
   183  	if factory == nil {
   184  		return
   185  	}
   186  	dataFactory := factory.MakeBlockFactory()
   187  	entry.blkData = dataFactory(entry)
   188  }
   189  func (entry *BlockEntry) GetBlockData() data.Block { return entry.blkData }
   190  func (entry *BlockEntry) GetSchema() *Schema       { return entry.GetSegment().GetTable().GetSchema() }
   191  func (entry *BlockEntry) PrepareRollback() (err error) {
   192  	var empty bool
   193  	empty, err = entry.MetaBaseEntry.PrepareRollback()
   194  	if err != nil {
   195  		panic(err)
   196  	}
   197  	if empty {
   198  		if err = entry.GetSegment().RemoveEntry(entry); err != nil {
   199  			return
   200  		}
   201  	}
   202  	return
   203  }
   204  
   205  func (entry *BlockEntry) WriteTo(w io.Writer) (n int64, err error) {
   206  	if n, err = entry.MetaBaseEntry.WriteAllTo(w); err != nil {
   207  		return
   208  	}
   209  	if err = binary.Write(w, binary.BigEndian, entry.state); err != nil {
   210  		return
   211  	}
   212  	n += 1
   213  	return
   214  }
   215  
   216  func (entry *BlockEntry) ReadFrom(r io.Reader) (n int64, err error) {
   217  	if n, err = entry.MetaBaseEntry.ReadAllFrom(r); err != nil {
   218  		return
   219  	}
   220  	err = binary.Read(r, binary.BigEndian, &entry.state)
   221  	n += 1
   222  	return
   223  }
   224  
   225  func (entry *BlockEntry) MakeKey() []byte {
   226  	return model.EncodeBlockKeyPrefix(entry.segment.ID, entry.ID)
   227  }
   228  
   229  // PrepareCompact is performance insensitive
   230  // a block can be compacted:
   231  // 1. no uncommited node
   232  // 2. at least one committed node
   233  // 3. not compacted
   234  func (entry *BlockEntry) PrepareCompact() bool {
   235  	entry.RLock()
   236  	defer entry.RUnlock()
   237  	if entry.HasUncommittedNode() {
   238  		return false
   239  	}
   240  	if !entry.HasCommittedNode() {
   241  		return false
   242  	}
   243  	if entry.HasDropCommittedLocked() {
   244  		return false
   245  	}
   246  	return true
   247  }
   248  
   249  // IsActive is coarse API: no consistency check
   250  func (entry *BlockEntry) IsActive() bool {
   251  	segment := entry.GetSegment()
   252  	if !segment.IsActive() {
   253  		return false
   254  	}
   255  	return !entry.HasDropCommitted()
   256  }
   257  
   258  // GetTerminationTS is coarse API: no consistency check
   259  func (entry *BlockEntry) GetTerminationTS() (ts types.TS, terminated bool) {
   260  	segmentEntry := entry.GetSegment()
   261  	tableEntry := segmentEntry.GetTable()
   262  	dbEntry := tableEntry.GetDB()
   263  
   264  	dbEntry.RLock()
   265  	terminated, ts = dbEntry.TryGetTerminatedTS(true)
   266  	if terminated {
   267  		dbEntry.RUnlock()
   268  		return
   269  	}
   270  	dbEntry.RUnlock()
   271  
   272  	tableEntry.RLock()
   273  	terminated, ts = tableEntry.TryGetTerminatedTS(true)
   274  	if terminated {
   275  		tableEntry.RUnlock()
   276  		return
   277  	}
   278  	tableEntry.RUnlock()
   279  
   280  	// segmentEntry.RLock()
   281  	// terminated,ts = segmentEntry.TryGetTerminatedTS(true)
   282  	// segmentEntry.RUnlock()
   283  	return
   284  }