/*
 * MiningMart Version 1.0
 * 
 * Copyright (C) 2006 Martin Scholz, Timm Euler, 
 *                    Daniel Hakenjos, Katharina Morik
 *
 * Contact: miningmart@ls8.cs.uni-dortmund.de
 *
 * A list of contributing developers (other than the copyright 
 * holders) can be found at
 * http://mmart.cs.uni-dortmund.de/downloads/download.html
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program, see the file MM_HOME/LICENSE; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301, USA.
 */
package edu.udo.cs.miningmart.compiler;

import edu.udo.cs.miningmart.exception.M4CompilerError;

/**
 * This class is used in CompilerAccessLogic in order to avoid database
 * deadlocks when garbage collection and single step compilation threads
 * are mixed.
 * Current strategy:<ul>
 * <li>Compiling steps in parallel is allowed.</li>
 * <li>A garbage collection thread runs on its own.</li>
 * <li>Update statistic threads are considered compilation steps.</li>
 * <li>Status message threads are not synchronized at all.</li>
 * </ul>
 * 
 * @author Martin Scholz
 * @version $Id: CompilerThreadControl.java,v 1.4 2006/04/11 14:10:09 euler Exp $
 */
public class CompilerThreadControl {

		/** constant for state 
		 * &quot;resource is free&quot; */
		public static final short RESOURCE_FREE      = 0;

		/** constant for state
		 * &quot;resource is occupied by garbage collection&quot; */
		public static final short GARBAGE_COLLECTION = 1;
		
		/** constant for state
		 * &quot;resource is occupied by the single step compiler&quot; */
		public static final short STEP_COMPILATION   = 2;
		
		
		private short state       = RESOURCE_FREE;
		private int   threadCount = 0;

		/**
		 * This method registers a thread before execution, in order to regulate
		 * concurrent access to resources. If the resource is not free, the
		 * method waits until the thread may continue.
		 * @param type One of the constants (public static fields) of this class,
		 * representing different types of threads.
		 */
		public void addThread(short type) throws M4CompilerError {
			while (! this.changeFields(true, type)) {
				Thread.yield();
			}
		}
		
		/**
		 * This method unregisters a thread of a specified type. It <b>must</b> be
		 * called exactly for those threads registered via <code>addThread(short)</code>
		 * after the critical resource is no longer accessed.
		 * 
		 * @param type One of the constants (public static fields) of this class,
		 * representing different types of threads.
		 */
		public void subThread(short type) throws M4CompilerError {
			while (! this.changeFields(false, type)) {
				Thread.yield();
			}
		}

		// ---------------------------------------------------------------------
				
		synchronized private boolean changeFields(boolean add, short type)
			throws M4CompilerError
		{
			if (!this.isValidType(type)) {
				throw new M4CompilerError
				("CompilerThreadControl: invalid type '" + type + "' !");
			}
			
			if (add == true) {
				return this.handleAdd(type);
			}
			else {
				return this.handleSub(type);
			}
		}

		// ---------------------------------------------------------------------

		private boolean isValidType(short type) {
			return ( (type == GARBAGE_COLLECTION) || (type == STEP_COMPILATION) );
		}

		private boolean handleAdd(short type) {
			if (this.state == RESOURCE_FREE ||
			   (this.state == type && type == STEP_COMPILATION))
			{
				this.state = type;
				this.threadCount++;
				return true;
			}
			else {
				return false;
			}
		}

		private boolean handleSub(short type) throws M4CompilerError {
				if ((type != this.state) || (this.threadCount <= 0))
				{
					String msg =
						"CompilerThreadControl.subThread(short):\n" +
						"Trying to free resource, which is not allocated!\n";
					if (this.threadCount == 0) {
						msg += "Resource is currently free, but you tried to " +
						       "unregister parameter " + type + " !";
					}
					else {
						msg += "Current state is " + this.state +
						   ", but found parameter " + type + " !";
					}
					throw new M4CompilerError(msg);
				}

				this.threadCount--;
				if (this.threadCount <= 0) {
					this.threadCount = 0;
					this.state = RESOURCE_FREE;
				}
				return true;
		}

}
/*
 * Historie
 * --------
 *
 * $Log: CompilerThreadControl.java,v $
 * Revision 1.4  2006/04/11 14:10:09  euler
 * Updated license text.
 *
 * Revision 1.3  2006/04/06 16:31:09  euler
 * Prepended license remark.
 *
 * Revision 1.2  2006/03/30 16:07:16  scholz
 * fixed author tags for release
 *
 * Revision 1.1  2006/01/03 09:54:31  hakenjos
 * Initial version!
 *
 */
