/* * Copyright 2018, Oath Inc * Licensed under the terms of the Apache License 2.0. Please refer to accompanying LICENSE file for terms. */ package com.oath.halodb; import com.google.common.primitives.Longs; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; import java.util.Random; public class MemoryPoolChunkTest { private MemoryPoolChunk chunk = null; @AfterMethod(alwaysRun = true) private void destroyChunk() { if (chunk != null) { chunk.destroy(); } } @Test public void testSetAndGetMethods() { int chunkSize = 16 * 1024; int fixedKeyLength = 12, fixedValueLength = 20; int slotSize = MemoryPoolHashEntries.HEADER_SIZE + fixedKeyLength + fixedValueLength; chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); int offset = chunk.getWriteOffset(); Assert.assertEquals(chunk.remaining(), chunkSize); Assert.assertEquals(chunk.getWriteOffset(), 0); // write to an empty slot. byte[] key = Longs.toByteArray(101); byte[] value = HashTableTestUtils.randomBytes(fixedValueLength); MemoryPoolAddress nextAddress = new MemoryPoolAddress((byte) 10, 34343); chunk.fillNextSlot(key, value, nextAddress); Assert.assertEquals(chunk.getWriteOffset(), offset + slotSize); Assert.assertEquals(chunk.remaining(), chunkSize-slotSize); Assert.assertTrue(chunk.compareKey(offset, key)); Assert.assertTrue(chunk.compareValue(offset, value)); MemoryPoolAddress actual = chunk.getNextAddress(offset); Assert.assertEquals(actual.chunkIndex, nextAddress.chunkIndex); Assert.assertEquals(actual.chunkOffset, nextAddress.chunkOffset); // write to the next empty slot. byte[] key2 = HashTableTestUtils.randomBytes(fixedKeyLength); byte[] value2 = HashTableTestUtils.randomBytes(fixedValueLength); MemoryPoolAddress nextAddress2 = new MemoryPoolAddress((byte) 0, 4454545); chunk.fillNextSlot(key2, value2, nextAddress2); Assert.assertEquals(chunk.getWriteOffset(), offset + 2*slotSize); Assert.assertEquals(chunk.remaining(), chunkSize-2*slotSize); offset += slotSize; Assert.assertTrue(chunk.compareKey(offset, key2)); Assert.assertTrue(chunk.compareValue(offset, value2)); actual = chunk.getNextAddress(offset); Assert.assertEquals(actual.chunkIndex, nextAddress2.chunkIndex); Assert.assertEquals(actual.chunkOffset, nextAddress2.chunkOffset); // update an existing slot. byte[] key3 = Longs.toByteArray(0x64735981289L); byte[] value3 = HashTableTestUtils.randomBytes(fixedValueLength); MemoryPoolAddress nextAddress3 = new MemoryPoolAddress((byte)-1, -1); chunk.fillSlot(0, key3, value3, nextAddress3); offset = 0; Assert.assertTrue(chunk.compareKey(offset, key3)); Assert.assertTrue(chunk.compareValue(offset, value3)); // write offset should remain unchanged. Assert.assertEquals(chunk.getWriteOffset(), offset + 2*slotSize); Assert.assertEquals(chunk.remaining(), chunkSize-2*slotSize); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Invalid offset.*") public void testWithInvalidOffset() { int chunkSize = 256; int fixedKeyLength = 100, fixedValueLength = 100; MemoryPoolAddress next = new MemoryPoolAddress((byte)-1, -1); chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); chunk.fillSlot(chunkSize - 5, HashTableTestUtils.randomBytes(fixedKeyLength), HashTableTestUtils.randomBytes(fixedValueLength), next); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Invalid request. Key length.*") public void testWithInvalidKey() { int chunkSize = 256; int fixedKeyLength = 32, fixedValueLength = 100; MemoryPoolAddress next = new MemoryPoolAddress((byte)-1, -1); chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); chunk.fillSlot(chunkSize - 5, HashTableTestUtils.randomBytes(fixedKeyLength + 10), HashTableTestUtils.randomBytes(fixedValueLength), next); } @Test public void testCompare() { int chunkSize = 1024; int fixedKeyLength = 9, fixedValueLength = 15; chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); byte[] key = HashTableTestUtils.randomBytes(fixedKeyLength); byte[] value = HashTableTestUtils.randomBytes(fixedValueLength); int offset = 0; chunk.fillSlot(offset, key, value, new MemoryPoolAddress((byte)-1, -1)); Assert.assertTrue(chunk.compareKey(offset, key)); Assert.assertTrue(chunk.compareValue(offset, value)); byte[] smallKey = new byte[key.length-1]; System.arraycopy(key, 0, smallKey, 0, smallKey.length); Assert.assertFalse(chunk.compareKey(offset, smallKey)); key[fixedKeyLength-1] = (byte)~key[fixedKeyLength-1]; Assert.assertFalse(chunk.compareKey(offset, key)); value[0] = (byte)~value[0]; Assert.assertFalse(chunk.compareValue(offset, value)); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Invalid request.*") public void testCompareKeyWithException() { int chunkSize = 1024; Random r = new Random(); int fixedKeyLength = 1 + r.nextInt(100), fixedValueLength = 1 + r.nextInt(100); chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); byte[] key = HashTableTestUtils.randomBytes(fixedKeyLength); byte[] value = HashTableTestUtils.randomBytes(fixedValueLength); int offset = 0; chunk.fillSlot(offset, key, value, new MemoryPoolAddress((byte)-1, -1)); byte[] bigKey = HashTableTestUtils.randomBytes(fixedKeyLength + 1); chunk.compareKey(offset, bigKey); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Invalid request.*") public void testCompareValueWithException() { int chunkSize = 1024; Random r = new Random(); int fixedKeyLength = 1 + r.nextInt(100), fixedValueLength = 1 + r.nextInt(100); chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); byte[] key = HashTableTestUtils.randomBytes(fixedKeyLength); byte[] value = HashTableTestUtils.randomBytes(fixedValueLength); int offset = 0; chunk.fillSlot(offset, key, value, new MemoryPoolAddress((byte)-1, -1)); byte[] bigValue = HashTableTestUtils.randomBytes(fixedValueLength + 1); chunk.compareValue(offset, bigValue); } @Test public void setAndGetNextAddress() { int chunkSize = 1024; Random r = new Random(); int fixedKeyLength = 1 + r.nextInt(100), fixedValueLength = 1 + r.nextInt(100); chunk = MemoryPoolChunk.create(chunkSize, fixedKeyLength, fixedValueLength); MemoryPoolAddress nextAddress = new MemoryPoolAddress((byte)r.nextInt(Byte.MAX_VALUE), r.nextInt()); int offset = r.nextInt(chunkSize - fixedKeyLength - fixedValueLength - MemoryPoolHashEntries.HEADER_SIZE); chunk.setNextAddress(offset, nextAddress); Assert.assertEquals(chunk.getNextAddress(offset), nextAddress); } }