public double measure(MetricConfig config, long now) { return free.availableMemory(); } };
/** * Package private for unit test. Get the buffer pool remaining size in bytes. */ long bufferPoolAvailableMemory() { return free.availableMemory(); }
@Test public void outOfMemoryOnAllocation() { BufferPool bufferPool = new BufferPool(1024, 1024, metrics, time, metricGroup) { @Override protected ByteBuffer allocateByteBuffer(int size) { throw new OutOfMemoryError(); } }; try { bufferPool.allocateByteBuffer(1024); // should not reach here fail("Should have thrown OutOfMemoryError"); } catch (OutOfMemoryError ignored) { } assertEquals(bufferPool.availableMemory(), 1024); }
/** * This test creates lots of threads that hammer on the pool */ @Test public void testStressfulSituation() throws Exception { int numThreads = 10; final int iterations = 50000; final int poolableSize = 1024; final long totalMemory = numThreads / 2 * poolableSize; final BufferPool pool = new BufferPool(totalMemory, poolableSize, metrics, time, metricGroup); List<StressTestThread> threads = new ArrayList<StressTestThread>(); for (int i = 0; i < numThreads; i++) threads.add(new StressTestThread(pool, iterations)); for (StressTestThread thread : threads) thread.start(); for (StressTestThread thread : threads) thread.join(); for (StressTestThread thread : threads) assertTrue("Thread should have completed all iterations successfully.", thread.success.get()); assertEquals(totalMemory, pool.availableMemory()); }
/** * Test the simple non-blocking allocation paths */ @Test public void testSimple() throws Exception { long totalMemory = 64 * 1024; int size = 1024; BufferPool pool = new BufferPool(totalMemory, size, metrics, time, metricGroup); ByteBuffer buffer = pool.allocate(size, maxBlockTimeMs); assertEquals("Buffer size should equal requested size.", size, buffer.limit()); assertEquals("Unallocated memory should have shrunk", totalMemory - size, pool.unallocatedMemory()); assertEquals("Available memory should have shrunk", totalMemory - size, pool.availableMemory()); buffer.putInt(1); buffer.flip(); pool.deallocate(buffer); assertEquals("All memory should be available", totalMemory, pool.availableMemory()); assertEquals("But now some is on the free list", totalMemory - size, pool.unallocatedMemory()); buffer = pool.allocate(size, maxBlockTimeMs); assertEquals("Recycled buffer should be cleared.", 0, buffer.position()); assertEquals("Recycled buffer should be cleared.", buffer.capacity(), buffer.limit()); pool.deallocate(buffer); assertEquals("All memory should be available", totalMemory, pool.availableMemory()); assertEquals("Still a single buffer on the free list", totalMemory - size, pool.unallocatedMemory()); buffer = pool.allocate(2 * size, maxBlockTimeMs); pool.deallocate(buffer); assertEquals("All memory should be available", totalMemory, pool.availableMemory()); assertEquals("Non-standard size didn't go to the free list.", totalMemory - size, pool.unallocatedMemory()); }
@Test public void testCleanupMemoryAvailabilityOnMetricsException() throws Exception { BufferPool bufferPool = spy(new BufferPool(2, 1, new Metrics(), time, metricGroup)); doThrow(new OutOfMemoryError()).when(bufferPool).recordWaitTime(anyLong()); bufferPool.allocate(1, 0); try { bufferPool.allocate(2, 1000); fail("Expected oom."); } catch (OutOfMemoryError expected) { } assertEquals(1, bufferPool.availableMemory()); assertEquals(0, bufferPool.queued()); assertEquals(1, bufferPool.unallocatedMemory()); //This shouldn't timeout bufferPool.allocate(1, 0); verify(bufferPool).recordWaitTime(anyLong()); }
/** * Test if Timeout exception is thrown when there is not enough memory to allocate and the elapsed time is greater than the max specified block time. * And verify that the allocation attempt finishes soon after the maxBlockTimeMs. */ @Test public void testBlockTimeout() throws Exception { BufferPool pool = new BufferPool(10, 1, metrics, Time.SYSTEM, metricGroup); ByteBuffer buffer1 = pool.allocate(1, maxBlockTimeMs); ByteBuffer buffer2 = pool.allocate(1, maxBlockTimeMs); ByteBuffer buffer3 = pool.allocate(1, maxBlockTimeMs); // The first two buffers will be de-allocated within maxBlockTimeMs since the most recent allocation delayedDeallocate(pool, buffer1, maxBlockTimeMs / 2); delayedDeallocate(pool, buffer2, maxBlockTimeMs); // The third buffer will be de-allocated after maxBlockTimeMs since the most recent allocation delayedDeallocate(pool, buffer3, maxBlockTimeMs / 2 * 5); long beginTimeMs = Time.SYSTEM.milliseconds(); try { pool.allocate(10, maxBlockTimeMs); fail("The buffer allocated more memory than its maximum value 10"); } catch (TimeoutException e) { // this is good } // Thread scheduling sometimes means that deallocation varies by this point assertTrue("available memory " + pool.availableMemory(), pool.availableMemory() >= 8 && pool.availableMemory() <= 10); long durationMs = Time.SYSTEM.milliseconds() - beginTimeMs; assertTrue("TimeoutException should not throw before maxBlockTimeMs", durationMs >= maxBlockTimeMs); assertTrue("TimeoutException should throw soon after maxBlockTimeMs", durationMs < maxBlockTimeMs + 1000); }
/** * Test if the waiter that is waiting on availability of more memory is cleaned up when a timeout occurs */ @Test public void testCleanupMemoryAvailabilityWaiterOnBlockTimeout() throws Exception { BufferPool pool = new BufferPool(2, 1, metrics, time, metricGroup); pool.allocate(1, maxBlockTimeMs); try { pool.allocate(2, maxBlockTimeMs); fail("The buffer allocated more memory than its maximum value 2"); } catch (TimeoutException e) { // this is good } assertEquals(0, pool.queued()); assertEquals(1, pool.availableMemory()); }
public double measure(MetricConfig config, long now) { return free.availableMemory(); } });