use of com.questdb.cairo.pool.ex.EntryUnavailableException in project questdb by bluestreak01.
the class ReaderPoolTest method testLockBusyReader.
@Test
public void testLockBusyReader() throws Exception {
final int readerCount = 5;
int threadCount = 2;
final int iterations = 10000;
Rnd dataRnd = new Rnd();
StringSink sink = new StringSink();
RecordSourcePrinter printer = new RecordSourcePrinter(sink);
final String[] names = new String[readerCount];
final String[] expectedRows = new String[readerCount];
for (int i = 0; i < readerCount; i++) {
names[i] = "x" + i;
try (TableModel model = new TableModel(configuration, names[i], PartitionBy.NONE).col("ts", ColumnType.DATE)) {
CairoTestUtils.create(model);
}
try (TableWriter w = new TableWriter(configuration, names[i])) {
for (int k = 0; k < 10; k++) {
TableWriter.Row r = w.newRow(0);
r.putDate(0, dataRnd.nextLong());
r.append();
}
w.commit();
}
sink.clear();
try (TableReader r = new TableReader(configuration, names[i])) {
printer.print(r.getCursor(), true, r.getMetadata());
}
expectedRows[i] = sink.toString();
}
LOG.info().$("testLockBusyReader BEGIN").$();
assertWithPool(pool -> {
final CyclicBarrier barrier = new CyclicBarrier(threadCount);
final CountDownLatch halt = new CountDownLatch(threadCount);
final AtomicInteger errors = new AtomicInteger();
final LongList lockTimes = new LongList();
final LongList workerTimes = new LongList();
new Thread(() -> {
Rnd rnd = new Rnd();
try {
barrier.await();
String name;
for (int i = 0; i < iterations; i++) {
name = names[rnd.nextPositiveInt() % readerCount];
while (true) {
if (pool.lock(name)) {
lockTimes.add(System.currentTimeMillis());
LockSupport.parkNanos(10L);
pool.unlock(name);
break;
}
}
}
} catch (Exception e) {
errors.incrementAndGet();
e.printStackTrace();
} finally {
halt.countDown();
}
}).start();
new Thread(() -> {
Rnd rnd = new Rnd();
try {
workerTimes.add(System.currentTimeMillis());
for (int i = 0; i < iterations; i++) {
int index = rnd.nextPositiveInt() % readerCount;
String name = names[index];
try (TableReader r = pool.get(name)) {
RecordCursor cursor = r.getCursor();
sink.clear();
printer.print(cursor, true, r.getMetadata());
TestUtils.assertEquals(expectedRows[index], sink);
if (name.equals(names[readerCount - 1]) && barrier.getNumberWaiting() > 0) {
barrier.await();
}
LockSupport.parkNanos(10L);
} catch (EntryLockedException | EntryUnavailableException ignored) {
} catch (Exception e) {
errors.incrementAndGet();
e.printStackTrace();
break;
}
}
workerTimes.add(System.currentTimeMillis());
} finally {
halt.countDown();
}
}).start();
halt.await();
Assert.assertEquals(0, halt.getCount());
Assert.assertEquals(0, errors.get());
// check that there are lock times between worker times
int count = 0;
// ensure that we have worker times
Assert.assertEquals(2, workerTimes.size());
long lo = workerTimes.get(0);
long hi = workerTimes.get(1);
Assert.assertTrue(lockTimes.size() > 0);
for (int i = 0, n = lockTimes.size(); i < n; i++) {
long t = lockTimes.getQuick(i);
if (t > lo && t < hi) {
count++;
}
}
Assert.assertTrue(count > 0);
LOG.info().$("testLockBusyReader END").$();
});
}
use of com.questdb.cairo.pool.ex.EntryUnavailableException in project questdb by bluestreak01.
the class ReaderPoolTest method testAllocateAndClear.
@Test
public void testAllocateAndClear() throws Exception {
assertWithPool(pool -> {
int n = 2;
final CyclicBarrier barrier = new CyclicBarrier(n);
final CountDownLatch halt = new CountDownLatch(n);
final AtomicInteger errors = new AtomicInteger();
final AtomicInteger readerCount = new AtomicInteger();
new Thread(() -> {
try {
for (int i = 0; i < 1000; i++) {
try (TableReader ignored = pool.get("u")) {
readerCount.incrementAndGet();
} catch (EntryUnavailableException ignored) {
}
if (i == 1) {
barrier.await();
}
LockSupport.parkNanos(10L);
}
} catch (Exception e) {
e.printStackTrace();
errors.incrementAndGet();
} finally {
halt.countDown();
}
}).start();
new Thread(() -> {
try {
barrier.await();
for (int i = 0; i < 1000; i++) {
pool.releaseInactive();
LockSupport.parkNanos(10L);
}
} catch (Exception e) {
e.printStackTrace();
errors.incrementAndGet();
} finally {
halt.countDown();
}
}).start();
halt.await();
Assert.assertTrue(readerCount.get() > 0);
Assert.assertEquals(0, errors.get());
});
}
use of com.questdb.cairo.pool.ex.EntryUnavailableException in project questdb by bluestreak01.
the class WriterPoolTest method testTwoThreadsRaceToAllocate.
@Test
public void testTwoThreadsRaceToAllocate() throws Exception {
assertWithPool(pool -> {
for (int k = 0; k < 1000; k++) {
int n = 2;
final CyclicBarrier barrier = new CyclicBarrier(n);
final CountDownLatch halt = new CountDownLatch(n);
final AtomicInteger errors = new AtomicInteger();
final AtomicInteger writerCount = new AtomicInteger();
for (int i = 0; i < n; i++) {
new Thread(() -> {
try {
barrier.await();
try (TableWriter w = pool.get("z")) {
writerCount.incrementAndGet();
populate(w);
} catch (EntryUnavailableException ignored) {
}
} catch (Exception e) {
e.printStackTrace();
errors.incrementAndGet();
} finally {
halt.countDown();
}
}).start();
}
halt.await();
// this check is unreliable on slow build servers
// it is very often the case that there are limited number of cores
// available and threads execute sequentially rather than
// simultaneously. We should check that none of the threads
// receive error.
Assert.assertTrue(writerCount.get() > 0);
Assert.assertEquals(0, errors.get());
Assert.assertEquals(1, pool.countFreeWriters());
}
});
}
use of com.questdb.cairo.pool.ex.EntryUnavailableException in project questdb by bluestreak01.
the class ReaderPoolTest method testConcurrentRead.
@Test
public void testConcurrentRead() throws Exception {
final int readerCount = 5;
int threadCount = 2;
final int iterations = 1000000;
Rnd dataRnd = new Rnd();
final String[] names = new String[readerCount];
final String[] expectedRows = new String[readerCount];
final CharSequenceObjHashMap<String> expectedRowMap = new CharSequenceObjHashMap<>();
for (int i = 0; i < readerCount; i++) {
names[i] = "x" + i;
try (TableModel model = new TableModel(configuration, names[i], PartitionBy.NONE).col("ts", ColumnType.DATE)) {
CairoTestUtils.create(model);
}
try (TableWriter w = new TableWriter(configuration, names[i])) {
for (int k = 0; k < 10; k++) {
TableWriter.Row r = w.newRow(0);
r.putDate(0, dataRnd.nextLong());
r.append();
}
w.commit();
}
sink.clear();
try (TableReader r = new TableReader(configuration, names[i])) {
printer.print(r.getCursor(), true, r.getMetadata());
}
expectedRows[i] = sink.toString();
expectedRowMap.put(names[i], expectedRows[i]);
}
assertWithPool((ReaderPool pool) -> {
final CyclicBarrier barrier = new CyclicBarrier(threadCount);
final CountDownLatch halt = new CountDownLatch(threadCount);
final AtomicInteger errors = new AtomicInteger();
for (int k = 0; k < threadCount; k++) {
new Thread(new Runnable() {
final ObjHashSet<TableReader> readers = new ObjHashSet<>();
final StringSink sink = new StringSink();
final RecordSourcePrinter printer = new RecordSourcePrinter(sink);
@Override
public void run() {
Rnd rnd = new Rnd();
try {
barrier.await();
String name;
// 3. it will close of of readers if has opened
for (int i = 0; i < iterations; i++) {
if (readers.size() == 0 || (readers.size() < 40 && rnd.nextPositiveInt() % 4 == 0)) {
name = names[rnd.nextPositiveInt() % readerCount];
try {
Assert.assertTrue(readers.add(pool.get(name)));
} catch (EntryUnavailableException ignore) {
}
}
Thread.yield();
if (readers.size() == 0) {
continue;
}
int index = rnd.nextPositiveInt() % readers.size();
TableReader reader = readers.get(index);
Assert.assertTrue(reader.isOpen());
// read rows
RecordCursor cursor = reader.getCursor();
sink.clear();
printer.print(cursor, true, reader.getMetadata());
TestUtils.assertEquals(expectedRowMap.get(reader.getTableName()), sink);
Thread.yield();
if (readers.size() > 0 && rnd.nextPositiveInt() % 4 == 0) {
TableReader r2 = readers.get(rnd.nextPositiveInt() % readers.size());
Assert.assertTrue(r2.isOpen());
r2.close();
Assert.assertTrue(readers.remove(r2));
}
Thread.yield();
}
} catch (Exception e) {
errors.incrementAndGet();
e.printStackTrace();
} finally {
for (int i = 0; i < readers.size(); i++) {
readers.get(i).close();
}
halt.countDown();
}
}
}).start();
}
halt.await();
Assert.assertEquals(0, halt.getCount());
Assert.assertEquals(0, errors.get());
});
}
use of com.questdb.cairo.pool.ex.EntryUnavailableException in project questdb by bluestreak01.
the class WriterPoolTest method testAllocateAndClear.
@Test
public void testAllocateAndClear() throws Exception {
assertWithPool(pool -> {
int n = 2;
final CyclicBarrier barrier = new CyclicBarrier(n);
final CountDownLatch halt = new CountDownLatch(n);
final AtomicInteger errors1 = new AtomicInteger();
final AtomicInteger errors2 = new AtomicInteger();
final AtomicInteger writerCount = new AtomicInteger();
new Thread(() -> {
try {
for (int i = 0; i < 10000; i++) {
try (TableWriter ignored = pool.get("z")) {
writerCount.incrementAndGet();
} catch (EntryUnavailableException ignored) {
}
if (i == 1) {
barrier.await();
} else {
LockSupport.parkNanos(1L);
}
}
} catch (Exception e) {
e.printStackTrace();
errors1.incrementAndGet();
} finally {
halt.countDown();
}
}).start();
new Thread(() -> {
try {
barrier.await();
for (int i = 0; i < 10000; i++) {
pool.releaseInactive();
LockSupport.parkNanos(1L);
}
} catch (Exception e) {
e.printStackTrace();
errors2.incrementAndGet();
} finally {
halt.countDown();
}
}).start();
halt.await();
Assert.assertTrue(writerCount.get() > 0);
Assert.assertEquals(0, errors1.get());
Assert.assertEquals(0, errors2.get());
});
}
Aggregations