@@ -305,18 +305,41 @@ public void exportCDataBuffers(List<ArrowBuf> buffers, ArrowBuf buffersPtr, long
305305
306306 /** Set the reader and writer indexes for the inner buffers. */
307307 private void setReaderAndWriterIndex () {
308+ final long requiredOffsetBufferCapacity = (long ) (valueCount + 1 ) * OFFSET_WIDTH ;
308309 validityBuffer .readerIndex (0 );
309310 offsetBuffer .readerIndex (0 );
310311 if (valueCount == 0 ) {
311312 validityBuffer .writerIndex (0 );
313+ ensureEmptyOffsetBufferCapacity (requiredOffsetBufferCapacity );
312314 } else {
313315 validityBuffer .writerIndex (BitVectorHelper .getValidityBufferSizeFromCount (valueCount ));
314316 }
315317 // IPC serializer will determine readable bytes based on `readerIndex` and `writerIndex`.
316318 // Both are set to 0 means 0 bytes are written to the IPC stream which will crash IPC readers
317319 // in other libraries. According to Arrow spec, we should still output the offset buffer which
318320 // is [0].
319- offsetBuffer .writerIndex ((long ) (valueCount + 1 ) * OFFSET_WIDTH );
321+ offsetBuffer .writerIndex (requiredOffsetBufferCapacity );
322+ }
323+
324+ private void ensureEmptyOffsetBufferCapacity (long requiredCapacity ) {
325+ if (offsetBuffer .capacity () >= requiredCapacity ) {
326+ return ;
327+ }
328+ long previousOffsetAllocationSizeInBytes = offsetAllocationSizeInBytes ;
329+ ArrowBuf oldOffsetBuffer = offsetBuffer ;
330+ offsetBuffer = allocateOffsetBuffer (requiredCapacity );
331+ final long bytesToCopy = Math .min (oldOffsetBuffer .capacity (), requiredCapacity );
332+ offsetBuffer .setBytes (0 , oldOffsetBuffer , 0 , bytesToCopy );
333+
334+ final int copiedOffsets = (int ) (bytesToCopy / OFFSET_WIDTH );
335+ final int requiredOffsets = (int ) (requiredCapacity / OFFSET_WIDTH );
336+ final long lastCopiedOffset =
337+ copiedOffsets == 0 ? 0 : offsetBuffer .getLong ((long ) (copiedOffsets - 1 ) * OFFSET_WIDTH );
338+ for (int i = copiedOffsets ; i < requiredOffsets ; i ++) {
339+ offsetBuffer .setLong ((long ) i * OFFSET_WIDTH , lastCopiedOffset );
340+ }
341+ offsetAllocationSizeInBytes = previousOffsetAllocationSizeInBytes ;
342+ oldOffsetBuffer .getReferenceManager ().release ();
320343 }
321344
322345 /**
@@ -674,24 +697,30 @@ public void splitAndTransfer(int startIndex, int length) {
674697 startIndex ,
675698 length ,
676699 valueCount );
677- final long startPoint = offsetBuffer .getLong ((long ) startIndex * OFFSET_WIDTH );
678- final long sliceLength =
679- offsetBuffer .getLong ((long ) (startIndex + length ) * OFFSET_WIDTH ) - startPoint ;
680700 to .clear ();
681- to .offsetBuffer = to .allocateOffsetBuffer ((length + 1 ) * OFFSET_WIDTH );
682- /* splitAndTransfer offset buffer */
683- for (int i = 0 ; i < length + 1 ; i ++) {
684- final long relativeOffset =
685- offsetBuffer .getLong ((long ) (startIndex + i ) * OFFSET_WIDTH ) - startPoint ;
686- to .offsetBuffer .setLong ((long ) i * OFFSET_WIDTH , relativeOffset );
701+ if (length > 0 ) {
702+ final long startPoint = offsetBuffer .getLong ((long ) startIndex * OFFSET_WIDTH );
703+ final long sliceLength =
704+ offsetBuffer .getLong ((long ) (startIndex + length ) * OFFSET_WIDTH ) - startPoint ;
705+ to .offsetBuffer = to .allocateOffsetBuffer ((length + 1 ) * OFFSET_WIDTH );
706+ /* splitAndTransfer offset buffer */
707+ for (int i = 0 ; i < length + 1 ; i ++) {
708+ final long relativeOffset =
709+ offsetBuffer .getLong ((long ) (startIndex + i ) * OFFSET_WIDTH ) - startPoint ;
710+ to .offsetBuffer .setLong ((long ) i * OFFSET_WIDTH , relativeOffset );
711+ }
712+ /* splitAndTransfer validity buffer */
713+ splitAndTransferValidityBuffer (startIndex , length , to );
714+ /* splitAndTransfer data buffer */
715+ dataTransferPair .splitAndTransfer (
716+ checkedCastToInt (startPoint ), checkedCastToInt (sliceLength ));
717+ to .lastSet = length - 1 ;
718+ to .setValueCount (length );
719+ } else {
720+ to .ensureEmptyOffsetBufferCapacity (OFFSET_WIDTH );
721+ dataTransferPair .splitAndTransfer (0 , 0 );
722+ to .setValueCount (0 );
687723 }
688- /* splitAndTransfer validity buffer */
689- splitAndTransferValidityBuffer (startIndex , length , to );
690- /* splitAndTransfer data buffer */
691- dataTransferPair .splitAndTransfer (
692- checkedCastToInt (startPoint ), checkedCastToInt (sliceLength ));
693- to .lastSet = length - 1 ;
694- to .setValueCount (length );
695724 }
696725
697726 @ Override
0 commit comments