Search in sources :

Example 6 with EventListener

use of org.cojen.tupl.diag.EventListener in project Tupl by cojen.

the class IndexBackfill method run.

@Override
public void run() {
    EventListener listener;
    checkNotify: {
        try {
            if (mManager.mPrimaryIndex.isEmpty()) {
                // No need to notify if index is empty because there isn't really a backfill.
                listener = null;
                break checkNotify;
            }
        } catch (IOException e) {
        }
        listener = mRowStore.mDatabase.eventListener();
    }
    if (listener != null) {
        listener.notify(EventType.TABLE_INDEX_INFO, "Starting backfill for %1$s", mSecondaryStr);
    }
    boolean success = false;
    try {
        success = doRun();
        if (!success && listener != null) {
            listener.notify(EventType.TABLE_INDEX_INFO, "Stopped backfill for %1$s", mSecondaryStr);
        }
    } catch (Throwable e) {
        error("Unable to backfill %1$s: %2$s", e);
    }
    try {
        mRowStore.activateSecondaryIndex(this, success);
        if (success && listener != null) {
            listener.notify(EventType.TABLE_INDEX_INFO, "Finished backfill for %1$s", mSecondaryStr);
        }
    } catch (Throwable e) {
        error("Unable to activate %1$s: %2$s", e);
    }
}
Also used : EventListener(org.cojen.tupl.diag.EventListener) IOException(java.io.IOException) InterruptedIOException(java.io.InterruptedIOException)

Example 7 with EventListener

use of org.cojen.tupl.diag.EventListener in project Tupl by cojen.

the class DatabaseReplicatorTest method startGroup.

/**
 * @return first is the leader
 */
private Database[] startGroup(int members, Role replicaRole, Supplier<PrepareHandler> handlerSupplier) throws Exception {
    if (members < 1) {
        throw new IllegalArgumentException();
    }
    mSockets = new ServerSocket[members];
    for (int i = 0; i < members; i++) {
        mSockets[i] = TestUtils.newServerSocket();
    }
    mReplBaseFiles = new File[members];
    mReplConfigs = new ReplicatorConfig[members];
    mReplicators = new StreamReplicator[members];
    mDbConfigs = new DatabaseConfig[members];
    mDatabases = new Database[members];
    for (int i = 0; i < members; i++) {
        mReplBaseFiles[i] = TestUtils.newTempBaseFile(getClass());
        EventListener listener = false ? EventListener.printTo(System.out) : null;
        mReplConfigs[i] = new ReplicatorConfig().groupToken(1).localSocket(mSockets[i]).baseFile(mReplBaseFiles[i]).eventListener(listener);
        if (i > 0) {
            mReplConfigs[i].addSeed(mSockets[0].getLocalSocketAddress());
            mReplConfigs[i].localRole(replicaRole);
        }
        mReplicators[i] = StreamReplicator.open(mReplConfigs[i]);
        ((Controller) mReplicators[i]).keepServerSocket();
        mDbConfigs[i] = new DatabaseConfig().baseFile(mReplBaseFiles[i]).replicate(mReplicators[i]).eventListener(listener).lockTimeout(5, TimeUnit.SECONDS).directPageAccess(false);
        if (handlerSupplier != null) {
            mDbConfigs[i].prepareHandlers(Map.of("TestHandler", handlerSupplier.get()));
        }
        Database db = Database.open(mDbConfigs[i]);
        mDatabases[i] = db;
        readyCheck: {
            for (int trial = 0; trial < 100; trial++) {
                TestUtils.sleep(100);
                if (i == 0) {
                    try {
                        db.openIndex("control");
                        // Ensure that replicas obtain the index in the snapshot.
                        db.checkpoint();
                        break readyCheck;
                    } catch (UnmodifiableReplicaException e) {
                    // Not leader yet.
                    }
                } else {
                    assertNotNull(db.openIndex("control"));
                    break readyCheck;
                }
            }
            throw new AssertionError(i == 0 ? "No leader" : "Not joined");
        }
    }
    return mDatabases;
}
Also used : UnmodifiableReplicaException(org.cojen.tupl.UnmodifiableReplicaException) Database(org.cojen.tupl.Database) EventListener(org.cojen.tupl.diag.EventListener) DatabaseConfig(org.cojen.tupl.DatabaseConfig)

Example 8 with EventListener

use of org.cojen.tupl.diag.EventListener 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);
}
Also used : EventType(org.cojen.tupl.diag.EventType) PrepareHandler(org.cojen.tupl.ext.PrepareHandler) EventListener(org.cojen.tupl.diag.EventListener)

Aggregations

EventListener (org.cojen.tupl.diag.EventListener)8 EventType (org.cojen.tupl.diag.EventType)2 IOException (java.io.IOException)1 InterruptedIOException (java.io.InterruptedIOException)1 Level (java.lang.System.Logger.Level)1 Database (org.cojen.tupl.Database)1 DatabaseConfig (org.cojen.tupl.DatabaseConfig)1 DatabaseException (org.cojen.tupl.DatabaseException)1 UnmodifiableReplicaException (org.cojen.tupl.UnmodifiableReplicaException)1 Crypto (org.cojen.tupl.ext.Crypto)1 PrepareHandler (org.cojen.tupl.ext.PrepareHandler)1 WeakPool (org.cojen.tupl.util.WeakPool)1