Search in sources :

Example 1 with EntryUnavailableException

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").$();
    });
}
Also used : RecordCursor(com.questdb.common.RecordCursor) RecordSourcePrinter(com.questdb.ql.RecordSourcePrinter) StringSink(com.questdb.std.str.StringSink) CountDownLatch(java.util.concurrent.CountDownLatch) EntryLockedException(com.questdb.cairo.pool.ex.EntryLockedException) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) PoolClosedException(com.questdb.cairo.pool.ex.PoolClosedException) CyclicBarrier(java.util.concurrent.CyclicBarrier) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Test(org.junit.Test)

Example 2 with EntryUnavailableException

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());
    });
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) CountDownLatch(java.util.concurrent.CountDownLatch) EntryLockedException(com.questdb.cairo.pool.ex.EntryLockedException) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) PoolClosedException(com.questdb.cairo.pool.ex.PoolClosedException) CyclicBarrier(java.util.concurrent.CyclicBarrier) Test(org.junit.Test)

Example 3 with EntryUnavailableException

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());
        }
    });
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) CountDownLatch(java.util.concurrent.CountDownLatch) EntryLockedException(com.questdb.cairo.pool.ex.EntryLockedException) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) PoolClosedException(com.questdb.cairo.pool.ex.PoolClosedException) CyclicBarrier(java.util.concurrent.CyclicBarrier) Test(org.junit.Test)

Example 4 with EntryUnavailableException

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());
    });
}
Also used : RecordCursor(com.questdb.common.RecordCursor) RecordSourcePrinter(com.questdb.ql.RecordSourcePrinter) StringSink(com.questdb.std.str.StringSink) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) CountDownLatch(java.util.concurrent.CountDownLatch) EntryLockedException(com.questdb.cairo.pool.ex.EntryLockedException) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) PoolClosedException(com.questdb.cairo.pool.ex.PoolClosedException) CyclicBarrier(java.util.concurrent.CyclicBarrier) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Test(org.junit.Test)

Example 5 with EntryUnavailableException

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());
    });
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) CountDownLatch(java.util.concurrent.CountDownLatch) EntryLockedException(com.questdb.cairo.pool.ex.EntryLockedException) EntryUnavailableException(com.questdb.cairo.pool.ex.EntryUnavailableException) PoolClosedException(com.questdb.cairo.pool.ex.PoolClosedException) CyclicBarrier(java.util.concurrent.CyclicBarrier) Test(org.junit.Test)

Aggregations

EntryLockedException (com.questdb.cairo.pool.ex.EntryLockedException)7 EntryUnavailableException (com.questdb.cairo.pool.ex.EntryUnavailableException)7 CountDownLatch (java.util.concurrent.CountDownLatch)7 Test (org.junit.Test)7 PoolClosedException (com.questdb.cairo.pool.ex.PoolClosedException)6 CyclicBarrier (java.util.concurrent.CyclicBarrier)6 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)6 RecordCursor (com.questdb.common.RecordCursor)2 RecordSourcePrinter (com.questdb.ql.RecordSourcePrinter)2 StringSink (com.questdb.std.str.StringSink)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1