This is an automated email from the ASF dual-hosted git repository.

ifesdjeen pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 93ddd3a976 Simulator: Add instrumentation for Semaphore
93ddd3a976 is described below

commit 93ddd3a976a3a1dc6694eba7330598f5f83d2fec
Author: Alex Petrov <[email protected]>
AuthorDate: Tue Jul 23 17:58:12 2024 +0200

    Simulator: Add instrumentation for Semaphore
    
    Patch by Alex Petrov; reviewed by David Capwell for CASSANDRA-19695.
---
 .../org/apache/cassandra/utils/MonotonicClock.java |   9 +-
 .../distributed/test/log/CMSTestBase.java          |   9 +-
 .../systems/InterceptingGlobalMethods.java         |  13 ++
 .../simulator/systems/InterceptingSemaphore.java   | 197 +++++++++++++++++++++
 .../systems/InterceptorOfGlobalMethods.java        |  27 ++-
 .../cassandra/simulator/test/SemaphoreTest.java    | 154 ++++++++++++++++
 .../simulator/test/SimulationTestBase.java         |  51 +++++-
 .../simulator/test/TrivialSimulationTest.java      |  14 +-
 8 files changed, 458 insertions(+), 16 deletions(-)

diff --git a/src/java/org/apache/cassandra/utils/MonotonicClock.java 
b/src/java/org/apache/cassandra/utils/MonotonicClock.java
index 7be54c008b..c68ed5d9ef 100644
--- a/src/java/org/apache/cassandra/utils/MonotonicClock.java
+++ b/src/java/org/apache/cassandra/utils/MonotonicClock.java
@@ -248,7 +248,14 @@ public interface MonotonicClock
 
     public static class SystemClock extends AbstractEpochSamplingClock
     {
-        private SystemClock()
+        // Without making this constructor public you may start getting the 
following exception in the simulator:
+        //    java.lang.IncompatibleClassChangeError: Type
+        //       org.apache.cassandra.utils.MonotonicClock$Global is not a 
nest member of
+        //       org.apache.cassandra.utils.MonotonicClock: types are in 
different packages
+        // There might be a problem with a simulator and how we allow access, 
but I verified the change access
+        // flags on <init> method of the 
org/apache/cassandra/utils/MonotonicClock$SystemClock
+        // class to ACC_PUBLIC, and ensured proper testing relationship from 
both the surrounding and nested class.
+        public SystemClock()
         {
             super(Clock.Global::currentTimeMillis);
         }
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/log/CMSTestBase.java 
b/test/distributed/org/apache/cassandra/distributed/test/log/CMSTestBase.java
index c1975cdbfe..e254798915 100644
--- 
a/test/distributed/org/apache/cassandra/distributed/test/log/CMSTestBase.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/test/log/CMSTestBase.java
@@ -91,10 +91,15 @@ public class CMSTestBase
         public final TokenPlacementModel.ReplicationFactor rf;
 
         public CMSSut(IIsolatedExecutor.SerializableFunction<LocalLog, 
Processor> processorFactory, boolean addListeners, 
TokenPlacementModel.ReplicationFactor rf)
+        {
+            this(processorFactory, addListeners, 
Mockito.mock(SchemaProvider.class), rf);
+        }
+
+        public CMSSut(IIsolatedExecutor.SerializableFunction<LocalLog, 
Processor> processorFactory, boolean addListeners, SchemaProvider 
schemaProvider, TokenPlacementModel.ReplicationFactor rf)
         {
             partitioner = Murmur3Partitioner.instance;
             this.rf = rf;
-            schemaProvider = Mockito.mock(SchemaProvider.class);
+            this.schemaProvider = schemaProvider;
             ClusterMetadata initial = new ClusterMetadata(partitioner);
             log = LocalLog.logSpec()
                           .sync()
@@ -127,7 +132,7 @@ public class CMSTestBase
             }, schemaProvider));
         }
 
-        public void close() throws Exception
+        public void close()
         {
             ClusterMetadataService.unsetInstance();
         }
diff --git 
a/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingGlobalMethods.java
 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingGlobalMethods.java
