Search in sources :

Example 1 with SafeRunnable

use of org.apache.bookkeeper.util.SafeRunnable in project distributedlog by twitter.

the class TestZKSessionLock method testLockWhenSiblingUseSameLockId.

private void testLockWhenSiblingUseSameLockId(long timeout, final boolean isUnlock) throws Exception {
    String lockPath = "/test-lock-when-sibling-use-same-lock-id-" + timeout + "-" + isUnlock + "-" + System.currentTimeMillis();
    String clientId = "client-id";
    createLockPath(zkc.get(), lockPath);
    final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor);
    final ZKSessionLock lock1 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor);
    lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
    List<String> children = getLockWaiters(zkc0, lockPath);
    assertEquals(1, children.size());
    assertEquals(State.CLAIMED, lock0.getLockState());
    assertEquals(lock0.getLockId(), Await.result(asyncParseClientID(zkc0.get(), lockPath, children.get(0))));
    lock1.tryLock(timeout, TimeUnit.MILLISECONDS);
    children = getLockWaiters(zkc0, lockPath);
    assertEquals(2, children.size());
    assertEquals(State.CLAIMED, lock0.getLockState());
    assertEquals(lock0.getLockId(), Await.result(asyncParseClientID(zkc0.get(), lockPath, children.get(0))));
    assertEquals(State.CLAIMED, lock1.getLockState());
    assertEquals(lock1.getLockId(), Await.result(asyncParseClientID(zkc0.get(), lockPath, children.get(1))));
    if (isUnlock) {
        lock0.unlock();
        assertEquals(State.CLOSED, lock0.getLockState());
        children = getLockWaiters(zkc0, lockPath);
        assertEquals(1, children.size());
        assertEquals(State.CLAIMED, lock1.getLockState());
        assertEquals(lock1.getLockId(), Await.result(asyncParseClientID(zkc0.get(), lockPath, children.get(0))));
        lock1.unlock();
    } else {
        ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs);
        final CountDownLatch latch = new CountDownLatch(1);
        lockStateExecutor.submit(lockPath, new SafeRunnable() {

            @Override
            public void safeRun() {
                latch.countDown();
            }
        });
        latch.await();
        children = getLockWaiters(zkc, lockPath);
        assertEquals(0, children.size());
        assertEquals(State.EXPIRED, lock0.getLockState());
        assertEquals(State.EXPIRED, lock1.getLockState());
    }
}
Also used : SafeRunnable(org.apache.bookkeeper.util.SafeRunnable) ZKSessionLock(com.twitter.distributedlog.lock.ZKSessionLock) CountDownLatch(java.util.concurrent.CountDownLatch)

Example 2 with SafeRunnable

use of org.apache.bookkeeper.util.SafeRunnable in project distributedlog by twitter.

the class ZKSessionLock method checkOrClaimLockOwner.

private boolean checkOrClaimLockOwner(final Pair<String, Long> currentOwner, final Promise<String> result) {
    if (lockId.compareTo(currentOwner) != 0 && !lockContext.hasLockId(currentOwner)) {
        lockStateExecutor.submit(lockPath, new SafeRunnable() {

            @Override
            public void safeRun() {
                result.setValue(currentOwner.getLeft());
            }
        });
        return false;
    }
    // current owner is itself
    final int curEpoch = epoch.incrementAndGet();
    executeLockAction(curEpoch, new LockAction() {

        @Override
        public void execute() {
            if (!lockState.inState(State.INIT)) {
                result.setException(new LockStateChangedException(lockPath, lockId, State.INIT, lockState.getState()));
                return;
            }
            asyncTryLock(false, result);
        }

        @Override
        public String getActionName() {
            return "claimOwnership(owner=" + currentOwner + ")";
        }
    }, result);
    return true;
}
Also used : SafeRunnable(org.apache.bookkeeper.util.SafeRunnable)

Example 3 with SafeRunnable

use of org.apache.bookkeeper.util.SafeRunnable in project distributedlog by twitter.

the class ZKSessionLock method asyncTryLock.

