]> git.proxmox.com Git - ceph.git/blob - ceph/src/arrow/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
ded58b22b00c364d38909f4e7cb65ff2b6b3ca2b
[ceph.git] / ceph / src / arrow / java / vector / src / main / java / org / apache / arrow / vector / BaseFixedWidthVector.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.arrow.vector;
19
20 import static org.apache.arrow.memory.util.LargeMemoryUtil.capAtMaxInt;
21
22 import java.nio.ByteBuffer;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26
27 import org.apache.arrow.memory.ArrowBuf;
28 import org.apache.arrow.memory.BufferAllocator;
29 import org.apache.arrow.memory.util.ArrowBufPointer;
30 import org.apache.arrow.memory.util.ByteFunctionHelpers;
31 import org.apache.arrow.memory.util.hash.ArrowBufHasher;
32 import org.apache.arrow.util.Preconditions;
33 import org.apache.arrow.vector.compare.VectorVisitor;
34 import org.apache.arrow.vector.ipc.message.ArrowFieldNode;
35 import org.apache.arrow.vector.types.pojo.Field;
36 import org.apache.arrow.vector.util.CallBack;
37 import org.apache.arrow.vector.util.OversizedAllocationException;
38 import org.apache.arrow.vector.util.TransferPair;
39
40 import io.netty.util.internal.PlatformDependent;
41
42 /**
43 * BaseFixedWidthVector provides an abstract interface for
44 * implementing vectors of fixed width values. The vectors are nullable
45 * implying that zero or more elements in the vector could be NULL.
46 */
47 public abstract class BaseFixedWidthVector extends BaseValueVector
48 implements FixedWidthVector, FieldVector, VectorDefinitionSetter {
49 private final int typeWidth;
50
51 protected int lastValueCapacity;
52 protected int actualValueCapacity;
53
54 protected final Field field;
55 private int allocationMonitor;
56 protected ArrowBuf validityBuffer;
57 protected ArrowBuf valueBuffer;
58 protected int valueCount;
59
60 /**
61 * Constructs a new instance.
62 *
63 * @param field field materialized by this vector
64 * @param allocator The allocator to use for allocating memory for the vector.
65 * @param typeWidth The width in bytes of the type.
66 */
67 public BaseFixedWidthVector(Field field, final BufferAllocator allocator, final int typeWidth) {
68 super(allocator);
69 this.typeWidth = typeWidth;
70 this.field = field;
71 valueCount = 0;
72 allocationMonitor = 0;
73 validityBuffer = allocator.getEmpty();
74 valueBuffer = allocator.getEmpty();
75 lastValueCapacity = INITIAL_VALUE_ALLOCATION;
76 refreshValueCapacity();
77 }
78
79
80 public int getTypeWidth() {
81 return typeWidth;
82 }
83
84 @Override
85 public String getName() {
86 return field.getName();
87 }
88
89 /* TODO:
90 * see if getNullCount() can be made faster -- O(1)
91 */
92
93 /* TODO:
94 * Once the entire hierarchy has been refactored, move common functions
95 * like getNullCount(), splitAndTransferValidityBuffer to top level
96 * base class BaseValueVector.
97 *
98 * Along with this, some class members (validityBuffer) can also be
99 * abstracted out to top level base class.
100 *
101 * Right now BaseValueVector is the top level base class for other
102 * vector types in ValueVector hierarchy (non-nullable) and those
103 * vectors have not yet been refactored/removed so moving things to
104 * the top class as of now is not a good idea.
105 */
106
107 /**
108 * Get the memory address of buffer that manages the validity
109 * (NULL or NON-NULL nature) of elements in the vector.
110 * @return starting address of the buffer
111 */
112 @Override
113 public long getValidityBufferAddress() {
114 return (validityBuffer.memoryAddress());
115 }
116
117 /**
118 * Get the memory address of buffer that stores the data for elements
119 * in the vector.
120 * @return starting address of the buffer
121 */
122 @Override
123 public long getDataBufferAddress() {
124 return (valueBuffer.memoryAddress());
125 }
126
127 /**
128 * Get the memory address of buffer that stores the offsets for elements
129 * in the vector. This operation is not supported for fixed-width vectors.
130 * @return starting address of the buffer
131 * @throws UnsupportedOperationException for fixed width vectors
132 */
133 @Override
134 public long getOffsetBufferAddress() {
135 throw new UnsupportedOperationException("not supported for fixed-width vectors");
136 }
137
138 /**
139 * Get buffer that manages the validity (NULL or NON-NULL nature) of
140 * elements in the vector. Consider it as a buffer for internal bit vector
141 * data structure.
142 * @return buffer
143 */
144 @Override
145 public ArrowBuf getValidityBuffer() {
146 return validityBuffer;
147 }
148
149 /**
150 * Get the buffer that stores the data for elements in the vector.
151 * @return buffer
152 */
153 @Override
154 public ArrowBuf getDataBuffer() {
155 return valueBuffer;
156 }
157
158 /**
159 * buffer that stores the offsets for elements
160 * in the vector. This operation is not supported for fixed-width vectors.
161 * @return buffer
162 * @throws UnsupportedOperationException for fixed width vectors
163 */
164 @Override
165 public ArrowBuf getOffsetBuffer() {
166 throw new UnsupportedOperationException("not supported for fixed-width vectors");
167 }
168
169 /**
170 * Sets the desired value capacity for the vector. This function doesn't
171 * allocate any memory for the vector.
172 * @param valueCount desired number of elements in the vector
173 */
174 @Override
175 public void setInitialCapacity(int valueCount) {
176 computeAndCheckBufferSize(valueCount);
177 lastValueCapacity = valueCount;
178 }
179
180 /**
181 * Get the current value capacity for the vector.
182 *
183 * @return number of elements that vector can hold.
184 */
185 @Override
186 public int getValueCapacity() {
187 return actualValueCapacity;
188 }
189
190 /**
191 * Call this if you change the capacity of valueBuffer or validityBuffer.
192 */
193 protected void refreshValueCapacity() {
194 actualValueCapacity = Math.min(getValueBufferValueCapacity(), getValidityBufferValueCapacity());
195 }
196
197 protected int getValueBufferValueCapacity() {
198 return capAtMaxInt(valueBuffer.capacity() / typeWidth);
199 }
200
201 protected int getValidityBufferValueCapacity() {
202 return capAtMaxInt(validityBuffer.capacity() * 8);
203 }
204
205 /**
206 * zero out the vector and the data in associated buffers.
207 */
208 @Override
209 public void zeroVector() {
210 initValidityBuffer();
211 initValueBuffer();
212 }
213
214 /* zero out the validity buffer */
215 private void initValidityBuffer() {
216 validityBuffer.setZero(0, validityBuffer.capacity());
217 }
218
219 /* zero out the data buffer */
220 private void initValueBuffer() {
221 valueBuffer.setZero(0, valueBuffer.capacity());
222 }
223
224 /**
225 * Reset the vector to initial state. Same as {@link #zeroVector()}.
226 * Note that this method doesn't release any memory.
227 */
228 @Override
229 public void reset() {
230 valueCount = 0;
231 zeroVector();
232 }
233
234 /**
235 * Close the vector and release the associated buffers.
236 */
237 @Override
238 public void close() {
239 clear();
240 }
241
242 /**
243 * Same as {@link #close()}.
244 */
245 @Override
246 public void clear() {
247 valueCount = 0;
248 validityBuffer = releaseBuffer(validityBuffer);
249 valueBuffer = releaseBuffer(valueBuffer);
250 refreshValueCapacity();
251 }
252
253 /* used to step down the memory allocation */
254 protected void incrementAllocationMonitor() {
255 if (allocationMonitor < 0) {
256 allocationMonitor = 0;
257 }
258 allocationMonitor++;
259 }
260
261 /* used to step up the memory allocation */
262 protected void decrementAllocationMonitor() {
263 if (allocationMonitor > 0) {
264 allocationMonitor = 0;
265 }
266 allocationMonitor--;
267 }
268
269 /**
270 * Same as {@link #allocateNewSafe()}.
271 */
272 @Override
273 public void allocateNew() {
274 allocateNew(lastValueCapacity);
275 }
276
277 /**
278 * Allocate memory for the vector. We internally use a default value count
279 * of 4096 to allocate memory for at least these many elements in the
280 * vector. See {@link #allocateNew(int)} for allocating memory for specific
281 * number of elements in the vector.
282 *
283 * @return false if memory allocation fails, true otherwise.
284 */
285 @Override
286 public boolean allocateNewSafe() {
287 try {
288 allocateNew(lastValueCapacity);
289 return true;
290 } catch (Exception e) {
291 return false;
292 }
293 }
294
295 /**
296 * Allocate memory for the vector to support storing at least the provided number of
297 * elements in the vector. This method must be called prior to using the ValueVector.
298 *
299 * @param valueCount the desired number of elements in the vector
300 * @throws org.apache.arrow.memory.OutOfMemoryException on error
301 */
302 public void allocateNew(int valueCount) {
303 computeAndCheckBufferSize(valueCount);
304
305 /* we are doing a new allocation -- release the current buffers */
306 clear();
307
308 try {
309 allocateBytes(valueCount);
310 } catch (Exception e) {
311 clear();
312 throw e;
313 }
314 }
315
316 /*
317 * Compute the buffer size required for 'valueCount', and check if it's within bounds.
318 */
319 private long computeAndCheckBufferSize(int valueCount) {
320 final long size = computeCombinedBufferSize(valueCount, typeWidth);
321 if (size > MAX_ALLOCATION_SIZE) {
322 throw new OversizedAllocationException("Memory required for vector capacity " +
323 valueCount +
324 " is (" + size + "), which is more than max allowed (" + MAX_ALLOCATION_SIZE + ")");
325 }
326 return size;
327 }
328
329 /**
330 * Actual memory allocation is done by this function. All the calculations
331 * and knowledge about what size to allocate is upto the callers of this
332 * method.
333 * Callers appropriately handle errors if memory allocation fails here.
334 * Callers should also take care of determining that desired size is
335 * within the bounds of max allocation allowed and any other error
336 * conditions.
337 */
338 private void allocateBytes(int valueCount) {
339 DataAndValidityBuffers buffers = allocFixedDataAndValidityBufs(valueCount, typeWidth);
340 valueBuffer = buffers.getDataBuf();
341 validityBuffer = buffers.getValidityBuf();
342 zeroVector();
343
344 refreshValueCapacity();
345 lastValueCapacity = getValueCapacity();
346 }
347
348 /**
349 * During splitAndTransfer, if we splitting from a random position within a byte,
350 * we can't just slice the source buffer so we have to explicitly allocate the
351 * validityBuffer of the target vector. This is unlike the databuffer which we can
352 * always slice for the target vector.
353 */
354 private void allocateValidityBuffer(final int validityBufferSize) {
355 validityBuffer = allocator.buffer(validityBufferSize);
356 validityBuffer.readerIndex(0);
357 refreshValueCapacity();
358 }
359
360 /**
361 * Get the potential buffer size for a particular number of records.
362 * @param count desired number of elements in the vector
363 * @return estimated size of underlying buffers if the vector holds
364 * a given number of elements
365 */
366 @Override
367 public int getBufferSizeFor(final int count) {
368 if (count == 0) {
369 return 0;
370 }
371 return (count * typeWidth) + getValidityBufferSizeFromCount(count);
372 }
373
374 /**
375 * Get the size (number of bytes) of underlying buffers used by this
376 * vector.
377 * @return size of underlying buffers.
378 */
379 @Override
380 public int getBufferSize() {
381 if (valueCount == 0) {
382 return 0;
383 }
384 return (valueCount * typeWidth) + getValidityBufferSizeFromCount(valueCount);
385 }
386
387 /**
388 * Get information about how this field is materialized.
389 * @return the field corresponding to this vector
390 */
391 @Override
392 public Field getField() {
393 return field;
394 }
395
396 /**
397 * Return the underlying buffers associated with this vector. Note that this doesn't
398 * impact the reference counts for this buffer so it only should be used for in-context
399 * access. Also note that this buffer changes regularly thus
400 * external classes shouldn't hold a reference to it (unless they change it).
401 *
402 * @param clear Whether to clear vector before returning; the buffers will still be refcounted
403 * but the returned array will be the only reference to them
404 * @return The underlying {@link ArrowBuf buffers} that is used by this
405 * vector instance.
406 */
407 @Override
408 public ArrowBuf[] getBuffers(boolean clear) {
409 final ArrowBuf[] buffers;
410 setReaderAndWriterIndex();
411 if (getBufferSize() == 0) {
412 buffers = new ArrowBuf[0];
413 } else {
414 buffers = new ArrowBuf[2];
415 buffers[0] = validityBuffer;
416 buffers[1] = valueBuffer;
417 }
418 if (clear) {
419 for (final ArrowBuf buffer : buffers) {
420 buffer.getReferenceManager().retain(1);
421 }
422 clear();
423 }
424 return buffers;
425 }
426
427 /**
428 * Resize the vector to increase the capacity. The internal behavior is to
429 * double the current value capacity.
430 */
431 @Override
432 public void reAlloc() {
433 int targetValueCount = getValueCapacity() * 2;
434 if (targetValueCount == 0) {
435 if (lastValueCapacity > 0) {
436 targetValueCount = lastValueCapacity;
437 } else {
438 targetValueCount = INITIAL_VALUE_ALLOCATION * 2;
439 }
440 }
441 computeAndCheckBufferSize(targetValueCount);
442
443 DataAndValidityBuffers buffers = allocFixedDataAndValidityBufs(targetValueCount, typeWidth);
444 final ArrowBuf newValueBuffer = buffers.getDataBuf();
445 newValueBuffer.setBytes(0, valueBuffer, 0, valueBuffer.capacity());
446 newValueBuffer.setZero(valueBuffer.capacity(), newValueBuffer.capacity() - valueBuffer.capacity());
447 valueBuffer.getReferenceManager().release();
448 valueBuffer = newValueBuffer;
449
450 final ArrowBuf newValidityBuffer = buffers.getValidityBuf();
451 newValidityBuffer.setBytes(0, validityBuffer, 0, validityBuffer.capacity());
452 newValidityBuffer.setZero(validityBuffer.capacity(), newValidityBuffer.capacity() - validityBuffer.capacity());
453 validityBuffer.getReferenceManager().release();
454 validityBuffer = newValidityBuffer;
455
456 refreshValueCapacity();
457 lastValueCapacity = getValueCapacity();
458 }
459
460 /**
461 * Get the inner vectors.
462 *
463 * @deprecated This API will be removed as the current implementations no longer support inner vectors.
464 *
465 * @return the inner vectors for this field as defined by the TypeLayout
466 */
467 @Deprecated
468 @Override
469 public List<BufferBacked> getFieldInnerVectors() {
470 throw new UnsupportedOperationException("There are no inner vectors. Use getFieldBuffers");
471 }
472
473 /**
474 * Initialize the children in schema for this Field. This operation is a
475 * NO-OP for scalar types since they don't have any children.
476 * @param children the schema
477 * @throws IllegalArgumentException if children is a non-empty list for scalar types.
478 */
479 @Override
480 public void initializeChildrenFromFields(List<Field> children) {
481 if (!children.isEmpty()) {
482 throw new IllegalArgumentException("primitive type vector can not have children");
483 }
484 }
485
486 /**
487 * Get the inner child vectors.
488 * @return list of child vectors for complex types, empty list for scalar vector types
489 */
490 @Override
491 public List<FieldVector> getChildrenFromFields() {
492 return Collections.emptyList();
493 }
494
495 /**
496 * Load the buffers of this vector with provided source buffers.
497 * The caller manages the source buffers and populates them before invoking
498 * this method.
499 * @param fieldNode the fieldNode indicating the value count
500 * @param ownBuffers the buffers for this Field (own buffers only, children not included)
501 */
502 @Override
503 public void loadFieldBuffers(ArrowFieldNode fieldNode, List<ArrowBuf> ownBuffers) {
504 if (ownBuffers.size() != 2) {
505 throw new IllegalArgumentException("Illegal buffer count, expected " + 2 + ", got: " + ownBuffers.size());
506 }
507
508 ArrowBuf bitBuffer = ownBuffers.get(0);
509 ArrowBuf dataBuffer = ownBuffers.get(1);
510
511 validityBuffer.getReferenceManager().release();
512 validityBuffer = BitVectorHelper.loadValidityBuffer(fieldNode, bitBuffer, allocator);
513 valueBuffer.getReferenceManager().release();
514 valueBuffer = dataBuffer.getReferenceManager().retain(dataBuffer, allocator);
515 refreshValueCapacity();
516
517 valueCount = fieldNode.getLength();
518 }
519
520 /**
521 * Get the buffers belonging to this vector.
522 *
523 * @return the inner buffers.
524 */
525 public List<ArrowBuf> getFieldBuffers() {
526 List<ArrowBuf> result = new ArrayList<>(2);
527 setReaderAndWriterIndex();
528 result.add(validityBuffer);
529 result.add(valueBuffer);
530
531 return result;
532 }
533
534 /**
535 * Set the reader and writer indexes for the inner buffers.
536 */
537 private void setReaderAndWriterIndex() {
538 validityBuffer.readerIndex(0);
539 valueBuffer.readerIndex(0);
540 if (valueCount == 0) {
541 validityBuffer.writerIndex(0);
542 valueBuffer.writerIndex(0);
543 } else {
544 validityBuffer.writerIndex(getValidityBufferSizeFromCount(valueCount));
545 if (typeWidth == 0) {
546 /* specialized handling for BitVector */
547 valueBuffer.writerIndex(getValidityBufferSizeFromCount(valueCount));
548 } else {
549 valueBuffer.writerIndex((long) valueCount * typeWidth);
550 }
551 }
552 }
553
554 /**
555 * Construct a transfer pair of this vector and another vector of same type.
556 * @param ref name of the target vector
557 * @param allocator allocator for the target vector
558 * @param callBack not used
559 * @return TransferPair
560 */
561 @Override
562 public TransferPair getTransferPair(String ref, BufferAllocator allocator, CallBack callBack) {
563 return getTransferPair(ref, allocator);
564 }
565
566 /**
567 * Construct a transfer pair of this vector and another vector of same type.
568 * @param allocator allocator for the target vector
569 * @return TransferPair
570 */
571 @Override
572 public TransferPair getTransferPair(BufferAllocator allocator) {
573 return getTransferPair(getName(), allocator);
574 }
575
576 /**
577 * Construct a transfer pair of this vector and another vector of same type.
578 * @param ref name of the target vector
579 * @param allocator allocator for the target vector
580 * @return TransferPair
581 */
582 public abstract TransferPair getTransferPair(String ref, BufferAllocator allocator);
583
584 /**
585 * Transfer this vector'data to another vector. The memory associated
586 * with this vector is transferred to the allocator of target vector
587 * for accounting and management purposes.
588 * @param target destination vector for transfer
589 */
590 public void transferTo(BaseFixedWidthVector target) {
591 compareTypes(target, "transferTo");
592 target.clear();
593 target.validityBuffer = transferBuffer(validityBuffer, target.allocator);
594 target.valueBuffer = transferBuffer(valueBuffer, target.allocator);
595 target.valueCount = valueCount;
596 target.refreshValueCapacity();
597 clear();
598 }
599
600 /**
601 * Slice this vector at desired index and length and transfer the
602 * corresponding data to the target vector.
603 * @param startIndex start position of the split in source vector.
604 * @param length length of the split.
605 * @param target destination vector
606 */
607 public void splitAndTransferTo(int startIndex, int length,
608 BaseFixedWidthVector target) {
609 Preconditions.checkArgument(startIndex >= 0 && length >= 0 && startIndex + length <= valueCount,
610 "Invalid parameters startIndex: %s, length: %s for valueCount: %s", startIndex, length, valueCount);
611 compareTypes(target, "splitAndTransferTo");
612 target.clear();
613 splitAndTransferValidityBuffer(startIndex, length, target);
614 splitAndTransferValueBuffer(startIndex, length, target);
615 target.setValueCount(length);
616 }
617
618 /**
619 * Data buffer can always be split and transferred using slicing.
620 */
621 private void splitAndTransferValueBuffer(int startIndex, int length,
622 BaseFixedWidthVector target) {
623 final int startPoint = startIndex * typeWidth;
624 final int sliceLength = length * typeWidth;
625 final ArrowBuf slicedBuffer = valueBuffer.slice(startPoint, sliceLength);
626 target.valueBuffer = transferBuffer(slicedBuffer, target.allocator);
627 target.refreshValueCapacity();
628 }
629
630 /**
631 * Validity buffer has multiple cases of split and transfer depending on
632 * the starting position of the source index.
633 */
634 private void splitAndTransferValidityBuffer(int startIndex, int length,
635 BaseFixedWidthVector target) {
636 int firstByteSource = BitVectorHelper.byteIndex(startIndex);
637 int lastByteSource = BitVectorHelper.byteIndex(valueCount - 1);
638 int byteSizeTarget = getValidityBufferSizeFromCount(length);
639 int offset = startIndex % 8;
640
641 if (length > 0) {
642 if (offset == 0) {
643 /* slice */
644 if (target.validityBuffer != null) {
645 target.validityBuffer.getReferenceManager().release();
646 }
647 target.validityBuffer = validityBuffer.slice(firstByteSource, byteSizeTarget);
648 target.validityBuffer.getReferenceManager().retain(1);
649 target.refreshValueCapacity();
650 } else {
651 /* Copy data
652 * When the first bit starts from the middle of a byte (offset != 0),
653 * copy data from src BitVector.
654 * Each byte in the target is composed by a part in i-th byte,
655 * another part in (i+1)-th byte.
656 */
657 target.allocateValidityBuffer(byteSizeTarget);
658
659 for (int i = 0; i < byteSizeTarget - 1; i++) {
660 byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
661 firstByteSource + i, offset);
662 byte b2 = BitVectorHelper.getBitsFromNextByte(this.validityBuffer,
663 firstByteSource + i + 1, offset);
664
665 target.validityBuffer.setByte(i, (b1 + b2));
666 }
667
668 /* Copying the last piece is done in the following manner:
669 * if the source vector has 1 or more bytes remaining, we copy
670 * the last piece as a byte formed by shifting data
671 * from the current byte and the next byte.
672 *
673 * if the source vector has no more bytes remaining
674 * (we are at the last byte), we copy the last piece as a byte
675 * by shifting data from the current byte.
676 */
677 if ((firstByteSource + byteSizeTarget - 1) < lastByteSource) {
678 byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
679 firstByteSource + byteSizeTarget - 1, offset);
680 byte b2 = BitVectorHelper.getBitsFromNextByte(this.validityBuffer,
681 firstByteSource + byteSizeTarget, offset);
682
683 target.validityBuffer.setByte(byteSizeTarget - 1, b1 + b2);
684 } else {
685 byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
686 firstByteSource + byteSizeTarget - 1, offset);
687 target.validityBuffer.setByte(byteSizeTarget - 1, b1);
688 }
689 }
690 }
691 }
692
693
694 /*----------------------------------------------------------------*
695 | |
696 | common getters and setters |
697 | |
698 *----------------------------------------------------------------*/
699
700
701 /**
702 * Get the number of elements that are null in the vector.
703 *
704 * @return the number of null elements.
705 */
706 @Override
707 public int getNullCount() {
708 return BitVectorHelper.getNullCount(validityBuffer, valueCount);
709 }
710
711 /**
712 * Get the value count of vector. This will always be zero unless
713 * {@link #setValueCount(int)} has been called prior to calling this.
714 *
715 * @return valueCount for the vector
716 */
717 @Override
718 public int getValueCount() {
719 return valueCount;
720 }
721
722 /**
723 * Set value count for the vector.
724 *
725 * @param valueCount value count to set
726 */
727 @Override
728 public void setValueCount(int valueCount) {
729 this.valueCount = valueCount;
730 final int currentValueCapacity = getValueCapacity();
731 while (valueCount > getValueCapacity()) {
732 reAlloc();
733 }
734 /*
735 * We are trying to understand the pattern of memory allocation.
736 * If initially, the user did vector.allocateNew(), we would have
737 * allocated memory of default size (4096 * type width).
738 * Later on user invokes setValueCount(count).
739 *
740 * If the existing value capacity is twice as large as the
741 * valueCount, we know that we over-provisioned memory in the
742 * first place when default memory allocation was done because user
743 * really needs a much less value count in the vector.
744 *
745 * We record this by bumping up the allocationMonitor. If this pattern
746 * happens for certain number of times and allocationMonitor
747 * reaches the threshold (internal hardcoded) value, subsequent
748 * call to allocateNew() will take care of stepping down the
749 * default memory allocation size.
750 *
751 * Another case would be under-provisioning the initial memory and
752 * thus going through a lot of realloc(). Here the goal is to
753 * see if we can minimize the number of reallocations. Again the
754 * state is recorded in allocationMonitor by decrementing it
755 * (negative value). If a threshold is hit, realloc will try to
756 * allocate more memory in order to possibly avoid a future realloc.
757 * This case is also applicable to setSafe() methods which can trigger
758 * a realloc() and thus we record the state there as well.
759 */
760 if (valueCount > 0) {
761 if (currentValueCapacity >= (valueCount * 2)) {
762 incrementAllocationMonitor();
763 } else if (currentValueCapacity <= (valueCount / 2)) {
764 decrementAllocationMonitor();
765 }
766 }
767 setReaderAndWriterIndex();
768 }
769
770 /**
771 * Check if the given index is within the current value capacity
772 * of the vector.
773 *
774 * @param index position to check
775 * @return true if index is within the current value capacity
776 */
777 public boolean isSafe(int index) {
778 return index < getValueCapacity();
779 }
780
781 /**
782 * Check if element at given index is null.
783 *
784 * @param index position of element
785 * @return true if element at given index is null, false otherwise
786 */
787 @Override
788 public boolean isNull(int index) {
789 return (isSet(index) == 0);
790 }
791
792 /**
793 * Same as {@link #isNull(int)}.
794 *
795 * @param index position of element
796 * @return 1 if element at given index is not null, 0 otherwise
797 */
798 public int isSet(int index) {
799 final int byteIndex = index >> 3;
800 final byte b = validityBuffer.getByte(byteIndex);
801 final int bitIndex = index & 7;
802 return (b >> bitIndex) & 0x01;
803 }
804
805 /**
806 * Mark the particular position in the vector as non-null.
807 *
808 * @param index position of the element.
809 */
810 @Override
811 public void setIndexDefined(int index) {
812 handleSafe(index);
813 BitVectorHelper.setBit(validityBuffer, index);
814 }
815
816 public void set(int index, byte[] value, int start, int length) {
817 throw new UnsupportedOperationException();
818 }
819
820 public void setSafe(int index, byte[] value, int start, int length) {
821 throw new UnsupportedOperationException();
822 }
823
824 public void set(int index, ByteBuffer value, int start, int length) {
825 throw new UnsupportedOperationException();
826 }
827
828 public void setSafe(int index, ByteBuffer value, int start, int length) {
829 throw new UnsupportedOperationException();
830 }
831
832
833 /*----------------------------------------------------------------*
834 | |
835 | helper methods for setters |
836 | |
837 *----------------------------------------------------------------*/
838
839
840 protected void handleSafe(int index) {
841 while (index >= getValueCapacity()) {
842 decrementAllocationMonitor();
843 reAlloc();
844 }
845 }
846
847 /**
848 * Copy a cell value from a particular index in source vector to a particular
849 * position in this vector. The source vector should be of the same type as this one.
850 *
851 * @param fromIndex position to copy from in source vector
852 * @param thisIndex position to copy to in this vector
853 * @param from source vector
854 */
855 @Override
856 public void copyFrom(int fromIndex, int thisIndex, ValueVector from) {
857 Preconditions.checkArgument(this.getMinorType() == from.getMinorType());
858 if (from.isNull(fromIndex)) {
859 BitVectorHelper.unsetBit(this.getValidityBuffer(), thisIndex);
860 } else {
861 BitVectorHelper.setBit(this.getValidityBuffer(), thisIndex);
862 PlatformDependent.copyMemory(from.getDataBuffer().memoryAddress() + (long) fromIndex * typeWidth,
863 this.getDataBuffer().memoryAddress() + (long) thisIndex * typeWidth, typeWidth);
864 }
865 }
866
867 /**
868 * Same as {@link #copyFrom(int, int, ValueVector)} except that
869 * it handles the case when the capacity of the vector needs to be expanded
870 * before copy.
871 *
872 * @param fromIndex position to copy from in source vector
873 * @param thisIndex position to copy to in this vector
874 * @param from source vector
875 */
876 @Override
877 public void copyFromSafe(int fromIndex, int thisIndex, ValueVector from) {
878 Preconditions.checkArgument(this.getMinorType() == from.getMinorType());
879 handleSafe(thisIndex);
880 copyFrom(fromIndex, thisIndex, from);
881 }
882
883 /**
884 * Set the element at the given index to null.
885 *
886 * @param index position of element
887 */
888 public void setNull(int index) {
889 handleSafe(index);
890 // not really needed to set the bit to 0 as long as
891 // the buffer always starts from 0.
892 BitVectorHelper.unsetBit(validityBuffer, index);
893 }
894
895 @Override
896 public ArrowBufPointer getDataPointer(int index) {
897 return getDataPointer(index, new ArrowBufPointer());
898 }
899
900 @Override
901 public ArrowBufPointer getDataPointer(int index, ArrowBufPointer reuse) {
902 if (isNull(index)) {
903 reuse.set(null, 0, 0);
904 } else {
905 reuse.set(valueBuffer, (long) index * typeWidth, typeWidth);
906 }
907 return reuse;
908 }
909
910 @Override
911 public int hashCode(int index) {
912 return hashCode(index, null);
913 }
914
915 @Override
916 public int hashCode(int index, ArrowBufHasher hasher) {
917 if (isNull(index)) {
918 return ArrowBufPointer.NULL_HASH_CODE;
919 }
920 long start = (long) typeWidth * index;
921 long end = (long) typeWidth * (index + 1);
922 return ByteFunctionHelpers.hash(hasher, this.getDataBuffer(), start, end);
923 }
924
925 @Override
926 public <OUT, IN> OUT accept(VectorVisitor<OUT, IN> visitor, IN value) {
927 return visitor.visit(this, value);
928 }
929
930 }