/*
* 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.Test;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class LocalBufferPoolDestroyTest {
/**
* Tests that a blocking request fails properly if the buffer pool is
* destroyed.
*
* <p>Starts a Thread, which triggers an unsatisfiable blocking buffer
* request. After making sure that the Thread is actually waiting in the
* blocking call, the buffer pool is destroyed and we check whether the
* request Thread threw the expected Exception.
*/
@Test
public void testDestroyWhileBlockingRequest() throws Exception {
AtomicReference<Exception> asyncException = new AtomicReference<>();
NetworkBufferPool networkBufferPool = null;
LocalBufferPool localBufferPool = null;
try {
networkBufferPool = new NetworkBufferPool(1, 4096, MemoryType.HEAP);
localBufferPool = new LocalBufferPool(networkBufferPool, 1);
// Drain buffer pool
assertNotNull(localBufferPool.requestBuffer());
assertNull(localBufferPool.requestBuffer());
// Start request Thread
Thread thread = new Thread(new BufferRequestTask(localBufferPool, asyncException));
thread.start();
// Wait for request
boolean success = false;
for (int i = 0; i < 50; i++) {
StackTraceElement[] stackTrace = thread.getStackTrace();
success = isInBlockingBufferRequest(stackTrace);
if (success) {
break;
} else {
// Retry
Thread.sleep(500);
}
}
// Verify that Thread was in blocking request
assertTrue("Did not trigger blocking buffer request.", success);
// Destroy the buffer pool
localBufferPool.lazyDestroy();
// Wait for Thread to finish
thread.join();
// Verify expected Exception
assertNotNull("Did not throw expected Exception", asyncException.get());
assertTrue(asyncException.get() instanceof IllegalStateException);
} finally {
if (localBufferPool != null) {
localBufferPool.lazyDestroy();
}
if (networkBufferPool != null) {
networkBufferPool.destroyAllBufferPools();
networkBufferPool.destroy();
}
}
}
/**
* Returns whether the stack trace represents a Thread in a blocking buffer
* request.
*
* @param stackTrace Stack trace of the Thread to check
*
* @return Flag indicating whether the Thread is in a blocking buffer
* request or not
*/
private boolean isInBlockingBufferRequest(StackTraceElement[] stackTrace) {
if (stackTrace.length >= 3) {
return stackTrace[0].getMethodName().equals("wait") &&
stackTrace[1].getMethodName().equals("requestBuffer") &&
stackTrace[2].getMethodName().equals("requestBufferBlocking");
} else {
return false;
}
}
/**
* Task triggering a blocking buffer request (the test assumes that no
* buffer is available).
*/
private static class BufferRequestTask implements Runnable {
private final BufferPool bufferPool;
private final AtomicReference<Exception> asyncException;
public BufferRequestTask(BufferPool bufferPool, AtomicReference<Exception> asyncException) {
this.bufferPool = bufferPool;
this.asyncException = asyncException;
}
@Override
public void run() {
try {
String msg = "Test assumption violated: expected no available buffer";
assertNull(msg, bufferPool.requestBuffer());
bufferPool.requestBufferBlocking();
} catch (Exception t) {
asyncException.set(t);
}
}
}
}