github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/tables/txnentries/mergeobjects.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 txnentries 16 17 import ( 18 "fmt" 19 "math" 20 "sync" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/container/types" 24 "github.com/matrixorigin/matrixone/pkg/container/vector" 25 "github.com/matrixorigin/matrixone/pkg/logutil" 26 "github.com/matrixorigin/matrixone/pkg/objectio" 27 "github.com/matrixorigin/matrixone/pkg/pb/api" 28 v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db/dbutils" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 34 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model" 35 ) 36 37 type mergeObjectsEntry struct { 38 sync.RWMutex 39 txn txnif.AsyncTxn 40 relation handle.Relation 41 droppedObjs []*catalog.ObjectEntry 42 createdObjs []*catalog.ObjectEntry 43 transMappings *api.BlkTransferBooking 44 skipTransfer bool 45 46 rt *dbutils.Runtime 47 pageIds []*common.ID 48 delTbls [][]*model.TransDels 49 collectTs types.TS 50 transCntBeforeCommit int 51 nextRoundDirties map[*catalog.ObjectEntry]struct{} 52 } 53 54 func NewMergeObjectsEntry( 55 txn txnif.AsyncTxn, 56 relation handle.Relation, 57 droppedObjs, createdObjs []*catalog.ObjectEntry, 58 transMappings *api.BlkTransferBooking, 59 rt *dbutils.Runtime, 60 ) (*mergeObjectsEntry, error) { 61 totalCreatedBlkCnt := 0 62 for _, obj := range createdObjs { 63 totalCreatedBlkCnt += obj.BlockCnt() 64 } 65 entry := &mergeObjectsEntry{ 66 txn: txn, 67 relation: relation, 68 createdObjs: createdObjs, 69 droppedObjs: droppedObjs, 70 transMappings: transMappings, 71 skipTransfer: transMappings == nil, 72 rt: rt, 73 } 74 75 if !entry.skipTransfer && totalCreatedBlkCnt > 0 { 76 entry.delTbls = make([][]*model.TransDels, len(createdObjs)) 77 for i := 0; i < len(createdObjs); i++ { 78 entry.delTbls[i] = make([]*model.TransDels, createdObjs[i].BlockCnt()) 79 } 80 entry.nextRoundDirties = make(map[*catalog.ObjectEntry]struct{}) 81 entry.collectTs = rt.Now() 82 var err error 83 // phase 1 transfer 84 entry.transCntBeforeCommit, _, err = entry.collectDelsAndTransfer(entry.txn.GetStartTS(), entry.collectTs) 85 if err != nil { 86 return nil, err 87 } 88 entry.prepareTransferPage() 89 } 90 return entry, nil 91 } 92 93 func (entry *mergeObjectsEntry) prepareTransferPage() { 94 k := 0 95 for _, obj := range entry.droppedObjs { 96 for j := 0; j < obj.BlockCnt(); j++ { 97 if len(entry.transMappings.Mappings[k].M) == 0 { 98 k++ 99 continue 100 } 101 mapping := entry.transMappings.Mappings[k].M 102 if len(mapping) == 0 { 103 panic("cannot tranfer empty block") 104 } 105 tblEntry := obj.GetTable() 106 isTransient := !tblEntry.GetLastestSchema().HasPK() 107 id := obj.AsCommonID() 108 id.SetBlockOffset(uint16(j)) 109 page := model.NewTransferHashPage(id, time.Now(), isTransient) 110 for srcRow, dst := range mapping { 111 objID := entry.createdObjs[dst.ObjIdx].ID 112 blkID := objectio.NewBlockidWithObjectID(&objID, uint16(dst.BlkIdx)) 113 page.Train(uint32(srcRow), *objectio.NewRowid(blkID, uint32(dst.RowIdx))) 114 } 115 entry.pageIds = append(entry.pageIds, id) 116 _ = entry.rt.TransferTable.AddPage(page) 117 k++ 118 } 119 } 120 if k != len(entry.transMappings.Mappings) { 121 panic(fmt.Sprintf("k %v, mapping %v", k, len(entry.transMappings.Mappings))) 122 } 123 } 124 125 func (entry *mergeObjectsEntry) PrepareRollback() (err error) { 126 for _, id := range entry.pageIds { 127 _ = entry.rt.TransferTable.DeletePage(id) 128 } 129 entry.pageIds = nil 130 return 131 } 132 133 func (entry *mergeObjectsEntry) ApplyRollback() (err error) { 134 //TODO::? 135 return 136 } 137 138 func (entry *mergeObjectsEntry) ApplyCommit() (err error) { 139 return 140 } 141 142 func (entry *mergeObjectsEntry) MakeCommand(csn uint32) (cmd txnif.TxnCmd, err error) { 143 droppedObjs := make([]*common.ID, 0) 144 for _, blk := range entry.droppedObjs { 145 id := blk.AsCommonID() 146 droppedObjs = append(droppedObjs, id) 147 } 148 createdObjs := make([]*common.ID, 0) 149 for _, blk := range entry.createdObjs { 150 id := blk.AsCommonID() 151 createdObjs = append(createdObjs, id) 152 } 153 cmd = newMergeBlocksCmd( 154 entry.relation.ID(), 155 droppedObjs, 156 createdObjs, 157 entry.txn, 158 csn) 159 return 160 } 161 162 func (entry *mergeObjectsEntry) Set1PC() {} 163 func (entry *mergeObjectsEntry) Is1PC() bool { return false } 164 165 // ATTENTION !!! (from, to] !!! 166 func (entry *mergeObjectsEntry) transferObjectDeletes( 167 dropped *catalog.ObjectEntry, 168 from, to types.TS, 169 blkOffsetBase int) (transCnt int, collect, transfer time.Duration, err error) { 170 171 dataBlock := dropped.GetObjectData() 172 173 inst := time.Now() 174 bat, _, err := dataBlock.CollectDeleteInRange( 175 entry.txn.GetContext(), 176 from.Next(), 177 to, 178 false, 179 common.MergeAllocator, 180 ) 181 if err != nil { 182 return 183 } 184 collect = time.Since(inst) 185 if bat == nil || bat.Length() == 0 { 186 return 187 } 188 inst = time.Now() 189 defer func() { transfer = time.Since(inst) }() 190 191 entry.nextRoundDirties[dropped] = struct{}{} 192 193 rowid := vector.MustFixedCol[types.Rowid](bat.GetVectorByName(catalog.PhyAddrColumnName).GetDownstreamVector()) 194 ts := vector.MustFixedCol[types.TS](bat.GetVectorByName(catalog.AttrCommitTs).GetDownstreamVector()) 195 196 count := len(rowid) 197 transCnt += count 198 for i := 0; i < count; i++ { 199 row := rowid[i].GetRowOffset() 200 blkOffsetInObj := int(rowid[i].GetBlockOffset()) 201 blkOffset := blkOffsetBase + blkOffsetInObj 202 mapping := entry.transMappings.Mappings[blkOffset].M 203 if len(mapping) == 0 { 204 // this block had been all deleted, skip 205 // Note: it is possible that the block is empty, but not the object 206 continue 207 } 208 destpos, ok := mapping[int32(row)] 209 if !ok { 210 _min, _max := int32(math.MaxInt32), int32(0) 211 for k := range mapping { 212 if k < _min { 213 _min = k 214 } 215 if k > _max { 216 _max = k 217 } 218 } 219 panic(fmt.Sprintf( 220 "%s-%d find no transfer mapping for row %d, mapping range (%d, %d)", 221 dropped.ID.String(), blkOffsetInObj, row, _min, _max)) 222 } 223 if entry.delTbls[destpos.ObjIdx][destpos.BlkIdx] == nil { 224 entry.delTbls[destpos.ObjIdx][destpos.BlkIdx] = model.NewTransDels(entry.txn.GetPrepareTS()) 225 } 226 entry.delTbls[destpos.ObjIdx][destpos.BlkIdx].Mapping[int(destpos.RowIdx)] = ts[i] 227 var targetObj handle.Object 228 targetObj, err = entry.relation.GetObject(&entry.createdObjs[destpos.ObjIdx].ID) 229 if err != nil { 230 return 231 } 232 if err = targetObj.RangeDelete( 233 uint16(destpos.BlkIdx), uint32(destpos.RowIdx), uint32(destpos.RowIdx), handle.DT_MergeCompact, common.MergeAllocator, 234 ); err != nil { 235 return 236 } 237 } 238 return 239 } 240 241 type tempStat struct { 242 transObj int 243 pcost, ccost, tcost, mpt, mct, mtt time.Duration 244 } 245 246 func (s *tempStat) String() string { 247 return fmt.Sprintf("transObj %d, pcost %v, ccost %v, tcost %v, mpt %v, mct %v, mtt %v", 248 s.transObj, s.pcost, s.ccost, s.tcost, s.mpt, s.mct, s.mtt) 249 } 250 251 // ATTENTION !!! (from, to] !!! 252 func (entry *mergeObjectsEntry) collectDelsAndTransfer(from, to types.TS) (transCnt int, stat tempStat, err error) { 253 if len(entry.createdObjs) == 0 { 254 return 255 } 256 257 blksOffsetBase := 0 258 var pcost, ccost, tcost time.Duration 259 var mpt, mct, mtt time.Duration 260 transobj := 0 261 for _, dropped := range entry.droppedObjs { 262 inst := time.Now() 263 // handle object transfer 264 hasMappingInThisObj := false 265 blkCnt := dropped.BlockCnt() 266 for iblk := 0; iblk < blkCnt; iblk++ { 267 if len(entry.transMappings.Mappings[blksOffsetBase+iblk].M) != 0 { 268 hasMappingInThisObj = true 269 break 270 } 271 } 272 if !hasMappingInThisObj { 273 // this object had been all deleted, skip 274 blksOffsetBase += blkCnt 275 continue 276 } 277 pcost += time.Since(inst) 278 if pcost > mpt { 279 mpt = pcost 280 } 281 cnt := 0 282 283 var ct, tt time.Duration 284 cnt, ct, tt, err = entry.transferObjectDeletes(dropped, from, to, blksOffsetBase) 285 if err != nil { 286 return 287 } 288 if ct > mct { 289 mct = ct 290 } 291 if tt > mtt { 292 mtt = tt 293 } 294 ccost += ct 295 tcost += tt 296 transCnt += cnt 297 transobj++ 298 blksOffsetBase += blkCnt 299 } 300 stat = tempStat{ 301 transObj: transobj, 302 pcost: pcost, 303 ccost: ccost, 304 tcost: tcost, 305 mpt: mpt, 306 mct: mct, 307 mtt: mtt, 308 } 309 return 310 } 311 312 func (entry *mergeObjectsEntry) PrepareCommit() (err error) { 313 inst := time.Now() 314 defer func() { 315 v2.TaskCommitMergeObjectsDurationHistogram.Observe(time.Since(inst).Seconds()) 316 }() 317 if len(entry.createdObjs) == 0 || entry.skipTransfer { 318 logutil.Infof("mergeblocks commit %v, [%v,%v], no transfer", 319 entry.relation.ID(), 320 entry.txn.GetStartTS().ToString(), 321 entry.txn.GetCommitTS().ToString()) 322 return 323 } 324 325 // phase 2 transfer 326 transCnt, stat, err := entry.collectDelsAndTransfer(entry.collectTs, entry.txn.GetPrepareTS()) 327 if err != nil { 328 return nil 329 } 330 331 inst1 := time.Now() 332 tblEntry := entry.droppedObjs[0].GetTable() 333 tblEntry.Stats.Lock() 334 for dropped := range entry.nextRoundDirties { 335 tblEntry.DeletedDirties = append(tblEntry.DeletedDirties, dropped) 336 } 337 tblEntry.Stats.Unlock() 338 339 for objIdx := range entry.delTbls { 340 for blkIdx, delTbl := range entry.delTbls[objIdx] { 341 if delTbl != nil { 342 destId := objectio.NewBlockidWithObjectID(&entry.createdObjs[objIdx].ID, uint16(blkIdx)) 343 entry.rt.TransferDelsMap.SetDelsForBlk(*destId, delTbl) 344 } 345 } 346 } 347 rest := time.Since(inst1) 348 logutil.Infof("mergeblocks commit %v, [%v,%v], trans %d on %d objects, %d in commit queue", 349 entry.relation.ID(), 350 entry.txn.GetStartTS().ToString(), 351 entry.txn.GetCommitTS().ToString(), 352 entry.transCntBeforeCommit+transCnt, 353 len(entry.nextRoundDirties), 354 transCnt, 355 ) 356 if total := time.Since(inst); total > 300*time.Millisecond { 357 logutil.Infof("mergeblocks slow commit total %v, transfer: %v, rest %v", total, stat.String(), rest) 358 } 359 360 return 361 }