/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.flink.runtime.io.network.buffer; import org.apache.flink.core.memory.MemoryType; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; public class BufferPoolFactoryTest { private final static int numBuffers = 1024; private final static int memorySegmentSize = 128; private NetworkBufferPool networkBufferPool; @Before public void setupNetworkBufferPool() { networkBufferPool = new NetworkBufferPool(numBuffers, memorySegmentSize, MemoryType.HEAP); } @After public void verifyAllBuffersReturned() { String msg = "Did not return all buffers to network buffer pool after test."; assertEquals(msg, numBuffers, networkBufferPool.getNumberOfAvailableMemorySegments()); // in case buffers have actually been requested, we must release them again networkBufferPool.destroy(); } @Test(expected = IOException.class) public void testRequireMoreThanPossible() throws IOException { networkBufferPool.createBufferPool(networkBufferPool.getTotalNumberOfMemorySegments() * 2, Integer.MAX_VALUE); } @Test public void testBoundedPools() throws IOException { BufferPool lbp = networkBufferPool.createBufferPool(1, 1); assertEquals(1, lbp.getNumBuffers()); lbp = networkBufferPool.createBufferPool(1, 2); assertEquals(2, lbp.getNumBuffers()); } @Test public void testSingleManagedPoolGetsAll() throws IOException { BufferPool lbp = networkBufferPool.createBufferPool(1, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), lbp.getNumBuffers()); } @Test public void testSingleManagedPoolGetsAllExceptFixedOnes() throws IOException { BufferPool fixed = networkBufferPool.createBufferPool(24, 24); BufferPool lbp = networkBufferPool.createBufferPool(1, Integer.MAX_VALUE); assertEquals(24, fixed.getNumBuffers()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() - fixed.getNumBuffers(), lbp.getNumBuffers()); } @Test public void testUniformDistribution() throws IOException { BufferPool first = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), first.getNumBuffers()); BufferPool second = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, first.getNumBuffers()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, second.getNumBuffers()); } /** * Tests that buffers, once given to an initial buffer pool, get re-distributed to a second one * in case both buffer pools request half of the available buffer count. */ @Test public void testUniformDistributionAllBuffers() throws IOException { BufferPool first = networkBufferPool .createBufferPool(networkBufferPool.getTotalNumberOfMemorySegments() / 2, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), first.getNumBuffers()); BufferPool second = networkBufferPool .createBufferPool(networkBufferPool.getTotalNumberOfMemorySegments() / 2, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, first.getNumBuffers()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, second.getNumBuffers()); } @Test public void testUniformDistributionBounded1() throws IOException { BufferPool first = networkBufferPool.createBufferPool(0, networkBufferPool.getTotalNumberOfMemorySegments()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), first.getNumBuffers()); BufferPool second = networkBufferPool.createBufferPool(0, networkBufferPool.getTotalNumberOfMemorySegments()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, first.getNumBuffers()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, second.getNumBuffers()); } @Test public void testUniformDistributionBounded2() throws IOException { BufferPool first = networkBufferPool.createBufferPool(0, 10); assertEquals(10, first.getNumBuffers()); BufferPool second = networkBufferPool.createBufferPool(0, 10); assertEquals(10, first.getNumBuffers()); assertEquals(10, second.getNumBuffers()); } @Test public void testUniformDistributionBounded3() throws IOException { NetworkBufferPool globalPool = new NetworkBufferPool(3, 128, MemoryType.HEAP); BufferPool first = globalPool.createBufferPool(0, 10); assertEquals(3, first.getNumBuffers()); BufferPool second = globalPool.createBufferPool(0, 10); // the order of which buffer pool received 2 or 1 buffer is undefined assertEquals(3, first.getNumBuffers() + second.getNumBuffers()); assertNotEquals(3, first.getNumBuffers()); assertNotEquals(3, second.getNumBuffers()); BufferPool third = globalPool.createBufferPool(0, 10); assertEquals(1, first.getNumBuffers()); assertEquals(1, second.getNumBuffers()); assertEquals(1, third.getNumBuffers()); // similar to #verifyAllBuffersReturned() String msg = "Did not return all buffers to network buffer pool after test."; assertEquals(msg, 3, globalPool.getNumberOfAvailableMemorySegments()); // in case buffers have actually been requested, we must release them again globalPool.destroy(); } @Test public void testBufferRedistributionMixed1() throws IOException { // try multiple times for various orders during redistribution for (int i = 0; i < 1_000; ++i) { BufferPool first = networkBufferPool.createBufferPool(0, 10); assertEquals(10, first.getNumBuffers()); BufferPool second = networkBufferPool.createBufferPool(0, 10); assertEquals(10, first.getNumBuffers()); assertEquals(10, second.getNumBuffers()); BufferPool third = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); // note: exact buffer distribution depends on the order during the redistribution for (BufferPool bp : new BufferPool[] {first, second, third}) { int size = networkBufferPool.getTotalNumberOfMemorySegments() * Math.min(networkBufferPool.getTotalNumberOfMemorySegments(), bp.getMaxNumberOfMemorySegments()) / (networkBufferPool.getTotalNumberOfMemorySegments() + 20); if (bp.getNumBuffers() != size && bp.getNumBuffers() != (size + 1)) { fail("wrong buffer pool size after redistribution: " + bp.getNumBuffers()); } } BufferPool fourth = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); // note: exact buffer distribution depends on the order during the redistribution for (BufferPool bp : new BufferPool[] {first, second, third, fourth}) { int size = networkBufferPool.getTotalNumberOfMemorySegments() * Math.min(networkBufferPool.getTotalNumberOfMemorySegments(), bp.getMaxNumberOfMemorySegments()) / (2 * networkBufferPool.getTotalNumberOfMemorySegments() + 20); if (bp.getNumBuffers() != size && bp.getNumBuffers() != (size + 1)) { fail("wrong buffer pool size after redistribution: " + bp.getNumBuffers()); } } verifyAllBuffersReturned(); setupNetworkBufferPool(); } } @Test public void testAllDistributed() throws IOException { // try multiple times for various orders during redistribution for (int i = 0; i < 1_000; ++i) { Random random = new Random(); List<BufferPool> pools = new ArrayList<BufferPool>(); int numPools = numBuffers / 32; long maxTotalUsed = 0; for (int j = 0; j < numPools; j++) { int numRequiredBuffers = random.nextInt(7 + 1); // make unbounded buffers more likely: int maxUsedBuffers = random.nextBoolean() ? Integer.MAX_VALUE : Math.max(1, random.nextInt(10) + numRequiredBuffers); pools.add(networkBufferPool.createBufferPool(numRequiredBuffers, maxUsedBuffers)); maxTotalUsed = Math.min(numBuffers, maxTotalUsed + maxUsedBuffers); // after every iteration, all buffers (up to maxTotalUsed) must be distributed int numDistributedBuffers = 0; for (BufferPool pool : pools) { numDistributedBuffers += pool.getNumBuffers(); } assertEquals(maxTotalUsed, numDistributedBuffers); } verifyAllBuffersReturned(); setupNetworkBufferPool(); } } @Test public void testCreateDestroy() throws IOException { BufferPool first = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), first.getNumBuffers()); BufferPool second = networkBufferPool.createBufferPool(0, Integer.MAX_VALUE); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, first.getNumBuffers()); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments() / 2, second.getNumBuffers()); first.lazyDestroy(); assertEquals(networkBufferPool.getTotalNumberOfMemorySegments(), second.getNumBuffers()); } }