use of org.cojen.tupl.diag.EventType in project Tupl by cojen.
the class TxnPrepareTest method reopenNoHandler.
@Test
public void reopenNoHandler() throws Exception {
// When database is reopened without a recovery handler, the recovered transactions
// aren't lost.
var recovery = new PrepareHandler() {
volatile byte[] message;
volatile boolean prepareCommit;
@Override
public void prepare(Transaction txn, byte[] message) throws IOException {
this.message = message;
txn.commit();
}
@Override
public void prepareCommit(Transaction txn, byte[] message) throws IOException {
prepareCommit = true;
prepare(txn, message);
}
};
DatabaseConfig config = newConfig(recovery);
Database db = newTempDatabase(config);
PrepareHandler handler = db.prepareWriter("TestHandler");
Index ix = db.openIndex("test");
Transaction txn = db.newTransaction();
byte[] key = "hello".getBytes();
ix.store(txn, key, "world".getBytes());
prepare(handler, txn, "message".getBytes());
// Reopen without the handler.
config.prepareHandlers(null);
// Install a listener which is notified that recovery fails.
var listener = new EventListener() {
private boolean notified;
@Override
public void notify(EventType type, String message, Object... args) {
if (type == EventType.RECOVERY_HANDLER_UNCAUGHT) {
synchronized (this) {
notified = true;
notifyAll();
}
}
}
synchronized void waitForNotify() throws InterruptedException {
while (!notified) {
wait();
}
}
};
config.eventListener(listener);
db = reopenTempDatabase(getClass(), db, config);
// Still locked (unless prepareCommit)
ix = db.openIndex("test");
txn = db.newTransaction();
if (isPrepareCommit()) {
assertEquals(LockResult.ACQUIRED, ix.tryLockShared(txn, key, 0));
} else {
assertEquals(LockResult.TIMED_OUT_LOCK, ix.tryLockShared(txn, key, 0));
}
txn.reset();
listener.waitForNotify();
// Reopen with the handler installed.
config.prepareHandlers(Map.of("TestHandler", recovery));
config.eventListener(null);
recovery.message = null;
recovery.prepareCommit = false;
db = reopenTempDatabase(getClass(), db, config);
// Verify that the handler has committed the recovered transaction.
ix = db.openIndex("test");
fastAssertArrayEquals("world".getBytes(), ix.load(null, key));
byte[] message = recovery.message;
if (message == null && isPrepareCommit()) {
// Wait for it since no lock was held.
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
message = recovery.message;
if (message != null) {
break;
}
}
}
fastAssertArrayEquals("message".getBytes(), recovery.message);
assertEquals(isPrepareCommit(), recovery.prepareCommit);
}
Aggregations