Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions persistit/core/src/test/java/com/persistit/ExchangeLockTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@
* 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.
* Portions Copyright 2026 3A Systems, LLC.
*/

package com.persistit;

import com.persistit.exception.InUseException;
import com.persistit.exception.InvalidKeyException;
import com.persistit.exception.PersistitException;
import com.persistit.exception.RollbackException;
import org.junit.Test;

import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Semaphore;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -83,7 +86,7 @@ private class Locker implements Runnable {
final Semaphore _semaphore = new Semaphore(0);
final long _timeout;
final int[] _sequence;
Exception _exception;
volatile Exception _exception;
volatile int _expectedReleases;

volatile boolean _committed;
Expand Down Expand Up @@ -205,8 +208,15 @@ public void deadlock() throws Exception {
}
join(threads);
final long end = System.currentTimeMillis();
assertTrue(end - start < DMILLIS);
assertTrue(a._committed ^ b._committed);
final String state = describe(end - start, a, b);
assertTrue(state, end - start < DMILLIS);
/*
* Deadlock detection is distributed: every waiter on the cycle checks for
* it, and more than one may detect it before the cycle is broken. So
* both lockers may be rolled back, but never can both commit.
*/
assertFalse(state, a._committed && b._committed);
assertDeadlockVictims(state, a, b);
}

@Test
Expand All @@ -228,14 +238,35 @@ public void multiWayDeadlock() throws Exception {
}
join(threads);
final long end = System.currentTimeMillis();
assertTrue(end - start < DMILLIS);
final Locker[] lockers = {a, b, c, d, e};
final String state = describe(end - start, lockers);
assertTrue(state, end - start < DMILLIS);
int succeeded = 0;
for (final Locker l : new Locker[] {a, b, c, d, e}) {
for (final Locker l : lockers) {
if (l._committed) {
succeeded++;
}
}
assertEquals(1, succeeded);
// More than one participant may detect the deadlock; see deadlock()
assertTrue(state, succeeded <= 1);
assertDeadlockVictims(state, lockers);
}

private static void assertDeadlockVictims(final String state, final Locker... lockers) {
for (final Locker l : lockers) {
if (!l._committed) {
assertTrue(state, l._exception instanceof RollbackException);
}
}
}

private static String describe(final long elapsed, final Locker... lockers) {
final StringBuilder sb = new StringBuilder("elapsed=").append(elapsed);
for (int i = 0; i < lockers.length; i++) {
sb.append(" locker").append(i).append("[committed=").append(lockers[i]._committed)
.append(", exception=").append(lockers[i]._exception).append(']');
}
return sb.toString();
}

/**
Expand Down
Loading