mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-6.0' into trunk
* cassandra-6.0: Reduce memory allocations in row merge logic
This commit is contained in:
commit
0998495417
|
|
@ -12,6 +12,7 @@ Merged from 5.0:
|
||||||
|
|
||||||
|
|
||||||
6.0-alpha2
|
6.0-alpha2
|
||||||
|
* Reduce memory allocations in row merge logic (CASSANDRA-21359)
|
||||||
* Restore option to avoid hint transfer during decommission (CASSANDRA-21341)
|
* Restore option to avoid hint transfer during decommission (CASSANDRA-21341)
|
||||||
* Add an offline cluster metadata tool (CASSANDRA-19151)
|
* Add an offline cluster metadata tool (CASSANDRA-19151)
|
||||||
* Accord: Tail Latency Improvements (CASSANDRA-21361)
|
* Accord: Tail Latency Improvements (CASSANDRA-21361)
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,13 @@ import org.apache.cassandra.schema.ColumnMetadata;
|
||||||
import org.apache.cassandra.schema.TableMetadata;
|
import org.apache.cassandra.schema.TableMetadata;
|
||||||
import org.apache.cassandra.service.paxos.Commit;
|
import org.apache.cassandra.service.paxos.Commit;
|
||||||
import org.apache.cassandra.utils.BiLongAccumulator;
|
import org.apache.cassandra.utils.BiLongAccumulator;
|
||||||
|
import org.apache.cassandra.utils.BulkIterator;
|
||||||
import org.apache.cassandra.utils.LongAccumulator;
|
import org.apache.cassandra.utils.LongAccumulator;
|
||||||
import org.apache.cassandra.utils.MergeIterator;
|
import org.apache.cassandra.utils.MergeIterator;
|
||||||
import org.apache.cassandra.utils.ObjectSizes;
|
import org.apache.cassandra.utils.ObjectSizes;
|
||||||
import org.apache.cassandra.utils.SearchIterator;
|
import org.apache.cassandra.utils.SearchIterator;
|
||||||
import org.apache.cassandra.utils.btree.BTree;
|
import org.apache.cassandra.utils.btree.BTree;
|
||||||
|
import org.apache.cassandra.utils.btree.UpdateFunction;
|
||||||
import org.apache.cassandra.utils.memory.Cloner;
|
import org.apache.cassandra.utils.memory.Cloner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -716,7 +718,10 @@ public interface Row extends Unfiltered, Iterable<ColumnData>, IMeasurableMemory
|
||||||
private int rowsToMerge;
|
private int rowsToMerge;
|
||||||
private int lastRowSet = -1;
|
private int lastRowSet = -1;
|
||||||
|
|
||||||
private final List<ColumnData> dataBuffer = new ArrayList<>();
|
private static final ColumnData[] EMPTY_DATA_BUFFER = new ColumnData[0];
|
||||||
|
|
||||||
|
private ColumnData[] dataBuffer = EMPTY_DATA_BUFFER;
|
||||||
|
private int dataBufferSize;
|
||||||
private final ColumnDataReducer columnDataReducer;
|
private final ColumnDataReducer columnDataReducer;
|
||||||
|
|
||||||
public Merger(int size, boolean hasComplex)
|
public Merger(int size, boolean hasComplex)
|
||||||
|
|
@ -728,7 +733,8 @@ public interface Row extends Unfiltered, Iterable<ColumnData>, IMeasurableMemory
|
||||||
|
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
dataBuffer.clear();
|
Arrays.fill(dataBuffer, 0, dataBufferSize, null);
|
||||||
|
dataBufferSize = 0;
|
||||||
Arrays.fill(rows, null);
|
Arrays.fill(rows, null);
|
||||||
columnDataIterators.clear();
|
columnDataIterators.clear();
|
||||||
rowsToMerge = 0;
|
rowsToMerge = 0;
|
||||||
|
|
@ -778,8 +784,22 @@ public interface Row extends Unfiltered, Iterable<ColumnData>, IMeasurableMemory
|
||||||
if (activeDeletion.deletes(rowInfo))
|
if (activeDeletion.deletes(rowInfo))
|
||||||
rowInfo = LivenessInfo.EMPTY;
|
rowInfo = LivenessInfo.EMPTY;
|
||||||
|
|
||||||
|
int columnsCountEstimation = 0;
|
||||||
for (Row row : rows)
|
for (Row row : rows)
|
||||||
columnDataIterators.add(row == null ? Collections.emptyIterator() : row.iterator());
|
{
|
||||||
|
if (row != null)
|
||||||
|
{
|
||||||
|
columnDataIterators.add(row.iterator());
|
||||||
|
columnsCountEstimation = Math.max(columnsCountEstimation, row.columnCount());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
columnDataIterators.add(Collections.emptyIterator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// try to estimate and set a potential target capacity
|
||||||
|
if (dataBuffer.length < columnsCountEstimation)
|
||||||
|
dataBuffer = new ColumnData[columnsCountEstimation];
|
||||||
|
|
||||||
columnDataReducer.setActiveDeletion(activeDeletion);
|
columnDataReducer.setActiveDeletion(activeDeletion);
|
||||||
Iterator<ColumnData> merged = MergeIterator.get(columnDataIterators, ColumnData.comparator, columnDataReducer);
|
Iterator<ColumnData> merged = MergeIterator.get(columnDataIterators, ColumnData.comparator, columnDataReducer);
|
||||||
|
|
@ -787,13 +807,28 @@ public interface Row extends Unfiltered, Iterable<ColumnData>, IMeasurableMemory
|
||||||
{
|
{
|
||||||
ColumnData data = merged.next();
|
ColumnData data = merged.next();
|
||||||
if (data != null)
|
if (data != null)
|
||||||
dataBuffer.add(data);
|
{
|
||||||
|
ensureDataBufferCapacity();
|
||||||
|
dataBuffer[dataBufferSize++] = data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because some data might have been shadowed by the 'activeDeletion', we could have an empty row
|
// Because some data might have been shadowed by the 'activeDeletion', we could have an empty row
|
||||||
return rowInfo.isEmpty() && rowDeletion.isLive() && dataBuffer.isEmpty()
|
if (rowInfo.isEmpty() && rowDeletion.isLive() && dataBufferSize == 0)
|
||||||
? null
|
return null;
|
||||||
: BTreeRow.create(clustering, rowInfo, rowDeletion, BTree.build(dataBuffer));
|
|
||||||
|
try (BulkIterator<ColumnData> it = BulkIterator.of(dataBuffer))
|
||||||
|
{
|
||||||
|
return BTreeRow.create(clustering, rowInfo, rowDeletion,
|
||||||
|
BTree.build(it, dataBufferSize, UpdateFunction.noOp()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureDataBufferCapacity()
|
||||||
|
{
|
||||||
|
if (dataBufferSize == dataBuffer.length)
|
||||||
|
// increase capacity by 50%, use 4 as a default capacity
|
||||||
|
dataBuffer = Arrays.copyOf(dataBuffer, Math.max(dataBuffer.length + (dataBuffer.length >> 1), 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Clustering<?> mergedClustering()
|
public Clustering<?> mergedClustering()
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,8 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
{
|
{
|
||||||
protected final Candidate<In>[] heap;
|
protected final Candidate<In>[] heap;
|
||||||
|
|
||||||
|
private final Comparator<? super In> comp;
|
||||||
|
|
||||||
/** Number of non-exhausted iterators. */
|
/** Number of non-exhausted iterators. */
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
|
@ -174,9 +176,10 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
this.heap = heap;
|
this.heap = heap;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
|
this.comp = comp;
|
||||||
for (int i = 0; i < iters.size(); i++)
|
for (int i = 0; i < iters.size(); i++)
|
||||||
{
|
{
|
||||||
Candidate<In> candidate = new Candidate<>(i, iters.get(i), comp);
|
Candidate<In> candidate = new Candidate<>(i, iters.get(i));
|
||||||
heap[size++] = candidate;
|
heap[size++] = candidate;
|
||||||
}
|
}
|
||||||
needingAdvance = size;
|
needingAdvance = size;
|
||||||
|
|
@ -292,7 +295,7 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
{
|
{
|
||||||
if (!heap[nextIdx].equalParent) // if we were greater then an (or were the) equal parent, we are >= the child
|
if (!heap[nextIdx].equalParent) // if we were greater then an (or were the) equal parent, we are >= the child
|
||||||
{
|
{
|
||||||
int cmp = candidate.compareTo(heap[nextIdx]);
|
int cmp = candidate.compareTo(heap[nextIdx], comp);
|
||||||
if (cmp <= 0)
|
if (cmp <= 0)
|
||||||
{
|
{
|
||||||
heap[nextIdx].equalParent = cmp == 0;
|
heap[nextIdx].equalParent = cmp == 0;
|
||||||
|
|
@ -316,12 +319,12 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
if (!heap[nextIdx + 1].equalParent)
|
if (!heap[nextIdx + 1].equalParent)
|
||||||
{
|
{
|
||||||
// pick the smallest of the two children
|
// pick the smallest of the two children
|
||||||
int siblingCmp = heap[nextIdx + 1].compareTo(heap[nextIdx]);
|
int siblingCmp = heap[nextIdx + 1].compareTo(heap[nextIdx], comp);
|
||||||
if (siblingCmp < 0)
|
if (siblingCmp < 0)
|
||||||
++nextIdx;
|
++nextIdx;
|
||||||
|
|
||||||
// if we're smaller than this, we are done, and must only restore the heap and equalParent properties
|
// if we're smaller than this, we are done, and must only restore the heap and equalParent properties
|
||||||
int cmp = candidate.compareTo(heap[nextIdx]);
|
int cmp = candidate.compareTo(heap[nextIdx], comp);
|
||||||
if (cmp <= 0)
|
if (cmp <= 0)
|
||||||
{
|
{
|
||||||
if (cmp == 0)
|
if (cmp == 0)
|
||||||
|
|
@ -362,7 +365,7 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
// ... but sometimes we will have one last child to compare against, that has no siblings
|
// ... but sometimes we will have one last child to compare against, that has no siblings
|
||||||
if (!heap[nextIdx].equalParent)
|
if (!heap[nextIdx].equalParent)
|
||||||
{
|
{
|
||||||
int cmp = candidate.compareTo(heap[nextIdx]);
|
int cmp = candidate.compareTo(heap[nextIdx], comp);
|
||||||
if (cmp <= 0)
|
if (cmp <= 0)
|
||||||
{
|
{
|
||||||
heap[nextIdx].equalParent = cmp == 0;
|
heap[nextIdx].equalParent = cmp == 0;
|
||||||
|
|
@ -377,19 +380,17 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds and is comparable by the head item of an iterator it owns
|
// Holds and is comparable by the head item of an iterator it owns
|
||||||
protected static final class Candidate<In> implements Comparable<Candidate<In>>
|
protected static final class Candidate<In>
|
||||||
{
|
{
|
||||||
private final Iterator<? extends In> iter;
|
private final Iterator<? extends In> iter;
|
||||||
private final Comparator<? super In> comp;
|
|
||||||
private final int idx;
|
private final int idx;
|
||||||
private In item;
|
private In item;
|
||||||
private In lowerBound;
|
private In lowerBound;
|
||||||
boolean equalParent;
|
boolean equalParent;
|
||||||
|
|
||||||
public Candidate(int idx, Iterator<? extends In> iter, Comparator<? super In> comp)
|
public Candidate(int idx, Iterator<? extends In> iter)
|
||||||
{
|
{
|
||||||
this.iter = iter;
|
this.iter = iter;
|
||||||
this.comp = comp;
|
|
||||||
this.idx = idx;
|
this.idx = idx;
|
||||||
this.lowerBound = iter instanceof IteratorWithLowerBound ? ((IteratorWithLowerBound<In>)iter).lowerBound() : null;
|
this.lowerBound = iter instanceof IteratorWithLowerBound ? ((IteratorWithLowerBound<In>)iter).lowerBound() : null;
|
||||||
}
|
}
|
||||||
|
|
@ -410,7 +411,7 @@ public abstract class MergeIterator<In,Out> extends AbstractIterator<Out> implem
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(Candidate<In> that)
|
int compareTo(Candidate<In> that, Comparator<? super In> comp)
|
||||||
{
|
{
|
||||||
assert this.item != null && that.item != null;
|
assert this.item != null && that.item != null;
|
||||||
int ret = comp.compare(this.item, that.item);
|
int ret = comp.compare(this.item, that.item);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue