/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.flink.core.memory;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runners.Parameterized;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
import static org.junit.Assert.*;
/**
* Tests for the access and transfer methods of the HeapMemorySegment.
*/
public abstract class MemorySegmentTestBase {
private final Random random = new Random();
private final int pageSize;
public MemorySegmentTestBase(int pageSize) {
this.pageSize = pageSize;
}
// ------------------------------------------------------------------------
// Access to primitives
// ------------------------------------------------------------------------
abstract MemorySegment createSegment(int size);
abstract MemorySegment createSegment(int size, Object owner);
// ------------------------------------------------------------------------
// Access to primitives
// ------------------------------------------------------------------------
@Test
public void testByteAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.put(-1, (byte) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(pageSize, (byte) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MAX_VALUE, (byte) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MIN_VALUE, (byte) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i < pageSize; i++) {
segment.put(i, (byte) random.nextInt());
}
random.setSeed(seed);
for (int i = 0; i < pageSize; i++) {
assertEquals((byte) random.nextInt(), segment.get(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize);
if (occupied[pos]) {
continue;
} else {
occupied[pos] = true;
}
segment.put(pos, (byte) random.nextInt());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize);
if (occupied[pos]) {
continue;
} else {
occupied[pos] = true;
}
assertEquals((byte) random.nextInt(), segment.get(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testBooleanAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putBoolean(-1, false);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putBoolean(pageSize, false);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putBoolean(Integer.MAX_VALUE, false);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putBoolean(Integer.MIN_VALUE, false);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getBoolean(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getBoolean(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getBoolean(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getBoolean(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i < pageSize; i++) {
segment.putBoolean(i, random.nextBoolean());
}
random.setSeed(seed);
for (int i = 0; i < pageSize; i++) {
assertEquals(random.nextBoolean(), segment.getBoolean(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize);
if (occupied[pos]) {
continue;
} else {
occupied[pos] = true;
}
segment.putBoolean(pos, random.nextBoolean());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize);
if (occupied[pos]) {
continue;
} else {
occupied[pos] = true;
}
assertEquals(random.nextBoolean(), segment.getBoolean(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testCharAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putChar(-1, 'a');
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putChar(pageSize, 'a');
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putChar(Integer.MIN_VALUE, 'a');
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putChar(Integer.MAX_VALUE, 'a');
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putChar(Integer.MAX_VALUE - 1, 'a');
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getChar(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getChar(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getChar(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getChar(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getChar(Integer.MAX_VALUE - 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 2; i += 2) {
segment.putChar(i, (char) (random.nextInt(Character.MAX_VALUE)));
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 2; i += 2) {
assertEquals((char) (random.nextInt(Character.MAX_VALUE)), segment.getChar(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 1);
if (occupied[pos] || occupied[pos + 1]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
}
segment.putChar(pos, (char) (random.nextInt(Character.MAX_VALUE)));
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 1);
if (occupied[pos] || occupied[pos + 1]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
}
assertEquals((char) (random.nextInt(Character.MAX_VALUE)), segment.getChar(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testShortAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putShort(-1, (short) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putShort(pageSize, (short) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putShort(Integer.MIN_VALUE, (short) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putShort(Integer.MAX_VALUE, (short) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putShort(Integer.MAX_VALUE - 1, (short) 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getShort(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getShort(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getShort(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getShort(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getShort(Integer.MAX_VALUE - 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 2; i += 2) {
segment.putShort(i, (short) random.nextInt());
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 2; i += 2) {
assertEquals((short) random.nextInt(), segment.getShort(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 1);
if (occupied[pos] || occupied[pos + 1]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
}
segment.putShort(pos, (short) random.nextInt());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 1);
if (occupied[pos] || occupied[pos + 1]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
}
assertEquals((short) random.nextInt(), segment.getShort(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testIntAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putInt(-1, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putInt(pageSize, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putInt(pageSize - 3, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putInt(Integer.MIN_VALUE, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putInt(Integer.MAX_VALUE, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putInt(Integer.MAX_VALUE - 3, 0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(pageSize - 3);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getInt(Integer.MAX_VALUE - 3);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 4; i += 4) {
segment.putInt(i, random.nextInt());
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 4; i += 4) {
assertEquals(random.nextInt(), segment.getInt(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 3);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
}
segment.putInt(pos, random.nextInt());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 3);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
}
assertEquals(random.nextInt(), segment.getInt(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testLongAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putLong(-1, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putLong(pageSize, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putLong(pageSize - 7, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putLong(Integer.MIN_VALUE, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putLong(Integer.MAX_VALUE, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putLong(Integer.MAX_VALUE - 7, 0L);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(pageSize - 7);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getLong(Integer.MAX_VALUE - 7);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 8; i += 8) {
segment.putLong(i, random.nextLong());
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 8; i += 8) {
assertEquals(random.nextLong(), segment.getLong(i));
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 7);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3] ||
occupied[pos + 4] || occupied[pos + 5] || occupied[pos + 6] || occupied[pos + 7])
{
continue;
}
else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
occupied[pos+4] = true;
occupied[pos+5] = true;
occupied[pos+6] = true;
occupied[pos+7] = true;
}
segment.putLong(pos, random.nextLong());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 7);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3] ||
occupied[pos + 4] || occupied[pos + 5] || occupied[pos + 6] || occupied[pos + 7])
{
continue;
}
else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
occupied[pos+4] = true;
occupied[pos+5] = true;
occupied[pos+6] = true;
occupied[pos+7] = true;
}
assertEquals(random.nextLong(), segment.getLong(pos));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testFloatAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putFloat(-1, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putFloat(pageSize, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putFloat(pageSize - 3, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putFloat(Integer.MIN_VALUE, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putFloat(Integer.MAX_VALUE, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putFloat(Integer.MAX_VALUE - 3, 0.0f);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(pageSize - 3);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getFloat(Integer.MAX_VALUE - 3);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 4; i += 4) {
segment.putFloat(i, random.nextFloat());
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 4; i += 4) {
assertEquals(random.nextFloat(), segment.getFloat(i), 0.0);
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 3);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
}
segment.putFloat(pos, random.nextFloat());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 3);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3]) {
continue;
} else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
}
assertEquals(random.nextFloat(), segment.getFloat(pos), 0.0);
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testDoubleAccess() {
try {
final MemorySegment segment = createSegment(pageSize);
// test exceptions
try {
segment.putDouble(-1, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putDouble(pageSize, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putDouble(pageSize - 7, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putDouble(Integer.MIN_VALUE, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putDouble(Integer.MAX_VALUE, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.putDouble(Integer.MAX_VALUE - 7, 0.0);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(-1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(pageSize);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(pageSize - 7);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(Integer.MIN_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(Integer.MAX_VALUE);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.getDouble(Integer.MAX_VALUE - 7);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// test expected correct behavior, sequential access
long seed = random.nextLong();
random.setSeed(seed);
for (int i = 0; i <= pageSize - 8; i += 8) {
segment.putDouble(i, random.nextDouble());
}
random.setSeed(seed);
for (int i = 0; i <= pageSize - 8; i += 8) {
assertEquals(random.nextDouble(), segment.getDouble(i), 0.0);
}
// test expected correct behavior, random access
random.setSeed(seed);
boolean[] occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 7);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3] ||
occupied[pos + 4] || occupied[pos + 5] || occupied[pos + 6] || occupied[pos + 7])
{
continue;
}
else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
occupied[pos+4] = true;
occupied[pos+5] = true;
occupied[pos+6] = true;
occupied[pos+7] = true;
}
segment.putDouble(pos, random.nextDouble());
}
random.setSeed(seed);
occupied = new boolean[pageSize];
for (int i = 0; i < 1000; i++) {
int pos = random.nextInt(pageSize - 7);
if (occupied[pos] || occupied[pos + 1] || occupied[pos + 2] || occupied[pos + 3] ||
occupied[pos + 4] || occupied[pos + 5] || occupied[pos + 6] || occupied[pos + 7])
{
continue;
}
else {
occupied[pos] = true;
occupied[pos+1] = true;
occupied[pos+2] = true;
occupied[pos+3] = true;
occupied[pos+4] = true;
occupied[pos+5] = true;
occupied[pos+6] = true;
occupied[pos+7] = true;
}
assertEquals(random.nextDouble(), segment.getDouble(pos), 0.0);
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// Bulk Byte Movements
// ------------------------------------------------------------------------
@Test
public void testBulkBytePutExceptions() {
try {
final MemorySegment segment = createSegment(pageSize);
byte[] bytes = new byte[pageSize / 4 + (pageSize%4)];
random.nextBytes(bytes);
// wrong positions into memory segment
try {
segment.put(-1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(-1, bytes, 4, 5);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MIN_VALUE, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MIN_VALUE, bytes, 4, 5);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(pageSize, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(pageSize, bytes, 6, 44);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(pageSize - bytes.length + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(pageSize - 5, bytes, 3, 6);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MAX_VALUE, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MAX_VALUE, bytes, 10, 20);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MAX_VALUE - bytes.length + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(Integer.MAX_VALUE - 11, bytes, 11, 11);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(3 * (pageSize / 4) + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(3 * (pageSize / 4) + 2, bytes, 0, bytes.length - 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(7 * (pageSize / 8) + 1, bytes, 0, bytes.length / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// wrong source array positions / lengths
try {
segment.put(0, bytes, -1, 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(0, bytes, -1, bytes.length + 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(0, bytes, Integer.MIN_VALUE, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(0, bytes, Integer.MAX_VALUE, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.put(0, bytes, Integer.MAX_VALUE - bytes.length + 1, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// case where negative offset and negative index compensate each other
try {
segment.put(-2, bytes, -1, bytes.length / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testBulkByteGetExceptions() {
try {
final MemorySegment segment = createSegment(pageSize);
byte[] bytes = new byte[pageSize / 4];
// wrong positions into memory segment
try {
segment.get(-1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(-1, bytes, 4, 5);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MIN_VALUE, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MIN_VALUE, bytes, 4, 5);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(pageSize, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(pageSize, bytes, 6, 44);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(pageSize - bytes.length + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(pageSize - 5, bytes, 3, 6);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MAX_VALUE, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MAX_VALUE, bytes, 10, 20);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MAX_VALUE - bytes.length + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(Integer.MAX_VALUE - 11, bytes, 11, 11);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(3 * (pageSize / 4) + 1, bytes);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(3 * (pageSize / 4) + 2, bytes, 0, bytes.length - 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(7 * (pageSize / 8) + 1, bytes, 0, bytes.length / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// wrong source array positions / lengths
try {
segment.get(0, bytes, -1, 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(0, bytes, -1, bytes.length + 1);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(0, bytes, Integer.MIN_VALUE, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(0, bytes, Integer.MAX_VALUE, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
segment.get(0, bytes, Integer.MAX_VALUE - bytes.length + 1, bytes.length);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
// case where negative offset and negative index compensate each other
try {
segment.get(-2, bytes, -1, bytes.length / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testBulkByteAccess() {
try {
// test expected correct behavior with default offset / length
{
final MemorySegment segment = createSegment(pageSize);
long seed = random.nextLong();
random.setSeed(seed);
byte[] src = new byte[pageSize / 8];
for (int i = 0; i < 8; i++) {
random.nextBytes(src);
segment.put(i * (pageSize / 8), src);
}
random.setSeed(seed);
byte[] expected = new byte[pageSize / 8];
byte[] actual = new byte[pageSize / 8];
for (int i = 0; i < 8; i++) {
random.nextBytes(expected);
segment.get(i * (pageSize / 8), actual);
assertArrayEquals(expected, actual);
}
}
// test expected correct behavior with specific offset / length
{
final MemorySegment segment = createSegment(pageSize);
byte[] expected = new byte[pageSize];
random.nextBytes(expected);
for (int i = 0; i < 16; i++) {
segment.put(i * (pageSize / 16), expected, i * (pageSize / 16),
pageSize / 16);
}
byte[] actual = new byte[pageSize];
for (int i = 0; i < 16; i++) {
segment.get(i * (pageSize / 16), actual, i * (pageSize / 16),
pageSize / 16);
}
assertArrayEquals(expected, actual);
}
// put segments of various lengths to various positions
{
final MemorySegment segment = createSegment(pageSize);
byte[] expected = new byte[pageSize];
for (int i = 0; i < 200; i++) {
int numBytes = random.nextInt(pageSize - 10) + 1;
int pos = random.nextInt(pageSize - numBytes + 1);
byte[] data = new byte[(random.nextInt(3) + 1) * numBytes];
int dataStartPos = random.nextInt(data.length - numBytes + 1);
random.nextBytes(data);
// copy to the expected
System.arraycopy(data, dataStartPos, expected, pos, numBytes);
// put to the memory segment
segment.put(pos, data, dataStartPos, numBytes);
}
byte[] validation = new byte[pageSize];
segment.get(0, validation);
assertArrayEquals(expected, validation);
}
// get segments with various contents
{
final MemorySegment segment = createSegment(pageSize);
byte[] contents = new byte[pageSize];
random.nextBytes(contents);
segment.put(0, contents);
for (int i = 0; i < 200; i++) {
int numBytes = random.nextInt(pageSize / 8) + 1;
int pos = random.nextInt(pageSize - numBytes + 1);
byte[] data = new byte[(random.nextInt(3) + 1) * numBytes];
int dataStartPos = random.nextInt(data.length - numBytes + 1);
segment.get(pos, data, dataStartPos, numBytes);
byte[] expected = Arrays.copyOfRange(contents, pos, pos + numBytes);
byte[] validation = Arrays.copyOfRange(data, dataStartPos, dataStartPos + numBytes);
assertArrayEquals(expected, validation);
}
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// Writing / Reading to/from DataInput / DataOutput
// ------------------------------------------------------------------------
@Test
public void testDataInputOutput() {
try {
MemorySegment seg = createSegment(pageSize);
byte[] contents = new byte[pageSize];
random.nextBytes(contents);
seg.put(0, contents);
ByteArrayOutputStream buffer = new ByteArrayOutputStream(pageSize);
DataOutputStream out = new DataOutputStream(buffer);
// write the segment in chunks into the stream
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(200);
len = Math.min(len, pageSize - pos);
seg.get(out, pos, len);
pos += len;
}
// verify that we wrote the same bytes
byte[] result = buffer.toByteArray();
assertArrayEquals(contents, result);
// re-read the bytes into a new memory segment
MemorySegment reader = createSegment(pageSize);
DataInputStream in = new DataInputStream(new ByteArrayInputStream(result));
pos = 0;
while (pos < pageSize) {
int len = random.nextInt(200);
len = Math.min(len, pageSize - pos);
reader.put(in, pos, len);
pos += len;
}
byte[] targetBuffer = new byte[pageSize];
reader.get(0, targetBuffer);
assertArrayEquals(contents, targetBuffer);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testDataInputOutputOutOfBounds() {
try {
final int segmentSize = 52;
// segment with random contents
MemorySegment seg = createSegment(segmentSize);
byte[] bytes = new byte[segmentSize];
random.nextBytes(bytes);
seg.put(0, bytes);
// out of bounds when writing
{
DataOutputStream out = new DataOutputStream(new ByteArrayOutputStream());
try {
seg.get(out, -1, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.get(out, segmentSize, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.get(out, -segmentSize, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.get(out, Integer.MIN_VALUE, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.get(out, Integer.MAX_VALUE, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
}
// out of bounds when reading
{
DataInputStream in = new DataInputStream(new ByteArrayInputStream(new byte[segmentSize]));
try {
seg.put(in, -1, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.put(in, segmentSize, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.put(in, -segmentSize, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.put(in, Integer.MIN_VALUE, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
try {
seg.put(in, Integer.MAX_VALUE, segmentSize / 2);
fail("IndexOutOfBoundsException expected");
}
catch (Exception e) {
assertTrue(e instanceof IndexOutOfBoundsException);
}
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testDataInputOutputStreamUnderflowOverflow() {
try {
final int segmentSize = 1337;
// segment with random contents
MemorySegment seg = createSegment(segmentSize);
byte[] bytes = new byte[segmentSize];
random.nextBytes(bytes);
seg.put(0, bytes);
// a stream that we cannot fully write to
DataOutputStream out = new DataOutputStream(new OutputStream() {
int bytesSoFar = 0;
@Override
public void write(int b) throws IOException {
bytesSoFar++;
if (bytesSoFar > segmentSize / 2) {
throw new IOException("overflow");
}
}
});
// write the segment in chunks into the stream
try {
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(segmentSize / 10);
len = Math.min(len, pageSize - pos);
seg.get(out, pos, len);
pos += len;
}
fail("Should fail with an IOException");
}
catch (IOException e) {
// expected
}
DataInputStream in = new DataInputStream(new ByteArrayInputStream(new byte[segmentSize / 2]));
try {
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(segmentSize / 10);
len = Math.min(len, pageSize - pos);
seg.put(in, pos, len);
pos += len;
}
fail("Should fail with an EOFException");
}
catch (EOFException e) {
// expected
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// ByteBuffer Ops
// ------------------------------------------------------------------------
@Test
public void testByteBufferGet() {
try {
testByteBufferGet(false);
testByteBufferGet(true);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
private void testByteBufferGet(boolean directBuffer) {
MemorySegment seg = createSegment(pageSize);
byte[] bytes = new byte[pageSize];
random.nextBytes(bytes);
seg.put(0, bytes);
ByteBuffer target = directBuffer ?
ByteBuffer.allocateDirect(3 * pageSize) :
ByteBuffer.allocate(3 * pageSize);
target.position(2 * pageSize);
// transfer the segment in chunks into the byte buffer
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(pageSize / 10);
len = Math.min(len, pageSize - pos);
seg.get(pos, target, len);
pos += len;
}
// verify that we wrote the same bytes
byte[] result = new byte[pageSize];
target.position(2 * pageSize);
target.get(result);
assertArrayEquals(bytes, result);
}
@Test
public void testByteBufferPut() {
try {
testByteBufferPut(false);
testByteBufferPut(true);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
private void testByteBufferPut(boolean directBuffer) {
byte[] bytes = new byte[pageSize];
random.nextBytes(bytes);
ByteBuffer source = directBuffer ?
ByteBuffer.allocateDirect(pageSize) :
ByteBuffer.allocate(pageSize);
source.put(bytes);
source.clear();
MemorySegment seg = createSegment(3 * pageSize);
int offset = 2 * pageSize;
// transfer the segment in chunks into the byte buffer
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(pageSize / 10);
len = Math.min(len, pageSize - pos);
seg.put(offset + pos, source, len);
pos += len;
}
// verify that we read the same bytes
byte[] result = new byte[pageSize];
seg.get(offset, result);
assertArrayEquals(bytes, result);
}
// ------------------------------------------------------------------------
// ByteBuffer Ops on sliced byte buffers
// ------------------------------------------------------------------------
@Test
public void testSlicedByteBufferGet() {
try {
testSlicedByteBufferGet(false);
testSlicedByteBufferGet(true);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
private void testSlicedByteBufferGet(boolean directBuffer) {
MemorySegment seg = createSegment(pageSize);
byte[] bytes = new byte[pageSize];
random.nextBytes(bytes);
seg.put(0, bytes);
ByteBuffer target = directBuffer ?
ByteBuffer.allocateDirect(pageSize + 49) :
ByteBuffer.allocate(pageSize + 49);
target.position(19).limit(19 + pageSize);
ByteBuffer slicedTarget = target.slice();
// transfer the segment in chunks into the byte buffer
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(pageSize / 10);
len = Math.min(len, pageSize - pos);
seg.get(pos, slicedTarget, len);
pos += len;
}
// verify that we wrote the same bytes
byte[] result = new byte[pageSize];
target.position(19);
target.get(result);
assertArrayEquals(bytes, result);
}
@Test
public void testSlicedByteBufferPut() {
try {
testSlicedByteBufferPut(false);
testSlicedByteBufferPut(true);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
private void testSlicedByteBufferPut(boolean directBuffer) {
byte[] bytes = new byte[pageSize + 49];
random.nextBytes(bytes);
ByteBuffer source = directBuffer ?
ByteBuffer.allocateDirect(pageSize + 49) :
ByteBuffer.allocate(pageSize + 49);
source.put(bytes);
source.position(19).limit(19 + pageSize);
ByteBuffer slicedSource = source.slice();
MemorySegment seg = createSegment(3 * pageSize);
final int offset = 2 * pageSize;
// transfer the segment in chunks into the byte buffer
int pos = 0;
while (pos < pageSize) {
int len = random.nextInt(pageSize / 10);
len = Math.min(len, pageSize - pos);
seg.put(offset + pos, slicedSource, len);
pos += len;
}
// verify that we read the same bytes
byte[] result = new byte[pageSize];
seg.get(offset, result);
byte[] expected = Arrays.copyOfRange(bytes, 19, 19 + pageSize);
assertArrayEquals(expected, result);
}
// ------------------------------------------------------------------------
// ByteBuffer overflow / underflow and out of bounds
// ------------------------------------------------------------------------
@Test
public void testByteBufferOutOfBounds() {
try {
final int bbCapacity = pageSize / 10;
final int[] validOffsets = { 0, 1, pageSize / 10 * 9 };
final int[] invalidOffsets = { -1, pageSize + 1, -pageSize, Integer.MAX_VALUE, Integer.MIN_VALUE };
final int[] validLengths = { 0, 1, bbCapacity, pageSize };
final int[] invalidLengths = { -1, -pageSize, Integer.MAX_VALUE, Integer.MIN_VALUE };
final MemorySegment seg = createSegment(pageSize);
for (ByteBuffer bb : new ByteBuffer[] {
ByteBuffer.allocate(bbCapacity),
ByteBuffer.allocateDirect(bbCapacity) } )
{
for (int off : validOffsets) {
for (int len : invalidLengths) {
try {
seg.put(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferUnderflowException ignored) {}
try {
seg.get(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferOverflowException ignored) {}
// position/limit may not have changed
assertEquals(0, bb.position());
assertEquals(bb.capacity(), bb.limit());
}
}
for (int off : invalidOffsets) {
for (int len : validLengths) {
try {
seg.put(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferUnderflowException ignored) {}
try {
seg.get(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferOverflowException ignored) {}
// position/limit may not have changed
assertEquals(0, bb.position());
assertEquals(bb.capacity(), bb.limit());
}
}
for (int off : validOffsets) {
for (int len : validLengths) {
if (off + len > pageSize) {
try {
seg.put(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferUnderflowException ignored) {}
try {
seg.get(off, bb, len);
fail("should fail with an IndexOutOfBoundsException");
}
catch (IndexOutOfBoundsException | BufferOverflowException ignored) {}
// position/limit may not have changed
assertEquals(0, bb.position());
assertEquals(bb.capacity(), bb.limit());
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testByteBufferOverflowUnderflow() {
try {
final int bbCapacity = pageSize / 10;
ByteBuffer bb = ByteBuffer.allocate(bbCapacity);
MemorySegment seg = createSegment(pageSize);
try {
seg.get(pageSize / 5, bb, pageSize / 10 + 2);
fail("should fail with an exception");
}
catch (BufferOverflowException ignored) {}
// position / limit should not have been modified
assertEquals(0, bb.position());
assertEquals(bb.capacity(), bb.limit());
try {
seg.put(pageSize / 5, bb, pageSize / 10 + 2);
fail("should fail with an exception");
}
catch (BufferUnderflowException ignored) {}
// position / limit should not have been modified
assertEquals(0, bb.position());
assertEquals(bb.capacity(), bb.limit());
int pos = bb.capacity() / 3;
int limit = 2 * bb.capacity() / 3;
bb.limit(limit);
bb.position(pos);
try {
seg.get(20, bb, bb.capacity() / 3 + 3);
fail("should fail with an exception");
}
catch (BufferOverflowException ignored) {}
// position / limit should not have been modified
assertEquals(pos, bb.position());
assertEquals(limit, bb.limit());
try {
seg.put(20, bb, bb.capacity() / 3 + 3);
fail("should fail with an exception");
}
catch (BufferUnderflowException ignored) {}
// position / limit should not have been modified
assertEquals(pos, bb.position());
assertEquals(limit, bb.limit());
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// Comparing and swapping
// ------------------------------------------------------------------------
@Test
public void testCompareBytes() {
try {
final byte[] bytes1 = new byte[pageSize];
final byte[] bytes2 = new byte[pageSize];
final int stride = pageSize / 255;
final int shift = 16666;
for (int i = 0; i < pageSize; i++) {
byte val = (byte) ((i / stride) & 0xff);
bytes1[i] = val;
if (i + shift < bytes2.length) {
bytes2[i + shift] = val;
}
}
MemorySegment seg1 = createSegment(pageSize);
MemorySegment seg2 = createSegment(pageSize);
seg1.put(0, bytes1);
seg2.put(0, bytes2);
for (int i = 0; i < 1000; i++) {
int pos1 = random.nextInt(bytes1.length);
int pos2 = random.nextInt(bytes2.length);
int len = Math.min(Math.min(bytes1.length - pos1, bytes2.length - pos2),
random.nextInt(pageSize / 50 ));
int cmp = seg1.compare(seg2, pos1, pos2, len);
if (pos1 < pos2 - shift) {
assertTrue(cmp <= 0);
}
else {
assertTrue(cmp >= 0);
}
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testSwapBytes() {
try {
final int HALF_SIZE = pageSize / 2;
final byte[] bytes1 = new byte[pageSize];
final byte[] bytes2 = new byte[HALF_SIZE];
Arrays.fill(bytes2, (byte) 1);
MemorySegment seg1 = createSegment(pageSize);
MemorySegment seg2 = createSegment(HALF_SIZE);
seg1.put(0, bytes1);
seg2.put(0, bytes2);
// wap the second half of the first segment with the second segment
int pos = 0;
while (pos < HALF_SIZE) {
int len = random.nextInt(pageSize / 40);
len = Math.min(len, HALF_SIZE - pos);
seg1.swapBytes(new byte[len], seg2, pos + HALF_SIZE, pos, len);
pos += len;
}
// the second segment should now be all zeros, the first segment should have one in its second half
for (int i = 0; i < HALF_SIZE; i++) {
assertEquals((byte) 0, seg1.get(i));
assertEquals((byte) 0, seg2.get(i));
assertEquals((byte) 1, seg1.get(i + HALF_SIZE));
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testCheckAgainstOverflowUnderflowOnRelease() {
try {
MemorySegment seg = createSegment(512);
seg.free();
// --- bytes (smallest type) ---
try {
seg.get(0);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
try {
seg.get(Integer.MAX_VALUE);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
try {
seg.get(Integer.MIN_VALUE);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
// --- longs (largest type) ---
try {
seg.getLong(0);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
try {
seg.getLong(Integer.MAX_VALUE);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
try {
seg.getLong(Integer.MIN_VALUE);
fail("Expecting an IllegalStateException");
}
catch (Exception e) {
assertTrue(e instanceof IllegalStateException || e instanceof NullPointerException);
}
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// Miscellaneous
// ------------------------------------------------------------------------
@Test
public void testByteBufferWrapping() {
try {
MemorySegment seg = createSegment(1024);
ByteBuffer buf1 = seg.wrap(13, 47);
assertEquals(13, buf1.position());
assertEquals(60, buf1.limit());
assertEquals(47, buf1.remaining());
ByteBuffer buf2 = seg.wrap(500, 267);
assertEquals(500, buf2.position());
assertEquals(767, buf2.limit());
assertEquals(267, buf2.remaining());
ByteBuffer buf3 = seg.wrap(0, 1024);
assertEquals(0, buf3.position());
assertEquals(1024, buf3.limit());
assertEquals(1024, buf3.remaining());
// verify that operations on the byte buffer are correctly reflected
// in the memory segment
buf3.order(ByteOrder.LITTLE_ENDIAN);
buf3.putInt(112, 651797651);
assertEquals(651797651, seg.getIntLittleEndian(112));
buf3.order(ByteOrder.BIG_ENDIAN);
buf3.putInt(187, 992288337);
assertEquals(992288337, seg.getIntBigEndian(187));
try {
seg.wrap(-1, 20);
fail("should throw an exception");
}
catch (IndexOutOfBoundsException | IllegalArgumentException ignored) {}
try {
seg.wrap(10, -20);
fail("should throw an exception");
}
catch (IndexOutOfBoundsException | IllegalArgumentException ignored) {}
try {
seg.wrap(10, 1024);
fail("should throw an exception");
}
catch (IndexOutOfBoundsException | IllegalArgumentException ignored) {}
// after freeing, no wrapping should be possible any more.
seg.free();
try {
seg.wrap(13, 47);
fail("should fail with an exception");
}
catch (IllegalStateException e) {
// expected
}
// existing wraps should stay valid after freeing
buf3.order(ByteOrder.LITTLE_ENDIAN);
buf3.putInt(112, 651797651);
assertEquals(651797651, buf3.getInt(112));
buf3.order(ByteOrder.BIG_ENDIAN);
buf3.putInt(187, 992288337);
assertEquals(992288337, buf3.getInt(187));
}
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
@Test
public void testOwner() {
try {
// a segment without an owner has a null owner
assertNull(createSegment(64).getOwner());
Object theOwner = new Object();
MemorySegment seg = createSegment(64, theOwner);
assertEquals(theOwner, seg.getOwner());
// freeing must release the owner, to prevent leaks that prevent class unloading!
seg.free();
assertNotNull(seg.getOwner());
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void testSizeAndFreeing() {
try {
// a segment without an owner has a null owner
final int SIZE = 651;
MemorySegment seg = createSegment(SIZE);
assertEquals(SIZE, seg.size());
assertFalse(seg.isFreed());
seg.free();
assertTrue(seg.isFreed());
assertEquals(SIZE, seg.size());
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
// ------------------------------------------------------------------------
// Parametrization to run with different segment sizes
// ------------------------------------------------------------------------
@Parameterized.Parameters(name = "segment-size = {0}")
public static Collection<Object[]> executionModes(){
return Arrays.asList(
new Object[] { 32*1024 },
new Object[] { 4*1024 },
new Object[] { 512*1024 } );
}
}