github.com/matrixorigin/matrixone@v1.2.0/pkg/objectio/writer.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 objectio 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "go.uber.org/zap" 22 "math" 23 "sync" 24 25 "github.com/matrixorigin/matrixone/pkg/compress" 26 "github.com/matrixorigin/matrixone/pkg/container/batch" 27 "github.com/matrixorigin/matrixone/pkg/container/types" 28 "github.com/pierrec/lz4/v4" 29 30 "github.com/matrixorigin/matrixone/pkg/common/moerr" 31 "github.com/matrixorigin/matrixone/pkg/fileservice" 32 "github.com/matrixorigin/matrixone/pkg/logutil" 33 ) 34 35 type objectWriterV1 struct { 36 sync.RWMutex 37 schemaVer uint32 38 seqnums *Seqnums 39 object *Object 40 blocks [][]blockData 41 tombstonesColmeta []ColumnMeta 42 totalRow uint32 43 colmeta []ColumnMeta 44 buffer *ObjectBuffer 45 fileName string 46 lastId uint32 47 name ObjectName 48 compressBuf []byte 49 bloomFilter []byte 50 objStats []ObjectStats 51 sortKeySeqnum uint16 52 appendable bool 53 originSize uint32 54 size uint32 55 } 56 57 type blockData struct { 58 meta BlockObject 59 seqnums *Seqnums 60 data [][]byte 61 bloomFilter []byte 62 } 63 64 type WriterType int8 65 66 const ( 67 WriterNormal = iota 68 WriterCheckpoint 69 WriterQueryResult 70 WriterGC 71 WriterETL 72 ) 73 74 func newObjectWriterSpecialV1(wt WriterType, fileName string, fs fileservice.FileService) (*objectWriterV1, error) { 75 var name ObjectName 76 object := NewObject(fileName, fs) 77 switch wt { 78 case WriterNormal: 79 name = BuildNormalName() 80 case WriterCheckpoint: 81 name = BuildCheckpointName() 82 case WriterQueryResult: 83 name = BuildQueryResultName() 84 case WriterGC: 85 name = BuildDiskCleanerName() 86 case WriterETL: 87 name = BuildETLName() 88 } 89 writer := &objectWriterV1{ 90 seqnums: NewSeqnums(nil), 91 fileName: fileName, 92 name: name, 93 object: object, 94 buffer: NewObjectBuffer(fileName), 95 blocks: make([][]blockData, 2), 96 lastId: 0, 97 sortKeySeqnum: math.MaxUint16, 98 } 99 writer.blocks[SchemaData] = make([]blockData, 0) 100 writer.blocks[SchemaTombstone] = make([]blockData, 0) 101 return writer, nil 102 } 103 104 func newObjectWriterV1(name ObjectName, fs fileservice.FileService, schemaVersion uint32, seqnums []uint16) (*objectWriterV1, error) { 105 fileName := name.String() 106 object := NewObject(fileName, fs) 107 writer := &objectWriterV1{ 108 schemaVer: schemaVersion, 109 seqnums: NewSeqnums(seqnums), 110 fileName: fileName, 111 name: name, 112 object: object, 113 buffer: NewObjectBuffer(fileName), 114 blocks: make([][]blockData, 2), 115 lastId: 0, 116 sortKeySeqnum: math.MaxUint16, 117 } 118 writer.blocks[SchemaData] = make([]blockData, 0) 119 writer.blocks[SchemaTombstone] = make([]blockData, 0) 120 return writer, nil 121 } 122 123 func (w *objectWriterV1) GetObjectStats() []ObjectStats { 124 return w.objStats 125 } 126 127 func describeObjectHelper(w *objectWriterV1, colmeta []ColumnMeta, idx DataMetaType) ObjectStats { 128 ss := NewObjectStats() 129 SetObjectStatsObjectName(ss, w.name) 130 SetObjectStatsExtent(ss, Header(w.buffer.vector.Entries[0].Data).Extent()) 131 SetObjectStatsRowCnt(ss, w.totalRow) 132 SetObjectStatsBlkCnt(ss, uint32(len(w.blocks[idx]))) 133 134 if len(colmeta) > int(w.sortKeySeqnum) { 135 SetObjectStatsSortKeyZoneMap(ss, colmeta[w.sortKeySeqnum].ZoneMap()) 136 } 137 SetObjectStatsSize(ss, w.size) 138 SetObjectStatsOriginSize(ss, w.originSize) 139 140 return *ss 141 } 142 143 // DescribeObject generates two object stats: 144 // 145 // 0: data object stats 146 // 147 // 1: tombstone object stats 148 // 149 // if an object only has inserts, only the data object stats valid. 150 // 151 // if an object only has deletes, only the tombstone object stats valid. 152 // 153 // if an object has both inserts and deletes, both stats are valid. 154 func (w *objectWriterV1) DescribeObject() ([]ObjectStats, error) { 155 stats := make([]ObjectStats, 2) 156 if len(w.blocks[SchemaData]) != 0 { 157 stats[SchemaData] = describeObjectHelper(w, w.colmeta, SchemaData) 158 } 159 160 if len(w.blocks[SchemaTombstone]) != 0 { 161 stats[SchemaTombstone] = describeObjectHelper(w, w.tombstonesColmeta, SchemaTombstone) 162 } 163 164 return stats, nil 165 } 166 167 func (w *objectWriterV1) GetSeqnums() []uint16 { 168 return w.seqnums.Seqs 169 } 170 171 func (w *objectWriterV1) GetMaxSeqnum() uint16 { 172 return w.seqnums.MaxSeq 173 } 174 175 func (w *objectWriterV1) Write(batch *batch.Batch) (BlockObject, error) { 176 if col := len(w.seqnums.Seqs); col == 0 { 177 w.seqnums.InitWithColCnt(len(batch.Vecs)) 178 } else if col != len(batch.Vecs) { 179 panic(fmt.Sprintf("Unmatched Write Batch, expect %d, get %d, %v", col, len(batch.Vecs), batch.Attrs)) 180 } 181 block := NewBlock(w.seqnums) 182 w.AddBlock(block, batch, w.seqnums) 183 return block, nil 184 } 185 186 func (w *objectWriterV1) WriteTombstone(batch *batch.Batch) (BlockObject, error) { 187 denseSeqnums := NewSeqnums(nil) 188 denseSeqnums.InitWithColCnt(len(batch.Vecs)) 189 block := NewBlock(denseSeqnums) 190 w.AddTombstone(block, batch, denseSeqnums) 191 return block, nil 192 } 193 194 func (w *objectWriterV1) WriteSubBlock(batch *batch.Batch, dataType DataMetaType) (BlockObject, int, error) { 195 denseSeqnums := NewSeqnums(nil) 196 denseSeqnums.InitWithColCnt(len(batch.Vecs)) 197 block := NewBlock(denseSeqnums) 198 size, err := w.AddSubBlock(block, batch, denseSeqnums, dataType) 199 return block, size, err 200 } 201 202 func (w *objectWriterV1) WriteWithoutSeqnum(batch *batch.Batch) (BlockObject, error) { 203 denseSeqnums := NewSeqnums(nil) 204 denseSeqnums.InitWithColCnt(len(batch.Vecs)) 205 block := NewBlock(denseSeqnums) 206 w.AddBlock(block, batch, denseSeqnums) 207 return block, nil 208 } 209 210 func (w *objectWriterV1) UpdateBlockZM(tye DataMetaType, blkIdx int, seqnum uint16, zm ZoneMap) { 211 w.blocks[tye][blkIdx].meta.ColumnMeta(seqnum).SetZoneMap(zm) 212 } 213 214 func (w *objectWriterV1) WriteBF(blkIdx int, seqnum uint16, buf []byte) (err error) { 215 w.blocks[SchemaData][blkIdx].bloomFilter = buf 216 return 217 } 218 219 func (w *objectWriterV1) SetAppendable() { 220 w.appendable = true 221 } 222 223 func (w *objectWriterV1) SetSortKeySeqnum(seqnum uint16) { 224 w.sortKeySeqnum = seqnum 225 } 226 227 func (w *objectWriterV1) WriteObjectMetaBF(buf []byte) (err error) { 228 w.bloomFilter = buf 229 return 230 } 231 232 func (w *objectWriterV1) WriteObjectMeta(ctx context.Context, totalrow uint32, metas []ColumnMeta) { 233 w.totalRow = totalrow 234 w.colmeta = metas 235 } 236 237 func (w *objectWriterV1) prepareDataMeta(objectMeta objectDataMetaV1, blocks []blockData, offset uint32, offsetId uint16) ([]byte, Extent, error) { 238 var columnCount uint16 239 columnCount = 0 240 metaColCnt := uint16(0) 241 maxSeqnum := uint16(0) 242 var seqnums *Seqnums 243 if len(blocks) != 0 { 244 columnCount = blocks[0].meta.GetColumnCount() 245 metaColCnt = blocks[0].meta.GetMetaColumnCount() 246 maxSeqnum = blocks[0].meta.GetMaxSeqnum() 247 seqnums = blocks[0].seqnums 248 } 249 objectMeta.BlockHeader().SetColumnCount(columnCount) 250 objectMeta.BlockHeader().SetMetaColumnCount(metaColCnt) 251 objectMeta.BlockHeader().SetMaxSeqnum(maxSeqnum) 252 253 // prepare object meta and block index 254 meta, extent, err := w.prepareObjectMeta(blocks, objectMeta, offset, seqnums, offsetId) 255 if err != nil { 256 return nil, nil, err 257 } 258 return meta, extent, err 259 } 260 261 func (w *objectWriterV1) prepareObjectMeta(blocks []blockData, objectMeta objectDataMetaV1, offset uint32, seqnums *Seqnums, offsetId uint16) ([]byte, Extent, error) { 262 length := uint32(0) 263 blockCount := uint32(len(blocks)) 264 sid := w.name.SegmentId() 265 objectMeta.BlockHeader().SetSequence(uint16(blockCount)) 266 blockId := NewBlockid(&sid, w.name.Num(), uint16(blockCount)) 267 objectMeta.BlockHeader().SetBlockID(blockId) 268 objectMeta.BlockHeader().SetStartID(offsetId) 269 objectMeta.BlockHeader().SetRows(w.totalRow) 270 // write column meta 271 if seqnums != nil && len(seqnums.Seqs) > 0 { 272 for i, colMeta := range w.colmeta { 273 if i >= len(seqnums.Seqs) { 274 break 275 } 276 objectMeta.AddColumnMeta(seqnums.Seqs[i], colMeta) 277 } 278 } 279 length += objectMeta.Length() 280 blockIndex := BuildBlockIndex(blockCount) 281 blockIndex.SetBlockCount(blockCount) 282 length += blockIndex.Length() 283 for i, block := range blocks { 284 n := uint32(len(block.meta)) 285 blockIndex.SetBlockMetaPos(uint32(i), length, n) 286 length += n 287 } 288 extent := NewExtent(compress.None, offset, 0, length) 289 objectMeta.BlockHeader().SetMetaLocation(extent) 290 291 var buf bytes.Buffer 292 buf.Write(objectMeta) 293 buf.Write(blockIndex) 294 // writer block metadata 295 for _, block := range blocks { 296 buf.Write(block.meta) 297 } 298 return buf.Bytes(), extent, nil 299 } 300 301 func (w *objectWriterV1) prepareBlockMeta(offset uint32, blocks []blockData, colmeta []ColumnMeta) uint32 { 302 maxIndex := w.getMaxIndex(blocks) 303 var off, size, oSize uint32 304 for idx := uint16(0); idx < maxIndex; idx++ { 305 off = offset 306 size = 0 307 oSize = 0 308 alg := uint8(0) 309 for i, block := range blocks { 310 if block.meta.BlockHeader().ColumnCount() <= idx { 311 continue 312 } 313 blk := blocks[i] 314 location := blk.meta.ColumnMeta(blk.seqnums.Seqs[idx]).Location() 315 location.SetOffset(offset) 316 blk.meta.ColumnMeta(blk.seqnums.Seqs[idx]).setLocation(location) 317 offset += location.Length() 318 size += location.Length() 319 oSize += location.OriginSize() 320 alg = location.Alg() 321 } 322 if uint16(len(colmeta)) <= idx { 323 continue 324 } 325 colmeta[idx].Location().SetAlg(alg) 326 colmeta[idx].Location().SetOffset(off) 327 colmeta[idx].Location().SetLength(size) 328 colmeta[idx].Location().SetOriginSize(oSize) 329 } 330 return offset 331 } 332 333 func (w *objectWriterV1) prepareBloomFilter(blocks []blockData, blockCount uint32, offset uint32) ([]byte, Extent, error) { 334 buf := new(bytes.Buffer) 335 h := IOEntryHeader{IOET_BF, IOET_BloomFilter_CurrVer} 336 buf.Write(EncodeIOEntryHeader(&h)) 337 bloomFilterStart := uint32(0) 338 bloomFilterIndex := BuildBlockIndex(blockCount + 1) 339 bloomFilterIndex.SetBlockCount(blockCount + 1) 340 bloomFilterStart += bloomFilterIndex.Length() 341 for i, block := range blocks { 342 n := uint32(len(block.bloomFilter)) 343 bloomFilterIndex.SetBlockMetaPos(uint32(i), bloomFilterStart, n) 344 bloomFilterStart += n 345 } 346 bloomFilterIndex.SetBlockMetaPos(blockCount, bloomFilterStart, uint32(len(w.bloomFilter))) 347 buf.Write(bloomFilterIndex) 348 for _, block := range blocks { 349 buf.Write(block.bloomFilter) 350 } 351 buf.Write(w.bloomFilter) 352 length := uint32(len(buf.Bytes())) 353 extent := NewExtent(compress.None, offset, length, length) 354 return buf.Bytes(), extent, nil 355 } 356 357 func (w *objectWriterV1) prepareZoneMapArea(blocks []blockData, blockCount uint32, offset uint32) ([]byte, Extent, error) { 358 buf := new(bytes.Buffer) 359 h := IOEntryHeader{IOET_ZM, IOET_ZoneMap_CurrVer} 360 buf.Write(EncodeIOEntryHeader(&h)) 361 zoneMapAreaStart := uint32(0) 362 zoneMapAreaIndex := BuildBlockIndex(blockCount) 363 zoneMapAreaIndex.SetBlockCount(blockCount) 364 zoneMapAreaStart += zoneMapAreaIndex.Length() 365 for i, block := range blocks { 366 n := uint32(block.meta.GetMetaColumnCount() * ZoneMapSize) 367 zoneMapAreaIndex.SetBlockMetaPos(uint32(i), zoneMapAreaStart, n) 368 zoneMapAreaStart += n 369 } 370 buf.Write(zoneMapAreaIndex) 371 for _, block := range blocks { 372 for seqnum := uint16(0); seqnum < block.meta.GetMetaColumnCount(); seqnum++ { 373 buf.Write(block.meta.ColumnMeta(seqnum).ZoneMap()) 374 } 375 } 376 return w.WriteWithCompress(offset, buf.Bytes()) 377 } 378 379 func (w *objectWriterV1) getMaxIndex(blocks []blockData) uint16 { 380 if len(blocks) == 0 { 381 return 0 382 } 383 maxIndex := len(blocks[0].data) 384 for _, block := range blocks { 385 idxes := len(block.data) 386 if idxes > maxIndex { 387 maxIndex = idxes 388 } 389 } 390 return uint16(maxIndex) 391 } 392 393 func (w *objectWriterV1) writerBlocks(blocks []blockData) { 394 maxIndex := w.getMaxIndex(blocks) 395 for idx := uint16(0); idx < maxIndex; idx++ { 396 for _, block := range blocks { 397 if block.meta.BlockHeader().ColumnCount() <= idx { 398 continue 399 } 400 w.buffer.Write(block.data[idx]) 401 } 402 } 403 } 404 405 func (w *objectWriterV1) WriteEnd(ctx context.Context, items ...WriteOptions) ([]BlockObject, error) { 406 var err error 407 w.RLock() 408 defer w.RUnlock() 409 410 objectHeader := BuildHeader() 411 objectHeader.SetSchemaVersion(w.schemaVer) 412 offset := uint32(HeaderSize) 413 w.originSize += HeaderSize 414 415 for i := range w.blocks { 416 if i == int(SchemaData) { 417 offset = w.prepareBlockMeta(offset, w.blocks[SchemaData], w.colmeta) 418 continue 419 } 420 offset = w.prepareBlockMeta(offset, w.blocks[i], w.tombstonesColmeta) 421 } 422 423 metaHeader := buildObjectMetaV3() 424 objectMetas := make([]objectDataMetaV1, len(w.blocks)) 425 bloomFilterDatas := make([][]byte, len(w.blocks)) 426 bloomFilterExtents := make([]Extent, len(w.blocks)) 427 zoneMapAreaDatas := make([][]byte, len(w.blocks)) 428 zoneMapAreaExtents := make([]Extent, len(w.blocks)) 429 metas := make([][]byte, len(w.blocks)) 430 metaExtents := make([]Extent, len(w.blocks)) 431 for i := range w.blocks { 432 colMetaCount := uint16(0) 433 if len(w.blocks[i]) > 0 { 434 colMetaCount = w.blocks[i][0].meta.GetMetaColumnCount() 435 } 436 objectMetas[i] = BuildObjectMeta(colMetaCount) 437 // prepare bloom filter 438 bloomFilterDatas[i], bloomFilterExtents[i], err = w.prepareBloomFilter(w.blocks[i], uint32(len(w.blocks[i])), offset) 439 if err != nil { 440 return nil, err 441 } 442 objectMetas[i].BlockHeader().SetBFExtent(bloomFilterExtents[i]) 443 objectMetas[i].BlockHeader().SetAppendable(w.appendable) 444 objectMetas[i].BlockHeader().SetSortKey(w.sortKeySeqnum) 445 offset += bloomFilterExtents[i].Length() 446 w.originSize += bloomFilterExtents[i].OriginSize() 447 448 // prepare zone map area 449 zoneMapAreaDatas[i], zoneMapAreaExtents[i], err = w.prepareZoneMapArea(w.blocks[i], uint32(len(w.blocks[i])), offset) 450 if err != nil { 451 return nil, err 452 } 453 objectMetas[i].BlockHeader().SetZoneMapArea(zoneMapAreaExtents[i]) 454 offset += zoneMapAreaExtents[i].Length() 455 w.originSize += zoneMapAreaExtents[i].OriginSize() 456 } 457 subMetaCount := uint16(len(w.blocks) - 2) 458 subMetachIndex := BuildSubMetaIndex(subMetaCount) 459 subMetachIndex.SetSubMetaCount(subMetaCount) 460 startID := uint16(0) 461 start := uint32(0) 462 idxStart := metaHeader.HeaderLength() + subMetachIndex.Length() 463 for i := range w.blocks { 464 // prepare object meta and block index 465 metas[i], metaExtents[i], err = w.prepareDataMeta(objectMetas[i], w.blocks[i], offset, startID) 466 if err != nil { 467 return nil, err 468 } 469 if i == int(SchemaData) { 470 start = metaExtents[SchemaData].Offset() 471 metaHeader.SetDataMetaOffset(idxStart) 472 metaHeader.SetDataMetaCount(uint16(len(w.blocks[i]))) 473 } else if i == int(SchemaTombstone) { 474 metaHeader.SetTombstoneMetaOffset(idxStart) 475 metaHeader.SetTombstoneMetaCount(uint16(len(w.blocks[SchemaTombstone]))) 476 } else { 477 subMetachIndex.SetSchemaMeta(uint16(i-2), uint16(i-2), uint16(len(w.blocks[i])), idxStart) 478 } 479 idxStart += metaExtents[i].OriginSize() 480 startID += uint16(len(w.blocks[i])) 481 } 482 var buf bytes.Buffer 483 h := IOEntryHeader{IOET_ObjMeta, IOET_ObjectMeta_CurrVer} 484 buf.Write(EncodeIOEntryHeader(&h)) 485 buf.Write(metaHeader) 486 buf.Write(subMetachIndex) 487 488 for i := range metas { 489 buf.Write(metas[i]) 490 } 491 objMeta, extent, err := w.WriteWithCompress(start, buf.Bytes()) 492 objectHeader.SetExtent(extent) 493 494 // begin write 495 496 // writer object header 497 w.buffer.Write(objectHeader) 498 499 // writer data 500 for i := range w.blocks { 501 w.writerBlocks(w.blocks[i]) 502 } 503 // writer bloom filter 504 for i := range bloomFilterDatas { 505 w.buffer.Write(bloomFilterDatas[i]) 506 w.buffer.Write(zoneMapAreaDatas[i]) 507 } 508 // writer object metadata 509 w.buffer.Write(objMeta) 510 511 // write footer 512 footer := Footer{ 513 metaExtent: extent, 514 version: Version, 515 magic: Magic, 516 } 517 footerBuf := footer.Marshal() 518 w.buffer.Write(footerBuf) 519 if err != nil { 520 return nil, err 521 } 522 w.originSize += objectHeader.Extent().OriginSize() 523 w.originSize += uint32(len(footerBuf)) 524 w.size = objectHeader.Extent().End() + uint32(len(footerBuf)) 525 blockObjects := make([]BlockObject, 0) 526 for i := range w.blocks { 527 for j := range w.blocks[i] { 528 header := w.blocks[i][j].meta.BlockHeader() 529 header.SetMetaLocation(objectHeader.Extent()) 530 blockObjects = append(blockObjects, w.blocks[i][j].meta) 531 } 532 } 533 err = w.Sync(ctx, items...) 534 if err != nil { 535 return nil, err 536 } 537 // The buffer needs to be released at the end of WriteEnd 538 // Because the outside may hold this writer 539 // After WriteEnd is called, no more data can be written 540 w.buffer = nil 541 return blockObjects, err 542 } 543 544 // Sync is for testing 545 func (w *objectWriterV1) Sync(ctx context.Context, items ...WriteOptions) error { 546 var err error 547 w.buffer.SetDataOptions(items...) 548 defer func() { 549 if err != nil { 550 w.buffer = nil 551 logutil.Error("[DoneWithErr] Write Sync error", zap.Error(err)) 552 } 553 }() 554 // if a compact task is rollbacked, it may leave a written file in fs 555 // here we just delete it and write again 556 _, err = fileservice.DoWithRetry( 557 "ObjectSync", 558 func() (int, error) { 559 return 0, w.object.fs.Write(ctx, w.buffer.GetData()) 560 }, 561 64, 562 fileservice.IsRetryableError, 563 ) 564 if moerr.IsMoErrCode(err, moerr.ErrFileAlreadyExists) { 565 if err = w.object.fs.Delete(ctx, w.fileName); err != nil { 566 return err 567 } 568 _, err = fileservice.DoWithRetry( 569 "ObjectSync", 570 func() (int, error) { 571 return 0, w.object.fs.Write(ctx, w.buffer.GetData()) 572 }, 573 64, 574 fileservice.IsRetryableError, 575 ) 576 } 577 578 if err != nil { 579 return err 580 } 581 582 w.objStats, err = w.DescribeObject() 583 return err 584 } 585 586 func (w *objectWriterV1) GetDataStats() ObjectStats { 587 return w.objStats[SchemaData] 588 } 589 590 func (w *objectWriterV1) WriteWithCompress(offset uint32, buf []byte) (data []byte, extent Extent, err error) { 591 var tmpData []byte 592 dataLen := len(buf) 593 compressBlockBound := lz4.CompressBlockBound(dataLen) 594 if len(w.compressBuf) < compressBlockBound { 595 w.compressBuf = make([]byte, compressBlockBound) 596 } 597 if tmpData, err = compress.Compress(buf, w.compressBuf[:compressBlockBound], compress.Lz4); err != nil { 598 return 599 } 600 length := uint32(len(tmpData)) 601 data = make([]byte, length) 602 copy(data, tmpData[:length]) 603 extent = NewExtent(compress.Lz4, offset, length, uint32(dataLen)) 604 return 605 } 606 607 func (w *objectWriterV1) addBlock(blocks *[]blockData, blockMeta BlockObject, bat *batch.Batch, seqnums *Seqnums) (int, error) { 608 // CHANGE ME 609 // block.BlockHeader()return w.WriteWithCompress(offset, buf.Bytes()).SetBlockID(w.lastId) 610 blockMeta.BlockHeader().SetSequence(uint16(w.lastId)) 611 612 block := blockData{meta: blockMeta, seqnums: seqnums} 613 var data []byte 614 var buf bytes.Buffer 615 var rows int 616 var size int 617 for i, vec := range bat.Vecs { 618 if i == 0 { 619 rows = vec.Length() 620 } else if rows != vec.Length() { 621 attr := "unknown" 622 if len(bat.Attrs) > i { 623 attr = bat.Attrs[i] 624 } 625 logutil.Debugf("%s unmatched length, expect %d, get %d", attr, rows, vec.Length()) 626 } 627 buf.Reset() 628 h := IOEntryHeader{IOET_ColData, IOET_ColumnData_CurrVer} 629 buf.Write(EncodeIOEntryHeader(&h)) 630 err := vec.MarshalBinaryWithBuffer(&buf) 631 if err != nil { 632 return 0, err 633 } 634 var ext Extent 635 if data, ext, err = w.WriteWithCompress(0, buf.Bytes()); err != nil { 636 return 0, err 637 } 638 size += len(data) 639 block.data = append(block.data, data) 640 blockMeta.ColumnMeta(seqnums.Seqs[i]).setLocation(ext) 641 blockMeta.ColumnMeta(seqnums.Seqs[i]).setDataType(uint8(vec.GetType().Oid)) 642 if vec.GetType().Oid == types.T_any { 643 panic("any type batch") 644 } 645 blockMeta.ColumnMeta(seqnums.Seqs[i]).SetNullCnt(uint32(vec.GetNulls().GetCardinality())) 646 w.originSize += ext.OriginSize() 647 } 648 blockMeta.BlockHeader().SetRows(uint32(rows)) 649 *blocks = append(*blocks, block) 650 w.lastId++ 651 return size, nil 652 } 653 654 func (w *objectWriterV1) AddBlock(blockMeta BlockObject, bat *batch.Batch, seqnums *Seqnums) (int, error) { 655 w.Lock() 656 defer w.Unlock() 657 658 return w.addBlock(&w.blocks[SchemaData], blockMeta, bat, seqnums) 659 } 660 661 func (w *objectWriterV1) AddTombstone(blockMeta BlockObject, bat *batch.Batch, seqnums *Seqnums) (int, error) { 662 w.Lock() 663 defer w.Unlock() 664 if w.tombstonesColmeta == nil { 665 w.tombstonesColmeta = make([]ColumnMeta, len(bat.Vecs)) 666 } 667 for i := range w.tombstonesColmeta { 668 w.tombstonesColmeta[i] = BuildObjectColumnMeta() 669 } 670 return w.addBlock(&w.blocks[SchemaTombstone], blockMeta, bat, seqnums) 671 } 672 673 func (w *objectWriterV1) AddSubBlock(blockMeta BlockObject, bat *batch.Batch, seqnums *Seqnums, dataType DataMetaType) (int, error) { 674 w.Lock() 675 defer w.Unlock() 676 if dataType < CkpMetaStart { 677 panic("invalid data type") 678 } 679 for i := int(CkpMetaStart); i <= int(CkpMetaEnd); i++ { 680 if len(w.blocks) <= i { 681 blocks := make([]blockData, 0) 682 w.blocks = append(w.blocks, blocks) 683 } 684 } 685 return w.addBlock(&w.blocks[dataType], blockMeta, bat, seqnums) 686 } 687 688 func (w *objectWriterV1) GetBlock(id uint32) BlockObject { 689 w.Lock() 690 defer w.Unlock() 691 return w.blocks[SchemaData][id].meta 692 }