@Override
public Future<LockWaiter> asyncTryLock(final long timeout, final TimeUnit unit) {
    final Promise<String> result = new Promise<String>();
    final boolean wait = DistributedLogConstants.LOCK_IMMEDIATE != timeout;
    if (wait) {
        asyncTryLock(wait, result);
    } else {
        // try to check locks first
        zk.getChildren(lockPath, null, new AsyncCallback.Children2Callback() {

            @Override
            public void processResult(final int rc, String path, Object ctx, final List<String> children, Stat stat) {
                lockStateExecutor.submit(lockPath, new SafeRunnable() {

                    @Override
                    public void safeRun() {
                        if (!lockState.inState(State.INIT)) {
                            result.setException(new LockStateChangedException(lockPath, lockId, State.INIT, lockState.getState()));
                            return;
                        }
                        if (KeeperException.Code.OK.intValue() != rc) {
                            result.setException(KeeperException.create(KeeperException.Code.get(rc)));
                            return;
                        }
                        FailpointUtils.checkFailPointNoThrow(FailpointUtils.FailPointName.FP_LockTryAcquire);
                        Collections.sort(children, MEMBER_COMPARATOR);
                        if (children.size() > 0) {
                            asyncParseClientID(zk, lockPath, children.get(0)).addEventListener(new FutureEventListener<Pair<String, Long>>() {

                                @Override
                                public void onSuccess(Pair<String, Long> owner) {
                                    if (!checkOrClaimLockOwner(owner, result)) {
                                        acquireFuture.updateIfEmpty(new Return<Boolean>(false));
                                    }
                                }

                                @Override
                                public void onFailure(final Throwable cause) {
                                    lockStateExecutor.submit(lockPath, new SafeRunnable() {

                                        @Override
                                        public void safeRun() {
                                            result.setException(cause);
                                        }
                                    });
                                }
                            });
                        } else {
                            asyncTryLock(wait, result);
                        }
                    }
                });
            }
        }, null);
    }
    final Promise<Boolean> waiterAcquireFuture = new Promise<Boolean>(new com.twitter.util.Function<Throwable, BoxedUnit>() {

        @Override
        public BoxedUnit apply(Throwable t) {
            acquireFuture.raise(t);
            return BoxedUnit.UNIT;
        }
    });
    return result.map(new AbstractFunction1<String, LockWaiter>() {

        @Override
        public LockWaiter apply(final String currentOwner) {
            final Exception acquireException = new OwnershipAcquireFailedException(lockPath, currentOwner);
            FutureUtils.within(acquireFuture, timeout, unit, acquireException, lockStateExecutor, lockPath).addEventListener(new FutureEventListener<Boolean>() {

                @Override
                public void onSuccess(Boolean acquired) {
                    completeOrFail(acquireException);
                }

                @Override
                public void onFailure(final Throwable acquireCause) {
                    completeOrFail(acquireException);
                }

                private void completeOrFail(final Throwable acquireCause) {
                    if (isLockHeld()) {
                        waiterAcquireFuture.setValue(true);
                    } else {
                        asyncUnlock().addEventListener(new FutureEventListener<BoxedUnit>() {

                            @Override
                            public void onSuccess(BoxedUnit value) {
                                waiterAcquireFuture.setException(acquireCause);
                            }

                            @Override
                            public void onFailure(Throwable cause) {
                                waiterAcquireFuture.setException(acquireCause);
                            }
                        });
                    }
                }
            });
            ;
            return new LockWaiter(lockId.getLeft(), currentOwner, waiterAcquireFuture);
        }
    });
}
Also used : AsyncCallback(org.apache.zookeeper.AsyncCallback) Stat(org.apache.zookeeper.data.Stat) BoxedUnit(scala.runtime.BoxedUnit) Pair(org.apache.commons.lang3.tuple.Pair) OwnershipAcquireFailedException(com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException) Return(com.twitter.util.Return) SafeRunnable(org.apache.bookkeeper.util.SafeRunnable) UnexpectedException(com.twitter.distributedlog.exceptions.UnexpectedException) ZKException(com.twitter.distributedlog.exceptions.ZKException) DLInterruptedException(com.twitter.distributedlog.exceptions.DLInterruptedException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) LockingException(com.twitter.distributedlog.exceptions.LockingException) KeeperException(org.apache.zookeeper.KeeperException) TimeoutException(com.twitter.util.TimeoutException) IOException(java.io.IOException) OwnershipAcquireFailedException(com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException) Promise(com.twitter.util.Promise) FutureEventListener(com.twitter.util.FutureEventListener)

Example 4 with SafeRunnable

use of org.apache.bookkeeper.util.SafeRunnable in project distributedlog by twitter.

the class ZKSessionLock method asyncUnlock.

