github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/tables/jobs/compactblk.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 jobs 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 23 "github.com/RoaringBitmap/roaring" 24 "github.com/matrixorigin/matrixone/pkg/logutil" 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/dataio/blockio" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/mergesort" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/txnentries" 34 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks" 35 ) 36 37 var CompactBlockTaskFactory = func(meta *catalog.BlockEntry, scheduler tasks.TaskScheduler) tasks.TxnTaskFactory { 38 return func(ctx *tasks.Context, txn txnif.AsyncTxn) (tasks.Task, error) { 39 return NewCompactBlockTask(ctx, txn, meta, scheduler) 40 } 41 } 42 43 type compactBlockTask struct { 44 *tasks.BaseTask 45 txn txnif.AsyncTxn 46 compacted handle.Block 47 created handle.Block 48 meta *catalog.BlockEntry 49 scheduler tasks.TaskScheduler 50 scopes []common.ID 51 mapping []uint32 52 deletes *roaring.Bitmap 53 } 54 55 func NewCompactBlockTask( 56 ctx *tasks.Context, 57 txn txnif.AsyncTxn, 58 meta *catalog.BlockEntry, 59 scheduler tasks.TaskScheduler) (task *compactBlockTask, err error) { 60 task = &compactBlockTask{ 61 txn: txn, 62 meta: meta, 63 scheduler: scheduler, 64 } 65 dbId := meta.GetSegment().GetTable().GetDB().GetID() 66 database, err := txn.UnsafeGetDatabase(dbId) 67 if err != nil { 68 return 69 } 70 tableId := meta.GetSegment().GetTable().GetID() 71 rel, err := database.UnsafeGetRelation(tableId) 72 if err != nil { 73 return 74 } 75 seg, err := rel.GetSegment(meta.GetSegment().GetID()) 76 if err != nil { 77 return 78 } 79 task.compacted, err = seg.GetBlock(meta.GetID()) 80 if err != nil { 81 return 82 } 83 task.scopes = append(task.scopes, *task.compacted.Fingerprint()) 84 task.BaseTask = tasks.NewBaseTask(task, tasks.DataCompactionTask, ctx) 85 return 86 } 87 88 func (task *compactBlockTask) Scopes() []common.ID { return task.scopes } 89 90 func (task *compactBlockTask) PrepareData() (preparer *model.PreparedCompactedBlockData, empty bool, err error) { 91 preparer = model.NewPreparedCompactedBlockData() 92 preparer.Columns = containers.NewBatch() 93 94 schema := task.meta.GetSchema() 95 var view *model.ColumnView 96 for _, def := range schema.ColDefs { 97 if def.IsPhyAddr() { 98 continue 99 } 100 view, err = task.compacted.GetColumnDataById(def.Idx, nil) 101 if err != nil { 102 return 103 } 104 task.deletes = view.DeleteMask 105 view.ApplyDeletes() 106 vec := view.Orphan() 107 if vec.Length() == 0 { 108 empty = true 109 vec.Close() 110 return 111 } 112 preparer.Columns.AddVector(def.Name, vec) 113 } 114 // Sort only if sort key is defined 115 if schema.HasSortKey() { 116 idx := schema.GetSingleSortKeyIdx() 117 preparer.SortKey = preparer.Columns.Vecs[idx] 118 if task.mapping, err = mergesort.SortBlockColumns(preparer.Columns.Vecs, idx); err != nil { 119 return preparer, false, err 120 } 121 } 122 return 123 } 124 125 func (task *compactBlockTask) GetNewBlock() handle.Block { return task.created } 126 func (task *compactBlockTask) Name() string { 127 return fmt.Sprintf("[%d]compact", task.ID()) 128 } 129 130 func (task *compactBlockTask) Execute() (err error) { 131 logutil.Info("[Start]", common.OperationField(task.Name()), 132 common.OperandField(task.meta.Repr())) 133 now := time.Now() 134 seg := task.compacted.GetSegment() 135 // Prepare a block placeholder 136 oldBMeta := task.compacted.GetMeta().(*catalog.BlockEntry) 137 // data, sortCol, closer, err := task.PrepareData(newMeta.MakeKey()) 138 preparer, empty, err := task.PrepareData() 139 if err != nil { 140 return 141 } 142 defer preparer.Close() 143 if err = seg.SoftDeleteBlock(task.compacted.Fingerprint().BlockID); err != nil { 144 return err 145 } 146 oldBlkData := oldBMeta.GetBlockData() 147 var deletes *containers.Batch 148 if !oldBMeta.IsAppendable() { 149 deletes, err = oldBlkData.CollectDeleteInRange(types.TS{}, task.txn.GetStartTS(), true) 150 if err != nil { 151 return 152 } 153 if deletes != nil { 154 defer deletes.Close() 155 } 156 } 157 158 if !empty { 159 task.createAndFlushNewBlock(seg, preparer, deletes) 160 } 161 162 table := task.meta.GetSegment().GetTable() 163 // write ablock 164 if oldBMeta.IsAppendable() { 165 var data *containers.Batch 166 data, err = oldBlkData.CollectAppendInRange(types.TS{}, task.txn.GetStartTS(), true) 167 if err != nil { 168 return 169 } 170 defer data.Close() 171 deletes, err = oldBlkData.CollectDeleteInRange(types.TS{}, task.txn.GetStartTS(), true) 172 if err != nil { 173 return 174 } 175 if deletes != nil { 176 defer deletes.Close() 177 } 178 ablockTask := NewFlushBlkTask( 179 tasks.WaitableCtx, 180 oldBlkData.GetFs(), 181 task.txn.GetStartTS(), 182 oldBMeta, 183 data, 184 deletes, 185 ) 186 if err = task.scheduler.Schedule(ablockTask); err != nil { 187 return 188 } 189 if err = ablockTask.WaitDone(); err != nil { 190 return 191 } 192 var metaLocABlk string 193 metaLocABlk, err = blockio.EncodeMetaLocWithObject( 194 ablockTask.blocks[0].GetExtent(), 195 uint32(data.Length()), 196 ablockTask.blocks) 197 if err != nil { 198 return 199 } 200 if err = task.compacted.UpdateMetaLoc(metaLocABlk); err != nil { 201 return err 202 } 203 if deletes != nil { 204 var deltaLoc string 205 deltaLoc, err = blockio.EncodeMetaLocWithObject( 206 ablockTask.blocks[1].GetExtent(), 207 uint32(deletes.Length()), 208 ablockTask.blocks) 209 if err != nil { 210 return 211 } 212 if err = task.compacted.UpdateDeltaLoc(deltaLoc); err != nil { 213 return err 214 } 215 } 216 // if err = oldBlkData.ReplayIndex(); err != nil { 217 // return err 218 // } 219 } 220 if !table.GetSchema().HasSortKey() && task.created != nil { 221 n := task.created.Rows() 222 task.mapping = make([]uint32, n) 223 for i := 0; i < n; i++ { 224 task.mapping[i] = uint32(i) 225 } 226 } 227 txnEntry := txnentries.NewCompactBlockEntry( 228 task.txn, 229 task.compacted, 230 task.created, 231 task.scheduler, 232 task.mapping, 233 task.deletes) 234 235 if err = task.txn.LogTxnEntry( 236 table.GetDB().ID, 237 table.ID, 238 txnEntry, 239 []*common.ID{task.compacted.Fingerprint()}); err != nil { 240 return 241 } 242 createdStr := "nil" 243 if task.created != nil { 244 createdStr = task.created.Fingerprint().BlockString() 245 } 246 logutil.Info("[Done]", 247 common.AnyField("txn-start-ts", task.txn.GetStartTS().ToString()), 248 common.OperationField(task.Name()), 249 common.AnyField("compacted", task.meta.Repr()), 250 common.AnyField("created", createdStr), 251 common.DurationField(time.Since(now))) 252 return 253 } 254 255 func (task *compactBlockTask) createAndFlushNewBlock( 256 seg handle.Segment, 257 preparer *model.PreparedCompactedBlockData, 258 deletes *containers.Batch, 259 ) (newBlk handle.Block, err error) { 260 newBlk, err = seg.CreateNonAppendableBlock() 261 if err != nil { 262 return 263 } 264 task.created = newBlk 265 newMeta := newBlk.GetMeta().(*catalog.BlockEntry) 266 newBlkData := newMeta.GetBlockData() 267 ioTask := NewFlushBlkTask( 268 tasks.WaitableCtx, 269 newBlkData.GetFs(), 270 task.txn.GetStartTS(), 271 newMeta, 272 preparer.Columns, 273 deletes) 274 if err = task.scheduler.Schedule(ioTask); err != nil { 275 return 276 } 277 if err = ioTask.WaitDone(); err != nil { 278 return 279 } 280 metaLoc, err := blockio.EncodeMetaLocWithObject( 281 ioTask.blocks[0].GetExtent(), 282 uint32(preparer.Columns.Length()), 283 ioTask.blocks) 284 if err != nil { 285 return 286 } 287 if err = newBlk.UpdateMetaLoc(metaLoc); err != nil { 288 return 289 } 290 if deletes != nil { 291 var deltaLoc string 292 deltaLoc, err = blockio.EncodeMetaLocWithObject( 293 ioTask.blocks[1].GetExtent(), 294 uint32(deletes.Length()), 295 ioTask.blocks) 296 if err != nil { 297 return 298 } 299 if err = task.compacted.UpdateDeltaLoc(deltaLoc); err != nil { 300 return 301 } 302 } 303 if err = newBlkData.Init(); err != nil { 304 return 305 } 306 return 307 }