index abc71eae35..34c0f6bacc 100644
--- 
a/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingGlobalMethods.java
+++ 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingGlobalMethods.java
@@ -33,6 +33,7 @@ import 
org.apache.cassandra.simulator.systems.InterceptedWait.InterceptedConditi
 import org.apache.cassandra.utils.Clock;
 import org.apache.cassandra.utils.concurrent.Condition;
 import org.apache.cassandra.utils.concurrent.CountDownLatch;
+import org.apache.cassandra.utils.concurrent.Semaphore;
 import org.apache.cassandra.utils.concurrent.WaitQueue;
 
 import static 
org.apache.cassandra.config.CassandraRelevantProperties.TEST_SIMULATOR_DETERMINISM_CHECK;
@@ -60,6 +61,18 @@ public class InterceptingGlobalMethods extends 
InterceptingMonitors implements I
         this.onUncaughtException = onUncaughtException;
     }
 
+    @Override
+    public Semaphore newSemaphore(int count)
+    {
+        return new InterceptingSemaphore(count, false);
+    }
+
+    @Override
+    public Semaphore newFairSemaphore(int count)
+    {
+        return new InterceptingSemaphore(count, true);
+    }
+
     @Override
     public WaitQueue newWaitQueue()
     {
diff --git 
a/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingSemaphore.java
 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingSemaphore.java
new file mode 100644
index 0000000000..60207e0c7f
--- /dev/null
+++ 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptingSemaphore.java
@@ -0,0 +1,197 @@
+/*
+ * 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.cassandra.simulator.systems;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.cassandra.utils.concurrent.Semaphore;
+import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
+
+import static 
org.apache.cassandra.simulator.systems.InterceptorOfGlobalMethods.Global.ifIntercepted;
+
+public class InterceptingSemaphore extends Semaphore.Standard
+{
+    final Queue<SemaphoreSignal> interceptible = new ConcurrentLinkedQueue<>();
+    final AtomicInteger permits;
+    final boolean fair;
+
+    private static class SemaphoreSignal extends 
InterceptingAwaitable.InterceptingSignal<Void>
+    {
+        private final int permits;
+
+        private SemaphoreSignal(int permits)
+        {
+            this.permits = permits;
+        }
+    }
+
+    public InterceptingSemaphore(int permits, boolean fair)
+    {
+        super(permits);
+        this.permits = new AtomicInteger(permits);
+        this.fair = fair;
+    }
+
+    @Override
+    public int permits()
+    {
+        if (ifIntercepted() == null)
+            return super.permits();
+
+        return permits.get();
+    }
+
+    @Override
+    public int drain()
+    {
+        if (ifIntercepted() == null)
+            return super.drain();
+
+        for (int i = 0; i < 10; i++)
+        {
+            int current = permits.get();
+            if (permits.compareAndSet(current, 0))
+                return current;
+        }
+
+        throw new IllegalStateException("Too much contention");
+    }
+
+    @Override
+    public void release(int release)
+    {
+        if (ifIntercepted() == null)
+        {
+            super.release(release);
+            return;
+        }
+
+        int remaining = permits.addAndGet(release);
+        while (!interceptible.isEmpty() && remaining > 0)
+        {
+            SemaphoreSignal signal = interceptible.peek();
+            if (signal.permits >= remaining)
+                interceptible.poll().signal();
+            else if (fair)
+                // Do not break enqueue order if using fair scheduler
+                break;
+        }
+    }
+
+    @Override
+    public boolean tryAcquire(int acquire)
+    {
+        if (ifIntercepted() == null)
+            return super.tryAcquire(acquire);
+
+        for (int i = 0; i < 10; i++)
+        {
+            int current = permits.get();
+            if (current >= acquire)
+            {
+                if (permits.compareAndSet(current, current - acquire))
+                    return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        throw new IllegalStateException("Too much contention");
+    }
+
+    @Override
+    public boolean tryAcquire(int acquire, long time, TimeUnit unit) throws 
InterruptedException
+    {
+        if (ifIntercepted() == null)
+            return super.tryAcquire(acquire, time, unit);
+
+        while (true)
+        {
+            int current = permits.get();
+            if (current >= acquire && permits.compareAndSet(current, current - 
acquire))
+                return true;
+
+            SemaphoreSignal signal = new SemaphoreSignal(acquire);
+            interceptible.add(signal);
+            boolean res = signal.await(time, unit);
+            interceptible.remove(signal);
+            if (!res)
+                return false;
+        }
+    }
+
+    @Override
+    public boolean tryAcquireUntil(int acquire, long deadline) throws 
InterruptedException
+    {
+        if (ifIntercepted() == null)
+            return super.tryAcquireUntil(acquire, deadline);
+
+        while (true)
+        {
+            int current = permits.get();
+            if (current >= acquire && permits.compareAndSet(current, current - 
acquire))
+                    return true;
+
+            SemaphoreSignal signal = new SemaphoreSignal(acquire);
+            interceptible.add(signal);
+            boolean res = signal.awaitUntil(deadline);
+            interceptible.remove(signal);
+            if (!res)
+                return false;
+        }
+    }
+
+    @Override
+    public void acquire(int acquire) throws InterruptedException
+    {
+        if (ifIntercepted() == null)
+        {
+            super.acquire(acquire);
+            return;
+        }
+
+        while (true)
+        {
+            if (tryAcquire(acquire))
+                return;
+
+            SemaphoreSignal signal = new SemaphoreSignal(acquire);
+            interceptible.add(signal);
+            signal.await();
+            interceptible.remove(signal);
+        }
+    }
+
+    @Override
+    public void acquireThrowUncheckedOnInterrupt(int acquire) throws 
UncheckedInterruptedException
+    {
+        try
+        {
+            acquire(acquire);
+        }
+        catch (InterruptedException e)
+        {
+            throw new UncheckedInterruptedException(e);
+        }
+    }
+}
diff --git 
a/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptorOfGlobalMethods.java
 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptorOfGlobalMethods.java
index 749f91e42d..adb8183bff 100644
--- 
a/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptorOfGlobalMethods.java
+++ 
b/test/simulator/main/org/apache/cassandra/simulator/systems/InterceptorOfGlobalMethods.java
@@ -34,7 +34,6 @@ import org.apache.cassandra.utils.concurrent.BlockingQueues;
 import org.apache.cassandra.utils.concurrent.Condition;
 import org.apache.cassandra.utils.concurrent.CountDownLatch;
 import org.apache.cassandra.utils.concurrent.Semaphore;
-import org.apache.cassandra.utils.concurrent.Semaphore.Standard;
 import org.apache.cassandra.utils.concurrent.WaitQueue;
 
 import static org.apache.cassandra.utils.Shared.Recursive.INTERFACES;
@@ -44,6 +43,8 @@ import static 
org.apache.cassandra.utils.Shared.Scope.SIMULATION;
 @Shared(scope = SIMULATION, inner = INTERFACES)
 public interface InterceptorOfGlobalMethods extends 
InterceptorOfSystemMethods, Closeable
 {
+    Semaphore newSemaphore(int count);
+    Semaphore newFairSemaphore(int count);
     WaitQueue newWaitQueue();
     CountDownLatch newCountDownLatch(int count);
     Condition newOneTimeCondition();
@@ -69,6 +70,26 @@ public interface InterceptorOfGlobalMethods extends 
InterceptorOfSystemMethods,
     {
         static LongConsumer threadLocalRandomCheck;
 
+        @Override
+        public Semaphore newSemaphore(int count)
+        {
+            Thread thread = Thread.currentThread();
+            if (thread instanceof InterceptibleThread)
+                return ((InterceptibleThread) 
thread).interceptorOfGlobalMethods().newSemaphore(count);
+
+            return Semaphore.newSemaphore(count);
+        }
+
+        @Override
+        public Semaphore newFairSemaphore(int count)
+        {
+            Thread thread = Thread.currentThread();
+            if (thread instanceof InterceptibleThread)
+                return ((InterceptibleThread) 
thread).interceptorOfGlobalMethods().newFairSemaphore(count);
+
+            return Semaphore.newFairSemaphore(count);
+        }
+
         @Override
         public WaitQueue newWaitQueue()
         {
@@ -370,12 +391,12 @@ public interface InterceptorOfGlobalMethods extends 
InterceptorOfSystemMethods,
 
         public static Semaphore newSemaphore(int count)
         {
-            return new Standard(count, false);
+            return methods.newSemaphore(count);
         }
 
         public static Semaphore newFairSemaphore(int count)
         {
-            return new Standard(count, true);
+            return methods.newFairSemaphore(count);
         }
 
         public static Condition newOneTimeCondition()
diff --git 
a/test/simulator/test/org/apache/cassandra/simulator/test/SemaphoreTest.java 
b/test/simulator/test/org/apache/cassandra/simulator/test/SemaphoreTest.java
new file mode 100644
index 0000000000..9e1126a1e0
--- /dev/null
+++ b/test/simulator/test/org/apache/cassandra/simulator/test/SemaphoreTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.cassandra.simulator.test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.cassandra.concurrent.ExecutorFactory;
+import org.apache.cassandra.concurrent.ExecutorPlus;
+import org.apache.cassandra.utils.Clock;
+import org.apache.cassandra.utils.Shared;
+import org.apache.cassandra.utils.concurrent.CountDownLatch;
+import org.apache.cassandra.utils.concurrent.Semaphore;
+
+public class SemaphoreTest extends SimulationTestBase
+{
+    @Test
+    public void semaphoreAcquireUntilTest()
+    {
+        simulate(arr(() -> {
+                     try
+                     {
+                         Semaphore semaphore = Semaphore.newSemaphore(1);
+                         semaphore.acquire(1);
+                         long start = Clock.Global.nanoTime();
+                         Assert.assertFalse(semaphore.tryAcquire(1, 5000, 
TimeUnit.MILLISECONDS));
+                         long elapsed = 
TimeUnit.NANOSECONDS.toMillis(Clock.Global.nanoTime() - start);
+                         Assert.assertTrue(String.format("Elapsed only %sms, 
while should have at least 5000", elapsed),
+                                           elapsed > 5000);
+                     }
+                     catch (Throwable t)
+                     {
+                         throw new RuntimeException(t);
+                     }
+                 }),
+                 () -> {},
+                 System.currentTimeMillis());
+    }
+
+    @Test
+    public void semaphoreAcquireReleaseRepeatabilityTest()
+    {
+        long seed = System.currentTimeMillis();
+        semaphoreTestInternal(seed);
+        State.record = false;
+        // Verify that subsequent interleavings will be the same
+        semaphoreTestInternal(seed);
+    }
+
+    protected void semaphoreTestInternal(long seed)
+    {
+        simulate(arr(() -> {
+                     ExecutorPlus executor = 
ExecutorFactory.Global.executorFactory().pooled("semaphore-test-", 10);
+                     Semaphore semaphore = Semaphore.newSemaphore(5);
+                     CountDownLatch latch = 
CountDownLatch.newCountDownLatch(5);
+
+                     for (int i = 0; i < 5; i++)
+                     {
+                         int thread = i;
+                         executor.submit(() -> {
+                             for (int j = 0; j < 100; j++)
+                             {
+                                 int permits = semaphore.permits();
+                                 Assert.assertTrue(permits + " should be non 
negative", permits >= 0);
+
+                                 try
+                                 {
+                                     semaphore.acquire(1);
+                                     State.tick(thread, j);
+                                     semaphore.release(1);
+                                 }
+                                 catch (Throwable e)
+                                 {
+                                     throw new RuntimeException(e);
+                                 }
+                             }
+                             latch.decrement();
+                         });
+                     }
+
+                     latch.awaitUninterruptibly();
+                     int permits = semaphore.permits();
+                     Assert.assertEquals(5, permits);
+                 }),
+                 () -> {},
+                 seed);
+    }
+
+    @Shared
+    public static class State
+    {
+        static final List<Tick> ticks = new ArrayList<>();
+        static boolean record = true;
+        static int i = 0;
+
+        public static void tick(int thread, int iteration)
+        {
+            if (record)
+            {
+                Tick tick = new Tick(thread, iteration);
+                ticks.add(tick);
+            }
+            else
+            {
+                Tick tick = ticks.get(i);
+                Assert.assertEquals(tick.thread, thread);
+                Assert.assertEquals(tick.iteration, iteration);
+                i++;
+            }
+        }
+    }
+
+    @Shared
+    public static class Tick
+    {
+        final int thread;
+        final int iteration;
+
+        public Tick(int thread, int iteration)
+        {
+            this.thread = thread;
+            this.iteration = iteration;
+        }
+
+        @Override
+        public String toString()
+        {
+            return "Tick{" +
+                   "thread=" + thread +
+                   ", iteration=" + iteration +
+                   '}';
+        }
+    }
+}
diff --git 
a/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java
 
b/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java
index 925f6637d8..d1ebbf89cd 100644
--- 
a/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java
+++ 
b/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java
@@ -24,13 +24,16 @@ import java.util.Collections;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntSupplier;
+import java.util.function.LongConsumer;
 import java.util.function.Predicate;
 
 import com.google.common.collect.Iterators;
+import org.junit.BeforeClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.concurrent.ExecutorFactory;
+import org.apache.cassandra.config.CassandraRelevantProperties;
 import org.apache.cassandra.distributed.Cluster;
 import org.apache.cassandra.distributed.api.ConsistencyLevel;
 import org.apache.cassandra.distributed.api.IIsolatedExecutor;
@@ -42,6 +45,7 @@ import org.apache.cassandra.simulator.ActionSchedule.Work;
 import org.apache.cassandra.simulator.asm.InterceptClasses;
 import org.apache.cassandra.simulator.asm.NemesisFieldSelectors;
 import org.apache.cassandra.simulator.systems.Failures;
+import org.apache.cassandra.simulator.systems.InterceptedWait;
 import org.apache.cassandra.simulator.systems.InterceptibleThread;
 import org.apache.cassandra.simulator.systems.InterceptingExecutorFactory;
 import org.apache.cassandra.simulator.systems.InterceptingGlobalMethods;
@@ -51,24 +55,36 @@ import 
org.apache.cassandra.simulator.systems.SimulatedQuery;
 import org.apache.cassandra.simulator.systems.SimulatedSystems;
 import org.apache.cassandra.simulator.systems.SimulatedTime;
 import org.apache.cassandra.simulator.utils.LongRange;
+import org.apache.cassandra.utils.Clock;
 import org.apache.cassandra.utils.CloseableIterator;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.MINUTES;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_GLOBAL;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_APPROX;
+import static 
org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_PRECISE;
 import static org.apache.cassandra.simulator.ActionSchedule.Mode.TIME_LIMITED;
 import static org.apache.cassandra.simulator.ActionSchedule.Mode.UNLIMITED;
 import static org.apache.cassandra.simulator.ClusterSimulation.ISOLATE;
 import static org.apache.cassandra.simulator.ClusterSimulation.SHARE;
 import static org.apache.cassandra.simulator.SimulatorUtils.failWithOOM;
-import static 
org.apache.cassandra.simulator.systems.InterceptedWait.CaptureSites.Capture.NONE;
 import static org.apache.cassandra.simulator.utils.KindOfSequence.UNIFORM;
 import static org.apache.cassandra.utils.Shared.Scope.ANY;
 import static org.apache.cassandra.utils.Shared.Scope.SIMULATION;
 
 public class SimulationTestBase
 {
+    @BeforeClass
+    public static void beforeAll()
+    {
+        // Disallow time on the bootstrap classloader
+        for (CassandraRelevantProperties property : 
Arrays.asList(CLOCK_GLOBAL, CLOCK_MONOTONIC_APPROX, CLOCK_MONOTONIC_PRECISE))
+            
property.setString("org.apache.cassandra.simulator.systems.SimulatedTime$Delegating");
+        try { Clock.Global.nanoTime(); } catch (IllegalStateException e) {} // 
make sure static initializer gets called
+    }
+
     private static final Logger logger = LoggerFactory.getLogger(Logger.class);
 
     static abstract class DTestClusterSimulation implements Simulation
@@ -215,10 +231,16 @@ public class SimulationTestBase
 
     public static void simulate(IIsolatedExecutor.SerializableRunnable[] 
runnables,
                                 IIsolatedExecutor.SerializableRunnable check)
+    {
+        simulate(runnables, check, System.currentTimeMillis());
+    }
+
+    public static void simulate(IIsolatedExecutor.SerializableRunnable[] 
runnables,
+                                IIsolatedExecutor.SerializableRunnable check,
+                                long seed)
     {
         Failures failures = new HarrySimulatorTest.HaltOnError();
         RandomSource random = new RandomSource.Default();
-        long seed = System.currentTimeMillis();
         System.out.println("Using seed: " + seed);
         random.reset(seed);
         SimulatedTime time = new SimulatedTime(1, random, 1577836800000L /*Jan 
1st UTC*/, new LongRange(1, 100, MILLISECONDS, NANOSECONDS),
@@ -229,10 +251,16 @@ public class SimulationTestBase
         InstanceClassLoader classLoader = new InstanceClassLoader(1, 1, 
AbstractCluster.CURRENT_VERSION.classpath,
                                                                   
Thread.currentThread().getContextClassLoader(),
                                                                   
sharedClassPredicate,
-                                                                  new 
InterceptClasses(() -> 1.0f, () -> 1.0f, NemesisFieldSelectors.get(), 
ClassLoader.getSystemClassLoader(), sharedClassPredicate.negate())::apply);
+                                                                  new 
InterceptClasses(() -> 1.0f, () -> 1.0f,
+                                                                               
        NemesisFieldSelectors.get(),
+                                                                               
        ClassLoader.getSystemClassLoader(),
+                                                                               
        sharedClassPredicate.negate())::apply);
 
         ThreadGroup tg = new ThreadGroup("test");
