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  }