@Test public void testBufferCallbackUniqueBuffers() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); final int NUMBER_LINES = 1000; final int SIZE = 512; controller.open(fileName, 1000); controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); final ArrayList<ByteBuffer> buffers = new ArrayList<ByteBuffer>(); BufferCallback bufferCallback = new BufferCallback() { public void bufferDone(final ByteBuffer buffer) { buffers.add(buffer); } }; controller.setBufferCallback(bufferCallback); CountDownLatch latch = new CountDownLatch(NUMBER_LINES); ArrayList<Integer> result = new ArrayList<Integer>(); for (int i = 0; i < NUMBER_LINES; i++) { ByteBuffer buffer1 = AsynchronousFileImpl.newBuffer(SIZE); buffer1.rewind(); for (int j = 0; j < SIZE; j++) { buffer1.put((byte) (j % Byte.MAX_VALUE)); } CountDownCallback aio = new CountDownCallback(latch, null, result, i); controller.write(i * SIZE, SIZE, buffer1, aio); } // The buffer callback is only called after the complete callback was // called. // Because of that a race could happen on the assertions to // buffers.size what would invalidate the test // We close the file and that would guarantee the buffer callback was // called for all the elements controller.close(); CountDownCallback.checkResults(NUMBER_LINES, result); // Make sure all the buffers are unique ByteBuffer lineOne = null; for (ByteBuffer bufferTmp : buffers) { if (lineOne == null) { lineOne = bufferTmp; } else { Assert.assertTrue(lineOne != bufferTmp); } } for (ByteBuffer bufferTmp : buffers) { destroy(bufferTmp); } buffers.clear(); }
private void asyncData(final int numberOfLines, final int size, final int aioLimit) throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName, aioLimit); CountDownLatch latchDone = new CountDownLatch(numberOfLines); buffer = AsynchronousFileImpl.newBuffer(size); encodeBufer(buffer); preAlloc(controller, numberOfLines * size); ArrayList<CountDownCallback> list = new ArrayList<CountDownCallback>(); ArrayList<Integer> result = new ArrayList<Integer>(); for (int i = 0; i < numberOfLines; i++) { list.add(new CountDownCallback(latchDone, null, result, i)); } long valueInitial = System.currentTimeMillis(); long lastTime = System.currentTimeMillis(); int counter = 0; for (CountDownCallback tmp : list) { controller.write(counter * size, size, buffer, tmp); if (++counter % 20000 == 0) { AsynchronousFileTest.debug( 20000 * 1000 / (System.currentTimeMillis() - lastTime) + " rec/sec (Async)"); lastTime = System.currentTimeMillis(); } } UnitTestCase.waitForLatch(latchDone); long timeTotal = System.currentTimeMillis() - valueInitial; CountDownCallback.checkResults(numberOfLines, result); AsynchronousFileTest.debug( "After completions time = " + timeTotal + " for " + numberOfLines + " registers " + " size each line = " + size + ", Records/Sec=" + numberOfLines * 1000 / timeTotal + " (Assynchronous)"); for (CountDownCallback tmp : list) { Assert.assertEquals(1, tmp.timesDoneCalled.get()); Assert.assertTrue(tmp.doneCalled); Assert.assertEquals(0, tmp.errorCalled); } controller.close(); }
@Test public void testInvalidAlloc() throws Exception { try { @SuppressWarnings("unused") ByteBuffer buffer = AsynchronousFileImpl.newBuffer(300); Assert.fail("Exception expected"); } catch (Exception ignored) { } }
@Test public void testReleaseBuffers() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); WeakReference<ByteBuffer> bufferCheck = null; controller.open(fileName, 10000); bufferCheck = new WeakReference<ByteBuffer>(controller.getHandler()); controller.fill(0, 10, 1024, (byte) 0); ByteBuffer write = AsynchronousFileImpl.newBuffer(1024); for (int i = 0; i < 1024; i++) { write.put(UnitTestCase.getSamplebyte(i)); } final CountDownLatch latch = new CountDownLatch(1); controller.write( 0, 1024, write, new AIOCallback() { public void onError(final int errorCode, final String errorMessage) {} public void done() { latch.countDown(); } }); Assert.assertTrue(latch.await(10, TimeUnit.SECONDS)); WeakReference<ByteBuffer> bufferCheck2 = new WeakReference<ByteBuffer>(write); destroy(write); write = null; UnitTestCase.forceGC(bufferCheck2, 5000); Assert.assertNull(bufferCheck2.get()); controller.close(); controller = null; UnitTestCase.forceGC(bufferCheck, 5000); Assert.assertNull(bufferCheck.get()); }
@Test public void testDirectSynchronous() throws Exception { final int NUMBER_LINES = 3000; final int SIZE = 1024; controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName, 2000); buffer = AsynchronousFileImpl.newBuffer(SIZE); encodeBufer(buffer); preAlloc(controller, NUMBER_LINES * SIZE); long startTime = System.currentTimeMillis(); for (int i = 0; i < NUMBER_LINES; i++) { CountDownLatch latchDone = new CountDownLatch(1); CountDownCallback aioBlock = new CountDownCallback(latchDone, null, null, 0); controller.write(i * 512, 512, buffer, aioBlock); UnitTestCase.waitForLatch(latchDone); Assert.assertTrue(aioBlock.doneCalled); Assert.assertEquals(0, aioBlock.errorCalled); } long timeTotal = System.currentTimeMillis() - startTime; AsynchronousFileTest.debug( "time = " + timeTotal + " for " + NUMBER_LINES + " registers " + " size each line = " + SIZE + " Records/Sec=" + NUMBER_LINES * 1000 / timeTotal + " Synchronous"); controller.close(); }
@Test public void testInvalidWrite() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName, 2000); final int SIZE = 512; buffer = AsynchronousFileImpl.newBuffer(SIZE); encodeBufer(buffer); preAlloc(controller, 10 * 512); CountDownLatch latchDone = new CountDownLatch(1); CountDownCallback aioBlock = new CountDownCallback(latchDone, null, null, 0); controller.write(11, 512, buffer, aioBlock); UnitTestCase.waitForLatch(latchDone); Assert.assertTrue(aioBlock.errorCalled != 0); Assert.assertFalse(aioBlock.doneCalled); }
@Test public void testInternalWrite() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName, 2000); final int SIZE = 10 * 512; buffer = AsynchronousFileImpl.newBuffer(SIZE); for (int i = 0; i < SIZE; i++) { buffer.put(getSamplebyte(i)); } controller.writeInternal(0, SIZE, buffer); InputStream fileInput = new BufferedInputStream(new FileInputStream(new File(fileName))); for (int i = 0; i < SIZE; i++) { assertEquals(getSamplebyte(i), fileInput.read()); } assertEquals(-1, fileInput.read()); }
@Override public void run() { super.run(); ByteBuffer buffer = null; synchronized (MultiThreadAsynchronousFileTest.class) { buffer = AsynchronousFileImpl.newBuffer(MultiThreadAsynchronousFileTest.SIZE); } try { // I'm always reusing the same buffer, as I don't want any noise from // malloc on the measurement // Encoding buffer MultiThreadAsynchronousFileTest.addString( "Thread name=" + Thread.currentThread().getName() + ";" + "\n", buffer); for (int local = buffer.position(); local < buffer.capacity() - 1; local++) { buffer.put((byte) ' '); } buffer.put((byte) '\n'); latchStart.countDown(); latchStart.await(); CountDownLatch latchFinishThread = null; if (!sync) { latchFinishThread = new CountDownLatch(MultiThreadAsynchronousFileTest.NUMBER_OF_LINES); } LinkedList<CountDownCallback> list = new LinkedList<CountDownCallback>(); for (int i = 0; i < MultiThreadAsynchronousFileTest.NUMBER_OF_LINES; i++) { if (sync) { latchFinishThread = new CountDownLatch(1); } CountDownCallback callback = new CountDownCallback(latchFinishThread, null, null, 0); if (!sync) { list.add(callback); } addData(libaio, buffer, callback); if (sync) { latchFinishThread.await(); Assert.assertTrue(callback.doneCalled); Assert.assertFalse(callback.errorCalled != 0); } } if (!sync) { latchFinishThread.await(); } for (CountDownCallback callback : list) { Assert.assertTrue(callback.doneCalled); Assert.assertFalse(callback.errorCalled != 0); } for (CountDownCallback callback : list) { Assert.assertTrue(callback.doneCalled); Assert.assertFalse(callback.errorCalled != 0); } } catch (Throwable e) { e.printStackTrace(); failed = e; } finally { synchronized (MultiThreadAsynchronousFileTest.class) { AsynchronousFileImpl.destroyBuffer(buffer); } } }
/** * This test will call file.close() when there are still callbacks being processed. This could * cause a crash or callbacks missing and this test is validating both situations. The file is * also read after being written to validate its correctness */ @Test public void testConcurrentClose() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); final int NUMBER_LINES = 1000; CountDownLatch readLatch = new CountDownLatch(NUMBER_LINES); final int SIZE = 1024; controller.open(fileName, 10000); controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); controller.setBufferCallback(bufferCallbackDestroy); for (int i = 0; i < NUMBER_LINES; i++) { ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE); buffer.clear(); addString("Str value " + i + "\n", buffer); for (int j = buffer.position(); j < buffer.capacity() - 1; j++) { buffer.put((byte) ' '); } buffer.put((byte) '\n'); CountDownCallback aio = new CountDownCallback(readLatch, null, null, 0); controller.write(i * SIZE, SIZE, buffer, aio); } // If you call close you're supposed to wait events to finish before // closing it controller.close(); controller.setBufferCallback(null); Assert.assertEquals(0, readLatch.getCount()); waitForLatch(readLatch); controller.open(fileName, 10); ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(SIZE); ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE); for (int i = 0; i < NUMBER_LINES; i++) { newBuffer.clear(); addString("Str value " + i + "\n", newBuffer); for (int j = newBuffer.position(); j < newBuffer.capacity() - 1; j++) { newBuffer.put((byte) ' '); } newBuffer.put((byte) '\n'); CountDownLatch latch = new CountDownLatch(1); CountDownCallback aio = new CountDownCallback(latch, null, null, 0); controller.read(i * SIZE, SIZE, buffer, aio); waitForLatch(latch); Assert.assertEquals(0, aio.errorCalled); Assert.assertTrue(aio.doneCalled); byte bytesRead[] = new byte[SIZE]; byte bytesCompare[] = new byte[SIZE]; newBuffer.rewind(); newBuffer.get(bytesCompare); buffer.rewind(); buffer.get(bytesRead); for (int count = 0; count < SIZE; count++) { Assert.assertEquals( "byte position " + count + " differs on line " + i, bytesCompare[count], bytesRead[count]); } Assert.assertTrue(buffer.equals(newBuffer)); } destroy(newBuffer); }
@Test public void testRead() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.setBufferCallback(bufferCallbackDestroy); final int NUMBER_LINES = 1000; final int SIZE = 1024; controller.open(fileName, 1000); controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); { CountDownLatch latch = new CountDownLatch(NUMBER_LINES); ArrayList<Integer> result = new ArrayList<Integer>(); AtomicInteger errors = new AtomicInteger(0); for (int i = 0; i < NUMBER_LINES; i++) { if (i % 100 == 0) { System.out.println("Wrote " + i + " lines"); } final ByteBuffer buffer0 = AsynchronousFileImpl.newBuffer(SIZE); for (int j = 0; j < SIZE; j++) { buffer0.put(UnitTestCase.getSamplebyte(j)); } CountDownCallback aio = new CountDownCallback(latch, errors, result, i); controller.write(i * SIZE, SIZE, buffer0, aio); } waitForLatch(latch); Assert.assertEquals(0, errors.get()); CountDownCallback.checkResults(NUMBER_LINES, result); } // If you call close you're supposed to wait events to finish before // closing it controller.close(); controller.setBufferCallback(null); controller.open(fileName, 10); buffer = AsynchronousFileImpl.newBuffer(SIZE); for (int i = 0; i < NUMBER_LINES; i++) { if (i % 100 == 0) { System.out.println("Read " + i + " lines"); } AsynchronousFileImpl.clearBuffer(buffer); CountDownLatch latch = new CountDownLatch(1); AtomicInteger errors = new AtomicInteger(0); CountDownCallback aio = new CountDownCallback(latch, errors, null, 0); controller.read(i * SIZE, SIZE, buffer, aio); waitForLatch(latch); Assert.assertEquals(0, errors.get()); Assert.assertTrue(aio.doneCalled); byte bytesRead[] = new byte[SIZE]; buffer.get(bytesRead); for (int count = 0; count < SIZE; count++) { Assert.assertEquals( "byte position " + count + " differs on line " + i + " position = " + count, UnitTestCase.getSamplebyte(count), bytesRead[count]); } } }
@Test public void testInvalidReads() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); final int SIZE = 512; controller.open(fileName, 10); controller.close(); controller = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName, 10); controller.fill(0, 1, 512, (byte) 'j'); buffer = AsynchronousFileImpl.newBuffer(SIZE); buffer.clear(); for (int i = 0; i < SIZE; i++) { buffer.put((byte) (i % 100)); } LocalCallback callbackLocal = new LocalCallback(); controller.write(0, 512, buffer, callbackLocal); waitForLatch(callbackLocal.latch); { ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(512); try { callbackLocal = new LocalCallback(); controller.read(0, 50, newBuffer, callbackLocal); waitForLatch(callbackLocal.latch); Assert.assertTrue(callbackLocal.error); } finally { // We have to destroy the native buffer manually as it was created with a malloc like C // function destroy(newBuffer); newBuffer = null; } } callbackLocal = new LocalCallback(); byte bytes[] = new byte[512]; { try { ByteBuffer newBuffer = ByteBuffer.wrap(bytes); controller.read(0, 512, newBuffer, callbackLocal); Assert.fail("An exception was supposed to be thrown"); } catch (HornetQException ignored) { System.out.println(ignored); } } { final ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(512); try { callbackLocal = new LocalCallback(); controller.read(0, 512, newBuffer, callbackLocal); waitForLatch(callbackLocal.latch); Assert.assertFalse(callbackLocal.error); newBuffer.rewind(); byte[] bytesRead = new byte[SIZE]; newBuffer.get(bytesRead); for (int i = 0; i < SIZE; i++) { Assert.assertEquals((byte) (i % 100), bytesRead[i]); } } finally { destroy(newBuffer); } } }
/** * This test is validating if the AIO layer can open two different simultaneous files without * loose any callbacks. This test made the native layer to crash at some point during development */ @Test public void testTwoFiles() throws Exception { controller = new AsynchronousFileImpl(executor, pollerExecutor); final AsynchronousFileImpl controller2 = new AsynchronousFileImpl(executor, pollerExecutor); controller.open(fileName + ".1", 10000); controller2.open(fileName + ".2", 10000); int numberOfLines = 1000; int size = 1024; ArrayList<Integer> listResult1 = new ArrayList<Integer>(); ArrayList<Integer> listResult2 = new ArrayList<Integer>(); AtomicInteger errors = new AtomicInteger(0); try { CountDownLatch latchDone = new CountDownLatch(numberOfLines); CountDownLatch latchDone2 = new CountDownLatch(numberOfLines); buffer = AsynchronousFileImpl.newBuffer(size); encodeBufer(buffer); preAlloc(controller, numberOfLines * size); preAlloc(controller2, numberOfLines * size); ArrayList<CountDownCallback> list = new ArrayList<CountDownCallback>(); ArrayList<CountDownCallback> list2 = new ArrayList<CountDownCallback>(); for (int i = 0; i < numberOfLines; i++) { list.add(new CountDownCallback(latchDone, errors, listResult1, i)); list2.add(new CountDownCallback(latchDone2, errors, listResult2, i)); } int counter = 0; Iterator<CountDownCallback> iter2 = list2.iterator(); for (CountDownCallback cb1 : list) { CountDownCallback cb2 = iter2.next(); controller.write(counter * size, size, buffer, cb1); controller2.write(counter * size, size, buffer, cb2); ++counter; } UnitTestCase.waitForLatch(latchDone); UnitTestCase.waitForLatch(latchDone2); CountDownCallback.checkResults(numberOfLines, listResult1); CountDownCallback.checkResults(numberOfLines, listResult2); for (CountDownCallback callback : list) { Assert.assertEquals(1, callback.timesDoneCalled.get()); Assert.assertTrue(callback.doneCalled); } for (CountDownCallback callback : list2) { Assert.assertEquals(1, callback.timesDoneCalled.get()); Assert.assertTrue(callback.doneCalled); } Assert.assertEquals(0, errors.get()); controller.close(); } finally { try { controller2.close(); } catch (Exception ignored) { } } }