-        InterceptorOfGlobalMethods interceptorOfGlobalMethods = new 
InterceptingGlobalMethods(NONE, null, failures, random);
+        InterceptedWait.CaptureSites.Capture capture = new 
InterceptedWait.CaptureSites.Capture(false, false, false);
+        InterceptorOfGlobalMethods interceptorOfGlobalMethods = 
IsolatedExecutor.transferAdhoc((IIsolatedExecutor.SerializableQuadFunction<InterceptedWait.CaptureSites.Capture,
 LongConsumer, Consumer<Throwable>, RandomSource, InterceptorOfGlobalMethods>) 
InterceptingGlobalMethods::new, classLoader)
+                                                                               
 .apply(capture, (ignore) -> {}, failures, random);
+
         InterceptingExecutorFactory factory = 
execution.factory(interceptorOfGlobalMethods, classLoader, tg);
 
         time.setup(1, classLoader);
@@ -295,8 +323,23 @@ public class SimulationTestBase
 
         ActionSchedule testSchedule = new ActionSchedule(simulated.time, 
simulated.futureScheduler, () -> 0, runnableScheduler, new Work(UNLIMITED, 
Collections.singletonList(ActionList.of(entrypoint))));
         Iterators.advance(testSchedule, Integer.MAX_VALUE);
