use of net.openhft.chronicle.core.threads.InterruptedRuntimeException in project Chronicle-Queue by OpenHFT.
the class NotCompleteTest method testInterruptOrExceptionDuringSerialisation.
@Test
public void testInterruptOrExceptionDuringSerialisation() throws InterruptedException {
final File tmpDir = DirectoryUtils.tempDir("testInterruptedDuringSerialisation");
try {
DirectoryUtils.deleteDir(tmpDir);
tmpDir.mkdirs();
final List<String> names = Collections.synchronizedList(new ArrayList<>());
final Person person1 = new Person(40, "Terry");
final Person interrupter = new Person(50, Person.INTERRUPT);
final Person thrower = new Person(80, Person.THROW);
final Person person2 = new Person(90, "Bert");
try (final ChronicleQueue queueReader = createQueue(tmpDir);
final ChronicleQueue queueWriter = createQueue(tmpDir)) {
ExcerptTailer tailer = queueReader.createTailer();
MethodReader reader = tailer.methodReader((PersonListener) person -> names.add(person.name));
final StringBuilder queueDumpBeforeInterruptedWrite = new StringBuilder();
// set up
doWrite(queueWriter, (proxy, queue) -> {
proxy.accept(person1);
queueDumpBeforeInterruptedWrite.append(queue.dump());
});
String cleanedQueueDump = cleanQueueDump(queueDumpBeforeInterruptedWrite.toString());
// start up writer thread
Thread writerThread = new Thread(() -> doWrite(queueWriter, (proxy, queue) -> {
// thread is interrupted during this
try {
proxy.accept(interrupter);
Jvm.error().on(getClass(), "Should have interrupted");
} catch (InterruptedRuntimeException expected) {
// expected.
}
}));
writerThread.start();
writerThread.join();
try (final ChronicleQueue queue = createQueue(tmpDir)) {
String dump = cleanQueueDump(queue.dump());
assertEquals("queue should be unchanged by the interrupted write", cleanedQueueDump, dump);
}
// check only 1 written
assertTrue(reader.readOne());
assertEquals(1, names.size());
assertEquals(person1.name, names.get(0));
assertFalse(reader.readOne());
// do a write that throws an exception
doWrite(queueWriter, (proxy, queue) -> {
try {
proxy.accept(thrower);
} catch (NullPointerException npe) {
// ignore
}
});
try (final ChronicleQueue queue = createQueue(tmpDir)) {
String dump = cleanQueueDump(queue.dump());
assertEquals("queue should be unchanged by the failed (exception) write", cleanedQueueDump, dump);
// System.err.println(queue.dump());
}
// check nothing else written
assertFalse(reader.readOne());
// do an empty write
ExcerptAppender appender = queueWriter.acquireAppender();
DocumentContext wd = appender.writingDocument();
wd.rollbackOnClose();
wd.close();
// check queue unchanged
String dump = cleanQueueDump(queueWriter.dump());
assertEquals("queue should be unchanged by the failed (rollback) write", cleanedQueueDump, dump);
// check nothing else written
assertFalse(reader.readOne());
// write another person to same queue in this thread
doWrite(queueWriter, (proxy, queue) -> proxy.accept(person2));
assertTrue(reader.readOne());
assertEquals(2, names.size());
assertEquals(person2.name, names.get(1));
assertFalse(reader.readOne());
}
} finally {
try {
IOTools.deleteDirWithFiles(tmpDir, 2);
} catch (Exception e) {
if (e instanceof AccessDeniedException && OS.isWindows())
return;
throw e;
}
}
}
use of net.openhft.chronicle.core.threads.InterruptedRuntimeException in project Chronicle-Queue by OpenHFT.
the class TSQueueLock method acquireLock.
/**
* Stores current TID and PID to table store, and any other thread trying to acquire lock will wait for
* <code>chronicle.queue.lock.timeoutMS</code> millis (default is 30000) for the lock to be released, and if it is not
* able to lock, *overrides the lock*.
*/
@Override
public void acquireLock() {
throwExceptionIfClosed();
long tid = Thread.currentThread().getId();
if (isLockHeldByCurrentThread(tid)) {
return;
}
int count = 0;
long lockValueFromTid = getLockValueFromTid(tid);
long value = lock.getVolatileValue();
Pauser tlPauser = pauser.get();
try {
while (!lock.compareAndSwapValue(UNLOCKED, lockValueFromTid)) {
if (count++ > 1000 && Thread.currentThread().isInterrupted())
throw new InterruptedRuntimeException("Interrupted");
tlPauser.pause(timeout, TimeUnit.MILLISECONDS);
value = lock.getVolatileValue();
}
} catch (TimeoutException e) {
warnAndForceUnlock("Couldn't acquire lock", value);
acquireLock();
} finally {
tlPauser.reset();
}
}
use of net.openhft.chronicle.core.threads.InterruptedRuntimeException in project Chronicle-Queue by OpenHFT.
the class TSQueueLock method waitForLock.
/**
* checks if current thread holds lock. If not, it will wait for <code>chronicle.queue.lock.timeoutMS</code> millis for the lock to be
* released, and if it is not after timeout, forcibly unlocks and continues.
*/
// TODO combine logic for acquireLock with this method so recovery is consistent.
@Override
public void waitForLock() {
throwExceptionIfClosed();
long tid = Thread.currentThread().getId();
if (isLockHeldByCurrentThread(tid))
return;
long value = lock.getVolatileValue();
Pauser tlPauser = pauser.get();
try {
while (value != UNLOCKED) {
if (Thread.currentThread().isInterrupted())
throw new InterruptedRuntimeException("Interrupted");
tlPauser.pause(timeout, TimeUnit.MILLISECONDS);
value = lock.getVolatileValue();
}
} catch (TimeoutException e) {
warnAndForceUnlock("Queue lock is still held", value);
// try again.
waitForLock();
} catch (NullPointerException ex) {
if (!tableStore.isClosed())
throw ex;
throw new IllegalStateException("The table store is closed!", ex);
} finally {
tlPauser.reset();
}
}
use of net.openhft.chronicle.core.threads.InterruptedRuntimeException in project Chronicle-Queue by OpenHFT.
the class TableStoreWriteLock method lock.
/**
* Guaranteed to succeed in getting the lock (may involve timeout and recovery) or else throw.
* <p>This is not re-entrant i.e. if you lock and try and lock again it will timeout and recover
*/
@Override
public void lock() {
throwExceptionIfClosed();
assert checkNotAlreadyLocked();
long currentLockValue = 0;
TimingPauser tlPauser = pauser.get();
try {
currentLockValue = lock.getVolatileValue();
while (!lock.compareAndSwapValue(UNLOCKED, PID)) {
if (Thread.currentThread().isInterrupted())
throw new InterruptedRuntimeException("Interrupted for the lock file:" + path);
tlPauser.pause(timeout, TimeUnit.MILLISECONDS);
currentLockValue = lock.getVolatileValue();
}
// noinspection ConstantConditions,AssertWithSideEffects
assert (lockedByThread = Thread.currentThread()) != null && (lockedHere = new StackTrace()) != null;
// success
} catch (TimeoutException e) {
final String lockedBy = getLockedBy(currentLockValue);
final String warningMsg = "Couldn't acquire write lock " + "after " + timeout + " ms " + "for the lock file:" + path + ". " + "Lock was held by " + lockedBy;
if (forceUnlockOnTimeoutWhen == UnlockMode.NEVER)
throw new UnrecoverableTimeoutException(new IllegalStateException(warningMsg + UNLOCK_MAIN_MSG));
else if (forceUnlockOnTimeoutWhen == UnlockMode.LOCKING_PROCESS_DEAD) {
if (forceUnlockIfProcessIsDead())
lock();
else
throw new UnrecoverableTimeoutException(new IllegalStateException(warningMsg + UNLOCK_MAIN_MSG));
} else {
warn().on(getClass(), warningMsg + UNLOCKING_FORCIBLY_MSG);
forceUnlock(currentLockValue);
lock();
}
} finally {
tlPauser.reset();
}
}
Aggregations