/* Copyright 1996-2008 Ariba, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. $Id: //ariba/platform/util/core/ariba/util/core/LockHandler.java#6 $ */ package ariba.util.core; import ariba.util.log.Log; /** @aribaapi private */ public class LockHandler { /* Options a la bit-wise or */ public static final int OptionNone = 0; public static final int OptionContinueOnTimeout = 1; public static final int OptionWarnOnTimeout = 2; public static final int OptionDefault = (OptionContinueOnTimeout | OptionWarnOnTimeout); LockHandlerConditions conditions; public Object lock; // List waiterList = ListUtil.list(); public String name; int options = OptionNone; int waiters = 0; int maxWaiters = 0; int sumRequests = 0; int syncCount = 0; int sumWaitTimeSeconds = 0; public LockHandler (String name, LockHandlerConditions conditions, Object lock, int options) { this.name = name; this.lock = lock; this.conditions = conditions; this.options = options; } public LockHandler (String name, LockHandlerConditions conditions, int options) { this.name = name; this.lock = new Object(); this.conditions = conditions; this.options = options; } public int sumWaitTimeSeconds () { synchronized (this.lock) { return this.sumWaitTimeSeconds; } } public int maxWaiters () { synchronized (this.lock) { return this.waiters; } } public int sumRequests () { synchronized (this.lock) { return this.sumRequests; } } public int syncCount () { synchronized (this.lock) { return this.syncCount; } } public void resetMetrics () { synchronized (this.lock) { this.sumWaitTimeSeconds = 0; this.maxWaiters = 0; this.sumRequests = 0; this.syncCount = 0; } } public boolean doWithLock () { return this.doWithLock(new LockHandlerContext()); } public boolean doWithLock (LockHandlerContext lockHandlerContext) { long loopStartTimeMillis; int loopWaitTimeSeconds; lockHandlerContext.waitTimeSeconds = 0; boolean endLock; boolean inWait = false; // LockWaiter lockWaiter = null; for (lockHandlerContext.iteration = 0; ; lockHandlerContext.iteration++) { synchronized (this.lock) { this.syncCount++; lockHandlerContext.logger = null; endLock = this.conditions.doWithLock(lockHandlerContext); if (endLock) { if (inWait) { this.waiters--; // this.waiterList.remove(lockWaiter); } this.sumRequests++; break; } // if this is the first wait then update our bookeeping if (!inWait) { inWait = true; this.waiters++; // lockWaiter = new LockWaiter(Thread.currentThread(); // this.waiterList.add(lockWaiter); if (this.waiters > this.maxWaiters) { this.maxWaiters = this.waiters; } } // basically wait for notify or timeout and do // some book keeping to track excessive wait time loopStartTimeMillis = System.currentTimeMillis(); try { this.lock.wait(conditions.timeoutIntervalMillis()); } catch (InterruptedException e) { Log.util.warning(2799, this.name); } loopWaitTimeSeconds = (int) ((System.currentTimeMillis() - loopStartTimeMillis) / Date.MillisPerSecond); this.sumWaitTimeSeconds += loopWaitTimeSeconds; } // during doWithLock the implementor may have wished // to log a message - to avoid Logging while holding a // lock we do it here if (lockHandlerContext.logger != null) { lockHandlerContext.logger.debug( lockHandlerContext.message); } lockHandlerContext.waitTimeSeconds += loopWaitTimeSeconds; if (lockHandlerContext.waitTimeSeconds >= this.conditions.timeoutIntervalMillis()/Date.MillisPerSecond) { if ((this.options & OptionWarnOnTimeout)!=0) { Log.util.warning(2800, this.name, Integer.toString( (int)(conditions.timeoutIntervalMillis() /Date.MillisPerSecond)), Integer.toString( lockHandlerContext.waitTimeSeconds), this, Integer.toString( lockHandlerContext.iteration)); } if ((this.options & OptionContinueOnTimeout)==0) { this.sumRequests++; return false; } } } // we only get here when doWithLock returns true if (lockHandlerContext.logger != null) { lockHandlerContext.logger.debug( lockHandlerContext.message); } return true; } public String toString () { return Fmt.S("(LockHandler, name:(%s), waiters:(%s), " + "maxWaiters:(%s), sumRequests:(%s), " + "syncCount:(%s), sumWaitTimeSeconds:(%s)", this.name, Integer.toString(this.waiters), Integer.toString(this.maxWaiters), Integer.toString(this.sumRequests), Integer.toString(this.syncCount), Integer.toString(this.sumWaitTimeSeconds)); } }