package org.rrd4j.core;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rrd4j.ConsolFun;
import org.rrd4j.DsType;
/**
* @author Fabrice Bacchella
*
*/
public class RrdDbPoolTest {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Test(timeout=500)
public void testCount() throws IOException, InterruptedException {
final RrdDbPool instance = new RrdDbPool();
instance.setCapacity(10);
RrdDef def = new RrdDef(new File(testFolder.getRoot().getCanonicalFile(), "test.rrd").getCanonicalPath());
def.addArchive(ConsolFun.AVERAGE, 0.5, 1, 215);
def.addDatasource("bar", DsType.GAUGE, 3000, Double.NaN, Double.NaN);
RrdDb db = instance.requestRrdDb(def);
for(int i=0; i < 9; i++ ) {
instance.requestRrdDb(db.getPath());
}
Assert.assertEquals(1, instance.getOpenFileCount());
for(int i=0; i < 10; i++ ) {
instance.release(db);
}
String[] files = instance.getOpenFiles();
Assert.assertArrayEquals("not all rrd released", new String[]{}, files);
}
@Test(timeout=500)
public void testPoolFull() throws IOException, InterruptedException {
final RrdDbPool instance = new RrdDbPool();
instance.setCapacity(10);
final Queue<RrdDb> dbs = new ConcurrentLinkedQueue<RrdDb>();
final AtomicInteger done = new AtomicInteger(0);
final AtomicInteger created = new AtomicInteger(0);
final CountDownLatch full = new CountDownLatch(10);
//A thread that will count all release db
Thread t = new Thread() {
@Override
public void run() {
try {
//Wait until pool was filled once
full.await();
while(created.get() < 12 || instance.getOpenFileCount() > 0) {
Assert.assertTrue("too much open files", instance.getOpenFileCount() <= 10);
if(dbs.size() > 0) {
RrdDb release = dbs.poll();
instance.release(release);
done.incrementAndGet();
}
Thread.yield();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
t.start();
final CountDownLatch barrier = new CountDownLatch(1);
for(int i=0; i < 12; i++) {
final int locali = i;
new Thread() {
@Override
public void run() {
try {
RrdDef def = new RrdDef(new File(testFolder.getRoot().getCanonicalFile(), "test" + locali + ".rrd").getCanonicalPath());
def.addArchive(ConsolFun.AVERAGE, 0.5, 1, 215);
def.addDatasource("bar", DsType.GAUGE, 3000, Double.NaN, Double.NaN);
//All thread are synchronized and will try to create a db at the same time
barrier.await();
RrdDb db = instance.requestRrdDb(def);
dbs.add(db);
created.incrementAndGet();
full.countDown();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}.start();
}
Thread.yield();
//launch all the sub-threads
barrier.countDown();
//Finished when pool is empty
t.join();
String[] files = instance.getOpenFiles();
Assert.assertArrayEquals("not all rrd released", new String[]{}, files);
Assert.assertEquals("finished, but not all db seen", 12, done.get());
}
@Test(timeout=500)
public void testMultiOpen() throws IOException, InterruptedException {
final RrdDbPool instance = new RrdDbPool();
instance.setCapacity(2);
final Queue<RrdDb> dbs = new ConcurrentLinkedQueue<RrdDb>();
final AtomicInteger done = new AtomicInteger(0);
final CountDownLatch full = new CountDownLatch(12);
Thread t = new Thread() {
@Override
public void run() {
try {
full.await();
while(instance.getOpenFileCount() > 0) {
Assert.assertTrue("too much open files", instance.getOpenFileCount() <= 1);
if(dbs.size() > 0) {
RrdDb release = dbs.poll();
instance.release(release);
done.incrementAndGet();
Thread.yield();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
RrdDef def = new RrdDef(new File(testFolder.getRoot().getCanonicalFile(), "test.rrd").getCanonicalPath());
def.addArchive(ConsolFun.AVERAGE, 0.5, 1, 215);
def.addDatasource("bar", DsType.GAUGE, 3000, Double.NaN, Double.NaN);
final RrdDb db = instance.requestRrdDb(def);
dbs.add(db);
final CountDownLatch barrier = new CountDownLatch(1);
for(int i=0; i < 12; i++) {
new Thread() {
@Override
public void run() {
try {
barrier.await();
RrdDb againdb = instance.requestRrdDb(db.getCanonicalPath());
dbs.add(againdb);
full.countDown();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}.start();
}
barrier.countDown();
full.await();
t.start();
t.join();
Assert.assertEquals("failure in sub thread", 13, done.get());
String[] files = instance.getOpenFiles();
Assert.assertArrayEquals("not all rrd released", new String[]{}, files);
}
@Test(timeout=500)
public void testWaitEmpty() throws IOException, InterruptedException {
final RrdDbPool instance = new RrdDbPool();
final RrdDef def = new RrdDef(new File(testFolder.getRoot().getCanonicalFile(), "test.rrd").getCanonicalPath());
def.addArchive(ConsolFun.AVERAGE, 0.5, 1, 215);
def.addDatasource("bar", DsType.GAUGE, 3000, Double.NaN, Double.NaN);
RrdDb db = instance.requestRrdDb(def);
final long start = new Date().getTime();
final AtomicInteger done = new AtomicInteger(0);
Thread t = new Thread() {
@Override
public void run() {
try {
RrdDb db = instance.requestRrdDb(def);
instance.release(db);
done.set(1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
t.start();
Thread.sleep(100);
instance.release(db);
t.join();
long end = new Date().getTime();
Assert.assertEquals("failure in sub thread", 1, done.get());
Assert.assertTrue("requestRrdDb didn't wait for available path", (end - start) > 100);
String[] files = instance.getOpenFiles();
Assert.assertArrayEquals(new String[]{}, files);
}
}