/*

   Derby - Class org.apache.derby.impl.services.locks.ActiveLock

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to you 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.

 */

package org.apache.derby.impl.services.locks;

import org.apache.derby.iapi.services.locks.CompatibilitySpace;
import org.apache.derby.iapi.services.locks.Lockable;
import org.apache.derby.iapi.services.locks.C_LockFactory;

import org.apache.derby.iapi.error.StandardException;

/**
	A Lock represents a granted or waiting lock request.

	<BR>
	MT - Mutable - Immutable identity : Thread Aware
*/

public final class ActiveLock extends Lock {

	/**
		Set to true if the object waiting on this thread should wake up,
		MT - mutable - java synchronized(this)
	*/
	byte wakeUpNow;

	/**
		Set to true if the Lock potentially could be granted.

		MT - mutable - single thread required
	*/
	boolean potentiallyGranted;

	/**
		If true then this lock can be granted even if
		it is not the first lock request on the wait queue.
		This can occur if the compatibility space already holds
		a lock on the object.
	*/
	protected boolean canSkip;

	/**
		Initialize the lock, should be seen as part of the constructor. A future
		version of this class may become mutable - mutable identity.

		MT - single thread required
	*/
	protected ActiveLock(CompatibilitySpace space, Lockable ref,
						 Object qualifier) {
		super(space, ref, qualifier);
	}

	/**	
		Set the potentially granted flag, returns true if the
		flag changed its state.

		MT - single thread required
	*/
	protected boolean setPotentiallyGranted() {
		if (!potentiallyGranted) {
			potentiallyGranted = true;
			return true;
		}
		return false;
	}

	/**	
		Clear the potentially granted flag.

		MT - single thread required
	*/
	protected void clearPotentiallyGranted() {
		potentiallyGranted = false;
	}

	/**
		Wait for a lock to be granted, returns when the lock is granted.
		<P>
		The sleep wakeup scheme depends on the two booleans wakeUpNow & potentiallyGranted.
		  
		MT - Single thread required - and assumed to be the thread requesting the lock.

		@return true if the wait ended early (ie. someone else woke us up).

		@exception StandardException timeout, deadlock or thread interrupted
	*/
	protected synchronized byte waitForGrant(int timeout)
		throws StandardException
	{

		if (wakeUpNow == Constants.WAITING_LOCK_IN_WAIT) {

			try {


				if (timeout == C_LockFactory.WAIT_FOREVER) {
					wait();
				}
				else if (timeout > 0) {
					wait(timeout);
				}

			} catch (InterruptedException ie) {
                wakeUpNow = Constants.WAITING_LOCK_INTERRUPTED;
			}
		}

		byte why = wakeUpNow;
		wakeUpNow = Constants.WAITING_LOCK_IN_WAIT;
		return why;
	}

	/**
		Wake up anyone sleeping on this lock.

		MT - Thread Safe
	*/
	protected synchronized void wakeUp(byte why) {
		// If we were picked as a deadlock victim then don't
		// override the wakeup reason with another one.
		if (wakeUpNow != Constants.WAITING_LOCK_DEADLOCK)
			wakeUpNow = why;
		notify();
	}
}

