Skip to content

Commit c85a554

Browse files
authored
GH-1190: Reserve view slots for empty view vector values (#1192)
## What's Changed Fixes `BaseVariableWidthViewVector.handleSafe` so `setSafe` reserves a full 16-byte view slot for the target index even when the value length is zero. Closes #1190.
1 parent 63a17fc commit c85a554

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthViewVector.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,9 @@ public final int getTotalValueLengthUpToIndex(int index) {
14051405
}
14061406

14071407
protected final void handleSafe(int index, int dataLength) {
1408-
final long targetCapacity = roundUpToMultipleOf16((long) index * ELEMENT_SIZE + dataLength);
1408+
// The view buffer stores one fixed-width view per value; payload bytes are allocated
1409+
// separately.
1410+
final long targetCapacity = roundUpToMultipleOf16(((long) index + 1) * ELEMENT_SIZE);
14091411
if (viewBuffer.capacity() < targetCapacity) {
14101412
reallocViewBuffer(targetCapacity);
14111413
}

vector/src/test/java/org/apache/arrow/vector/TestVariableWidthViewVector.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,60 @@ public void testSizeOfViewBufferElements() {
540540
}
541541
}
542542

543+
@ParameterizedTest
544+
@MethodSource({"vectorCreatorProvider"})
545+
public void testSetSafeEmptyValueAtViewBufferBoundary(
546+
Function<BufferAllocator, BaseVariableWidthViewVector> vectorCreator) {
547+
try (final BaseVariableWidthViewVector vector = vectorCreator.apply(allocator)) {
548+
final byte[] emptyValue = new byte[0];
549+
vector.allocateNew();
550+
final int valueCapacity = vector.getValueCapacity();
551+
552+
for (int i = 0; i <= valueCapacity; i++) {
553+
vector.setSafe(i, emptyValue);
554+
}
555+
556+
vector.setValueCount(valueCapacity + 1);
557+
assertTrue(vector.getValueCapacity() > valueCapacity);
558+
assertEquals(0, vector.getValueLength(valueCapacity));
559+
assertArrayEquals(emptyValue, vector.get(valueCapacity));
560+
}
561+
}
562+
563+
@ParameterizedTest
564+
@MethodSource({"vectorCreatorProvider"})
565+
public void testSetValueCountFillsEmptiesAtViewBufferBoundary(
566+
Function<BufferAllocator, BaseVariableWidthViewVector> vectorCreator) {
567+
try (final BaseVariableWidthViewVector vector = vectorCreator.apply(allocator)) {
568+
vector.allocateNew();
569+
final int valueCapacity = vector.getValueCapacity();
570+
571+
vector.setSafe(valueCapacity - 1, "x".getBytes(StandardCharsets.UTF_8));
572+
vector.setValueCount(valueCapacity + 1);
573+
574+
assertTrue(vector.getValueCapacity() > valueCapacity);
575+
assertTrue(vector.isNull(valueCapacity));
576+
}
577+
}
578+
579+
@ParameterizedTest
580+
@MethodSource({"vectorCreatorProvider"})
581+
public void testSetNullAtViewBufferBoundary(
582+
Function<BufferAllocator, BaseVariableWidthViewVector> vectorCreator) {
583+
try (final BaseVariableWidthViewVector vector = vectorCreator.apply(allocator)) {
584+
vector.allocateNew();
585+
final int valueCapacity = vector.getValueCapacity();
586+
587+
for (int i = 0; i <= valueCapacity; i++) {
588+
vector.setNull(i);
589+
}
590+
vector.setValueCount(valueCapacity + 1);
591+
592+
assertTrue(vector.getValueCapacity() > valueCapacity);
593+
assertTrue(vector.isNull(valueCapacity));
594+
}
595+
}
596+
543597
@Test
544598
public void testNullableVarType1() {
545599

0 commit comments

Comments
 (0)