// ======================================================================== // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jetty.toolchain.test.Stress; import org.junit.Test; public class ThreadLocalBuffersTest { private Buffers httpBuffers; private List<Thread> threadList = new ArrayList<Thread>(); private int numThreads = Stress.isEnabled()?100:10; private int runTestLength = Stress.isEnabled()?5000:1000; private boolean runTest = false; private AtomicLong buffersRetrieved; private void execAbstractBuffer() throws Exception { threadList.clear(); buffersRetrieved = new AtomicLong( 0 ); httpBuffers = new InnerBuffers(1024,4096); for ( int i = 0; i < numThreads; ++i ) { threadList.add( new BufferPeeper( "BufferPeeper: " + i ) ); } System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); long mem0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); runTest = true; Thread.sleep( runTestLength ); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); long mem1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); runTest = false; long totalBuffersRetrieved = buffersRetrieved.get(); System.out.println( "Buffers Retrieved: " + totalBuffersRetrieved ); System.out.println( "Memory Used: " + ( mem1 - mem0 ) ); for (Thread t : threadList) t.stop(); } @Test public void testAbstractBuffers() throws Exception { execAbstractBuffer( ); } @Test public void testDifferentSizes() throws Exception { InnerBuffers buffers = new InnerBuffers(128,256); Buffer h1 = buffers.getHeader(); Buffer h2 = buffers.getHeader(); Buffer b1 = buffers.getBuffer(); Buffer b2 = buffers.getBuffer(); Buffer b3 = buffers.getBuffer(512); buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); buffers.returnBuffer(b2); buffers.returnBuffer(b3); assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2!=buffers.getHeader()); // b2 replaced h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // b3 replaced b2 in other slot assertTrue(b3==buffers.getBuffer(512)); // b2 from other slot buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2==buffers.getHeader()); // h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // new buffer assertTrue(b3!=buffers.getBuffer(512)); // new buffer // check that sizes are respected buffers.returnBuffer(b3); buffers.returnBuffer(b1); buffers.returnBuffer(b2); buffers.returnBuffer(h1); buffers.returnBuffer(h2); assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2==buffers.getHeader()); // h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // new buffer assertTrue(b3!=buffers.getBuffer(512)); // new buffer } @Test public void testSameSizes() throws Exception { InnerBuffers buffers = new InnerBuffers(128,128); Buffer h1 = buffers.getHeader(); Buffer h2 = buffers.getHeader(); Buffer b1 = buffers.getBuffer(); Buffer b2 = buffers.getBuffer(); Buffer b3 = buffers.getBuffer(128); List<Buffer> known = new ArrayList<Buffer>(); known.add(h1); known.add(h2); known.add(b1); known.add(b2); known.add(b3); buffers.returnBuffer(h1); // header slot * buffers.returnBuffer(h2); // other slot buffers.returnBuffer(b1); // buffer slot * buffers.returnBuffer(b2); // other slot buffers.returnBuffer(b3); // other slot * assertTrue(h1==buffers.getHeader()); // pooled header Buffer buffer = buffers.getHeader(); for (Buffer b:known) assertTrue(b!=buffer); // new buffer assertTrue(b1==buffers.getBuffer()); // b1 used from buffer slot buffer = buffers.getBuffer(); for (Buffer b:known) assertTrue(b!=buffer); // new buffer assertTrue(b3==buffers.getBuffer(128)); // b3 from other slot } private static class HeaderBuffer extends ByteArrayBuffer { public HeaderBuffer(int size) { super(size); } } private static class InnerBuffers extends ThreadLocalBuffers { InnerBuffers(int headerSize,int bufferSize) { super(Type.DIRECT,headerSize,Type.BYTE_ARRAY,bufferSize,Type.INDIRECT); } } private class BufferPeeper extends Thread { private final String _bufferName; public BufferPeeper( String bufferName ) { _bufferName = bufferName; start(); } @Override public void run() { while ( true ) { try { if ( runTest ) { Buffer buf = httpBuffers.getHeader(); buffersRetrieved.getAndIncrement(); buf.put(new Byte("2")); // sleep( threadWaitTime ); httpBuffers.returnBuffer(buf); } else { sleep( 1 ); } } catch ( Exception e ) { e.printStackTrace(); break; } } } } }