Future<BoxedUnit> asyncUnlock(final Throwable cause) {
    final Promise<BoxedUnit> promise = new Promise<BoxedUnit>();
    // Use lock executor here rather than lock action, because we want this opertaion to be applied
    // whether the epoch has changed or not. The member node is EPHEMERAL_SEQUENTIAL so there's no
    // risk of an ABA problem where we delete and recreate a node and then delete it again here.
    lockStateExecutor.submit(lockPath, new SafeRunnable() {

        @Override
        public void safeRun() {
            acquireFuture.updateIfEmpty(new Throw<Boolean>(cause));
            unlockInternal(promise);
            promise.addEventListener(new OpStatsListener<BoxedUnit>(unlockStats));
        }
    });
    return promise;
}
Also used : Promise(com.twitter.util.Promise) Throw(com.twitter.util.Throw) SafeRunnable(org.apache.bookkeeper.util.SafeRunnable) BoxedUnit(scala.runtime.BoxedUnit) OpStatsListener(com.twitter.distributedlog.stats.OpStatsListener)

Example 5 with SafeRunnable

use of org.apache.bookkeeper.util.SafeRunnable in project distributedlog by twitter.

the class TestZKSessionLock method testSessionExpiredBeforeLock.

/**
     * Test Session Expired Before Lock does locking. The lock should be closed since
     * all zookeeper operations would be failed.
     *
     * @param timeout
     *          timeout to wait for the lock
     * @throws Exception
     */
private void testSessionExpiredBeforeLock(long timeout) throws Exception {
    String lockPath = "/test-session-expired-before-lock-" + timeout + "-" + System.currentTimeMillis();
    String clientId = "test-session-expired-before-lock-" + System.currentTimeMillis();
    createLockPath(zkc.get(), lockPath);
    final AtomicInteger expireCounter = new AtomicInteger(0);
    final CountDownLatch expiredLatch = new CountDownLatch(1);
    LockListener listener = new LockListener() {

        @Override
        public void onExpired() {
            expireCounter.incrementAndGet();
        }
    };
    final ZKSessionLock lock = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor).setLockListener(listener);
    // expire session
    ZooKeeperClientUtils.expireSession(zkc, zkServers, sessionTimeoutMs);
    // submit a runnable to lock state executor to ensure any state changes happened when session expired
    lockStateExecutor.submit(lockPath, new SafeRunnable() {

        @Override
        public void safeRun() {
            expiredLatch.countDown();
        }
    });
    expiredLatch.await();
    // no watcher was registered if never acquired lock successfully
    assertEquals(State.INIT, lock.getLockState());
    try {
        lock.tryLock(timeout, TimeUnit.MILLISECONDS);
        fail("Should fail locking using an expired lock");
    } catch (LockingException le) {
        assertTrue(le.getCause() instanceof KeeperException.SessionExpiredException);
    }
    assertEquals(State.CLOSED, lock.getLockState());
    List<String> children = getLockWaiters(zkc, lockPath);
    assertEquals(0, children.size());
}
Also used : LockingException(com.twitter.distributedlog.exceptions.LockingException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) SafeRunnable(org.apache.bookkeeper.util.SafeRunnable) ZKSessionLock(com.twitter.distributedlog.lock.ZKSessionLock) CountDownLatch(java.util.concurrent.CountDownLatch)

Aggregations

SafeRunnable (org.apache.bookkeeper.util.SafeRunnable)6 LockingException (com.twitter.distributedlog.exceptions.LockingException)2 ZKSessionLock (com.twitter.distributedlog.lock.ZKSessionLock)2 Promise (com.twitter.util.Promise)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 BoxedUnit (scala.runtime.BoxedUnit)2 DLInterruptedException (com.twitter.distributedlog.exceptions.DLInterruptedException)1 OwnershipAcquireFailedException (com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException)1 UnexpectedException (com.twitter.distributedlog.exceptions.UnexpectedException)1 ZKException (com.twitter.distributedlog.exceptions.ZKException)1 OpStatsListener (com.twitter.distributedlog.stats.OpStatsListener)1 FutureEventListener (com.twitter.util.FutureEventListener)1 Return (com.twitter.util.Return)1 Throw (com.twitter.util.Throw)1 TimeoutException (com.twitter.util.TimeoutException)1 IOException (java.io.IOException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Pair (org.apache.commons.lang3.tuple.Pair)1