4343import org .apache .cassandra .schema .TableMetadata ;
4444import org .apache .cassandra .service .paxos .Commit ;
4545import org .apache .cassandra .utils .BiLongAccumulator ;
46+ import org .apache .cassandra .utils .BulkIterator ;
4647import org .apache .cassandra .utils .LongAccumulator ;
4748import org .apache .cassandra .utils .MergeIterator ;
4849import org .apache .cassandra .utils .ObjectSizes ;
4950import org .apache .cassandra .utils .SearchIterator ;
5051import org .apache .cassandra .utils .btree .BTree ;
52+ import org .apache .cassandra .utils .btree .UpdateFunction ;
5153import org .apache .cassandra .utils .memory .Cloner ;
5254
5355/**
@@ -716,7 +718,10 @@ public static class Merger
716718 private int rowsToMerge ;
717719 private int lastRowSet = -1 ;
718720
719- private final List <ColumnData > dataBuffer = new ArrayList <>();
721+ private static final ColumnData [] EMPTY_DATA_BUFFER = new ColumnData [0 ];
722+
723+ private ColumnData [] dataBuffer = EMPTY_DATA_BUFFER ;
724+ private int dataBufferSize ;
720725 private final ColumnDataReducer columnDataReducer ;
721726
722727 public Merger (int size , boolean hasComplex )
@@ -728,7 +733,8 @@ public Merger(int size, boolean hasComplex)
728733
729734 public void clear ()
730735 {
731- dataBuffer .clear ();
736+ Arrays .fill (dataBuffer , 0 , dataBufferSize , null );
737+ dataBufferSize = 0 ;
732738 Arrays .fill (rows , null );
733739 columnDataIterators .clear ();
734740 rowsToMerge = 0 ;
@@ -778,22 +784,51 @@ public Row merge(DeletionTime activeDeletion)
778784 if (activeDeletion .deletes (rowInfo ))
779785 rowInfo = LivenessInfo .EMPTY ;
780786
787+ int columnsCountEstimation = 0 ;
781788 for (Row row : rows )
782- columnDataIterators .add (row == null ? Collections .emptyIterator () : row .iterator ());
789+ {
790+ if (row != null )
791+ {
792+ columnDataIterators .add (row .iterator ());
793+ columnsCountEstimation = Math .max (columnsCountEstimation , row .columnCount ());
794+ }
795+ else
796+ {
797+ columnDataIterators .add (Collections .emptyIterator ());
798+ }
799+ }
800+ // try to estimate and set a potential target capacity
801+ if (dataBuffer .length < columnsCountEstimation )
802+ dataBuffer = new ColumnData [columnsCountEstimation ];
783803
784804 columnDataReducer .setActiveDeletion (activeDeletion );
785805 Iterator <ColumnData > merged = MergeIterator .get (columnDataIterators , ColumnData .comparator , columnDataReducer );
786806 while (merged .hasNext ())
787807 {
788808 ColumnData data = merged .next ();
789809 if (data != null )
790- dataBuffer .add (data );
810+ {
811+ ensureDataBufferCapacity ();
812+ dataBuffer [dataBufferSize ++] = data ;
813+ }
791814 }
792815
793816 // Because some data might have been shadowed by the 'activeDeletion', we could have an empty row
794- return rowInfo .isEmpty () && rowDeletion .isLive () && dataBuffer .isEmpty ()
795- ? null
796- : BTreeRow .create (clustering , rowInfo , rowDeletion , BTree .build (dataBuffer ));
817+ if (rowInfo .isEmpty () && rowDeletion .isLive () && dataBufferSize == 0 )
818+ return null ;
819+
820+ try (BulkIterator <ColumnData > it = BulkIterator .of (dataBuffer ))
821+ {
822+ return BTreeRow .create (clustering , rowInfo , rowDeletion ,
823+ BTree .build (it , dataBufferSize , UpdateFunction .noOp ()));
824+ }
825+ }
826+
827+ private void ensureDataBufferCapacity ()
828+ {
829+ if (dataBufferSize == dataBuffer .length )
830+ // increase capacity by 50%, use 4 as a default capacity
831+ dataBuffer = Arrays .copyOf (dataBuffer , Math .max (dataBuffer .length + (dataBuffer .length >> 1 ), 4 ));
797832 }
798833
799834 public Clustering <?> mergedClustering ()
0 commit comments