+        if (failures.hasFailure())
+        {
+            AssertionError error = new 
AssertionError(String.format("Unexpected errors for seed %d", seed));
+            for (Throwable t : failures.get())
+                error.addSuppressed(t);
+            throw error;
+        }
+
         ActionSchedule checkSchedule = new ActionSchedule(simulated.time, 
simulated.futureScheduler, () -> 0, runnableScheduler, new Work(UNLIMITED, 
Collections.singletonList(ActionList.of(toAction(check, classLoader, factory, 
simulated)))));
         Iterators.advance(checkSchedule, Integer.MAX_VALUE);
+        if (failures.hasFailure())
+        {
+            AssertionError error = new 
AssertionError(String.format("Unexpected errors for seed %d", seed));
+            for (Throwable t : failures.get())
+                error.addSuppressed(t);
+            throw error;
+        }
     }
 
     public static Action toAction(IIsolatedExecutor.SerializableRunnable r, 
ClassLoader classLoader, InterceptingExecutorFactory factory, SimulatedSystems 
simulated)
diff --git 
a/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java
 
b/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java
index 548cf11671..7be09a1b5c 100644
--- 
a/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java
+++ 
b/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java
@@ -39,6 +39,13 @@ import static 
org.apache.cassandra.simulator.cluster.ClusterActions.Options.noAc
 
 public class TrivialSimulationTest extends SimulationTestBase
 {
+    @Test
+    public void identityHashMapTest()
+    {
+        simulate(arr(() -> new IdentityHashMap<>().put(1, 1)),
+                 () -> {});
+    }
+
     @Test
     public void trivialTest() throws IOException // for 
demonstration/experiment purposes
     {
@@ -84,10 +91,5 @@ public class TrivialSimulationTest extends SimulationTestBase
                  () -> {});
     }
 
-    @Test
-    public void identityHashMapTest()
-    {
-        simulate(arr(() -> new IdentityHashMap<>().put(1, 1)),
-                 () -> {});
-    }
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to