github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/txn/txnimpl/table_space.go (about) 1 // Copyright 2022 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 txnimpl 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/objectio" 23 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 25 26 "github.com/matrixorigin/matrixone/pkg/common/moerr" 27 "github.com/matrixorigin/matrixone/pkg/common/mpool" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle" 33 ) 34 35 type tableSpace struct { 36 entry *catalog.ObjectEntry 37 38 appendable InsertNode 39 //index for primary key 40 index TableIndex 41 //nodes contains anode and node. 42 nodes []InsertNode 43 table *txnTable 44 rows uint32 45 appends []*appendCtx 46 tableHandle data.TableHandle 47 nobj handle.Object 48 49 stats []objectio.ObjectStats 50 } 51 52 func newTableSpace(table *txnTable) *tableSpace { 53 return &tableSpace{ 54 entry: catalog.NewStandaloneObject( 55 table.entry, 56 table.store.txn.GetStartTS()), 57 nodes: make([]InsertNode, 0), 58 index: NewSimpleTableIndex(), 59 appends: make([]*appendCtx, 0), 60 table: table, 61 } 62 } 63 64 func (space *tableSpace) GetLocalPhysicalAxis(row uint32) (int, uint32) { 65 var sum uint32 66 for i, node := range space.nodes { 67 sum += node.Rows() 68 if row <= sum-1 { 69 return i, node.Rows() - (sum - (row + 1)) - 1 70 } 71 } 72 panic("Invalid row ") 73 } 74 75 // register a non-appendable insertNode. 76 func (space *tableSpace) registerStats(stats objectio.ObjectStats) { 77 if space.stats == nil { 78 space.stats = make([]objectio.ObjectStats, 0) 79 } 80 space.stats = append(space.stats, stats) 81 } 82 83 func (space *tableSpace) isStatsExisted(o objectio.ObjectStats) bool { 84 for _, stats := range space.stats { 85 if stats.ObjectName().Equal(o.ObjectName()) { 86 return true 87 } 88 } 89 return false 90 } 91 92 // register an appendable insertNode. 93 func (space *tableSpace) registerANode() { 94 n := NewANode( 95 space.table, 96 space.entry, 97 ) 98 space.appendable = n 99 space.nodes = append(space.nodes, n) 100 } 101 102 // ApplyAppend applies all the anodes into appendable blocks 103 // and un-reference the appendable blocks which had been referenced when PrepareApply. 104 func (space *tableSpace) ApplyAppend() (err error) { 105 var destOff int 106 defer func() { 107 // Close All unclosed Appends:un-reference the appendable block. 108 space.CloseAppends() 109 }() 110 for _, ctx := range space.appends { 111 bat, _ := ctx.node.Window(ctx.start, ctx.start+ctx.count) 112 defer bat.Close() 113 if destOff, err = ctx.driver.ApplyAppend( 114 bat, 115 space.table.store.txn); err != nil { 116 return 117 } 118 id := ctx.driver.GetID() 119 ctx.node.AddApplyInfo( 120 ctx.start, 121 ctx.count, 122 uint32(destOff), 123 ctx.count, id) 124 } 125 if space.tableHandle != nil { 126 space.table.entry.GetTableData().ApplyHandle(space.tableHandle) 127 } 128 return 129 } 130 131 func (space *tableSpace) PrepareApply() (err error) { 132 defer func() { 133 if err != nil { 134 // Close All unclosed Appends: un-reference all the appendable blocks. 135 space.CloseAppends() 136 } 137 }() 138 for _, node := range space.nodes { 139 if err = space.prepareApplyNode(node); err != nil { 140 return 141 } 142 } 143 for _, stats := range space.stats { 144 if err = space.prepareApplyObjectStats(stats); err != nil { 145 return 146 } 147 } 148 return 149 } 150 151 func (space *tableSpace) prepareApplyANode(node *anode) error { 152 node.Compact() 153 tableData := space.table.entry.GetTableData() 154 if space.tableHandle == nil { 155 space.tableHandle = tableData.GetHandle() 156 } 157 appended := uint32(0) 158 vec := space.table.store.rt.VectorPool.Small.GetVector(&objectio.RowidType) 159 for appended < node.Rows() { 160 appender, err := space.tableHandle.GetAppender() 161 if moerr.IsMoErrCode(err, moerr.ErrAppendableObjectNotFound) { 162 objH, err := space.table.CreateObject(true) 163 if err != nil { 164 return err 165 } 166 appender = space.tableHandle.SetAppender(objH.Fingerprint()) 167 objH.Close() 168 } 169 if !appender.IsSameColumns(space.table.GetLocalSchema()) { 170 return moerr.NewInternalErrorNoCtx("schema changed, please rollback and retry") 171 } 172 173 // see more notes in flushtabletail.go 174 /// ----------- Choose a ablock --------- 175 appender.LockFreeze() 176 // no one can touch freeze for now, check it 177 if appender.CheckFreeze() { 178 // freezed, try to find another ablock 179 appender.UnlockFreeze() 180 continue 181 } 182 183 // hold freezelock to attach AppendNode 184 //PrepareAppend: It is very important that appending a AppendNode into 185 // block's MVCCHandle before applying data into block. 186 anode, created, toAppend, err := appender.PrepareAppend( 187 node.Rows()-appended, 188 space.table.store.txn) 189 if err != nil { 190 appender.UnlockFreeze() 191 return err 192 } 193 appender.UnlockFreeze() 194 /// ------- Attach AppendNode Successfully ----- 195 196 objID := appender.GetMeta().(*catalog.ObjectEntry).ID 197 col := space.table.store.rt.VectorPool.Small.GetVector(&objectio.RowidType) 198 defer col.Close() 199 blkID := objectio.NewBlockidWithObjectID(&objID, 0) 200 if err = objectio.ConstructRowidColumnTo( 201 col.GetDownstreamVector(), 202 blkID, 203 anode.GetMaxRow()-toAppend, 204 toAppend, 205 col.GetAllocator(), 206 ); err != nil { 207 return err 208 } 209 if err = vec.ExtendVec(col.GetDownstreamVector()); err != nil { 210 return err 211 } 212 ctx := &appendCtx{ 213 driver: appender, 214 node: node, 215 anode: anode, 216 start: appended, 217 count: toAppend, 218 } 219 if created { 220 space.table.store.IncreateWriteCnt() 221 space.table.txnEntries.Append(anode) 222 } 223 id := appender.GetID() 224 space.table.store.warChecker.Insert(appender.GetMeta().(*catalog.ObjectEntry)) 225 space.table.store.txn.GetMemo().AddObject(space.table.entry.GetDB().ID, 226 id.TableID, id.ObjectID()) 227 space.appends = append(space.appends, ctx) 228 // logutil.Debugf("%s: toAppend %d, appended %d, blks=%d", 229 // id.String(), toAppend, appended, len(space.appends)) 230 appended += toAppend 231 if appended == node.Rows() { 232 break 233 } 234 } 235 node.data.Vecs[space.table.GetLocalSchema().PhyAddrKey.Idx].Close() 236 node.data.Vecs[space.table.GetLocalSchema().PhyAddrKey.Idx] = vec 237 return nil 238 } 239 240 func (space *tableSpace) prepareApplyObjectStats(stats objectio.ObjectStats) (err error) { 241 sid := stats.ObjectName().ObjectId() 242 shouldCreateNewObj := func() bool { 243 if space.nobj == nil { 244 return true 245 } 246 entry := space.nobj.GetMeta().(*catalog.ObjectEntry) 247 return !entry.ID.Eq(*sid) 248 } 249 250 if shouldCreateNewObj() { 251 space.nobj, err = space.table.CreateNonAppendableObject(true, new(objectio.CreateObjOpt).WithId(sid)) 252 if err != nil { 253 return 254 } 255 space.nobj.GetMeta().(*catalog.ObjectEntry).SetSorted() 256 err = space.nobj.UpdateStats(stats) 257 if err != nil { 258 return 259 } 260 } 261 262 return 263 } 264 265 func (space *tableSpace) prepareApplyNode(node InsertNode) (err error) { 266 if !node.IsPersisted() { 267 return space.prepareApplyANode(node.(*anode)) 268 } 269 return nil 270 } 271 272 // CloseAppends un-reference the appendable blocks 273 func (space *tableSpace) CloseAppends() { 274 for _, ctx := range space.appends { 275 if ctx.driver != nil { 276 ctx.driver.Close() 277 ctx.driver = nil 278 } 279 } 280 } 281 282 // Append appends batch of data into anode. 283 func (space *tableSpace) Append(data *containers.Batch) (err error) { 284 if space.appendable == nil { 285 space.registerANode() 286 } 287 appended := uint32(0) 288 offset := uint32(0) 289 length := uint32(data.Length()) 290 schema := space.table.GetLocalSchema() 291 for { 292 h := space.appendable 293 appended, err = h.Append(data, offset) 294 if err != nil { 295 return 296 } 297 dedupType := space.table.store.txn.GetDedupType() 298 if schema.HasPK() && dedupType == txnif.FullDedup { 299 if err = space.index.BatchInsert( 300 data.Attrs[schema.GetSingleSortKeyIdx()], 301 data.Vecs[schema.GetSingleSortKeyIdx()], 302 int(offset), 303 int(appended), 304 space.rows, 305 false); err != nil { 306 break 307 } 308 } 309 offset += appended 310 space.rows += appended 311 if offset >= length { 312 break 313 } 314 } 315 return 316 } 317 318 // AddObjsWithMetaLoc transfers blocks with meta location into non-appendable nodes 319 func (space *tableSpace) AddObjsWithMetaLoc( 320 pkVecs []containers.Vector, 321 stats objectio.ObjectStats, 322 ) (err error) { 323 space.registerStats(stats) 324 for i := range pkVecs { 325 dedupType := space.table.store.txn.GetDedupType() 326 //insert primary keys into space.index 327 if pkVecs != nil && dedupType == txnif.FullDedup { 328 if err = space.index.BatchInsert( 329 space.table.GetLocalSchema().GetSingleSortKey().Name, 330 pkVecs[i], 331 0, 332 pkVecs[i].Length(), 333 space.rows, 334 false, 335 ); err != nil { 336 return 337 } 338 space.rows += uint32(pkVecs[i].Length()) 339 } 340 } 341 return nil 342 } 343 344 func (space *tableSpace) DeleteFromIndex(from, to uint32, node InsertNode) (err error) { 345 schema := space.table.GetLocalSchema() 346 for i := from; i <= to; i++ { 347 v, _, err := node.GetValue(schema.GetSingleSortKeyIdx(), i) 348 if err != nil { 349 return err 350 } 351 if err = space.index.Delete(v); err != nil { 352 return err 353 } 354 } 355 return 356 } 357 358 // RangeDelete delete rows : [start, end] 359 func (space *tableSpace) RangeDelete(start, end uint32) error { 360 first, firstOffset := space.GetLocalPhysicalAxis(start) 361 last, lastOffset := space.GetLocalPhysicalAxis(end) 362 var err error 363 if last == first { 364 node := space.nodes[first] 365 err = node.RangeDelete(firstOffset, lastOffset) 366 if err != nil { 367 return err 368 } 369 if !space.table.GetLocalSchema().HasPK() { 370 // If no pk defined 371 return err 372 } 373 err = space.DeleteFromIndex(firstOffset, lastOffset, node) 374 return err 375 } 376 377 node := space.nodes[first] 378 if err = node.RangeDelete(firstOffset, node.Rows()-1); err != nil { 379 380 return err 381 } 382 if err = space.DeleteFromIndex(firstOffset, node.Rows()-1, node); err != nil { 383 return err 384 } 385 node = space.nodes[last] 386 if err = node.RangeDelete(0, lastOffset); err != nil { 387 return err 388 } 389 if err = space.DeleteFromIndex(0, lastOffset, node); err != nil { 390 return err 391 } 392 if last > first+1 { 393 for i := first + 1; i < last; i++ { 394 node = space.nodes[i] 395 if err = node.RangeDelete(0, node.Rows()-1); err != nil { 396 break 397 } 398 if err = space.DeleteFromIndex(0, node.Rows()-1, node); err != nil { 399 break 400 } 401 } 402 } 403 return err 404 } 405 406 // CollectCmd collect txnCmd for anode whose data resides in memory. 407 func (space *tableSpace) CollectCmd(cmdMgr *commandManager) (err error) { 408 for _, node := range space.nodes { 409 csn := uint32(0xffff) // Special cmd 410 cmd, err := node.MakeCommand(csn) 411 if err != nil { 412 panic(err) 413 } 414 if cmd != nil { 415 cmdMgr.AddInternalCmd(cmd) 416 } 417 } 418 return 419 } 420 421 func (space *tableSpace) DeletesToString() string { 422 var s string 423 for i, n := range space.nodes { 424 s = fmt.Sprintf("%s\t<INode-%d>: %s\n", s, i, n.PrintDeletes()) 425 } 426 return s 427 } 428 429 func (space *tableSpace) IsDeleted(row uint32) bool { 430 npos, noffset := space.GetLocalPhysicalAxis(row) 431 n := space.nodes[npos] 432 return n.IsRowDeleted(noffset) 433 } 434 435 func (space *tableSpace) Rows() (n uint32) { 436 for _, node := range space.nodes { 437 n += node.Rows() 438 } 439 return 440 } 441 442 func (space *tableSpace) GetByFilter(filter *handle.Filter) (id *common.ID, offset uint32, err error) { 443 if !space.table.GetLocalSchema().HasPK() { 444 id = space.table.entry.AsCommonID() 445 rid := filter.Val.(types.Rowid) 446 id.BlockID, offset = rid.Decode() 447 return 448 } 449 id = space.entry.AsCommonID() 450 if v, ok := filter.Val.([]byte); ok { 451 offset, err = space.index.Search(string(v)) 452 } else { 453 offset, err = space.index.Search(filter.Val) 454 } 455 if err != nil { 456 return 457 } 458 return 459 } 460 461 func (space *tableSpace) GetPKColumn() containers.Vector { 462 schema := space.table.entry.GetLastestSchemaLocked() 463 return space.index.KeyToVector(schema.GetSingleSortKeyType()) 464 } 465 466 func (space *tableSpace) GetPKVecs() []containers.Vector { 467 schema := space.table.entry.GetLastestSchemaLocked() 468 return space.index.KeyToVectors(schema.GetSingleSortKeyType()) 469 } 470 471 func (space *tableSpace) BatchDedup(key containers.Vector) error { 472 return space.index.BatchDedup(space.table.GetLocalSchema().GetSingleSortKey().Name, key) 473 } 474 475 func (space *tableSpace) GetColumnDataByIds( 476 obj *catalog.ObjectEntry, 477 colIdxes []int, 478 mp *mpool.MPool, 479 ) (view *containers.BlockView, err error) { 480 n := space.nodes[0] 481 return n.GetColumnDataByIds(colIdxes, mp) 482 } 483 484 func (space *tableSpace) GetColumnDataById( 485 ctx context.Context, 486 obj *catalog.ObjectEntry, 487 colIdx int, 488 mp *mpool.MPool, 489 ) (view *containers.ColumnView, err error) { 490 n := space.nodes[0] 491 return n.GetColumnDataById(ctx, colIdx, mp) 492 } 493 494 func (space *tableSpace) Prefetch(obj *catalog.ObjectEntry, idxes []uint16) error { 495 n := space.nodes[0] 496 return n.Prefetch(idxes) 497 } 498 499 func (space *tableSpace) GetValue(row uint32, col uint16) (any, bool, error) { 500 npos, noffset := space.GetLocalPhysicalAxis(row) 501 n := space.nodes[npos] 502 return n.GetValue(int(col), noffset) 503 } 504 505 // Close free the resource when transaction commits. 506 func (space *tableSpace) Close() (err error) { 507 for _, node := range space.nodes { 508 if err = node.Close(); err != nil { 509 return 510 } 511 } 512 space.index.Close() 513 space.index = nil 514 space.nodes = nil 515 space.appendable = nil 516 return 517 }