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