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 }