@Override public boolean tryLock(LockID lock, LockLevel level, long timeout) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException( "tryLock is passed with negative timeout, timeout=" + timeout); } waitUntilRunning(); while (true) { final ClientLock lockState = getOrCreateClientLockState(lock); try { if (lockState.tryLock( this.remoteLockManager, this.threadManager.getThreadID(), level, timeout)) { return true; } else { return false; } } catch (final GarbageLockException e) { // ignorable - thrown when operating on a garbage collected lock // gc thread should clear this object soon - spin and re-get... this.logger.info("Hitting garbage lock state during tryLock with timeout on " + lock); } } }
@Override public void unpinLock(LockID lock, long awardID) { final ClientLock lockState = getClientLockState(lock); if (lockState != null) { lockState.unpinLock(awardID); } }
@Override public int globalWaitingCount(LockID lock) { waitUntilRunning(); int waiterCount = 0; for (final ClientServerExchangeLockContext cselc : queryLock(lock)) { switch (cselc.getState()) { case WAITER: waiterCount++; break; // $CASES-OMITTED$ default: continue; } } if (waiterCount > 0) { return waiterCount; } final ClientLock lockState = getClientLockState(lock); if (lockState != null) { return lockState.waitingCount(); } else { return 0; } }
@ManagedOperation(description = "Unlocks all currently held locks") public void unlockAll() { List<ClientLock> lock_list = new ArrayList<ClientLock>(); Collection<Map<Owner, ClientLock>> maps = client_locks.values(); for (Map<Owner, ClientLock> map : maps) lock_list.addAll(map.values()); for (ClientLock lock : lock_list) lock.unlock(); }
@Override public void recall( SessionID session, LockID lock, ServerLockLevel level, int lease, boolean batch) { this.stateGuard.readLock().lock(); try { if (isShutdown() || (!sessionManager.isCurrentSession(session))) { this.logger.warn( "Ignoring recall request from a dead server :" + session + ", " + this.sessionManager + " : " + lock + ", interestedLevel : " + level + " state: " + state); return; } final ClientLock lockState = getClientLockState(lock); if (lockState != null) { if (lockState.recall(this.remoteLockManager, level, lease, batch)) { // schedule the greedy lease lockLeaseTimer.schedule( new LeaseTask(session, lock, level, batch), lease, TimeUnit.MILLISECONDS); } } } finally { this.stateGuard.readLock().unlock(); } }
@Override public void refuse(SessionID session, LockID lock, ThreadID thread, ServerLockLevel level) { this.stateGuard.readLock().lock(); try { if (!this.sessionManager.isCurrentSession(session)) { this.logger.warn( "Ignoring lock refuse from a dead server :" + session + ", " + this.sessionManager + " : " + lock + " " + thread + " " + level + " state = " + this.state); return; } final ClientLock lockState = getClientLockState(lock); if (lockState != null) { lockState.refuse(thread, level); return; } } finally { this.stateGuard.readLock().unlock(); } }
@Override public boolean isLocked(LockID lock, LockLevel level) { waitUntilRunning(); final ClientLock lockState = getClientLockState(lock); if (lockState != null) { if (lockState.isLocked(level)) { return true; } } for (final ClientServerExchangeLockContext cselc : queryLock(lock)) { if (this.remoteLockManager.getClientID().equals(cselc.getNodeID())) { continue; } switch (cselc.getState()) { case GREEDY_HOLDER_READ: case HOLDER_READ: if (level == LockLevel.READ) { return true; } break; case GREEDY_HOLDER_WRITE: case HOLDER_WRITE: if ((level == LockLevel.WRITE) || (level == LockLevel.SYNCHRONOUS_WRITE)) { return true; } break; // $CASES-OMITTED$ default: continue; } } return false; }
@Override public Collection<ClientServerExchangeLockContext> getAllLockContexts() { final Collection<ClientServerExchangeLockContext> contexts = new ArrayList<ClientServerExchangeLockContext>(); for (final ClientLock lock : this.locks.values()) { contexts.addAll(lock.getStateSnapshot(this.remoteLockManager.getClientID())); } return contexts; }
@Override public boolean isLockAwardValid(LockID lock, long awardID) { final ClientLock lockState = getClientLockState(lock); if (lockState == null) { return false; } else { return lockState.isAwardValid(awardID); } }
@Override public long getAwardIDFor(LockID lock) { final ClientLock lockState = getClientLockState(lock); if (lockState == null) { throw new IllegalStateException("LockState shouldn't be null"); } else { return lockState.getAwardID(); } }
@Override public int localHoldCount(LockID lock, LockLevel level) { waitUntilRunning(); final ClientLock lockState = getClientLockState(lock); if (lockState == null) { return 0; } else { return lockState.holdCount(level); } }
@Override public boolean isLockedByCurrentThread(LockLevel level) { final ThreadID thread = this.threadManager.getThreadID(); for (final ClientLock lockState : this.locks.values()) { if (lockState.isLockedBy(thread, level)) { return true; } } return false; }
/** ******************************* */ @Override public void wait(LockID lock, WaitListener listener, Object waitObject) throws InterruptedException { waitUntilRunning(); final ClientLock lockState = getOrCreateClientLockState(lock); if (logger.isDebugEnabled()) { logger.debug(this.threadManager.getThreadID() + " waiting on log " + lock); } lockState.wait(this.remoteLockManager, listener, this.threadManager.getThreadID(), waitObject); }
@Override public boolean isLockedByCurrentThread(LockID lock, LockLevel level) { waitUntilRunning(); final ClientLock lockState = getClientLockState(lock); if (lockState == null) { return false; } else { return lockState.isLockedBy(this.threadManager.getThreadID(), level); } }
@Override public Notify notifyAll(LockID lock, Object waitObject) { waitUntilRunning(); final ClientLock lockState = getOrCreateClientLockState(lock); final ThreadID thread = this.threadManager.getThreadID(); if (lockState.notifyAll(this.remoteLockManager, thread, null)) { return new NotifyImpl(lock, thread, true); } else { return NotifyImpl.NULL; } }
/** ******************************** */ @Override public void award(SessionID session, LockID lock, ThreadID thread, ServerLockLevel level) { this.stateGuard.readLock().lock(); try { if (!this.sessionManager.isCurrentSession(session)) { this.logger.warn( "Ignoring lock award from a dead server :" + session + ", " + this.sessionManager + " : " + lock + " " + thread + " " + level + " state = " + this.state); return; } if (ThreadID.VM_ID.equals(thread)) { while (true) { final ClientLock lockState = getOrCreateClientLockState(lock); try { lockState.award( this.remoteLockManager, thread, level, lockAwardSequence.incrementAndGet()); break; } catch (final GarbageLockException e) { // ignorable - thrown when operating on a garbage collected lock // gc thread should clear this object soon - spin and re-get... this.logger.info("Hitting garbage lock state during award on " + lock); } } } else { final ClientLock lockState = getClientLockState(lock); if (lockState == null) { this.remoteLockManager.unlock(lock, thread, level); } else { try { lockState.award( this.remoteLockManager, thread, level, lockAwardSequence.incrementAndGet()); } catch (final GarbageLockException e) { this.remoteLockManager.unlock(lock, thread, level); } } } } finally { this.stateGuard.readLock().unlock(); } }
/** ******************************** */ @Override public void initializeHandshake(ClientHandshakeMessage handshakeMessage) { this.stateGuard.writeLock().lock(); try { this.state = this.state.initialize(); if (this.state == State.STARTING) { for (final ClientLock cls : this.locks.values()) { cls.initializeHandshake(this.clientIdProvider.getClientID(), handshakeMessage); } } } finally { this.stateGuard.writeLock().unlock(); } }
protected void await(boolean throwInterrupt) throws InterruptedException { if (!signaled.get()) { lock.acquired = false; sendAwaitConditionRequest(lock.name, lock.owner); boolean interrupted = false; while (!signaled.get()) { parker.set(Thread.currentThread()); LockSupport.park(this); if (Thread.interrupted()) { // If we were interrupted and haven't received a response yet then we try to // clean up the lock request and throw the exception if (!signaled.get()) { sendDeleteAwaitConditionRequest(lock.name, lock.owner); throw new InterruptedException(); } // In the case that we were signaled and interrupted // we want to return the signal but still interrupt // our thread interrupted = true; } } if (interrupted) Thread.currentThread().interrupt(); } // We set as if this signal was no released. This way if the // condition is reused again, but the client condition isn't lost // we won't think we were signaled immediately signaled.set(false); }
/** ******************************* */ @Override public void lock(LockID lock, LockLevel level) { waitUntilRunning(); while (true) { final ClientLock lockState = getOrCreateClientLockState(lock); try { lockState.lock(this.remoteLockManager, this.threadManager.getThreadID(), level); break; } catch (final GarbageLockException e) { // ignorable - thrown when operating on a garbage collected lock // gc thread should clear this object soon - spin and re-get... this.logger.info("Hitting garbage lock state during lock on " + lock); } } }
@Override public void run() { try { int gcCount = 0; for (final Entry<LockID, ClientLock> entry : ClientLockManagerImpl.this.locks.entrySet()) { ClientLockManagerImpl.this.stateGuard.readLock().lock(); try { if (ClientLockManagerImpl.this.state != State.RUNNING) { return; } final LockID lock = entry.getKey(); final ClientLock lockState = entry.getValue(); if (lockState == null) { continue; } if (lockState.tryMarkAsGarbage(ClientLockManagerImpl.this.remoteLockManager) && ClientLockManagerImpl.this.locks.remove(lock, lockState)) { gcCount++; } } finally { ClientLockManagerImpl.this.stateGuard.readLock().unlock(); } } if (gcCount > 0) { ClientLockManagerImpl.this.logger.info("Lock GC collected " + gcCount + " garbage locks"); } if (gcCount > GCED_LOCK_THRESHOLD) { for (LockEventListener lockGCEventListener : lockEventListeners) { lockGCEventListener.fireLockGCEvent(gcCount); } } } catch (TCNotRunningException e) { logger.info( "Ignoring " + e.getMessage() + " in " + this.getClass().getName() + " and cancelling timer task"); } }
@Override public void awaitUninterruptibly() { try { await(false); } catch (InterruptedException e) { // This should never happen } finally { lock.lock(); } }
@Override public void notified(LockID lock, ThreadID thread) { this.stateGuard.readLock().lock(); try { if (this.logger.isDebugEnabled()) { this.logger.debug("Got a notification for " + lock + " with thread " + thread); } final ClientLock lockState = getClientLockState(lock); if (lockState == null) { throw new AssertionError("Server attempting to notify on non-existent lock " + lock); } else { lockState.notified(thread); return; } } finally { this.stateGuard.readLock().unlock(); } }
@Override public int globalHoldCount(LockID lock, LockLevel level) { waitUntilRunning(); int holdCount = 0; final ClientLock lockState = getClientLockState(lock); if (lockState != null) { holdCount += lockState.holdCount(level); } for (final ClientServerExchangeLockContext cselc : queryLock(lock)) { if (this.remoteLockManager.getClientID().equals(cselc.getNodeID())) { continue; } switch (cselc.getState()) { case GREEDY_HOLDER_READ: case HOLDER_READ: if (level == LockLevel.READ) { holdCount++; } break; case GREEDY_HOLDER_WRITE: holdCount++; break; case HOLDER_WRITE: if ((level == LockLevel.WRITE) || (level == LockLevel.SYNCHRONOUS_WRITE)) { holdCount++; } break; // $CASES-OMITTED$ default: break; } } return holdCount; }
@Override public int globalPendingCount(LockID lock) { waitUntilRunning(); int pendingCount = 0; final ClientLock lockState = getClientLockState(lock); if (lockState != null) { pendingCount += lockState.pendingCount(); } for (final ClientServerExchangeLockContext cselc : queryLock(lock)) { switch (cselc.getState()) { case PENDING_READ: case PENDING_WRITE: pendingCount++; break; // $CASES-OMITTED$ default: continue; } } return pendingCount; }
protected long await(long nanoSeconds) throws InterruptedException { long target_nano = System.nanoTime() + nanoSeconds; if (!signaled.get()) { // We release the lock at the same time as waiting on the // condition lock.acquired = false; sendAwaitConditionRequest(lock.name, lock.owner); boolean interrupted = false; while (!signaled.get()) { long wait_nano = target_nano - System.nanoTime(); // If we waited max time break out if (wait_nano > 0) { parker.set(Thread.currentThread()); LockSupport.parkNanos(this, wait_nano); if (Thread.interrupted()) { // If we were interrupted and haven't received a response yet then we try to // clean up the lock request and throw the exception if (!signaled.get()) { sendDeleteAwaitConditionRequest(lock.name, lock.owner); throw new InterruptedException(); } // In the case that we were signaled and interrupted // we want to return the signal but still interrupt // our thread interrupted = true; } } else { break; } } if (interrupted) Thread.currentThread().interrupt(); } // We set as if this signal was no released. This way if the // condition is reused again, but the client condition isn't lost // we won't think we were signaled immediately // If we weren't signaled then delete our request if (!signaled.getAndSet(false)) { sendDeleteAwaitConditionRequest(lock.name, lock.owner); } return target_nano - System.nanoTime(); }
@Override public void await() throws InterruptedException { InterruptedException ex = null; try { await(true); } catch (InterruptedException e) { ex = e; throw ex; } finally { lock.lock(); // If we are throwing an InterruptedException // then clear the interrupt state as well. if (ex != null) { Thread.interrupted(); } } }
@Override public long awaitNanos(long nanosTimeout) throws InterruptedException { long beforeLock; InterruptedException ex = null; try { beforeLock = await(nanosTimeout) + System.nanoTime(); } catch (InterruptedException e) { ex = e; throw ex; } finally { lock.lock(); // If we are throwing an InterruptedException // then clear the interrupt state as well. if (ex != null) { Thread.interrupted(); } } return beforeLock - System.nanoTime(); }
protected void handleLockGrantedResponse(String lock_name, Owner owner, Address sender) { ClientLock lock = getLock(lock_name, owner, false); if (lock != null) lock.handleLockGrantedResponse(owner, sender); }
@Override public void unlock(LockID lock, LockLevel level) { final ClientLock lockState = getOrCreateClientLockState(lock); lockState.unlock(this.remoteLockManager, this.threadManager.getThreadID(), level); }
protected void handleLockDeniedResponse(String lock_name, Owner owner) { ClientLock lock = getLock(lock_name, owner, false); if (lock != null) lock.lockDenied(); }