/** {@inheritDoc} */ @Override public void acquire(int permits) throws IgniteInterruptedException { ctx.kernalContext().gateway().readLock(); A.ensure(permits >= 0, "Number of permits must be non-negative."); try { initializeSemaphore(); sync.acquireSharedInterruptibly(permits); if (isBroken()) { Thread.interrupted(); // Clear interrupt flag. throw new InterruptedException(); } } catch (IgniteCheckedException e) { throw U.convertException(e); } catch (InterruptedException e) { throw new IgniteInterruptedException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override protected final boolean tryReleaseShared(int releases) { // Fail-fast path. if(broken) return true; // Check if some other node updated the state. // This method is called with release==0 only when trying to wake through update. if (releases == 0) return true; for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return true; int cur = getState(); int next = cur + releases; if (next < cur) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetGlobalState(cur, next, false)) return true; } }
/** {@inheritDoc} */ @Override public void onNodeRemoved(UUID nodeId) { try { initializeSemaphore(); } catch (IgniteCheckedException e) { U.error(log, "Failed to recover from failover because distributed semaphore cannot be initialized " + "(Ignore if this node is failing also)." ); // Degrade gracefully, no exception is thrown // because other semaphores might also attempt to recover from failover. return; } int numPermits = sync.getPermitsForNode(nodeId); if (numPermits > 0) { // Semaphore is broken if reaches this point in non-failover safe mode. boolean broken = !sync.failoverSafe; // Release permits acquired by threads on failing node. sync.releaseFailedNode(nodeId, broken); if (broken) { // Interrupt every waiting thread if this semaphore is not failover safe. sync.setBroken(true); for (Thread t : sync.getSharedQueuedThreads()) t.interrupt(); // Try to notify any waiting threads. sync.releaseShared(0); } } }
/** {@inheritDoc} */ @Override public void onNodeRemoved(UUID nodeId) { try { initializeSemaphore(); } catch (IgniteCheckedException e) { U.error(log, "Failed to recover from failover because distributed semaphore cannot be initialized " + "(Ignore if this node is failing also)." ); // Degrade gracefully, no exception is thrown // because other semaphores might also attempt to recover from failover. return; } int numPermits = sync.getPermitsForNode(nodeId); if (numPermits > 0) { // Semaphore is broken if reaches this point in non-failover safe mode. boolean broken = !sync.failoverSafe; // Release permits acquired by threads on failing node. sync.releaseFailedNode(nodeId, broken); if (broken) { // Interrupt every waiting thread if this semaphore is not failover safe. sync.setBroken(true); for (Thread t : sync.getSharedQueuedThreads()) t.interrupt(); // Try to notify any waiting threads. sync.releaseShared(0); } } }
/** {@inheritDoc} */ @Override public void acquire(int permits) throws IgniteInterruptedException { ctx.kernalContext().gateway().readLock(); A.ensure(permits >= 0, "Number of permits must be non-negative."); try { initializeSemaphore(); sync.acquireSharedInterruptibly(permits); if (isBroken()) { Thread.interrupted(); // Clear interrupt flag. throw new InterruptedException(); } } catch (IgniteCheckedException e) { throw U.convertException(e); } catch (InterruptedException e) { throw new IgniteInterruptedException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override protected final boolean tryReleaseShared(int releases) { // Fail-fast path. if(broken) return true; // Check if some other node updated the state. // This method is called with release==0 only when trying to wake through update. if (releases == 0) return true; for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return true; int cur = getState(); int next = cur + releases; if (next < cur) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetGlobalState(cur, next, false)) return true; } }
@Override public Sync call() throws Exception { try (GridNearTxLocal tx = CU.txStartInternal(ctx, cacheView, PESSIMISTIC, REPEATABLE_READ)) { GridCacheSemaphoreState val = cacheView.get(key); if (val == null) { if (log.isDebugEnabled()) log.debug("Failed to find semaphore with given name: " + name); return null; } final int cnt = val.getCount(); Map<UUID, Integer> waiters = val.getWaiters(); final boolean failoverSafe = val.isFailoverSafe(); tx.commit(); Sync sync = new Sync(cnt, waiters, failoverSafe); sync.setBroken(val.isBroken()); return sync; } } });
/** * This method is used by the AQS to test if the current thread should block or not. * * @param acquires Number of permits to acquire. * @return Negative number if thread should block, positive if thread successfully acquires permits. */ final int nonfairTryAcquireShared(int acquires) { for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return 1; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetGlobalState(available, remaining, false)) return remaining; } }
/** {@inheritDoc} */ @Override public void acquireUninterruptibly(int permits) { ctx.kernalContext().gateway().readLock(); A.ensure(permits >= 0, "Number of permits must be non-negative."); try { initializeSemaphore(); sync.acquireShared(permits); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override public int getQueueLength() { ctx.kernalContext().gateway().readLock(); try { initializeSemaphore(); return sync.getWaiters(); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override public void acquireUninterruptibly() { ctx.kernalContext().gateway().readLock(); try { initializeSemaphore(); sync.acquireShared(1); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override public boolean isBroken() { ctx.kernalContext().gateway().readLock(); try { initializeSemaphore(); return sync.isBroken(); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override public int drainPermits() { ctx.kernalContext().gateway().readLock(); try { initializeSemaphore(); return sync.drainPermits(); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** {@inheritDoc} */ @Override public boolean hasQueuedThreads() { ctx.kernalContext().gateway().readLock(); try { initializeSemaphore(); return sync.getWaiters() != 0; } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** * This method is used internally to implement {@linkplain GridCacheSemaphoreImpl#drainPermits()}. * * @return Number of permits to drain. */ final int drainPermits() { for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return 1; int curr = getState(); if (curr == 0 || compareAndSetGlobalState(curr, 0, true)) return curr; } }
/** * Gets the number of permissions currently available. * * @return Number of permits available at this semaphore. */ final int getPermits() { return getState(); }
@Override public Sync call() throws Exception { try (GridNearTxLocal tx = CU.txStartInternal(ctx, cacheView, PESSIMISTIC, REPEATABLE_READ)) { GridCacheSemaphoreState val = cacheView.get(key); if (val == null) { if (log.isDebugEnabled()) log.debug("Failed to find semaphore with given name: " + name); return null; } final int cnt = val.getCount(); Map<UUID, Integer> waiters = val.getWaiters(); final boolean failoverSafe = val.isFailoverSafe(); tx.commit(); Sync sync = new Sync(cnt, waiters, failoverSafe); sync.setBroken(val.isBroken()); return sync; } } });
/** * This method is used by the AQS to test if the current thread should block or not. * * @param acquires Number of permits to acquire. * @return Negative number if thread should block, positive if thread successfully acquires permits. */ final int nonfairTryAcquireShared(int acquires) { for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return 1; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetGlobalState(available, remaining, false)) return remaining; } }
/** {@inheritDoc} */ @Override public void acquireUninterruptibly(int permits) { ctx.kernalContext().gateway().readLock(); A.ensure(permits >= 0, "Number of permits must be non-negative."); try { initializeSemaphore(); sync.acquireShared(permits); } catch (IgniteCheckedException e) { throw U.convertException(e); } finally { ctx.kernalContext().gateway().readUnlock(); } }
/** * This method is used internally to implement {@linkplain GridCacheSemaphoreImpl#drainPermits()}. * * @return Number of permits to drain. */ final int drainPermits() { for (; ; ) { // If broken, return immediately, exception will be thrown anyway. if (broken) return 1; int curr = getState(); if (curr == 0 || compareAndSetGlobalState(curr, 0, true)) return curr; } }