github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/segment.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 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 "github.com/matrixorigin/matrixone/pkg/container/types" 25 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 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks" 31 ) 32 33 type SegmentDataFactory = func(meta *SegmentEntry) data.Segment 34 35 func compareSegmentFn(a, b *SegmentEntry) int { 36 return a.MetaBaseEntry.DoCompre(b.MetaBaseEntry) 37 } 38 39 type SegmentEntry struct { 40 *MetaBaseEntry 41 table *TableEntry 42 entries map[uint64]*common.GenericDLNode[*BlockEntry] 43 //link.head and tail is nil when new a segmentEntry object. 44 link *common.GenericSortedDList[*BlockEntry] 45 state EntryState 46 sorted bool 47 segData data.Segment 48 } 49 50 func NewSegmentEntry(table *TableEntry, txn txnif.AsyncTxn, state EntryState, dataFactory SegmentDataFactory) *SegmentEntry { 51 id := table.GetDB().catalog.NextSegment() 52 e := &SegmentEntry{ 53 MetaBaseEntry: NewMetaBaseEntry(id), 54 table: table, 55 link: common.NewGenericSortedDList(compareBlockFn), 56 entries: make(map[uint64]*common.GenericDLNode[*BlockEntry]), 57 state: state, 58 } 59 e.CreateWithTxn(txn) 60 if dataFactory != nil { 61 e.segData = dataFactory(e) 62 } 63 return e 64 } 65 66 func NewReplaySegmentEntry() *SegmentEntry { 67 e := &SegmentEntry{ 68 MetaBaseEntry: NewReplayMetaBaseEntry(), 69 link: common.NewGenericSortedDList(compareBlockFn), 70 entries: make(map[uint64]*common.GenericDLNode[*BlockEntry]), 71 } 72 return e 73 } 74 75 func NewStandaloneSegment(table *TableEntry, id uint64, ts types.TS) *SegmentEntry { 76 e := &SegmentEntry{ 77 MetaBaseEntry: NewMetaBaseEntry(id), 78 table: table, 79 link: common.NewGenericSortedDList(compareBlockFn), 80 entries: make(map[uint64]*common.GenericDLNode[*BlockEntry]), 81 state: ES_Appendable, 82 } 83 e.CreateWithTS(ts) 84 return e 85 } 86 87 func NewSysSegmentEntry(table *TableEntry, id uint64) *SegmentEntry { 88 e := &SegmentEntry{ 89 MetaBaseEntry: NewMetaBaseEntry(id), 90 table: table, 91 link: common.NewGenericSortedDList(compareBlockFn), 92 entries: make(map[uint64]*common.GenericDLNode[*BlockEntry]), 93 state: ES_Appendable, 94 } 95 e.CreateWithTS(types.SystemDBTS) 96 var bid uint64 97 if table.schema.Name == SystemTableSchema.Name { 98 bid = SystemBlock_Table_ID 99 } else if table.schema.Name == SystemDBSchema.Name { 100 bid = SystemBlock_DB_ID 101 } else if table.schema.Name == SystemColumnSchema.Name { 102 bid = SystemBlock_Columns_ID 103 } else { 104 panic("not supported") 105 } 106 block := NewSysBlockEntry(e, bid) 107 e.AddEntryLocked(block) 108 return e 109 } 110 111 func (entry *SegmentEntry) GetBlockEntryByID(id uint64) (blk *BlockEntry, err error) { 112 entry.RLock() 113 defer entry.RUnlock() 114 return entry.GetBlockEntryByIDLocked(id) 115 } 116 117 // XXX API like this, why do we need the error? Isn't blk is nil enough? 118 func (entry *SegmentEntry) GetBlockEntryByIDLocked(id uint64) (blk *BlockEntry, err error) { 119 node := entry.entries[id] 120 if node == nil { 121 err = moerr.GetOkExpectedEOB() 122 return 123 } 124 blk = node.GetPayload() 125 return 126 } 127 128 func (entry *SegmentEntry) MakeCommand(id uint32) (cmd txnif.TxnCmd, err error) { 129 cmdType := CmdUpdateSegment 130 entry.RLock() 131 defer entry.RUnlock() 132 return newSegmentCmd(id, cmdType, entry), nil 133 } 134 135 func (entry *SegmentEntry) Set1PC() { 136 entry.GetLatestNodeLocked().Set1PC() 137 } 138 func (entry *SegmentEntry) Is1PC() bool { 139 return entry.GetLatestNodeLocked().Is1PC() 140 } 141 func (entry *SegmentEntry) PPString(level common.PPLevel, depth int, prefix string) string { 142 var w bytes.Buffer 143 _, _ = w.WriteString(fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, entry.StringWithLevel(level))) 144 if level == common.PPL0 { 145 return w.String() 146 } 147 it := entry.MakeBlockIt(true) 148 for it.Valid() { 149 block := it.Get().GetPayload() 150 block.RLock() 151 _ = w.WriteByte('\n') 152 _, _ = w.WriteString(block.PPString(level, depth+1, prefix)) 153 block.RUnlock() 154 it.Next() 155 } 156 return w.String() 157 } 158 159 func (entry *SegmentEntry) StringLocked() string { 160 return entry.StringWithLevelLocked(common.PPL1) 161 } 162 163 func (entry *SegmentEntry) Repr() string { 164 id := entry.AsCommonID() 165 sorted := "-US" 166 if entry.sorted { 167 sorted = "-S" 168 } 169 return fmt.Sprintf("[%s%s]SEG[%s]", entry.state.Repr(), sorted, id.String()) 170 } 171 172 func (entry *SegmentEntry) String() string { 173 entry.RLock() 174 defer entry.RUnlock() 175 return entry.StringLocked() 176 } 177 178 func (entry *SegmentEntry) StringWithLevel(level common.PPLevel) string { 179 entry.RLock() 180 defer entry.RUnlock() 181 return entry.StringWithLevelLocked(level) 182 } 183 184 func (entry *SegmentEntry) StringWithLevelLocked(level common.PPLevel) string { 185 sorted := "-US" 186 if entry.sorted { 187 sorted = "-S" 188 } 189 if level <= common.PPL1 { 190 return fmt.Sprintf("[%s%s]SEG[%d][C@%s,D@%s]", 191 entry.state.Repr(), sorted, entry.ID, entry.GetCreatedAt().ToString(), entry.GetDeleteAt().ToString()) 192 } 193 return fmt.Sprintf("[%s%s]SEG%s", entry.state.Repr(), sorted, entry.MetaBaseEntry.StringLocked()) 194 } 195 196 func (entry *SegmentEntry) BlockCnt() int { 197 return len(entry.entries) 198 } 199 200 func (entry *SegmentEntry) IsAppendable() bool { 201 return entry.state == ES_Appendable 202 } 203 204 func (entry *SegmentEntry) SetSorted() { 205 // modifing segment interface to supporte a borned sorted seg is verbose 206 // use Lock instead, the contention won't be intense 207 entry.Lock() 208 defer entry.Unlock() 209 entry.sorted = true 210 } 211 212 func (entry *SegmentEntry) IsSorted() bool { 213 entry.RLock() 214 defer entry.RUnlock() 215 return entry.sorted 216 } 217 218 func (entry *SegmentEntry) GetTable() *TableEntry { 219 return entry.table 220 } 221 222 func (entry *SegmentEntry) GetAppendableBlockCnt() int { 223 cnt := 0 224 it := entry.MakeBlockIt(true) 225 for it.Valid() { 226 if it.Get().GetPayload().IsAppendable() { 227 cnt++ 228 } 229 it.Next() 230 } 231 return cnt 232 } 233 234 // GetNonAppendableBlockCnt Non-appendable segment only can contain non-appendable blocks; 235 // Appendable segment can contain both of appendable blocks and non-appendable blocks 236 func (entry *SegmentEntry) GetNonAppendableBlockCnt() int { 237 cnt := 0 238 it := entry.MakeBlockIt(true) 239 for it.Valid() { 240 if !it.Get().GetPayload().IsAppendable() { 241 cnt++ 242 } 243 it.Next() 244 } 245 return cnt 246 } 247 248 func (entry *SegmentEntry) GetAppendableBlock() (blk *BlockEntry) { 249 it := entry.MakeBlockIt(false) 250 for it.Valid() { 251 itBlk := it.Get().GetPayload() 252 if itBlk.IsAppendable() { 253 blk = itBlk 254 break 255 } 256 it.Next() 257 } 258 return 259 } 260 func (entry *SegmentEntry) LastAppendableBlock() (blk *BlockEntry) { 261 it := entry.MakeBlockIt(false) 262 for it.Valid() { 263 itBlk := it.Get().GetPayload() 264 dropped := itBlk.HasDropCommitted() 265 if itBlk.IsAppendable() && !dropped { 266 blk = itBlk 267 break 268 } 269 it.Next() 270 } 271 return 272 } 273 274 func (entry *SegmentEntry) CreateBlock(txn txnif.AsyncTxn, state EntryState, dataFactory BlockDataFactory) (created *BlockEntry, err error) { 275 entry.Lock() 276 defer entry.Unlock() 277 created = NewBlockEntry(entry, txn, state, dataFactory) 278 entry.AddEntryLocked(created) 279 return 280 } 281 282 func (entry *SegmentEntry) CreateBlockWithMeta( 283 txn txnif.AsyncTxn, 284 state EntryState, 285 dataFactory BlockDataFactory, 286 metaLoc string, 287 deltaLoc string) (created *BlockEntry, err error) { 288 entry.Lock() 289 defer entry.Unlock() 290 created = NewBlockEntryWithMeta(entry, txn, state, dataFactory, metaLoc, deltaLoc) 291 entry.AddEntryLocked(created) 292 return 293 } 294 295 func (entry *SegmentEntry) DropBlockEntry(id uint64, txn txnif.AsyncTxn) (deleted *BlockEntry, err error) { 296 blk, err := entry.GetBlockEntryByID(id) 297 if err != nil { 298 return 299 } 300 blk.Lock() 301 defer blk.Unlock() 302 needWait, waitTxn := blk.NeedWaitCommitting(txn.GetStartTS()) 303 if needWait { 304 blk.Unlock() 305 waitTxn.GetTxnState(true) 306 blk.Lock() 307 } 308 var isNewNode bool 309 isNewNode, err = blk.DropEntryLocked(txn) 310 if err == nil && isNewNode { 311 deleted = blk 312 } 313 return 314 } 315 316 func (entry *SegmentEntry) MakeBlockIt(reverse bool) *common.GenericSortedDListIt[*BlockEntry] { 317 entry.RLock() 318 defer entry.RUnlock() 319 return common.NewGenericSortedDListIt(entry.RWMutex, entry.link, reverse) 320 } 321 322 func (entry *SegmentEntry) AddEntryLocked(block *BlockEntry) { 323 n := entry.link.Insert(block) 324 entry.entries[block.GetID()] = n 325 } 326 327 func (entry *SegmentEntry) AsCommonID() *common.ID { 328 return &common.ID{ 329 TableID: entry.GetTable().GetID(), 330 SegmentID: entry.GetID(), 331 } 332 } 333 334 func (entry *SegmentEntry) GetCatalog() *Catalog { return entry.table.db.catalog } 335 336 func (entry *SegmentEntry) InitData(factory DataFactory) { 337 if factory == nil { 338 return 339 } 340 dataFactory := factory.MakeSegmentFactory() 341 entry.segData = dataFactory(entry) 342 } 343 func (entry *SegmentEntry) GetSegmentData() data.Segment { return entry.segData } 344 345 func (entry *SegmentEntry) deleteEntryLocked(block *BlockEntry) error { 346 if n, ok := entry.entries[block.GetID()]; !ok { 347 return moerr.GetOkExpectedEOB() 348 } else { 349 entry.link.Delete(n) 350 delete(entry.entries, block.GetID()) 351 } 352 // block.blkData.Close() 353 // block.blkData = nil 354 return nil 355 } 356 func (entry *SegmentEntry) Close() { 357 blks := entry.getAllBlks() 358 entry.Lock() 359 defer entry.Unlock() 360 for _, blk := range blks { 361 err := entry.deleteEntryLocked(blk) 362 if err != nil { 363 panic(err) 364 } 365 } 366 } 367 368 func (entry *SegmentEntry) getAllBlks() []*BlockEntry { 369 blks := make([]*BlockEntry, 0) 370 it := entry.MakeBlockIt(false) 371 for it.Valid() { 372 blks = append(blks, it.Get().GetPayload()) 373 it.Next() 374 } 375 return blks 376 } 377 func (entry *SegmentEntry) RemoveEntry(block *BlockEntry) (err error) { 378 logutil.Debug("[Catalog]", common.OperationField("remove"), 379 common.OperandField(block.String())) 380 entry.Lock() 381 defer entry.Unlock() 382 return entry.deleteEntryLocked(block) 383 } 384 385 func (entry *SegmentEntry) PrepareRollback() (err error) { 386 var isEmpty bool 387 if isEmpty, err = entry.MetaBaseEntry.PrepareRollback(); err != nil { 388 return 389 } 390 if isEmpty { 391 if err = entry.GetTable().RemoveEntry(entry); err != nil { 392 return 393 } 394 } 395 return 396 } 397 398 func (entry *SegmentEntry) WriteTo(w io.Writer) (n int64, err error) { 399 sn := int64(0) 400 if sn, err = entry.MetaBaseEntry.WriteAllTo(w); err != nil { 401 return 402 } 403 if err = binary.Write(w, binary.BigEndian, entry.state); err != nil { 404 return 405 } 406 n = sn + 1 407 if err = binary.Write(w, binary.BigEndian, entry.sorted); err != nil { 408 return 409 } 410 n = sn + 1 411 return 412 } 413 414 func (entry *SegmentEntry) ReadFrom(r io.Reader) (n int64, err error) { 415 if n, err = entry.MetaBaseEntry.ReadAllFrom(r); err != nil { 416 return 417 } 418 if err = binary.Read(r, binary.BigEndian, &entry.state); err != nil { 419 return 420 } 421 n += 1 422 if err = binary.Read(r, binary.BigEndian, &entry.sorted); err != nil { 423 return 424 } 425 n += 1 426 return 427 } 428 429 func (entry *SegmentEntry) GetScheduler() tasks.TaskScheduler { 430 return entry.GetTable().GetCatalog().GetScheduler() 431 } 432 433 func (entry *SegmentEntry) CollectBlockEntries(commitFilter func(be *MetaBaseEntry) bool, blockFilter func(be *BlockEntry) bool) []*BlockEntry { 434 blks := make([]*BlockEntry, 0) 435 blkIt := entry.MakeBlockIt(true) 436 for blkIt.Valid() { 437 blk := blkIt.Get().GetPayload() 438 blk.RLock() 439 if commitFilter != nil && blockFilter != nil { 440 if commitFilter(blk.MetaBaseEntry) && blockFilter(blk) { 441 blks = append(blks, blk) 442 } 443 } else if blockFilter != nil { 444 if blockFilter(blk) { 445 blks = append(blks, blk) 446 } 447 } else if commitFilter != nil { 448 if commitFilter(blk.MetaBaseEntry) { 449 blks = append(blks, blk) 450 } 451 } 452 blk.RUnlock() 453 blkIt.Next() 454 } 455 return blks 456 } 457 458 // IsActive is coarse API: no consistency check 459 func (entry *SegmentEntry) IsActive() bool { 460 table := entry.GetTable() 461 if !table.IsActive() { 462 return false 463 } 464 return !entry.HasDropCommitted() 465 } 466 467 func (entry *SegmentEntry) TreeMaxDropCommitEntry() BaseEntry { 468 table := entry.GetTable() 469 db := table.GetDB() 470 if db.HasDropCommittedLocked() { 471 return db.DBBaseEntry 472 } 473 if table.HasDropCommittedLocked() { 474 return table.TableBaseEntry 475 } 476 if entry.HasDropCommittedLocked() { 477 return entry.MetaBaseEntry 478 } 479 return nil 480 } 481 482 // GetTerminationTS is coarse API: no consistency check 483 func (entry *SegmentEntry) GetTerminationTS() (ts types.TS, terminated bool) { 484 tableEntry := entry.GetTable() 485 dbEntry := tableEntry.GetDB() 486 487 dbEntry.RLock() 488 terminated, ts = dbEntry.TryGetTerminatedTS(true) 489 if terminated { 490 dbEntry.RUnlock() 491 return 492 } 493 dbEntry.RUnlock() 494 495 tableEntry.RLock() 496 terminated, ts = tableEntry.TryGetTerminatedTS(true) 497 tableEntry.RUnlock() 498 return 499 }