DRILL-7341: Vector reAlloc may fail after exchange

closes #1838
diff --git a/exec/vector/src/main/codegen/templates/FixedValueVectors.java b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
index 508e484..5741555 100644
--- a/exec/vector/src/main/codegen/templates/FixedValueVectors.java
+++ b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
@@ -210,10 +210,17 @@
     // a zero-length buffer. Instead, just allocate a 256 byte
     // buffer if we start at 0.
 
-    final long newAllocationSize = allocationSizeInBytes == 0
+    long newAllocationSize = allocationSizeInBytes == 0
         ? 256
         : allocationSizeInBytes * 2L;
 
+    final int currentCapacity = data.capacity();
+    // Some operations, such as Value Vector#exchange, can be change DrillBuf data field without corresponding allocation size changes.
+    // Check that the size of the allocation is sufficient to copy the old buffer.
+    while (newAllocationSize < currentCapacity) {
+      newAllocationSize *= 2L;
+    }
+
     // TODO: Replace this with MAX_BUFFER_SIZE once all
     // code is aware of the maximum vector size.
 
@@ -222,8 +229,7 @@
     }
 
     reallocRaw((int) newAllocationSize);
-    final int halfNewCapacity = data.capacity() / 2;
-    data.setZero(halfNewCapacity, halfNewCapacity);
+    data.setZero(currentCapacity, data.capacity() - currentCapacity);
   }
 
   @Override
diff --git a/exec/vector/src/main/codegen/templates/VariableLengthVectors.java b/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
index 8dd8eb1..1bb758f 100644
--- a/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
+++ b/exec/vector/src/main/codegen/templates/VariableLengthVectors.java
@@ -390,7 +390,14 @@
   }
 
   public void reAlloc() {
-    final long newAllocationSize = allocationSizeInBytes*2L;
+    long newAllocationSize = allocationSizeInBytes*2L;
+
+    // Some operations, such as Value Vector#exchange, can be change DrillBuf data field without corresponding allocation size changes.
+    // Check that the size of the allocation is sufficient to copy the old buffer.
+    while (newAllocationSize < data.capacity()) {
+      newAllocationSize *= 2L;
+    }
+
     if (newAllocationSize > MAX_ALLOCATION_SIZE)  {
       throw new OversizedAllocationException("Unable to expand the buffer. Max allowed buffer size is reached.");
     }
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/vector/BitVector.java b/exec/vector/src/main/java/org/apache/drill/exec/vector/BitVector.java
index 634e4d6..7b2cd28 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/vector/BitVector.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/vector/BitVector.java
@@ -179,7 +179,14 @@
    * Allocate new buffer with double capacity, and copy data into the new buffer. Replace vector's buffer with new buffer, and release old one
    */
   public void reAlloc() {
-    final long newAllocationSize = allocationSizeInBytes * 2L;
+    long newAllocationSize = allocationSizeInBytes * 2L;
+
+    // Some operations, such as Value Vector#exchange, can be change DrillBuf data field without corresponding allocation size changes.
+    // Check that the size of the allocation is sufficient to copy the old buffer.
+    while (newAllocationSize < data.capacity()) {
+      newAllocationSize *= 2L;
+    }
+
     if (newAllocationSize > MAX_ALLOCATION_SIZE) {
       throw new OversizedAllocationException("Requested amount of memory is more than max allowed allocation size");
     }
diff --git a/exec/vector/src/test/java/org/apache/drill/exec/vector/VariableLengthVectorTest.java b/exec/vector/src/test/java/org/apache/drill/exec/vector/VariableLengthVectorTest.java
index 4c6aeed..c77854f 100644
--- a/exec/vector/src/test/java/org/apache/drill/exec/vector/VariableLengthVectorTest.java
+++ b/exec/vector/src/test/java/org/apache/drill/exec/vector/VariableLengthVectorTest.java
@@ -89,6 +89,30 @@
     }
   }
 
+  @Test
+  public void testDRILL7341() {
+    try (RootAllocator allocator = new RootAllocator(10_000_000)) {
+      final MaterializedField field = MaterializedField.create("stringCol", Types.optional(TypeProtos.MinorType.VARCHAR));
+      final NullableVarCharVector sourceVector = new NullableVarCharVector(field, allocator);
+      final NullableVarCharVector targetVector = new NullableVarCharVector(field, allocator);
+
+      sourceVector.allocateNew();
+      targetVector.allocateNew();
+
+      try {
+        final NullableVarCharVector.Mutator sourceMutator = sourceVector.getMutator();
+        sourceMutator.setValueCount(sourceVector.getValueCapacity() * 4);
+
+        targetVector.exchange(sourceVector);
+        final NullableVarCharVector.Mutator targetMutator = targetVector.getMutator();
+        targetMutator.setValueCount(targetVector.getValueCapacity() * 2);
+      } finally {
+        sourceVector.clear();
+        targetVector.clear();
+      }
+    }
+  }
+
   /**
    * Set 10000 values. Then go back and set new values starting at the 1001 the record.
    */