/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import junit.framework.TestCase;
import org.voltdb.utils.DBBPool.BBContainer;
public class DBBPoolTest extends TestCase {
final int NUM_BUFFERS = 10;
final int INITIAL_ALLOCATION = 8096;
@Override
public void setUp() {
}
public void testDefaultPoolCtor() {
DBBPool p1 = new DBBPool();
assertEquals(0, p1.bytesLoanedLocally());
BBContainer containers1[] = p1.acquire( NUM_BUFFERS, INITIAL_ALLOCATION);
assertTrue((NUM_BUFFERS * INITIAL_ALLOCATION) <= p1.bytesAllocatedGlobally());
for (BBContainer c : containers1) {
c.discard();
}
// verify that globalbytes is really all pools
DBBPool p2 = new DBBPool();
BBContainer containers2[] = p2.acquire( 33, INITIAL_ALLOCATION);
assertTrue(p1.bytesAllocatedGlobally() >=
(p1.bytesAllocatedLocally() + p2.bytesAllocatedLocally()));
for (BBContainer c : containers2) {
c.discard();
}
// discard the buffer and see that the pool has no bytes loaned.
assertEquals(0, p1.bytesLoanedLocally());
assertEquals(0, p2.bytesLoanedLocally());
p1.clear();
p2.clear();
}
public void testGrowingPool() {
int bufsize = 8096;
int bufsize2 = 80480;
DBBPool p1 = new DBBPool();
assertEquals(0, p1.bytesLoanedLocally());
// test that pool will grow if necessary
ArrayList<DBBPool.BBContainer> list = new ArrayList<DBBPool.BBContainer>();
for (int i=1; i<= 500; ++i) {
p1.acquire(bufsize2).discard();
}
for (int i=1; i<= 500; ++i) {
list.add(p1.acquire(bufsize));
assertTrue(bufsize*i <= p1.bytesLoanedLocally());
}
// and give them all back
for (DBBPool.BBContainer c : list) {
assertTrue(bufsize <= c.b.capacity());
long loaned = p1.bytesLoanedLocally();
c.discard();
c = null;
// see if bufsize bytes are no longer on loan.
assertTrue(loaned >= p1.bytesLoanedLocally() + bufsize);
}
// pool by design should shrink from that max size of 100MB.
//assertTrue(100*bufsize > p1.bytesAllocatedLocally());// Only give a warning now
assertEquals(0, p1.bytesLoanedLocally());
p1.clear();
}
public void testInputStreamReadWrite() {
DBBPool p1 = new DBBPool();
BBInputStream is = new BBInputStream();
byte val = 0;
// fill buffers with incrementing byte values, wrapping
// when byte reaches 255.
for (int i=0; i<100; ++i) {
DBBPool.BBContainer p1c = p1.acquire(4096);
for (int j=0; j < 50; ++j) {
p1c.b.put(val);
if (val == 255) {
val = 0;
} else {
val++;
}
}
p1c.b.flip();
is.offer(p1c);
}
// and read back the inputstream content, verifying the data.
try {
val = 0;
for (int i=0; i<100; i++) {
for (int j=0; j < 50; ++j) {
assertEquals(val, is.read());
if (val == 255) {
val = 0;
} else {
val++;
}
}
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
p1.clear();
}
public void testInputStreamReadByteArray() {
DBBPool p1 = new DBBPool();
BBInputStream is = new BBInputStream();
int numbufs = 5;
// fill buffers with incrementing byte values, wrapping
// when byte reaches 255.
byte val = 0;
for (int i=0; i < numbufs; ++i) {
DBBPool.BBContainer p1c = p1.acquire(8096);
for (int j=0; j < 50; ++j) {
p1c.b.put(val);
if (val == 255) {
val = 0;
} else {
val++;
}
}
p1c.b.flip();
is.offer(p1c);
}
// read the full contents with the same wrapping logic as above
byte content[] = new byte[50*numbufs];
try {
int bytes_read = is.read(content, 0, 50*numbufs);
assertEquals(50*numbufs, bytes_read);
} catch (Throwable e) {
throw new RuntimeException(e);
}
val = 0;
for (int j=0; j < 50*numbufs; ++j) {
Byte b1 = new Byte(val);
Byte b2 = new Byte(content[j]);
assertEquals(0, b1.compareTo(b2));
if (val == 255) {
val = 0;
} else {
val++;
}
}
// is.close();
p1.clear();
}
public void testCorrectArenaAllocation() {
DBBPool p = new DBBPool();
int allocationSize = 1;
DBBPool.BBContainer c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(16, c.b.capacity());
c.discard();
allocationSize = 2;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(16, c.b.capacity());
c.discard();
allocationSize = 4;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(16, c.b.capacity());
c.discard();
allocationSize = 8;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(16, c.b.capacity());
c.discard();
allocationSize = 16;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 32;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 64;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 128;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 256;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 512;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 1024;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 2048;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 4096;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 8192;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 16384;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 32768;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 65536;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 131072;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 262144;
c = p.acquire(allocationSize);
assertTrue(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
allocationSize = 262145;
c = p.acquire(allocationSize);
assertFalse(c.b.isDirect());
assertEquals(allocationSize, c.b.capacity());
c.discard();
}
public void testInputStreamAvailable() {
// fill up an array with random data and read it in chunks,
// checking that the stream reports valid available(). and
// that the data returned is valid.
int avail = 4096;
int bytes_read = 0;
byte content[] = new byte[avail];
byte read[] = new byte[avail];
DBBPool p = new DBBPool();
DBBPool.BBContainer pc = p.acquire(avail);
Random random = new Random(0);
random.nextBytes(content);
pc.b.put(content);
pc.b.flip();
BBInputStream is = new BBInputStream();
is.offer(pc);
is.EOF();
try {
// verify initial available() size.
System.out.println("available: " + is.available());
assertEquals(avail, is.available());
// read 200 byte chunks and verify
avail -= 200;
bytes_read = is.read(read, 0, 200);
assertEquals(200, bytes_read);
assertEquals(avail, is.available());
for (int i=0; i < 200; i++) {
assertEquals(content[i], read[i]);
}
// read 200 byte chunks and verify data.
avail -= 200;
bytes_read = is.read(read, 0, 200);
assertEquals(200, bytes_read);
assertEquals(avail, is.available());
for (int i=0; i < 200; i++) {
assertEquals(content[i+200], read[i]);
}
// read 200 byte chunks and verify data.
avail -= 200;
bytes_read = is.read(read, 0, 200);
assertEquals(200, bytes_read);
assertEquals(avail, is.available());
for (int i=0; i < 200; i++) {
assertEquals(content[i+400], read[i]);
}
// read exactly the rest of the data and verify
bytes_read = is.read(read, 0, avail);
assertEquals(avail, bytes_read);
assertEquals(0, is.available());
for (int i=0; i < avail; i++) {
assertEquals(content[i+600], read[i]);
}
// one more read should get eof
bytes_read = is.read(read, 0, 200);
assertEquals(-1, bytes_read);
assertEquals(0, is.available());
}
catch (IOException e) {
fail(e.getMessage());
}
p.clear();
}
public void testInputStreamLastRead() {
// fill up an array with random data and read it in two large
// chunks, asking for more than is available in the second
// read.
int avail = 4096;
int bytes_read = 0;
byte content[] = new byte[avail];
byte read[] = new byte[avail];
DBBPool p = new DBBPool();
DBBPool.BBContainer pc = p.acquire(avail);
Random random = new Random(0);
random.nextBytes(content);
pc.b.put(content);
pc.b.flip();
BBInputStream is = new BBInputStream();
is.offer(pc);
is.EOF();
try {
// read most of the data.
bytes_read = is.read(read, 0, 4000);
assertEquals(4000, bytes_read);
assertEquals(96, is.available());
for (int i=0; i < 4000; i++) {
assertEquals(content[i], read[i]);
}
// read the rest, requesting > avail.
bytes_read = is.read(read, 0, 4000);
assertEquals(96, bytes_read);
assertEquals(0, is.available());
for (int i=0; i < 96; i++) {
assertEquals(content[i+4000],read[i]);
}
// one more read should get eof
bytes_read = is.read(read, 0, 200);
assertEquals(-1, bytes_read);
assertEquals(0, is.available());
}
catch (IOException e) {
fail(e.getMessage());
}
p.clear();
}
public void testMultiBufferRead() {
// offer 2 4k buffers from a stream and read them
// back with a single 8k read.
int avail = 4096;
int bytes_read = 0;
byte content1[] = new byte[avail];
byte content2[] = new byte[avail];
byte read[] = new byte[avail*2];
BBInputStream is = new BBInputStream();
DBBPool p = new DBBPool();
DBBPool.BBContainer pc = p.acquire(avail);
Random random = new Random(0);
random.nextBytes(content1);
pc.b.put(content1);
pc.b.flip();
is.offer(pc);
pc = p.acquire(avail);
random.nextBytes(content2);
pc.b.put(content2);
pc.b.flip();
is.offer(pc);
is.EOF();
try {
assertEquals(avail*2, is.available());
bytes_read = is.read(read, 0, avail*2);
assertEquals(avail*2, bytes_read);
assertEquals(0, is.available());
for (int i=0; i < avail; i++) {
assertEquals(content1[i], read[i]);
}
for (int i=0; i < avail; i++) {
assertEquals(content2[i], read[avail+i]);
}
}
catch (IOException e) {
fail (e.getMessage());
}
p.clear();
}
}