github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/tables/txnentries/mergeblocks.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 "sync" 19 "time" 20 21 "github.com/RoaringBitmap/roaring" 22 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 23 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/compute" 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle" 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal" 30 ) 31 32 type mergeBlocksEntry struct { 33 sync.RWMutex 34 txn txnif.AsyncTxn 35 relation handle.Relation 36 droppedSegs []*catalog.SegmentEntry 37 deletes []*roaring.Bitmap 38 createdSegs []*catalog.SegmentEntry 39 droppedBlks []*catalog.BlockEntry 40 createdBlks []*catalog.BlockEntry 41 mapping []uint32 42 fromAddr []uint32 43 toAddr []uint32 44 scheduler tasks.TaskScheduler 45 skippedBlks []int 46 } 47 48 func NewMergeBlocksEntry( 49 txn txnif.AsyncTxn, 50 relation handle.Relation, 51 droppedSegs, createdSegs []*catalog.SegmentEntry, 52 droppedBlks, createdBlks []*catalog.BlockEntry, 53 mapping, fromAddr, toAddr []uint32, 54 deletes []*roaring.Bitmap, 55 skipBlks []int, 56 scheduler tasks.TaskScheduler) *mergeBlocksEntry { 57 return &mergeBlocksEntry{ 58 txn: txn, 59 relation: relation, 60 createdSegs: createdSegs, 61 droppedSegs: droppedSegs, 62 createdBlks: createdBlks, 63 droppedBlks: droppedBlks, 64 mapping: mapping, 65 fromAddr: fromAddr, 66 toAddr: toAddr, 67 scheduler: scheduler, 68 deletes: deletes, 69 skippedBlks: skipBlks, 70 } 71 } 72 73 func (entry *mergeBlocksEntry) PrepareRollback() (err error) { 74 // TODO: remove block file? (should be scheduled and executed async) 75 return 76 } 77 func (entry *mergeBlocksEntry) ApplyRollback(index *wal.Index) (err error) { 78 //TODO::? 79 return 80 } 81 82 func (entry *mergeBlocksEntry) ApplyCommit(index *wal.Index) (err error) { 83 return 84 } 85 86 func (entry *mergeBlocksEntry) MakeCommand(csn uint32) (cmd txnif.TxnCmd, err error) { 87 droppedSegs := make([]*common.ID, 0) 88 for _, blk := range entry.droppedSegs { 89 id := blk.AsCommonID() 90 droppedSegs = append(droppedSegs, id) 91 } 92 createdSegs := make([]*common.ID, 0) 93 for _, blk := range entry.createdSegs { 94 id := blk.AsCommonID() 95 createdSegs = append(createdSegs, id) 96 } 97 droppedBlks := make([]*common.ID, 0) 98 for _, blk := range entry.droppedBlks { 99 id := blk.AsCommonID() 100 droppedBlks = append(droppedBlks, id) 101 } 102 createdBlks := make([]*common.ID, 0) 103 for _, blk := range entry.createdBlks { 104 createdBlks = append(createdBlks, blk.AsCommonID()) 105 } 106 cmd = newMergeBlocksCmd( 107 entry.relation.ID(), 108 droppedSegs, 109 createdSegs, 110 droppedBlks, 111 createdBlks, 112 entry.mapping, 113 entry.fromAddr, 114 entry.toAddr, 115 entry.txn, 116 csn) 117 return 118 } 119 120 func (entry *mergeBlocksEntry) Set1PC() {} 121 func (entry *mergeBlocksEntry) Is1PC() bool { return false } 122 func (entry *mergeBlocksEntry) resolveAddr(fromPos int, fromOffset uint32) (toPos int, toOffset uint32) { 123 totalFromOffset := entry.fromAddr[fromPos] + fromOffset 124 totalToOffset := entry.mapping[totalFromOffset] 125 left, right := 0, len(entry.toAddr)-1 126 for left <= right { 127 toPos = (left + right) / 2 128 if entry.toAddr[toPos] < totalToOffset { 129 left = toPos + 1 130 } else if entry.toAddr[toPos] > totalToOffset { 131 right = toPos - 1 132 } else { 133 break 134 } 135 } 136 137 // if toPos == 0 && entry.toAddr[toPos] < totalToOffset { 138 if entry.toAddr[toPos] > totalToOffset { 139 toPos = toPos - 1 140 } 141 toOffset = totalToOffset - entry.toAddr[toPos] 142 // logutil.Infof("mapping=%v", entry.mapping) 143 // logutil.Infof("fromPos=%d, fromOff=%d", fromPos, fromOffset) 144 // logutil.Infof("fromAddr=%v", entry.fromAddr) 145 // logutil.Infof("toAddr=%v", entry.toAddr) 146 // logutil.Infof("toPos=%d, toOffset=%d", toPos, toOffset) 147 return 148 } 149 150 func (entry *mergeBlocksEntry) isSkipped(fromPos int) bool { 151 for _, offset := range entry.skippedBlks { 152 if offset == fromPos { 153 return true 154 } 155 } 156 return false 157 } 158 159 func (entry *mergeBlocksEntry) transferBlockDeletes( 160 dropped *catalog.BlockEntry, 161 blks []handle.Block, 162 fromPos int, 163 skippedCnt int) (err error) { 164 id := dropped.AsCommonID() 165 page := model.NewTransferHashPage(id, time.Now()) 166 var ( 167 length uint32 168 view *model.BlockView 169 ) 170 if fromPos-skippedCnt+1 == len(entry.fromAddr) { 171 length = uint32(len(entry.mapping)) - entry.fromAddr[fromPos-skippedCnt] 172 } else { 173 length = entry.fromAddr[fromPos-skippedCnt+1] - entry.fromAddr[fromPos-skippedCnt] 174 } 175 for i := uint32(0); i < length; i++ { 176 if entry.deletes[fromPos] != nil && entry.deletes[fromPos].Contains(i) { 177 continue 178 } 179 newOffset := i 180 if entry.deletes[fromPos] != nil { 181 newOffset = i - uint32(entry.deletes[fromPos].Rank(i)) 182 } 183 toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, newOffset) 184 toId := entry.createdBlks[toPos].AsCommonID() 185 prefix := model.EncodeBlockKeyPrefix(toId.SegmentID, toId.BlockID) 186 rowid := model.EncodePhyAddrKeyWithPrefix(prefix, uint32(i)) 187 page.Train(toRow, rowid) 188 } 189 _ = entry.scheduler.AddTransferPage(page) 190 191 dataBlock := dropped.GetBlockData() 192 if view, err = dataBlock.CollectChangesInRange( 193 entry.txn.GetStartTS(), 194 entry.txn.GetCommitTS()); err != nil || view == nil { 195 return 196 } 197 198 deletes := view.DeleteMask 199 for colIdx, column := range view.Columns { 200 view.DeleteMask = compute.ShuffleByDeletes( 201 deletes, entry.deletes[fromPos]) 202 for row, v := range column.UpdateVals { 203 toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, row) 204 if err = blks[toPos].Update(toRow, uint16(colIdx), v); err != nil { 205 return 206 } 207 } 208 } 209 view.DeleteMask = compute.ShuffleByDeletes(view.DeleteMask, entry.deletes[fromPos]) 210 if view.DeleteMask != nil { 211 it := view.DeleteMask.Iterator() 212 for it.HasNext() { 213 row := it.Next() 214 toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, row) 215 if err = blks[toPos].RangeDelete(toRow, toRow, handle.DT_MergeCompact); err != nil { 216 return 217 } 218 } 219 } 220 return 221 } 222 223 func (entry *mergeBlocksEntry) PrepareCommit() (err error) { 224 blks := make([]handle.Block, len(entry.createdBlks)) 225 for i, meta := range entry.createdBlks { 226 id := meta.AsCommonID() 227 seg, err := entry.relation.GetSegment(id.SegmentID) 228 if err != nil { 229 return err 230 } 231 blk, err := seg.GetBlock(id.BlockID) 232 if err != nil { 233 return err 234 } 235 blks[i] = blk 236 } 237 238 skippedCnt := 0 239 ids := make([]*common.ID, 0) 240 241 for fromPos, dropped := range entry.droppedBlks { 242 if entry.isSkipped(fromPos) { 243 skippedCnt++ 244 continue 245 } 246 247 if err = entry.transferBlockDeletes( 248 dropped, 249 blks, 250 fromPos, 251 skippedCnt); err != nil { 252 break 253 } 254 ids = append(ids, dropped.AsCommonID()) 255 } 256 if err != nil { 257 for _, id := range ids { 258 _ = entry.scheduler.DeleteTransferPage(id) 259 } 260 } 261 return 262 }