This is an automated email from the ASF dual-hosted git repository.
Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new fe892b228a8 Clean up multi-value limit enforcement in mutable segment
(#19431)
fe892b228a8 is described below
commit fe892b228a83437bb144a6c5abdd925c1e3faeda
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Tue Sep 1 23:01:20 2026 -0700
Clean up multi-value limit enforcement in mutable segment (#19431)
---
.../inputformat/clplog/CLPLogRecordExtractor.java | 4 +-
.../indexsegment/mutable/MutableSegmentImpl.java | 101 ++++-----
.../impl/forward/CLPMutableForwardIndex.java | 6 +-
.../forward/FixedByteMVMutableForwardIndex.java | 97 ++++-----
.../segment/index/forward/ForwardIndexType.java | 9 +-
...leSegmentImplNumMultiValuesValidationTest.java} | 238 ++++++++++-----------
.../FixedByteMVMutableForwardIndexTest.java | 66 +++---
.../segment/spi/index/ForwardIndexConfig.java | 5 +
.../mutable/provider/MutableIndexContext.java | 41 ++--
9 files changed, 258 insertions(+), 309 deletions(-)
diff --git
a/pinot-plugins/pinot-input-format/pinot-clp-log/src/main/java/org/apache/pinot/plugin/inputformat/clplog/CLPLogRecordExtractor.java
b/pinot-plugins/pinot-input-format/pinot-clp-log/src/main/java/org/apache/pinot/plugin/inputformat/clplog/CLPLogRecordExtractor.java
index d59073a3255..bfbbd08a300 100644
---
a/pinot-plugins/pinot-input-format/pinot-clp-log/src/main/java/org/apache/pinot/plugin/inputformat/clplog/CLPLogRecordExtractor.java
+++
b/pinot-plugins/pinot-input-format/pinot-clp-log/src/main/java/org/apache/pinot/plugin/inputformat/clplog/CLPLogRecordExtractor.java
@@ -34,7 +34,7 @@ import java.util.Set;
import javax.annotation.Nullable;
import org.apache.pinot.common.metrics.ServerMeter;
import org.apache.pinot.common.metrics.ServerMetrics;
-import org.apache.pinot.segment.local.segment.index.forward.ForwardIndexType;
+import org.apache.pinot.segment.spi.index.ForwardIndexConfig;
import org.apache.pinot.spi.data.readers.BaseRecordExtractor;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.data.readers.RecordExtractorConfig;
@@ -51,7 +51,7 @@ import org.slf4j.LoggerFactory;
/// `_dictionaryVars`, `_encodedVars`. All other fields are extracted as plain
JSON values.
public class CLPLogRecordExtractor extends BaseRecordExtractor<Map<String,
Object>> {
// The maximum number of variables that can be stored in a cell (row of a
single column).
- private static final int MAX_VARIABLES_PER_CELL =
ForwardIndexType.MAX_MULTI_VALUES_PER_ROW;
+ private static final int MAX_VARIABLES_PER_CELL =
ForwardIndexConfig.DEFAULT_MAX_NUM_MULTI_VALUES;
private static final Logger LOGGER =
LoggerFactory.getLogger(CLPLogRecordExtractor.class);
private final ServerMetrics _serverMetrics = ServerMetrics.get();
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
index 6f93fad11e2..ea54e6f9bd1 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
@@ -59,7 +59,6 @@ import
org.apache.pinot.segment.local.realtime.impl.RealtimeSegmentConfig;
import
org.apache.pinot.segment.local.realtime.impl.RealtimeSegmentStatsHistory;
import
org.apache.pinot.segment.local.realtime.impl.dictionary.BaseOffHeapMutableDictionary;
import
org.apache.pinot.segment.local.realtime.impl.dictionary.SameValueMutableDictionary;
-import
org.apache.pinot.segment.local.realtime.impl.forward.FixedByteMVMutableForwardIndex;
import
org.apache.pinot.segment.local.realtime.impl.forward.SameValueMutableForwardIndex;
import
org.apache.pinot.segment.local.realtime.impl.invertedindex.MultiColumnRealtimeLuceneTextIndex;
import
org.apache.pinot.segment.local.realtime.impl.nullvalue.MutableNullValueVector;
@@ -166,7 +165,7 @@ public class MutableSegmentImpl implements MutableSegment {
private final File _consumerDir;
private final Map<String, IndexContainer> _indexContainerMap = new
HashMap<>();
- private final MultiValueRowLimit[] _multiValueRowLimits;
+ private final MultiValueLimit[] _multiValueLimits;
private final IdMap<FixedIntArray> _recordIdMap;
private final int _numKeyColumns;
// Cache the physical (non-virtual) field specs
@@ -311,7 +310,7 @@ public class MutableSegmentImpl implements MutableSegment {
// Initialize for each column
boolean hasColumnWithReuseMutableTextIndex = false;
- List<MultiValueRowLimit> multiValueRowLimits = new ArrayList<>();
+ List<MultiValueLimit> multiValueLimits = new ArrayList<>();
for (FieldSpec fieldSpec : _physicalFieldSpecs) {
String column = fieldSpec.getName();
@@ -330,21 +329,27 @@ public class MutableSegmentImpl implements MutableSegment
{
Optional.ofNullable(config.getIndexConfigByCol().get(column)).orElse(FieldIndexConfigs.EMPTY);
VectorIndexConfig vectorIndexConfig =
indexConfigs.getConfig(StandardIndexes.vector());
boolean isDictionary = !isNoDictionaryColumn(indexConfigs, fieldSpec,
column);
- MutableIndexContext context =
- MutableIndexContext.builder()
- .withFieldSpec(fieldSpec)
- .withMemoryManager(_memoryManager)
- .withDictionary(isDictionary)
- .withCapacity(_capacity)
- .offHeap(_offHeap)
- .withSegmentName(_segmentName)
-
.withEstimatedCardinality(_statsHistory.getEstimatedCardinality(column))
-
.withEstimatedColSize(_statsHistory.getEstimatedAvgColSize(column))
-
.withAvgNumMultiValues(_statsHistory.getEstimatedAvgColSize(column))
- .withMaxNumMultiValuesPerRowOverride(
- vectorIndexConfig.isEnabled() ?
vectorIndexConfig.getVectorDimension() : 0)
- .withConsumerDir(_consumerDir)
- .withFixedLengthBytes(fixedByteSize).build();
+ MutableIndexContext.Builder contextBuilder =
MutableIndexContext.builder()
+ .withFieldSpec(fieldSpec)
+ .withMemoryManager(_memoryManager)
+ .withDictionary(isDictionary)
+ .withCapacity(_capacity)
+ .offHeap(_offHeap)
+ .withSegmentName(_segmentName)
+
.withEstimatedCardinality(_statsHistory.getEstimatedCardinality(column))
+ .withEstimatedColSize(_statsHistory.getEstimatedAvgColSize(column))
+ .withAvgNumMultiValues(config.getAvgNumMultiValues())
+ .withConsumerDir(_consumerDir)
+ .withFixedLengthBytes(fixedByteSize);
+ if (vectorIndexConfig.isEnabled()) {
+ // A vector column holds one value per dimension, which may exceed the
default cap
+
contextBuilder.withMaxNumMultiValues(vectorIndexConfig.getVectorDimension());
+ }
+ MutableIndexContext context = contextBuilder.build();
+
+ if (!fieldSpec.isSingleValueField()) {
+ multiValueLimits.add(new MultiValueLimit(column,
context.getMaxNumMultiValues()));
+ }
// Partition info
PartitionFunction partitionFunction = null;
@@ -411,14 +416,6 @@ public class MutableSegmentImpl implements MutableSegment {
String sourceColumn = columnAggregatorPair.getLeft();
ValueAggregator valueAggregator = columnAggregatorPair.getRight();
- // Capture the row cap from the concrete writer before a SameValue
wrapper hides the type.
- MutableIndex unwrappedForwardIndex =
mutableIndexes.get(StandardIndexes.forward());
- if (!fieldSpec.isSingleValueField()
- && unwrappedForwardIndex instanceof FixedByteMVMutableForwardIndex
fixedByteMVIndex) {
- multiValueRowLimits.add(
- new MultiValueRowLimit(column,
fixedByteMVIndex.getMaxNumberOfMultiValuesPerRow()));
- }
-
// TODO this can be removed after forward index contents no longer
depends on text index configs
// If the raw value is provided, use it for the forward/dictionary index
of this column by wrapping the
// already created MutableIndex with a SameValue implementation. This
optimization can only be done when
@@ -453,7 +450,7 @@ public class MutableSegmentImpl implements MutableSegment {
nullValueVector, sourceColumn, valueAggregator));
}
_hasColumnWithReuseMutableTextIndex = hasColumnWithReuseMutableTextIndex;
- _multiValueRowLimits =
multiValueRowLimits.toArray(MultiValueRowLimit[]::new);
+ _multiValueLimits = multiValueLimits.toArray(new MultiValueLimit[0]);
_partitionDedupMetadataManager = config.getPartitionDedupMetadataManager();
_dedupTimeColumn =
@@ -657,12 +654,12 @@ public class MutableSegmentImpl implements MutableSegment
{
int numDocsIndexed = _numDocsIndexed;
if (isUpsertEnabled()) {
// Validate the incoming row before partial-upsert strategies can copy
or expand oversized MV values.
- validateLengthOfMVColumns(row);
+ validateNumMultiValues(row);
RecordInfo recordInfo = getRecordInfo(row, numDocsIndexed);
GenericRow updatedRow =
_partitionUpsertMetadataManager.updateRecord(row, recordInfo);
if (_isPartialUpsert) {
// Strategies such as APPEND and UNION can produce a merged row that
is larger than the incoming row.
- validateLengthOfMVColumns(updatedRow);
+ validateNumMultiValues(updatedRow);
}
trackMismatchedPartition(mismatchedPartitionIndexContainer,
mismatchedPartition, mismatchedPartitionValue);
@@ -708,7 +705,7 @@ public class MutableSegmentImpl implements MutableSegment {
}
// Validate before dedup or partition tracking so a rejected row cannot
leave metadata state behind.
- validateLengthOfMVColumns(row);
+ validateNumMultiValues(row);
trackMismatchedPartition(mismatchedPartitionIndexContainer,
mismatchedPartition, mismatchedPartitionValue);
if (isDedupEnabled()) {
@@ -824,21 +821,21 @@ public class MutableSegmentImpl implements MutableSegment
{
return new ComparisonColumns(comparisonValues, comparableIndex);
}
- /// @param row
- /// @throws UnsupportedOperationException if the length of an MV column
exceeds the maximum number of values allowed
- /// in a single row of the forward index
- private void validateLengthOfMVColumns(GenericRow row)
- throws UnsupportedOperationException {
- for (int i = 0; i < _multiValueRowLimits.length; i++) {
- MultiValueRowLimit rowLimit = _multiValueRowLimits[i];
- Object value = row.getValue(rowLimit._column);
- if (value == null) {
- continue;
- }
- Object[] values = (Object[]) value;
- if (values.length > rowLimit._maxNumberOfMultiValuesPerRow) {
- throw new UnsupportedOperationException("MV column '" +
rowLimit._column + "' has " + values.length
- + " values, exceeding the maximum of " +
rowLimit._maxNumberOfMultiValuesPerRow + " values per row.");
+ /// Validates that no multi-value column in the row holds more values than
its forward index can store in a single
+ /// multi-value entry. Must run before any column of the row is indexed so
that a rejected row leaves no partial
+ /// state behind.
+ ///
+ /// @throws IllegalStateException if a multi-value column exceeds its
maximum number of values
+ private void validateNumMultiValues(GenericRow row) {
+ for (MultiValueLimit limit : _multiValueLimits) {
+ Object value = row.getValue(limit._column);
+ if (value != null) {
+ int numValues = ((Object[]) value).length;
+ if (numValues > limit._maxNumMultiValues) {
+ throw new IllegalStateException(
+ String.format("Number of values: %d in MV column: %s exceeds the
maximum allowed: %d", numValues,
+ limit._column, limit._maxNumMultiValues));
+ }
}
}
}
@@ -998,9 +995,6 @@ public class MutableSegmentImpl implements MutableSegment {
MutableIndex mutableIndex = indexEntry.getValue();
mutableIndex.add(values, dictIds, docId);
updateIndexCapacityThresholdBreached(mutableIndex,
indexEntry.getKey(), column);
- } catch (IllegalArgumentException e) {
- // Row-limit violations must fail the document. Other index errors
stay fail-soft (#16316).
- throw e;
} catch (Exception e) {
recordIndexingError(indexEntry.getKey(), e);
}
@@ -1693,15 +1687,8 @@ public class MutableSegmentImpl implements
MutableSegment {
}
}
- /// Immutable fixed-byte MV column descriptor used by the per-record length
validation hot path.
- private static final class MultiValueRowLimit {
- private final String _column;
- private final int _maxNumberOfMultiValuesPerRow;
-
- private MultiValueRowLimit(String column, int
maxNumberOfMultiValuesPerRow) {
- _column = column;
- _maxNumberOfMultiValuesPerRow = maxNumberOfMultiValuesPerRow;
- }
+ /// Per-column cap on the number of values in a multi-value entry, as
configured on the mutable index context.
+ private record MultiValueLimit(String _column, int _maxNumMultiValues) {
}
private class IndexContainer implements Closeable {
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/CLPMutableForwardIndex.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/CLPMutableForwardIndex.java
index 15f25d1220c..2341a6e6471 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/CLPMutableForwardIndex.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/CLPMutableForwardIndex.java
@@ -27,7 +27,7 @@ import java.io.IOException;
import
org.apache.pinot.segment.local.realtime.impl.dictionary.StringOffHeapMutableDictionary;
import
org.apache.pinot.segment.local.segment.creator.impl.stats.CLPStatsProvider;
import
org.apache.pinot.segment.local.segment.creator.impl.stats.StringColumnPreIndexStatsCollector;
-import org.apache.pinot.segment.local.segment.index.forward.ForwardIndexType;
+import org.apache.pinot.segment.spi.index.ForwardIndexConfig;
import org.apache.pinot.segment.spi.index.mutable.MutableDictionary;
import org.apache.pinot.segment.spi.index.mutable.MutableForwardIndex;
import org.apache.pinot.segment.spi.memory.PinotDataBufferMemoryManager;
@@ -71,10 +71,10 @@ public class CLPMutableForwardIndex implements
MutableForwardIndex {
_logTypeFwdIndex =
new FixedByteSVMutableForwardIndex(true, DataType.INT, capacity,
memoryManager, columnName + "_logType.fwd");
_dictVarsFwdIndex =
- new
FixedByteMVMutableForwardIndex(ForwardIndexType.MAX_MULTI_VALUES_PER_ROW, 20,
capacity, Integer.BYTES,
+ new
FixedByteMVMutableForwardIndex(ForwardIndexConfig.DEFAULT_MAX_NUM_MULTI_VALUES,
20, capacity, Integer.BYTES,
memoryManager, columnName + "_dictVars.fwd", true, DataType.INT);
_encodedVarsFwdIndex =
- new
FixedByteMVMutableForwardIndex(ForwardIndexType.MAX_MULTI_VALUES_PER_ROW, 20,
capacity, Long.BYTES,
+ new
FixedByteMVMutableForwardIndex(ForwardIndexConfig.DEFAULT_MAX_NUM_MULTI_VALUES,
20, capacity, Long.BYTES,
memoryManager, columnName + "_encodedVars.fwd", true,
DataType.LONG);
_clpMessageDecoder = new
MessageDecoder(BuiltInVariableHandlingRuleVersions.VariablesSchemaV2,
BuiltInVariableHandlingRuleVersions.VariableEncodingMethodsV1);
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/FixedByteMVMutableForwardIndex.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/FixedByteMVMutableForwardIndex.java
index bf91fb2b06a..2c69ab7c657 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/FixedByteMVMutableForwardIndex.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/forward/FixedByteMVMutableForwardIndex.java
@@ -28,7 +28,6 @@ import
org.apache.pinot.segment.local.io.writer.impl.FixedByteSingleValueMultiCo
import org.apache.pinot.segment.spi.index.mutable.MutableForwardIndex;
import org.apache.pinot.segment.spi.memory.PinotDataBuffer;
import org.apache.pinot.segment.spi.memory.PinotDataBufferMemoryManager;
-import org.apache.pinot.spi.data.FieldSpec;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -94,8 +93,6 @@ import org.slf4j.LoggerFactory;
public class FixedByteMVMutableForwardIndex implements MutableForwardIndex {
private static final Logger LOGGER =
LoggerFactory.getLogger(FixedByteMVMutableForwardIndex.class);
- /// number of columns is 1, column size is variable but less than
\_maxNumberOfMultiValuesPerRow
-
private static final int SIZE_OF_INT = 4;
private static final int NUM_COLS_IN_HEADER = 3;
@@ -110,16 +107,17 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
private final List<FixedByteSingleValueMultiColReader> _headerReaders = new
CopyOnWriteArrayList<>();
private final List<FixedByteSingleValueMultiColWriter> _dataWriters = new
ArrayList<>();
private final List<FixedByteSingleValueMultiColReader> _dataReaders = new
CopyOnWriteArrayList<>();
- private final int _headerSize;
- private final int _incrementalCapacity;
- private final int _columnSizeInBytes;
- private final int _maxNumberOfMultiValuesPerRow;
- private final int _rowCountPerChunk;
+
+ private final int _maxNumMultiValues;
+ private final int _numRowsPerChunk;
+ private final int _valueSizeInBytes;
private final PinotDataBufferMemoryManager _memoryManager;
private final String _context;
private final boolean _isDictionaryEncoded;
- private final FieldSpec.DataType _storedType;
- private final FieldSpec.DataType _dataType;
+ private final DataType _storedType;
+ private final DataType _dataType;
+ private final int _headerSize;
+ private final int _incrementalCapacity;
private FixedByteSingleValueMultiColWriter _curHeaderWriter;
private FixedByteSingleValueMultiColWriter _currentDataWriter;
@@ -128,33 +126,30 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
private int _prevRowLength = 0; // Number of values in the column for the
last row added.
private int _numValues = 0;
- public FixedByteMVMutableForwardIndex(int maxNumberOfMultiValuesPerRow, int
avgMultiValueCount, int rowCountPerChunk,
- int columnSizeInBytes, PinotDataBufferMemoryManager memoryManager,
String context, boolean isDictionaryEncoded,
- FieldSpec.DataType storedType) {
- this(maxNumberOfMultiValuesPerRow, avgMultiValueCount, rowCountPerChunk,
columnSizeInBytes, memoryManager, context,
+ public FixedByteMVMutableForwardIndex(int maxNumMultiValues, int
avgNumMultiValues, int numRowsPerChunk,
+ int valueSizeInBytes, PinotDataBufferMemoryManager memoryManager, String
context, boolean isDictionaryEncoded,
+ DataType storedType) {
+ this(maxNumMultiValues, avgNumMultiValues, numRowsPerChunk,
valueSizeInBytes, memoryManager, context,
isDictionaryEncoded, storedType, storedType);
}
- public FixedByteMVMutableForwardIndex(int maxNumberOfMultiValuesPerRow, int
avgMultiValueCount, int rowCountPerChunk,
- int columnSizeInBytes, PinotDataBufferMemoryManager memoryManager,
String context, boolean isDictionaryEncoded,
- FieldSpec.DataType storedType, FieldSpec.DataType dataType) {
+ public FixedByteMVMutableForwardIndex(int maxNumMultiValues, int
avgNumMultiValues, int numRowsPerChunk,
+ int valueSizeInBytes, PinotDataBufferMemoryManager memoryManager, String
context, boolean isDictionaryEncoded,
+ DataType storedType, DataType dataType) {
+ _maxNumMultiValues = maxNumMultiValues;
+ _numRowsPerChunk = numRowsPerChunk;
+ _valueSizeInBytes = valueSizeInBytes;
_memoryManager = memoryManager;
_context = context;
- int initialCapacity = Math.max(maxNumberOfMultiValuesPerRow,
rowCountPerChunk * avgMultiValueCount);
- int incrementalCapacity =
- Math.max(maxNumberOfMultiValuesPerRow, (int) (initialCapacity * 1.0f *
INCREMENT_PERCENTAGE / 100));
- _columnSizeInBytes = columnSizeInBytes;
- _maxNumberOfMultiValuesPerRow = maxNumberOfMultiValuesPerRow;
- _headerSize = rowCountPerChunk * SIZE_OF_INT * NUM_COLS_IN_HEADER;
- _rowCountPerChunk = rowCountPerChunk;
- addHeaderBuffer();
- //at least create space for million entries, which for INT translates into
4mb buffer
- _incrementalCapacity = incrementalCapacity;
- addDataBuffer(initialCapacity);
- //init(_rowCountPerChunk, _columnSizeInBytes,
_maxNumberOfMultiValuesPerRow, initialCapacity, _incrementalCapacity);
_isDictionaryEncoded = isDictionaryEncoded;
_storedType = storedType;
_dataType = dataType;
+
+ _headerSize = numRowsPerChunk * SIZE_OF_INT * NUM_COLS_IN_HEADER;
+ addHeaderBuffer();
+ int initialCapacity = Math.max(maxNumMultiValues, numRowsPerChunk *
avgNumMultiValues);
+ addDataBuffer(initialCapacity);
+ _incrementalCapacity = Math.max(maxNumMultiValues, (int) ((double)
initialCapacity * INCREMENT_PERCENTAGE / 100));
}
private void addHeaderBuffer() {
@@ -165,21 +160,21 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
_curHeaderWriter =
new FixedByteSingleValueMultiColWriter(headerBuffer, 3, new
int[]{SIZE_OF_INT, SIZE_OF_INT, SIZE_OF_INT});
_headerWriters.add(_curHeaderWriter);
- _headerReaders.add(new FixedByteSingleValueMultiColReader(headerBuffer,
_rowCountPerChunk,
+ _headerReaders.add(new FixedByteSingleValueMultiColReader(headerBuffer,
_numRowsPerChunk,
new int[]{SIZE_OF_INT, SIZE_OF_INT, SIZE_OF_INT}));
}
- /// This method automatically computes the space needed based on the
\_columnSizeInBytes
+ /// This method automatically computes the space needed based on the
\_valueSizeInBytes
/// @param rowCapacity Additional capacity to be added in terms of number of
rows
private void addDataBuffer(int rowCapacity) {
try {
- long size = (long) rowCapacity * (long) _columnSizeInBytes;
+ long size = (long) rowCapacity * (long) _valueSizeInBytes;
LOGGER.info("Allocating data buffer of size {} for column {}", size,
_context);
// NOTE: PinotDataBuffer is tracked in PinotDataBufferMemoryManager. No
need to track and close inside the class.
PinotDataBuffer dataBuffer = _memoryManager.allocate(size, _context);
- _currentDataWriter = new FixedByteSingleValueMultiColWriter(dataBuffer,
1, new int[]{_columnSizeInBytes});
+ _currentDataWriter = new FixedByteSingleValueMultiColWriter(dataBuffer,
1, new int[]{_valueSizeInBytes});
_dataWriters.add(_currentDataWriter);
- _dataReaders.add(new FixedByteSingleValueMultiColReader(dataBuffer,
rowCapacity, new int[]{_columnSizeInBytes}));
+ _dataReaders.add(new FixedByteSingleValueMultiColReader(dataBuffer,
rowCapacity, new int[]{_valueSizeInBytes}));
//update the capacity
_currentCapacity = rowCapacity;
} catch (Exception e) {
@@ -189,7 +184,7 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
}
private void writeIntoHeader(int row, int dataWriterIndex, int startIndex,
int length) {
- if (row >= _headerWriters.size() * _rowCountPerChunk) {
+ if (row >= _headerWriters.size() * _numRowsPerChunk) {
addHeaderBuffer();
}
_curHeaderWriter.setInt(getRowInCurrentHeader(row), 0, dataWriterIndex);
@@ -197,22 +192,19 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
_curHeaderWriter.setInt(getRowInCurrentHeader(row), 2, length);
}
- // TODO Use powers of two for _rowCountPerChunk to optimize computation for
the
+ // TODO Use powers of two for _numRowsPerChunk to optimize computation for
the
// methods below. Or, assert that the input values to the class are powers
of two. TBD.
private FixedByteSingleValueMultiColReader getCurrentReader(int row) {
- return _headerReaders.get(row / _rowCountPerChunk);
+ return _headerReaders.get(row / _numRowsPerChunk);
}
private int getRowInCurrentHeader(int row) {
- return row % _rowCountPerChunk;
+ return row % _numRowsPerChunk;
}
private int updateHeader(int row, int numValues) {
- if (numValues > _maxNumberOfMultiValuesPerRow) {
- Preconditions.checkArgument(numValues <= _maxNumberOfMultiValuesPerRow,
- "Row %s has %s multi-values, exceeding the maximum of %s", row,
numValues,
- _maxNumberOfMultiValuesPerRow);
- }
+ Preconditions.checkArgument(numValues <= _maxNumMultiValues,
+ "Row %s has %s multi-values, exceeding the maximum of %s", row,
numValues, _maxNumMultiValues);
_numValues += numValues;
int newStartIndex = _prevRowStartIndex + _prevRowLength;
if (newStartIndex + numValues > _currentCapacity) {
@@ -227,17 +219,6 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
return newStartIndex;
}
- /// Returns the maximum number of values allowed in a single row.
- public int getMaxNumberOfMultiValuesPerRow() {
- return _maxNumberOfMultiValuesPerRow;
- }
-
- public int getMaxChunkCapacity() {
- // The incremental capacity will be >= the initial capacity and (the way
the code is currently written) will be
- // the largest the buffer could ever get.
- return _incrementalCapacity;
- }
-
@Override
public boolean isDictionaryEncoded() {
return _isDictionaryEncoded;
@@ -255,12 +236,12 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
@Override
public int getLengthOfShortestElement() {
- return _columnSizeInBytes;
+ return _valueSizeInBytes;
}
@Override
public int getLengthOfLongestElement() {
- return _columnSizeInBytes;
+ return _valueSizeInBytes;
}
@Override
@@ -475,9 +456,9 @@ public class FixedByteMVMutableForwardIndex implements
MutableForwardIndex {
int newStartIndex = updateHeader(docId, values.length);
for (int i = 0; i < values.length; i++) {
byte[] value = values[i];
- if (value.length != _columnSizeInBytes) {
+ if (value.length != _valueSizeInBytes) {
throw new IllegalArgumentException(
- "Expected fixed-width bytes value of length: " +
_columnSizeInBytes + ", got: " + value.length);
+ "Expected fixed-width bytes value of length: " + _valueSizeInBytes
+ ", got: " + value.length);
}
_currentDataWriter.setBytes(newStartIndex + i, 0, value);
}
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java
index 33089d6ec06..47d1ea02c2e 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java
@@ -72,9 +72,6 @@ public class ForwardIndexType extends
AbstractIndexType<ForwardIndexConfig, Forw
private static final Logger LOGGER =
LoggerFactory.getLogger(ForwardIndexType.class);
public static final String INDEX_DISPLAY_NAME = "forward";
- // For multi-valued column, forward-index.
- // Default maximum number of multi-values per row. Some indexes, such as
vectors, configure a different row limit.
- public static final int MAX_MULTI_VALUES_PER_ROW = 1000;
private static final int
NODICT_VARIABLE_WIDTH_ESTIMATED_AVERAGE_VALUE_LENGTH_DEFAULT = 100;
private static final int
NODICT_VARIABLE_WIDTH_ESTIMATED_NUMBER_OF_VALUES_DEFAULT = 100_000;
//@formatter:off
@@ -368,8 +365,6 @@ public class ForwardIndexType extends
AbstractIndexType<ForwardIndexConfig, Forw
FieldSpec.DataType storedType = dataType.getStoredType();
int fixedLengthBytes = context.getFixedLengthBytes();
boolean isSingleValue = context.getFieldSpec().isSingleValueField();
- int maxNumMultiValuesPerRow = context.getMaxNumMultiValuesPerRowOverride()
> 0
- ? context.getMaxNumMultiValuesPerRowOverride() :
MAX_MULTI_VALUES_PER_ROW;
if (!context.hasDictionary()) {
if (isSingleValue) {
String allocationContext =
@@ -411,7 +406,7 @@ public class ForwardIndexType extends
AbstractIndexType<ForwardIndexConfig, Forw
IndexUtil.buildAllocationContext(context.getSegmentName(),
context.getFieldSpec().getName(),
V1Constants.Indexes.RAW_MV_FORWARD_INDEX_FILE_EXTENSION);
// TODO: Start with a smaller capacity on
FixedByteMVForwardIndexReaderWriter and let it expand
- return new FixedByteMVMutableForwardIndex(maxNumMultiValuesPerRow,
context.getAvgNumMultiValues(),
+ return new
FixedByteMVMutableForwardIndex(context.getMaxNumMultiValues(),
context.getAvgNumMultiValues(),
context.getCapacity(), dataType.size(),
context.getMemoryManager(), allocationContext, false, storedType,
dataType);
}
@@ -425,7 +420,7 @@ public class ForwardIndexType extends
AbstractIndexType<ForwardIndexConfig, Forw
String allocationContext =
IndexUtil.buildAllocationContext(segmentName, column,
V1Constants.Indexes.UNSORTED_MV_FORWARD_INDEX_FILE_EXTENSION);
// TODO: Start with a smaller capacity on
FixedByteMVForwardIndexReaderWriter and let it expand
- return new FixedByteMVMutableForwardIndex(maxNumMultiValuesPerRow,
context.getAvgNumMultiValues(),
+ return new
FixedByteMVMutableForwardIndex(context.getMaxNumMultiValues(),
context.getAvgNumMultiValues(),
context.getCapacity(), Integer.BYTES, context.getMemoryManager(),
allocationContext, true,
FieldSpec.DataType.INT);
}
diff --git
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplMVLengthValidationTest.java
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplNumMultiValuesValidationTest.java
similarity index 55%
rename from
pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplMVLengthValidationTest.java
rename to
pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplNumMultiValuesValidationTest.java
index 9af323b19f3..a802aee6404 100644
---
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplMVLengthValidationTest.java
+++
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImplNumMultiValuesValidationTest.java
@@ -40,35 +40,32 @@ import org.apache.pinot.segment.spi.index.reader.Dictionary;
import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.config.table.TableType;
import org.apache.pinot.spi.config.table.UpsertConfig;
-import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.data.Schema;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.data.readers.PrimaryKey;
import org.apache.pinot.spi.env.PinotConfiguration;
import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
-import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.expectThrows;
-/// Verifies mutable-segment enforcement of the fixed-byte multi-value row
limit. Each test owns its mutable segment,
-/// so no state is shared between test invocations.
-public class MutableSegmentImplMVLengthValidationTest implements
PinotBuffersAfterClassCheckRule {
+/// Verifies that the mutable segment enforces the maximum number of values
per fixed-byte multi-value entry. Each test
+/// owns its mutable segment, so no state is shared between test invocations.
+public class MutableSegmentImplNumMultiValuesValidationTest implements
PinotBuffersAfterClassCheckRule {
private static final String PARTITION_COLUMN = "partitionColumn";
private static final String PRIMARY_KEY_COLUMN = "primaryKey";
private static final String COMPARISON_COLUMN = "comparisonColumn";
private static final String MV_COLUMN = "mvColumn";
- private static final int MAX_MULTI_VALUES_PER_ROW = 1000;
+ private static final int MAX_NUM_MULTI_VALUES = 1000;
private static final int SMALL_VECTOR_DIMENSION = 768;
private static final int VECTOR_DIMENSION = 1536;
@@ -80,8 +77,8 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@Test
public void testRejectOversizedMultiValueRowBeforeWrites()
throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("mvLengthValidation")
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.INT)
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("numMultiValuesValidation")
+ .addMultiValueDimension(MV_COLUMN, DataType.INT)
.build();
MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImpl(schema);
try {
@@ -89,23 +86,21 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
mutableSegment.index(createRow(firstValues), null);
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
- FixedByteMVMutableForwardIndex forwardIndex =
- (FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
- Assert.assertTrue(forwardIndex.getMaxChunkCapacity() >
MAX_MULTI_VALUES_PER_ROW + 1);
-
- UnsupportedOperationException exception =
Assert.expectThrows(UnsupportedOperationException.class,
- () ->
mutableSegment.index(createRow(createValues(MAX_MULTI_VALUES_PER_ROW + 1, 10)),
null));
- Assert.assertTrue(exception.getMessage().contains(MV_COLUMN));
-
Assert.assertTrue(exception.getMessage().contains(Integer.toString(MAX_MULTI_VALUES_PER_ROW
+ 1)));
- Assert.assertTrue(exception.getMessage().contains("exceeding the maximum
of " + MAX_MULTI_VALUES_PER_ROW),
+ FixedByteMVMutableForwardIndex forwardIndex =
(FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
+
+ IllegalStateException exception =
expectThrows(IllegalStateException.class,
+ () ->
mutableSegment.index(createRow(createValues(MAX_NUM_MULTI_VALUES + 1, 10)),
null));
+ assertTrue(exception.getMessage().contains(MV_COLUMN));
+
assertTrue(exception.getMessage().contains(Integer.toString(MAX_NUM_MULTI_VALUES
+ 1)));
+ assertTrue(exception.getMessage().contains("exceeds the maximum allowed:
" + MAX_NUM_MULTI_VALUES),
exception.getMessage());
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 1);
+ assertEquals(mutableSegment.getNumDocsIndexed(), 1);
assertValues(dataSource, forwardIndex, 0, firstValues);
- Object[] maxLengthValues = createValues(MAX_MULTI_VALUES_PER_ROW, 10000);
- mutableSegment.index(createRow(maxLengthValues), null);
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 2);
- assertValues(dataSource, forwardIndex, 1, maxLengthValues);
+ Object[] valuesAtLimit = createValues(MAX_NUM_MULTI_VALUES, 10000);
+ mutableSegment.index(createRow(valuesAtLimit), null);
+ assertEquals(mutableSegment.getNumDocsIndexed(), 2);
+ assertValues(dataSource, forwardIndex, 1, valuesAtLimit);
} finally {
mutableSegment.destroy();
}
@@ -114,55 +109,52 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@Test
public void testAcceptVectorDimensionAboveDefaultMultiValueLimit()
throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("vectorMvLengthValidation")
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.FLOAT)
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("vectorNumMultiValuesValidation")
+ .addMultiValueDimension(MV_COLUMN, DataType.FLOAT)
.build();
- VectorIndexConfig vectorIndexConfig = new VectorIndexConfig(false, "HNSW",
VECTOR_DIMENSION, 1,
- VectorIndexConfig.VectorDistanceFunction.COSINE,
- Map.of("vectorIndexType", "HNSW", "vectorDimension",
Integer.toString(VECTOR_DIMENSION), "commitDocs", "1"));
- MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImplWithVectorIndexConfigs(
- schema, Set.of(MV_COLUMN), Set.of(), Set.of(), Map.of(MV_COLUMN,
vectorIndexConfig), null);
+ VectorIndexConfig vectorIndexConfig =
+ new VectorIndexConfig(false, "HNSW", VECTOR_DIMENSION, 1,
VectorIndexConfig.VectorDistanceFunction.COSINE,
+ Map.of("vectorIndexType", "HNSW", "vectorDimension",
Integer.toString(VECTOR_DIMENSION), "commitDocs",
+ "1"));
+ MutableSegmentImpl mutableSegment =
+
MutableSegmentImplTestUtils.createMutableSegmentImplWithVectorIndexConfigs(schema,
Set.of(MV_COLUMN), Set.of(),
+ Set.of(), Map.of(MV_COLUMN, vectorIndexConfig), null);
try {
Object[] vector = createFloatValues(VECTOR_DIMENSION);
mutableSegment.index(createRow(vector), null);
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
- FixedByteMVMutableForwardIndex forwardIndex =
- (FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
+ FixedByteMVMutableForwardIndex forwardIndex =
(FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
float[] queryVector = toPrimitiveFloatArray(vector);
- Assert.assertEquals(forwardIndex.getMaxNumberOfMultiValuesPerRow(),
VECTOR_DIMENSION);
- Assert.assertEquals(forwardIndex.getFloatMV(0), queryVector);
- Assert.assertNotNull(dataSource.getVectorIndex());
- Assert.assertEquals(dataSource.getVectorIndex().getDocIds(queryVector,
1).toArray(), new int[]{0});
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 1);
+ assertEquals(forwardIndex.getFloatMV(0), queryVector);
+ assertNotNull(dataSource.getVectorIndex());
+ assertEquals(dataSource.getVectorIndex().getDocIds(queryVector,
1).toArray(), new int[]{0});
+ assertEquals(mutableSegment.getNumDocsIndexed(), 1);
} finally {
mutableSegment.destroy();
}
}
@Test
- public void testRejectVectorAboveConfiguredDimensionBeforeWrites()
- throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("smallVectorMvLengthValidation")
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.FLOAT)
+ public void testRejectVectorAboveConfiguredDimensionBeforeWrites() {
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("smallVectorNumMultiValuesValidation")
+ .addMultiValueDimension(MV_COLUMN, DataType.FLOAT)
.build();
- VectorIndexConfig vectorIndexConfig = new VectorIndexConfig(false, "HNSW",
SMALL_VECTOR_DIMENSION, 1,
- VectorIndexConfig.VectorDistanceFunction.COSINE,
- Map.of("vectorIndexType", "HNSW", "vectorDimension",
Integer.toString(SMALL_VECTOR_DIMENSION),
- "commitDocs", "1"));
- MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImplWithVectorIndexConfigs(
- schema, Set.of(MV_COLUMN), Set.of(), Set.of(), Map.of(MV_COLUMN,
vectorIndexConfig), null);
+ VectorIndexConfig vectorIndexConfig =
+ new VectorIndexConfig(false, "HNSW", SMALL_VECTOR_DIMENSION, 1,
VectorIndexConfig.VectorDistanceFunction.COSINE,
+ Map.of("vectorIndexType", "HNSW", "vectorDimension",
Integer.toString(SMALL_VECTOR_DIMENSION), "commitDocs",
+ "1"));
+ MutableSegmentImpl mutableSegment =
+
MutableSegmentImplTestUtils.createMutableSegmentImplWithVectorIndexConfigs(schema,
Set.of(MV_COLUMN), Set.of(),
+ Set.of(), Map.of(MV_COLUMN, vectorIndexConfig), null);
try {
- Assert.expectThrows(UnsupportedOperationException.class,
+ expectThrows(IllegalStateException.class,
() ->
mutableSegment.index(createRow(createFloatValues(SMALL_VECTOR_DIMENSION + 1)),
null));
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
- FixedByteMVMutableForwardIndex forwardIndex =
- (FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
- Assert.assertEquals(forwardIndex.getMaxNumberOfMultiValuesPerRow(),
SMALL_VECTOR_DIMENSION);
- Assert.assertEquals(dataSource.getDataSourceMetadata().getNumValues(),
0);
- Assert.assertTrue(dataSource.getVectorIndex().getDocIds(new
float[SMALL_VECTOR_DIMENSION], 1).isEmpty());
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 0);
+ assertEquals(dataSource.getDataSourceMetadata().getNumValues(), 0);
+ assertTrue(dataSource.getVectorIndex().getDocIds(new
float[SMALL_VECTOR_DIMENSION], 1).isEmpty());
+ assertEquals(mutableSegment.getNumDocsIndexed(), 0);
} finally {
mutableSegment.destroy();
}
@@ -171,33 +163,32 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@Test
public void testRejectOversizedMultiValueRowBeforeDedupUpdate()
throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("dedupMvLengthValidation")
- .addSingleValueDimension(PRIMARY_KEY_COLUMN, FieldSpec.DataType.STRING)
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.INT)
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("dedupNumMultiValuesValidation")
+ .addSingleValueDimension(PRIMARY_KEY_COLUMN, DataType.STRING)
+ .addMultiValueDimension(MV_COLUMN, DataType.INT)
.setPrimaryKeyColumns(List.of(PRIMARY_KEY_COLUMN))
.build();
PartitionDedupMetadataManager dedupMetadataManager =
mock(PartitionDedupMetadataManager.class);
when(dedupMetadataManager.getContext()).thenReturn(mock(DedupContext.class));
Set<PrimaryKey> seenPrimaryKeys = new HashSet<>();
-
when(dedupMetadataManager.checkRecordPresentOrUpdate(any(DedupRecordInfo.class),
any()))
- .thenAnswer(invocation -> {
- DedupRecordInfo recordInfo = invocation.getArgument(0);
- return !seenPrimaryKeys.add(recordInfo.getPrimaryKey());
- });
+
when(dedupMetadataManager.checkRecordPresentOrUpdate(any(DedupRecordInfo.class),
any())).thenAnswer(invocation -> {
+ DedupRecordInfo recordInfo = invocation.getArgument(0);
+ return !seenPrimaryKeys.add(recordInfo.getPrimaryKey());
+ });
MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImpl(schema, false,
null, null, dedupMetadataManager);
try {
String primaryKey = "same-key";
- Assert.expectThrows(UnsupportedOperationException.class, () ->
mutableSegment.index(
- createDedupRow(primaryKey, createValues(MAX_MULTI_VALUES_PER_ROW +
1, 0)), null));
- Assert.assertTrue(seenPrimaryKeys.isEmpty());
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 0);
+ expectThrows(IllegalStateException.class,
+ () -> mutableSegment.index(createDedupRow(primaryKey,
createValues(MAX_NUM_MULTI_VALUES + 1, 0)), null));
+ assertTrue(seenPrimaryKeys.isEmpty());
+ assertEquals(mutableSegment.getNumDocsIndexed(), 0);
Object[] validValues = createValues(3, 10000);
mutableSegment.index(createDedupRow(primaryKey, validValues), null);
- Assert.assertEquals(seenPrimaryKeys.size(), 1);
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 1);
+ assertEquals(seenPrimaryKeys.size(), 1);
+ assertEquals(mutableSegment.getNumDocsIndexed(), 1);
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
assertValues(dataSource, (FixedByteMVMutableForwardIndex)
dataSource.getForwardIndex(), 0, validValues);
@@ -209,33 +200,34 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@Test(dataProvider = "collectionMergeStrategies")
public void
testRejectOversizedMultiValueRowProducedByPartialUpsert(UpsertConfig.Strategy
strategy)
throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("partialUpsertMvLengthValidation")
- .addSingleValueDimension(PRIMARY_KEY_COLUMN, FieldSpec.DataType.STRING)
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.INT)
- .addDateTime(COMPARISON_COLUMN, FieldSpec.DataType.LONG,
"1:MILLISECONDS:EPOCH", "1:MILLISECONDS")
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("partialUpsertNumMultiValuesValidation")
+ .addSingleValueDimension(PRIMARY_KEY_COLUMN, DataType.STRING)
+ .addMultiValueDimension(MV_COLUMN, DataType.INT)
+ .addDateTime(COMPARISON_COLUMN, DataType.LONG, "1:MILLISECONDS:EPOCH",
"1:MILLISECONDS")
.setPrimaryKeyColumns(List.of(PRIMARY_KEY_COLUMN))
.build();
UpsertConfig upsertConfig = new UpsertConfig(UpsertConfig.Mode.PARTIAL);
upsertConfig.setComparisonColumns(List.of(COMPARISON_COLUMN));
upsertConfig.setPartialUpsertStrategies(Map.of(MV_COLUMN, strategy));
- TableConfig tableConfig = new TableConfigBuilder(TableType.REALTIME)
- .setTableName("partialUpsertMvLengthValidation")
- .setTimeColumnName(COMPARISON_COLUMN)
- .setUpsertConfig(upsertConfig)
- .setNullHandlingEnabled(true)
- .build();
- TableUpsertMetadataManager tableUpsertMetadataManager =
TableUpsertMetadataManagerFactory.create(
- new PinotConfiguration(), tableConfig, schema,
mock(TableDataManager.class), null);
+ TableConfig tableConfig =
+ new
TableConfigBuilder(TableType.REALTIME).setTableName("partialUpsertNumMultiValuesValidation")
+ .setTimeColumnName(COMPARISON_COLUMN)
+ .setUpsertConfig(upsertConfig)
+ .setNullHandlingEnabled(true)
+ .build();
+ TableUpsertMetadataManager tableUpsertMetadataManager =
+ TableUpsertMetadataManagerFactory.create(new PinotConfiguration(),
tableConfig, schema,
+ mock(TableDataManager.class), null);
PartitionUpsertMetadataManager upsertMetadataManager =
spy(tableUpsertMetadataManager.getOrCreatePartitionManager(0));
- MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImpl(schema, true,
- COMPARISON_COLUMN, upsertMetadataManager, null);
+ MutableSegmentImpl mutableSegment =
+ MutableSegmentImplTestUtils.createMutableSegmentImpl(schema, true,
COMPARISON_COLUMN, upsertMetadataManager,
+ null);
try {
String primaryKey = "same-key";
- Assert.expectThrows(UnsupportedOperationException.class,
- () -> mutableSegment.index(
- createUpsertRow(primaryKey, 0L,
createValues(MAX_MULTI_VALUES_PER_ROW + 1, 0)), null));
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 0);
+ expectThrows(IllegalStateException.class,
+ () -> mutableSegment.index(createUpsertRow(primaryKey, 0L,
createValues(MAX_NUM_MULTI_VALUES + 1, 0)), null));
+ assertEquals(mutableSegment.getNumDocsIndexed(), 0);
verify(upsertMetadataManager,
times(0)).updateRecord(any(GenericRow.class), any(RecordInfo.class));
verify(upsertMetadataManager, times(0)).addRecord(eq(mutableSegment),
any(RecordInfo.class));
@@ -243,29 +235,28 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
mutableSegment.index(createUpsertRow(primaryKey, 1L, firstValues), null);
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
- FixedByteMVMutableForwardIndex forwardIndex =
- (FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
+ FixedByteMVMutableForwardIndex forwardIndex =
(FixedByteMVMutableForwardIndex) dataSource.getForwardIndex();
int cardinalityBeforeRejection = dataSource.getDictionary().length();
int numValuesBeforeRejection =
dataSource.getDataSourceMetadata().getNumValues();
ImmutableRoaringBitmap validDocIds =
mutableSegment.getValidDocIds().getMutableRoaringBitmap();
- Assert.assertEquals(validDocIds.toArray(), new int[]{0});
+ assertEquals(validDocIds.toArray(), new int[]{0});
verify(upsertMetadataManager, times(1)).addRecord(eq(mutableSegment),
any(RecordInfo.class));
- Assert.expectThrows(UnsupportedOperationException.class,
+ expectThrows(IllegalStateException.class,
() -> mutableSegment.index(createUpsertRow(primaryKey, 2L,
createValues(500, 600)), null));
DataSource dataSourceAfterRejection =
mutableSegment.getDataSource(MV_COLUMN);
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 1);
- Assert.assertEquals(dataSourceAfterRejection.getDictionary().length(),
cardinalityBeforeRejection);
-
Assert.assertEquals(dataSourceAfterRejection.getDataSourceMetadata().getNumValues(),
numValuesBeforeRejection);
-
Assert.assertEquals(mutableSegment.getValidDocIds().getMutableRoaringBitmap().toArray(),
new int[]{0});
+ assertEquals(mutableSegment.getNumDocsIndexed(), 1);
+ assertEquals(dataSourceAfterRejection.getDictionary().length(),
cardinalityBeforeRejection);
+
assertEquals(dataSourceAfterRejection.getDataSourceMetadata().getNumValues(),
numValuesBeforeRejection);
+
assertEquals(mutableSegment.getValidDocIds().getMutableRoaringBitmap().toArray(),
new int[]{0});
verify(upsertMetadataManager, times(1)).addRecord(eq(mutableSegment),
any(RecordInfo.class));
assertValues(dataSourceAfterRejection, forwardIndex, 0, firstValues);
Object[] validUpdate = createValues(3, 600);
mutableSegment.index(createUpsertRow(primaryKey, 3L, validUpdate), null);
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 2);
-
Assert.assertEquals(mutableSegment.getValidDocIds().getMutableRoaringBitmap().toArray(),
new int[]{1});
+ assertEquals(mutableSegment.getNumDocsIndexed(), 2);
+
assertEquals(mutableSegment.getValidDocIds().getMutableRoaringBitmap().toArray(),
new int[]{1});
verify(upsertMetadataManager, times(2)).addRecord(eq(mutableSegment),
any(RecordInfo.class));
assertValues(mutableSegment.getDataSource(MV_COLUMN), forwardIndex, 1,
createValues(603, 0));
} finally {
@@ -278,25 +269,23 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@Test
public void testRejectOversizedMultiValueRowBeforePartitionTracking()
throws Exception {
- Schema schema = new
Schema.SchemaBuilder().setSchemaName("partitionMvLengthValidation")
- .addSingleValueDimension(PARTITION_COLUMN, FieldSpec.DataType.INT)
- .addMultiValueDimension(MV_COLUMN, FieldSpec.DataType.INT)
+ Schema schema = new
Schema.SchemaBuilder().setSchemaName("partitionNumMultiValuesValidation")
+ .addSingleValueDimension(PARTITION_COLUMN, DataType.INT)
+ .addMultiValueDimension(MV_COLUMN, DataType.INT)
.build();
MutableSegmentImpl mutableSegment =
MutableSegmentImplTestUtils.createMutableSegmentImpl(schema, PARTITION_COLUMN,
new ModuloPartitionFunction(4, null), 0, false);
try {
-
Assert.assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
- Set.of(0));
- Assert.expectThrows(UnsupportedOperationException.class,
- () -> mutableSegment.index(createPartitionedRow(1,
createValues(MAX_MULTI_VALUES_PER_ROW + 1, 0)), null));
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 0);
-
Assert.assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
- Set.of(0));
+
assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
Set.of(0));
+ expectThrows(IllegalStateException.class,
+ () -> mutableSegment.index(createPartitionedRow(1,
createValues(MAX_NUM_MULTI_VALUES + 1, 0)), null));
+ assertEquals(mutableSegment.getNumDocsIndexed(), 0);
+
assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
Set.of(0));
Object[] validValues = createValues(3, 0);
mutableSegment.index(createPartitionedRow(1, validValues), null);
- Assert.assertEquals(mutableSegment.getNumDocsIndexed(), 1);
-
Assert.assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
+ assertEquals(mutableSegment.getNumDocsIndexed(), 1);
+
assertEquals(mutableSegment.getDataSource(PARTITION_COLUMN).getDataSourceMetadata().getPartitions(),
Set.of(0, 1));
DataSource dataSource = mutableSegment.getDataSource(MV_COLUMN);
assertValues(dataSource, (FixedByteMVMutableForwardIndex)
dataSource.getForwardIndex(), 0, validValues);
@@ -308,8 +297,7 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
@DataProvider(name = "collectionMergeStrategies")
private static Object[][] collectionMergeStrategies() {
return new Object[][]{
- {UpsertConfig.Strategy.APPEND},
- {UpsertConfig.Strategy.UNION}
+ {UpsertConfig.Strategy.APPEND}, {UpsertConfig.Strategy.UNION}
};
}
@@ -337,17 +325,17 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
return row;
}
- private static Object[] createValues(int length, int offset) {
- Object[] values = new Object[length];
- for (int i = 0; i < length; i++) {
+ private static Object[] createValues(int numValues, int offset) {
+ Object[] values = new Object[numValues];
+ for (int i = 0; i < numValues; i++) {
values[i] = offset + i;
}
return values;
}
- private static Object[] createFloatValues(int length) {
- Object[] values = new Object[length];
- for (int i = 0; i < length; i++) {
+ private static Object[] createFloatValues(int numValues) {
+ Object[] values = new Object[numValues];
+ for (int i = 0; i < numValues; i++) {
values[i] = (float) i;
}
return values;
@@ -364,11 +352,11 @@ public class MutableSegmentImplMVLengthValidationTest
implements PinotBuffersAft
private static void assertValues(DataSource dataSource,
FixedByteMVMutableForwardIndex forwardIndex, int docId,
Object[] expectedValues) {
Dictionary dictionary = dataSource.getDictionary();
- Assert.assertNotNull(dictionary);
+ assertNotNull(dictionary);
int[] dictIds = forwardIndex.getDictIdMV(docId);
- Assert.assertEquals(dictIds.length, expectedValues.length);
+ assertEquals(dictIds.length, expectedValues.length);
for (int i = 0; i < expectedValues.length; i++) {
- Assert.assertEquals(dictionary.get(dictIds[i]), expectedValues[i]);
+ assertEquals(dictionary.get(dictIds[i]), expectedValues[i]);
}
}
}
diff --git
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/forward/mutable/FixedByteMVMutableForwardIndexTest.java
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/forward/mutable/FixedByteMVMutableForwardIndexTest.java
index dabf1f95ace..ac6a9ca95b5 100644
---
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/forward/mutable/FixedByteMVMutableForwardIndexTest.java
+++
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/forward/mutable/FixedByteMVMutableForwardIndexTest.java
@@ -74,13 +74,13 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
@Test
public void testRejectMultiValuesExceedingMaxPerRow()
throws Exception {
- int maxNumberOfMultiValuesPerRow = 5;
+ int maxNumMultiValues = 5;
FixedByteMVMutableForwardIndex readerWriter =
- new FixedByteMVMutableForwardIndex(maxNumberOfMultiValuesPerRow, 2,
10, Integer.BYTES, _memoryManager,
+ new FixedByteMVMutableForwardIndex(maxNumMultiValues, 2, 10,
Integer.BYTES, _memoryManager,
"RejectMultiValuesExceedingMaxPerRow", true,
FieldSpec.DataType.INT);
try {
Assert.expectThrows(IllegalArgumentException.class,
- () -> readerWriter.setIntMV(0, new int[maxNumberOfMultiValuesPerRow
+ 1]));
+ () -> readerWriter.setIntMV(0, new int[maxNumMultiValues + 1]));
Assert.assertEquals(getNumValues(readerWriter), 0);
Assert.assertEquals(readerWriter.getNumValuesMV(0), 0);
} finally {
@@ -91,9 +91,9 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
@Test
public void testAcceptMultiValuesAtMaxPerRow()
throws Exception {
- int maxNumberOfMultiValuesPerRow = 5;
+ int maxNumMultiValues = 5;
FixedByteMVMutableForwardIndex readerWriter =
- new FixedByteMVMutableForwardIndex(maxNumberOfMultiValuesPerRow, 2,
10, Integer.BYTES, _memoryManager,
+ new FixedByteMVMutableForwardIndex(maxNumMultiValues, 2, 10,
Integer.BYTES, _memoryManager,
"AcceptMultiValuesAtMaxPerRow", true, FieldSpec.DataType.INT);
try {
int[] values = new int[]{1, 2, 3, 4, 5};
@@ -108,24 +108,24 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
throws IOException {
FixedByteMVMutableForwardIndex readerWriter;
int rows = 1000;
- int columnSizeInBytes = Integer.BYTES;
- int maxNumberOfMultiValuesPerRow = 2000;
+ int valueSizeInBytes = Integer.BYTES;
+ int maxNumMultiValues = 2000;
readerWriter =
- new FixedByteMVMutableForwardIndex(maxNumberOfMultiValuesPerRow, 2,
rows / 2, columnSizeInBytes, _memoryManager,
+ new FixedByteMVMutableForwardIndex(maxNumMultiValues, 2, rows / 2,
valueSizeInBytes, _memoryManager,
"IntArray", isDictionaryEncoded, FieldSpec.DataType.INT);
int valuesAdded = 0;
Random r = new Random(seed);
int[][] data = new int[rows][];
for (int i = 0; i < rows; i++) {
- data[i] = new int[r.nextInt(maxNumberOfMultiValuesPerRow)];
+ data[i] = new int[r.nextInt(maxNumMultiValues)];
for (int j = 0; j < data[i].length; j++) {
data[i][j] = r.nextInt();
}
readerWriter.setIntMV(i, data[i]);
valuesAdded += data[i].length;
}
- int[] ret = new int[maxNumberOfMultiValuesPerRow];
+ int[] ret = new int[maxNumMultiValues];
for (int i = 0; i < rows; i++) {
int length = readerWriter.getIntMV(i, ret);
Assert.assertEquals(data[i].length, length, "Failed with seed=" + seed);
@@ -139,11 +139,11 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
throws IOException {
FixedByteMVMutableForwardIndex readerWriter;
int rows = 1000;
- int columnSizeInBytes = Integer.BYTES;
+ int valueSizeInBytes = Integer.BYTES;
// Keep the rowsPerChunk as a multiple of multiValuesPerRow to check the
cases when both data and header buffers
// transition to new ones
readerWriter = new FixedByteMVMutableForwardIndex(multiValuesPerRow,
multiValuesPerRow, multiValuesPerRow * 2,
- columnSizeInBytes, _memoryManager, "IntArrayFixedSize",
isDictionaryEncoded, FieldSpec.DataType.INT);
+ valueSizeInBytes, _memoryManager, "IntArrayFixedSize",
isDictionaryEncoded, FieldSpec.DataType.INT);
int valuesAdded = 0;
Random r = new Random(seed);
@@ -169,19 +169,19 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
public void testWithZeroSize(long seed, boolean isDictionaryEncoded)
throws IOException {
FixedByteMVMutableForwardIndex readerWriter;
- final int maxNumberOfMultiValuesPerRow = 5;
+ final int maxNumMultiValues = 5;
int rows = 1000;
- int columnSizeInBytes = Integer.BYTES;
+ int valueSizeInBytes = Integer.BYTES;
Random r = new Random(seed);
readerWriter =
- new FixedByteMVMutableForwardIndex(maxNumberOfMultiValuesPerRow, 3,
r.nextInt(rows) + 1, columnSizeInBytes,
+ new FixedByteMVMutableForwardIndex(maxNumMultiValues, 3,
r.nextInt(rows) + 1, valueSizeInBytes,
_memoryManager, "ZeroSize", isDictionaryEncoded,
FieldSpec.DataType.INT);
int valuesAdded = 0;
int[][] data = new int[rows][];
for (int i = 0; i < rows; i++) {
if (r.nextInt() > 0) {
- data[i] = new int[r.nextInt(maxNumberOfMultiValuesPerRow)];
+ data[i] = new int[r.nextInt(maxNumMultiValues)];
for (int j = 0; j < data[i].length; j++) {
data[i][j] = r.nextInt();
}
@@ -193,7 +193,7 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
valuesAdded += data[i].length;
}
}
- int[] ret = new int[maxNumberOfMultiValuesPerRow];
+ int[] ret = new int[maxNumMultiValues];
for (int i = 0; i < rows; i++) {
int length = readerWriter.getIntMV(i, ret);
Assert.assertEquals(data[i].length, length, "Failed with seed=" + seed);
@@ -204,11 +204,11 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
}
private FixedByteMVMutableForwardIndex createReaderWriter(FieldSpec.DataType
dataType, Random r, int rows,
- int maxNumberOfMultiValuesPerRow, boolean isDictionaryEncoded) {
- final int avgMultiValueCount = r.nextInt(maxNumberOfMultiValuesPerRow) + 1;
- final int rowCountPerChunk = r.nextInt(rows) + 1;
+ int maxNumMultiValues, boolean isDictionaryEncoded) {
+ final int avgNumMultiValues = r.nextInt(maxNumMultiValues) + 1;
+ final int numRowsPerChunk = r.nextInt(rows) + 1;
- return new FixedByteMVMutableForwardIndex(maxNumberOfMultiValuesPerRow,
avgMultiValueCount, rowCountPerChunk,
+ return new FixedByteMVMutableForwardIndex(maxNumMultiValues,
avgNumMultiValues, numRowsPerChunk,
dataType.size(), _memoryManager, "ReaderWriter", isDictionaryEncoded,
dataType);
}
@@ -229,15 +229,15 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
final long seed = generateSeed();
Random r = new Random(seed);
int rows = 1000;
- final int maxNumberOfMultiValuesPerRow = r.nextInt(100) + 1;
+ final int maxNumMultiValues = r.nextInt(100) + 1;
FixedByteMVMutableForwardIndex readerWriter =
- createReaderWriter(FieldSpec.DataType.LONG, r, rows,
maxNumberOfMultiValuesPerRow, isDictionaryEncoded);
+ createReaderWriter(FieldSpec.DataType.LONG, r, rows,
maxNumMultiValues, isDictionaryEncoded);
int valuesAdded = 0;
long[][] data = new long[rows][];
for (int i = 0; i < rows; i++) {
if (r.nextInt() > 0) {
- data[i] = new long[r.nextInt(maxNumberOfMultiValuesPerRow)];
+ data[i] = new long[r.nextInt(maxNumMultiValues)];
for (int j = 0; j < data[i].length; j++) {
data[i][j] = r.nextLong();
}
@@ -249,7 +249,7 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
valuesAdded += data[i].length;
}
}
- long[] ret = new long[maxNumberOfMultiValuesPerRow];
+ long[] ret = new long[maxNumMultiValues];
for (int i = 0; i < rows; i++) {
int length = readerWriter.getLongMV(i, ret);
Assert.assertEquals(data[i].length, length, "Failed with seed=" + seed);
@@ -271,15 +271,15 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
final long seed = generateSeed();
Random r = new Random(seed);
int rows = 1000;
- final int maxNumberOfMultiValuesPerRow = r.nextInt(100) + 1;
+ final int maxNumMultiValues = r.nextInt(100) + 1;
FixedByteMVMutableForwardIndex readerWriter =
- createReaderWriter(FieldSpec.DataType.FLOAT, r, rows,
maxNumberOfMultiValuesPerRow, isDictoinaryEncoded);
+ createReaderWriter(FieldSpec.DataType.FLOAT, r, rows,
maxNumMultiValues, isDictoinaryEncoded);
int valuesAdded = 0;
float[][] data = new float[rows][];
for (int i = 0; i < rows; i++) {
if (r.nextInt() > 0) {
- data[i] = new float[r.nextInt(maxNumberOfMultiValuesPerRow)];
+ data[i] = new float[r.nextInt(maxNumMultiValues)];
for (int j = 0; j < data[i].length; j++) {
data[i][j] = r.nextFloat();
}
@@ -291,7 +291,7 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
valuesAdded += data[i].length;
}
}
- float[] ret = new float[maxNumberOfMultiValuesPerRow];
+ float[] ret = new float[maxNumMultiValues];
for (int i = 0; i < rows; i++) {
int length = readerWriter.getFloatMV(i, ret);
Assert.assertEquals(data[i].length, length, "Failed with seed=" + seed);
@@ -313,15 +313,15 @@ public class FixedByteMVMutableForwardIndexTest
implements PinotBuffersAfterClas
final long seed = generateSeed();
Random r = new Random(seed);
int rows = 1000;
- final int maxNumberOfMultiValuesPerRow = r.nextInt(100) + 1;
+ final int maxNumMultiValues = r.nextInt(100) + 1;
FixedByteMVMutableForwardIndex readerWriter =
- createReaderWriter(FieldSpec.DataType.DOUBLE, r, rows,
maxNumberOfMultiValuesPerRow, isDictonaryEncoded);
+ createReaderWriter(FieldSpec.DataType.DOUBLE, r, rows,
maxNumMultiValues, isDictonaryEncoded);
int valuesAdded = 0;
double[][] data = new double[rows][];
for (int i = 0; i < rows; i++) {
if (r.nextInt() > 0) {
- data[i] = new double[r.nextInt(maxNumberOfMultiValuesPerRow)];
+ data[i] = new double[r.nextInt(maxNumMultiValues)];
for (int j = 0; j < data[i].length; j++) {
data[i][j] = r.nextDouble();
}
@@ -333,7 +333,7 @@ public class FixedByteMVMutableForwardIndexTest implements
PinotBuffersAfterClas
valuesAdded += data[i].length;
}
}
- double[] ret = new double[maxNumberOfMultiValuesPerRow];
+ double[] ret = new double[maxNumMultiValues];
for (int i = 0; i < rows; i++) {
int length = readerWriter.getDoubleMV(i, ret);
Assert.assertEquals(data[i].length, length, "Failed with seed=" + seed);
diff --git
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java
index 5bf316768e1..5a1fea5f3d6 100644
---
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java
+++
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java
@@ -37,6 +37,11 @@ import org.apache.pinot.spi.utils.DataSizeUtils;
public class ForwardIndexConfig extends IndexConfig {
+ // TODO: Make the maximum number of multi-values configurable, and also
enforce it when creating the immutable forward
+ // index, which currently accepts any number of values per entry.
+ /// Default maximum number of values in a single multi-value entry of the
mutable forward index.
+ public static final int DEFAULT_MAX_NUM_MULTI_VALUES = 1000;
+
private static int _defaultRawIndexWriterVersion = 4;
private static String _defaultTargetMaxChunkSize = "1MB";
private static int _defaultTargetMaxChunkSizeBytes = 1024 * 1024;
diff --git
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/mutable/provider/MutableIndexContext.java
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/mutable/provider/MutableIndexContext.java
index 010baead912..6eba8daf7c1 100644
---
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/mutable/provider/MutableIndexContext.java
+++
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/mutable/provider/MutableIndexContext.java
@@ -20,34 +20,28 @@ package org.apache.pinot.segment.spi.index.mutable.provider;
import java.io.File;
import java.util.Objects;
+import org.apache.pinot.segment.spi.index.ForwardIndexConfig;
import org.apache.pinot.segment.spi.memory.PinotDataBufferMemoryManager;
import org.apache.pinot.spi.data.FieldSpec;
public class MutableIndexContext {
- private final int _capacity;
private final FieldSpec _fieldSpec;
private final int _fixedLengthBytes;
private final boolean _hasDictionary;
+ private final String _segmentName;
+ private final PinotDataBufferMemoryManager _memoryManager;
+ private final int _capacity;
private final boolean _offHeap;
private final int _estimatedColSize;
private final int _estimatedCardinality;
+ private final int _maxNumMultiValues;
private final int _avgNumMultiValues;
- private final int _maxNumMultiValuesPerRowOverride;
- private final String _segmentName;
- private final PinotDataBufferMemoryManager _memoryManager;
private final File _consumerDir;
public MutableIndexContext(FieldSpec fieldSpec, int fixedLengthBytes,
boolean hasDictionary, String segmentName,
PinotDataBufferMemoryManager memoryManager, int capacity, boolean
offHeap, int estimatedColSize,
- int estimatedCardinality, int avgNumMultiValues, File consumerDir) {
- this(fieldSpec, fixedLengthBytes, hasDictionary, segmentName,
memoryManager, capacity, offHeap, estimatedColSize,
- estimatedCardinality, avgNumMultiValues, 0, consumerDir);
- }
-
- public MutableIndexContext(FieldSpec fieldSpec, int fixedLengthBytes,
boolean hasDictionary, String segmentName,
- PinotDataBufferMemoryManager memoryManager, int capacity, boolean
offHeap, int estimatedColSize,
- int estimatedCardinality, int avgNumMultiValues, int
maxNumMultiValuesPerRowOverride, File consumerDir) {
+ int estimatedCardinality, int maxNumMultiValues, int avgNumMultiValues,
File consumerDir) {
_fieldSpec = fieldSpec;
_fixedLengthBytes = fixedLengthBytes;
_hasDictionary = hasDictionary;
@@ -57,8 +51,8 @@ public class MutableIndexContext {
_offHeap = offHeap;
_estimatedColSize = estimatedColSize;
_estimatedCardinality = estimatedCardinality;
+ _maxNumMultiValues = maxNumMultiValues;
_avgNumMultiValues = avgNumMultiValues;
- _maxNumMultiValuesPerRowOverride = maxNumMultiValuesPerRowOverride;
_consumerDir = consumerDir;
}
@@ -98,13 +92,12 @@ public class MutableIndexContext {
return _estimatedCardinality;
}
- public int getAvgNumMultiValues() {
- return _avgNumMultiValues;
+ public int getMaxNumMultiValues() {
+ return _maxNumMultiValues;
}
- /// Returns the configured maximum number of values for one MV row, or 0
when the index default should be used.
- public int getMaxNumMultiValuesPerRowOverride() {
- return _maxNumMultiValuesPerRowOverride;
+ public int getAvgNumMultiValues() {
+ return _avgNumMultiValues;
}
public File getConsumerDir() {
@@ -125,8 +118,8 @@ public class MutableIndexContext {
private PinotDataBufferMemoryManager _memoryManager;
private int _estimatedColSize;
private int _estimatedCardinality;
+ private int _maxNumMultiValues =
ForwardIndexConfig.DEFAULT_MAX_NUM_MULTI_VALUES;
private int _avgNumMultiValues;
- private int _maxNumMultiValuesPerRowOverride;
private File _consumerDir;
public Builder withMemoryManager(PinotDataBufferMemoryManager
memoryManager) {
@@ -169,13 +162,13 @@ public class MutableIndexContext {
return this;
}
- public Builder withAvgNumMultiValues(int avgNumMultiValues) {
- _avgNumMultiValues = avgNumMultiValues;
+ public Builder withMaxNumMultiValues(int maxNumMultiValues) {
+ _maxNumMultiValues = maxNumMultiValues;
return this;
}
- public Builder withMaxNumMultiValuesPerRowOverride(int
maxNumMultiValuesPerRowOverride) {
- _maxNumMultiValuesPerRowOverride = maxNumMultiValuesPerRowOverride;
+ public Builder withAvgNumMultiValues(int avgNumMultiValues) {
+ _avgNumMultiValues = avgNumMultiValues;
return this;
}
@@ -192,7 +185,7 @@ public class MutableIndexContext {
public MutableIndexContext build() {
return new MutableIndexContext(Objects.requireNonNull(_fieldSpec),
_fixedLengthBytes, _hasDictionary,
Objects.requireNonNull(_segmentName),
Objects.requireNonNull(_memoryManager), _capacity, _offHeap,
- _estimatedColSize, _estimatedCardinality, _avgNumMultiValues,
_maxNumMultiValuesPerRowOverride, _consumerDir);
+ _estimatedColSize, _estimatedCardinality, _maxNumMultiValues,
_avgNumMultiValues, _consumerDir);
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]