ARTEMIS-4332 Add store operation trackers

This commit is contained in:
Domenico Francesco Bruscino 2023-06-24 09:41:16 +02:00 committed by clebertsuconic
parent 187ae9daec
commit b4230c62bf
2 changed files with 75 additions and 2 deletions

View File

@ -28,6 +28,9 @@ import org.apache.activemq.artemis.core.journal.impl.SimpleWaitIOCallback;
import org.apache.activemq.artemis.core.persistence.OperationContext; import org.apache.activemq.artemis.core.persistence.OperationContext;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.utils.ExecutorFactory; import org.apache.activemq.artemis.utils.ExecutorFactory;
import org.apache.commons.collections.Buffer;
import org.apache.commons.collections.BufferUtils;
import org.apache.commons.collections.buffer.CircularFifoBuffer;
/** /**
* Each instance of OperationContextImpl is associated with an executor (usually an ordered Executor). * Each instance of OperationContextImpl is associated with an executor (usually an ordered Executor).
@ -38,6 +41,9 @@ import org.apache.activemq.artemis.utils.ExecutorFactory;
* If there are no pending IO operations, the tasks are just executed at the callers thread without any context switch. * If there are no pending IO operations, the tasks are just executed at the callers thread without any context switch.
* *
* So, if you are doing operations that are not dependent on IO (e.g NonPersistentMessages) you wouldn't have any context switch. * So, if you are doing operations that are not dependent on IO (e.g NonPersistentMessages) you wouldn't have any context switch.
*
* If you need to track store operations you can set the system property "ARTEMIS_OPCONTEXT_MAX_DEBUG_TRACKERS"
* with the max number of trackers that you want to keep in memory.
*/ */
public class OperationContextImpl implements OperationContext { public class OperationContextImpl implements OperationContext {
@ -104,6 +110,24 @@ public class OperationContextImpl implements OperationContext {
private final Executor executor; private final Executor executor;
private static int maxDebugTrackers = Integer.parseInt(
System.getProperty("ARTEMIS_OPCONTEXT_MAX_DEBUG_TRACKERS", "0"));
private Buffer debugTrackers = OperationContextImpl.maxDebugTrackers > 0 ?
BufferUtils.synchronizedBuffer(new CircularFifoBuffer(OperationContextImpl.maxDebugTrackers)) : null;
protected static int getMaxDebugTrackers() {
return OperationContextImpl.maxDebugTrackers;
}
protected static void setMaxDebugTrackers(int maxDebugTrackers) {
OperationContextImpl.maxDebugTrackers = maxDebugTrackers;
}
protected Buffer getDebugTrackers() {
return debugTrackers;
}
public OperationContextImpl(final Executor executor) { public OperationContextImpl(final Executor executor) {
super(); super();
this.executor = executor; this.executor = executor;
@ -122,7 +146,10 @@ public class OperationContextImpl implements OperationContext {
@Override @Override
public void storeLineUp() { public void storeLineUp() {
STORE_LINEUP_UPDATER.incrementAndGet(this); long storeLineUpValue = STORE_LINEUP_UPDATER.incrementAndGet(this);
if (debugTrackers != null) {
debugTrackers.add(new Exception(">" + storeLineUpValue));
}
} }
@Override @Override
@ -216,7 +243,12 @@ public class OperationContextImpl implements OperationContext {
@Override @Override
public synchronized void done() { public synchronized void done() {
stored++; this.stored++;
if (debugTrackers != null) {
debugTrackers.add(new Exception("<" + stored));
}
checkTasks(); checkTasks();
} }

View File

@ -422,4 +422,45 @@ public class OperationContextUnitTest extends ActiveMQTestBase {
Assert.assertEquals(0, operations.get()); Assert.assertEquals(0, operations.get());
} }
@Test
public void testContextWithoutDebugTrackers() {
ExecutorService executor = Executors.newSingleThreadExecutor(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName()));
runAfter(executor::shutdownNow);
Assert.assertEquals(0, OperationContextImpl.getMaxDebugTrackers());
OperationContextImpl context = new OperationContextImpl(executor);
Assert.assertNull(context.getDebugTrackers());
context.storeLineUp();
Assert.assertNull(context.getDebugTrackers());
context.done();
Assert.assertNull(context.getDebugTrackers());
}
@Test
public void testContextWithDebugTrackers() {
int maxStoreOperationTrackers = OperationContextImpl.getMaxDebugTrackers();
ExecutorService executor = Executors.newSingleThreadExecutor(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName()));
runAfter(executor::shutdownNow);
OperationContextImpl.setMaxDebugTrackers(1);
try {
Assert.assertEquals(1, OperationContextImpl.getMaxDebugTrackers());
OperationContextImpl context = new OperationContextImpl(executor);
Assert.assertNotNull(context.getDebugTrackers());
context.storeLineUp();
Assert.assertEquals(1, context.getDebugTrackers().size());
Assert.assertEquals("storeLineUp", ((Exception)context.getDebugTrackers().get()).getStackTrace()[0].getMethodName());
Assert.assertEquals("testContextWithDebugTrackers", ((Exception)context.getDebugTrackers().get()).getStackTrace()[1].getMethodName());
context.done();
Assert.assertEquals(1, context.getDebugTrackers().size());
Assert.assertEquals("done", ((Exception)context.getDebugTrackers().get()).getStackTrace()[0].getMethodName());
Assert.assertEquals("testContextWithDebugTrackers", ((Exception)context.getDebugTrackers().get()).getStackTrace()[1].getMethodName());
} finally {
OperationContextImpl.setMaxDebugTrackers(maxStoreOperationTrackers);
}
}
} }