flink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From se...@apache.org
Subject [13/15] flink git commit: [FLINK-1320] [core] Add an off-heap variant of the managed memory
Date Tue, 08 Sep 2015 18:59:03 GMT
http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/EndiannessAccessChecks.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/EndiannessAccessChecks.java b/flink-core/src/test/java/org/apache/flink/core/memory/EndiannessAccessChecks.java
new file mode 100644
index 0000000..4c92234
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/EndiannessAccessChecks.java
@@ -0,0 +1,183 @@
+/*
+ * 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 java.nio.ByteBuffer;
+import java.util.Random;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class EndiannessAccessChecks {
+	
+	@Test
+	public void testHeapSegment() {
+		try {
+			testBigAndLittleEndianAccessUnaligned(new HeapMemorySegment(new byte[11111]));
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+
+	@Test
+	public void testHybridOnHeapSegment() {
+		try {
+			testBigAndLittleEndianAccessUnaligned(new HybridMemorySegment(new byte[11111]));
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+
+	@Test
+	public void testHybridOffHeapSegment() {
+		try {
+			testBigAndLittleEndianAccessUnaligned(new HybridMemorySegment(ByteBuffer.allocateDirect(11111)));
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+	
+	private void testBigAndLittleEndianAccessUnaligned(MemorySegment segment) {
+		final Random rnd = new Random();
+		
+		// longs
+		{
+			final long seed = rnd.nextLong();
+			
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				long val = rnd.nextLong();
+				int pos = rnd.nextInt(segment.size - 7);
+				
+				segment.putLongLittleEndian(pos, val);
+				long r = segment.getLongBigEndian(pos);
+				assertEquals(val, Long.reverseBytes(r));
+
+				segment.putLongBigEndian(pos, val);
+				r = segment.getLongLittleEndian(pos);
+				assertEquals(val, Long.reverseBytes(r));
+			}
+		}
+
+		// ints
+		{
+			final long seed = rnd.nextLong();
+
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				int val = rnd.nextInt();
+				int pos = rnd.nextInt(segment.size - 3);
+
+				segment.putIntLittleEndian(pos, val);
+				int r = segment.getIntBigEndian(pos);
+				assertEquals(val, Integer.reverseBytes(r));
+
+				segment.putIntBigEndian(pos, val);
+				r = segment.getIntLittleEndian(pos);
+				assertEquals(val, Integer.reverseBytes(r));
+			}
+		}
+
+		// shorts
+		{
+			final long seed = rnd.nextLong();
+
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				short val = (short) rnd.nextInt();
+				int pos = rnd.nextInt(segment.size - 1);
+
+				segment.putShortLittleEndian(pos, val);
+				short r = segment.getShortBigEndian(pos);
+				assertEquals(val, Short.reverseBytes(r));
+
+				segment.putShortBigEndian(pos, val);
+				r = segment.getShortLittleEndian(pos);
+				assertEquals(val, Short.reverseBytes(r));
+			}
+		}
+
+		// chars
+		{
+			final long seed = rnd.nextLong();
+
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				char val = (char) rnd.nextInt();
+				int pos = rnd.nextInt(segment.size - 1);
+
+				segment.putCharLittleEndian(pos, val);
+				char r = segment.getCharBigEndian(pos);
+				assertEquals(val, Character.reverseBytes(r));
+
+				segment.putCharBigEndian(pos, val);
+				r = segment.getCharLittleEndian(pos);
+				assertEquals(val, Character.reverseBytes(r));
+			}
+		}
+
+		// floats
+		{
+			final long seed = rnd.nextLong();
+
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				float val = rnd.nextFloat();
+				int pos = rnd.nextInt(segment.size - 3);
+
+				segment.putFloatLittleEndian(pos, val);
+				float r = segment.getFloatBigEndian(pos);
+				float reversed = Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(r)));
+				assertEquals(val, reversed, 0.0f);
+
+				segment.putFloatBigEndian(pos, val);
+				r = segment.getFloatLittleEndian(pos);
+				reversed = Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(r)));
+				assertEquals(val, reversed, 0.0f);
+			}
+		}
+
+		// doubles
+		{
+			final long seed = rnd.nextLong();
+
+			rnd.setSeed(seed);
+			for (int i = 0; i < 10000; i++) {
+				double val = rnd.nextDouble();
+				int pos = rnd.nextInt(segment.size - 7);
+
+				segment.putDoubleLittleEndian(pos, val);
+				double r = segment.getDoubleBigEndian(pos);
+				double reversed = Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(r)));
+				assertEquals(val, reversed, 0.0f);
+
+				segment.putDoubleBigEndian(pos, val);
+				r = segment.getDoubleLittleEndian(pos);
+				reversed = Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(r)));
+				assertEquals(val, reversed, 0.0f);
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/HeapMemorySegmentTest.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/HeapMemorySegmentTest.java b/flink-core/src/test/java/org/apache/flink/core/memory/HeapMemorySegmentTest.java
new file mode 100644
index 0000000..d7a5b03
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/HeapMemorySegmentTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.*;
+
+@RunWith(Parameterized.class)
+public class HeapMemorySegmentTest extends MemorySegmentTestBase {
+
+	public HeapMemorySegmentTest(int pageSize) {
+		super(pageSize);
+	}
+
+	@Override
+	MemorySegment createSegment(int size) {
+		return new HeapMemorySegment(new byte[size]);
+	}
+
+	@Override
+	MemorySegment createSegment(int size, Object owner) {
+		return new HeapMemorySegment(new byte[size], owner);
+	}
+	
+	@Test
+	public void testHeapSegmentSpecifics() {
+		try {
+			final byte[] buffer = new byte[411];
+			HeapMemorySegment seg = new HeapMemorySegment(buffer);
+			
+			assertFalse(seg.isFreed());
+			assertFalse(seg.isOffHeap());
+			assertEquals(buffer.length, seg.size());
+			assertTrue(buffer == seg.getArray());
+
+			ByteBuffer buf1 = seg.wrap(1, 2);
+			ByteBuffer buf2 = seg.wrap(3, 4);
+
+			assertTrue(buf1 != buf2);
+			assertEquals(1, buf1.position());
+			assertEquals(3, buf1.limit());
+			assertEquals(3, buf2.position());
+			assertEquals(7, buf2.limit());
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/HybridOffHeapMemorySegmentTest.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/HybridOffHeapMemorySegmentTest.java b/flink-core/src/test/java/org/apache/flink/core/memory/HybridOffHeapMemorySegmentTest.java
new file mode 100644
index 0000000..b09697e
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/HybridOffHeapMemorySegmentTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(Parameterized.class)
+public class HybridOffHeapMemorySegmentTest extends MemorySegmentTestBase {
+
+	public HybridOffHeapMemorySegmentTest(int pageSize) {
+		super(pageSize);
+	}
+
+	@Override
+	MemorySegment createSegment(int size) {
+		return new HybridMemorySegment(ByteBuffer.allocateDirect(size));
+	}
+
+	@Override
+	MemorySegment createSegment(int size, Object owner) {
+		return new HybridMemorySegment(ByteBuffer.allocateDirect(size), owner);
+	}
+
+	@Test
+	public void testHybridHeapSegmentSpecifics() {
+		try {
+			final ByteBuffer buffer = ByteBuffer.allocateDirect(411);
+			HybridMemorySegment seg = new HybridMemorySegment(buffer);
+
+			assertFalse(seg.isFreed());
+			assertTrue(seg.isOffHeap());
+			assertEquals(buffer.capacity(), seg.size());
+			assertTrue(buffer == seg.getOffHeapBuffer());
+
+			try {
+				seg.getArray();
+				fail("should throw an exception");
+			}
+			catch (IllegalStateException e) {
+				// expected
+			}
+
+			ByteBuffer buf1 = seg.wrap(1, 2);
+			ByteBuffer buf2 = seg.wrap(3, 4);
+
+			assertTrue(buf1 != buffer);
+			assertTrue(buf2 != buffer);
+			assertTrue(buf1 != buf2);
+			assertEquals(1, buf1.position());
+			assertEquals(3, buf1.limit());
+			assertEquals(3, buf2.position());
+			assertEquals(7, buf2.limit());
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/HybridOnHeapMemorySegmentTest.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/HybridOnHeapMemorySegmentTest.java b/flink-core/src/test/java/org/apache/flink/core/memory/HybridOnHeapMemorySegmentTest.java
new file mode 100644
index 0000000..55d333e
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/HybridOnHeapMemorySegmentTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(Parameterized.class)
+public class HybridOnHeapMemorySegmentTest extends MemorySegmentTestBase {
+
+	public HybridOnHeapMemorySegmentTest(int pageSize) {
+		super(pageSize);
+	}
+
+	@Override
+	MemorySegment createSegment(int size) {
+		return new HybridMemorySegment(new byte[size]);
+	}
+
+	@Override
+	MemorySegment createSegment(int size, Object owner) {
+		return new HybridMemorySegment(new byte[size], owner);
+	}
+	
+	@Test
+	public void testHybridHeapSegmentSpecifics() {
+		try {
+			final byte[] buffer = new byte[411];
+			HybridMemorySegment seg = new HybridMemorySegment(buffer);
+
+			assertFalse(seg.isFreed());
+			assertFalse(seg.isOffHeap());
+			assertEquals(buffer.length, seg.size());
+			assertTrue(buffer == seg.getArray());
+			
+			try {
+				seg.getOffHeapBuffer();
+				fail("should throw an exception");
+			}
+			catch (IllegalStateException e) {
+				// expected
+			}
+			
+			ByteBuffer buf1 = seg.wrap(1, 2);
+			ByteBuffer buf2 = seg.wrap(3, 4);
+			
+			assertTrue(buf1 != buf2);
+			assertEquals(1, buf1.position());
+			assertEquals(3, buf1.limit());
+			assertEquals(3, buf2.position());
+			assertEquals(7, buf2.limit());
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentChecksTest.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentChecksTest.java b/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentChecksTest.java
new file mode 100644
index 0000000..f50322c
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentChecksTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.Test;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.nio.ByteBuffer;
+
+/**
+ * Tests for the sanity checks of the memory segments.
+ */
+public class MemorySegmentChecksTest {
+	
+	@Test(expected = NullPointerException.class)
+	public void testHeapNullBuffer1() {
+		new HeapMemorySegment(null);
+	}
+
+	@Test(expected = NullPointerException.class)
+	public void testHeapNullBuffer2() {
+		new HeapMemorySegment(null, new Object());
+	}
+
+	@Test(expected = NullPointerException.class)
+	public void testHybridHeapNullBuffer1() {
+		new HybridMemorySegment((byte[]) null);
+	}
+
+	@Test(expected = NullPointerException.class)
+	public void testHybridHeapNullBuffer2() {
+		new HybridMemorySegment((byte[]) null, new Object());
+	}
+
+	@Test(expected = NullPointerException.class)
+	public void testHybridOffHeapNullBuffer1() {
+		new HybridMemorySegment((ByteBuffer) null);
+	}
+
+	@Test(expected = NullPointerException.class)
+	public void testHybridOffHeapNullBuffer2() {
+		new HybridMemorySegment((ByteBuffer) null, new Object());
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testHybridNonDirectBuffer() {
+		new HybridMemorySegment(ByteBuffer.allocate(1024));
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testZeroAddress(){
+		new MockSegment(0L, 4*1024, null);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testNegativeAddress(){
+		new MockSegment(-1L, 4*1024, null);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testTooLargeAddress(){
+		new MockSegment(Long.MAX_VALUE - 8*1024, 4*1024, null);
+	}
+	
+	// ------------------------------------------------------------------------
+	
+	final class MockSegment extends MemorySegment {
+
+		MockSegment(long offHeapAddress, int size, Object owner) {
+			super(offHeapAddress, size, owner);
+		}
+
+		@Override
+		public ByteBuffer wrap(int offset, int length) {
+			return null;
+		}
+
+		@Override
+		public byte get(int index) {
+			return 0;
+		}
+
+		@Override
+		public void put(int index, byte b) {}
+
+		@Override
+		public void get(int index, byte[] dst) {}
+
+		@Override
+		public void put(int index, byte[] src) {}
+
+		@Override
+		public void get(int index, byte[] dst, int offset, int length) {}
+
+		@Override
+		public void put(int index, byte[] src, int offset, int length) {}
+
+		@Override
+		public boolean getBoolean(int index) {
+			return false;
+		}
+
+		@Override
+		public void putBoolean(int index, boolean value) {}
+
+		@Override
+		public void get(DataOutput out, int offset, int length) {}
+
+		@Override
+		public void put(DataInput in, int offset, int length) {}
+
+		@Override
+		public void get(int offset, ByteBuffer target, int numBytes) {}
+
+		@Override
+		public void put(int offset, ByteBuffer source, int numBytes) {}
+	};
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/655a891d/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentTestBase.java
----------------------------------------------------------------------
diff --git a/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentTestBase.java b/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentTestBase.java
new file mode 100644
index 0000000..10c3622
--- /dev/null
+++ b/flink-core/src/test/java/org/apache/flink/core/memory/MemorySegmentTestBase.java
@@ -0,0 +1,2571 @@
+/*
+ * 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 } );
+	}
+}
\ No newline at end of file


Mime
View raw message