You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by dj...@apache.org on 2006/02/20 23:45:47 UTC

svn commit: r379265 - in /db/derby/code/trunk/java/engine/org/apache/derby: iapi/services/context/ContextManager.java impl/sql/conn/GenericLanguageConnectionContext.java

Author: djd
Date: Mon Feb 20 14:45:46 2006
New Revision: 379265

URL: http://svn.apache.org/viewcvs?rev=379265&view=rev
Log:
DERBY-938 Optimize ContextManager
Use an unsynchronized collection for the manager since
it is owned by a single thread, provide optimized
access to a set of contexts with the same identifier.
Contributed by Dyre Tjeldvoll Dyre.Tjeldvoll@sun.com

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/context/ContextManager.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/context/ContextManager.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/context/ContextManager.java?rev=379265&r1=379264&r2=379265&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/context/ContextManager.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/context/ContextManager.java Mon Feb 20 14:45:46 2006
@@ -37,9 +37,10 @@
 import org.apache.derby.iapi.services.i18n.LocaleFinder;
 import java.io.PrintWriter;
 
-import java.util.Hashtable;
-import java.util.Stack;
-import java.util.Vector;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
 import java.util.Locale;
 
 /**
@@ -58,121 +59,171 @@
  */
 
 public class ContextManager
-
 {
+	/**
+	 * The CtxStack implement a stack on top of an ArrayList (to avoid
+	 * the inherent overhead associated with java.util.Stack which is
+	 * built on top of java.util.Vector, which is fully
+	 * synchronized).
+	 */
+	private static final class CtxStack {
+		private ArrayList stack_ = new ArrayList();
+
+		// Keeping a reference to the top element on the stack
+		// optimizes the frequent accesses to this element. The
+		// tradeoff is that pushing and popping becomes more
+		// expensive, but those operations are infrequent.
+		private Context top_ = null;
+
+		void push(Context context) { 
+			stack_.add(context); 
+			top_ = context; 
+		}
+		void pop() {
+			stack_.remove(stack_.size()-1);
+			top_ = stack_.isEmpty() ? 
+				null : (Context) stack_.get(stack_.size()-1); 
+		}
+		void remove(Context context) {
+			if (context == top_) {
+				pop();
+				return;
+			}
+			stack_.remove(stack_.lastIndexOf(context)); 
+		}
+		Context top() { 
+			return top_; 
+		}
+		boolean isEmpty() { return stack_.isEmpty(); }
+		List getUnmodifiableList() { 
+		    return Collections.unmodifiableList(stack_); 
+		}
+	}
 
+	/**
+	 * Empty ArrayList to use as void value
+	 */
+	//private final ArrayList voidArrayList_ = new ArrayList(0);
 
-	private final Stack holder;
+	/**
+	 * HashMap that holds the Context objects. The Contexts are stored
+	 * with a String key.
+	 * @see ContextManager#pushContext(Context)
+	 */
+	private final HashMap ctxTable = new HashMap();
 
-	/*
-	 * ContextManager interface
+	/**
+	 * List of all Contexts
 	 */
+	private final ArrayList holder = new ArrayList();
 
+	/**
+	 * Add a Context object to the ContextManager. The object is added
+	 * both to the holder list and to a stack for the specific type of
+	 * Context.
+	 * @param newContext the new Context object
+	 */
 	public void pushContext(Context newContext)
 	{
 		checkInterrupt();
-
-		String contextId = newContext.getIdName();
-
-		Stack idStack = (Stack) ctxTable.get(contextId);
+		final String contextId = newContext.getIdName();
+		CtxStack idStack = (CtxStack) ctxTable.get(contextId);
 
 		// if the stack is null, create a new one.
-		if (idStack == null)
-		{
-			idStack = new Stack();
-			ctxTable.put(contextId,idStack);
+		if (idStack == null) {
+			idStack = new CtxStack();
+			ctxTable.put(contextId, idStack);
 		}
 
 		// add to top of id's stack
 		idStack.push(newContext);
 
 		// add to top of global stack too
-		holder.push(newContext);
+		holder.add(newContext);
 	}
-
+	
 	/**
-	 * @see org.apache.derby.iapi.services.context.ContextManager#getContext
+	 * Obtain the last pushed Context object of the type indicated by
+	 * the contextId argument.
+	 * @param contextId a String identifying the type of Context
+	 * @return The Context object with the corresponding contextId, or null if not found
 	 */
-	public Context getContext(String contextId)
-	{
+	public Context getContext(String contextId) {
 		checkInterrupt();
-
-		Stack idStack = (Stack)ctxTable.get(contextId);
-
+		
+		final CtxStack idStack = (CtxStack) ctxTable.get(contextId);
 		if (SanityManager.DEBUG)
-		SanityManager.ASSERT( idStack == null ||
-			idStack.empty() ||
-			((Context)idStack.peek()).getIdName().equals(contextId));
-
-		if (idStack == null ||
-		    idStack.empty())
-		{
-			return null;
-		}
-
-
-
-		return (Context) idStack.peek();
+			SanityManager.ASSERT( idStack == null ||
+								  idStack.isEmpty() ||
+								  idStack.top().getIdName() == contextId);
+		return (idStack==null?null:idStack.top());
 	}
 
 	/**
-	 * @see org.apache.derby.iapi.services.context.ContextManager#popContext
+	 * Remove the last pushed Context object, regardless of type. If
+	 * there are no Context objects, no action is taken.
 	 */
 	public void popContext()
 	{
 		checkInterrupt();
-
-		Context theContext;
-		String contextId;
-		Stack idStack;
-
 		// no contexts to remove, so we're done.
-		if (holder.empty())
-		{
+		if (holder.isEmpty()) {
 			return;
 		}
 
 		// remove the top context from the global stack
-		theContext = (Context) holder.pop();
+		Context theContext = (Context) holder.remove(holder.size()-1);
 
 		// now find its id and remove it from there, too
-		contextId = theContext.getIdName();
-		idStack = (Stack)ctxTable.get(contextId);
-
-		if (SanityManager.DEBUG)
-		SanityManager.ASSERT( idStack != null &&
-			(! idStack.empty()) &&
-			((Context)idStack.peek()).getIdName() == contextId);
+		final String contextId = theContext.getIdName();
+		final CtxStack idStack = (CtxStack) ctxTable.get(contextId);
 
+		if (SanityManager.DEBUG) {
+			SanityManager.ASSERT( idStack != null &&
+								  (! idStack.isEmpty()) &&
+								  idStack.top().getIdName() == contextId);
+		}
 		idStack.pop();
 	}
 
+	/**
+	 * Removes the specified Context object. If
+	 * the specified Context object does not exist, the call will fail.
+	 * @param theContext the Context object to remove.
+	 */
 	void popContext(Context theContext)
 	{
 		checkInterrupt();
-
-		Stack idStack;
-
 		if (SanityManager.DEBUG)
-		SanityManager.ASSERT(!holder.empty());
+			SanityManager.ASSERT(!holder.isEmpty());
 
 		// first, remove it from the global stack.
-		// to do this we treat it like its vector supertype.
-		int index = holder.lastIndexOf(theContext);
-		if (index != -1)
-			holder.removeElementAt(index);
-		else if (SanityManager.DEBUG) {
-			//SanityManager.THROWASSERT("Popped non-existent context by id " + theContext + " type " + theContext.getIdName());
-		}
+		holder.remove(holder.lastIndexOf(theContext));
+
+		final String contextId = theContext.getIdName();
+		final CtxStack idStack = (CtxStack) ctxTable.get(contextId);
 
 		// now remove it from its id's stack.
-		idStack = (Stack) ctxTable.get(theContext.getIdName());
-		boolean wasThere = idStack.removeElement(theContext);
-		if (SanityManager.DEBUG) {
-			//if (!wasThere)
-			//	SanityManager.THROWASSERT("Popped non-existent stack by id " + theContext + " type " + theContext.getIdName());
-		}
+		idStack.remove(theContext);
 	}
+	
+	/**
+	 * Return an unmodifiable list reference to the ArrayList backing
+	 * CtxStack object for this type of Contexts. This method allows
+	 * fast traversal of all Contexts on that stack. The first element
+	 * in the List corresponds to the bottom of the stack. The
+	 * assumption is that the Stack will not be modified while it is
+	 * being traversed.
+	 * @param contextId the type of Context stack to return.
+	 * @return an unmodifiable "view" of the ArrayList backing the stack
+	 * @see org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext#resetSavepoints()
+	 * @see org.apache.derby.iapi.sql.conn.StatementContext#resetSavePoint()
+	 */
+	public final List getContextStack(String contextId) {
+		final CtxStack cs = (CtxStack) ctxTable.get(contextId);
+		return (cs==null?Collections.EMPTY_LIST:cs.getUnmodifiableList());
+	}
+
 
 	/**
 		@return true if the context manager is shutdown, false otherwise.
@@ -264,7 +315,7 @@
 						break;
 					}
 
-					Context ctx = ((Context) holder.elementAt(index));
+					Context ctx = ((Context) holder.get(index));
 					lastHandler = ctx.isLastHandler(errorSeverity);
 
 					ctx.cleanupOnError(error);
@@ -443,23 +494,20 @@
 	}
 
 	/**
-	 * constructor specifying the hash table size and load
-	 * factor for the hashed-by-id context stacks.
+	 * Constructs a new instance. No CtxStacks are inserted into the
+	 * hashMap as they will be allocated on demand.
+	 * @param csf the ContextService owning this ContextManager
+	 * @param stream error stream for reporting errors
 	 */
 	ContextManager(ContextService csf, HeaderPrintWriter stream)
 	{
 		errorStream = stream;
-		ctxTable = new Hashtable();
 		owningCsf = csf;
 
 		logSeverityLevel = PropertyUtil.getSystemInt(Property.LOG_SEVERITY_LEVEL,
 			SanityManager.DEBUG ? 0 : ExceptionSeverity.SESSION_SEVERITY);
-
-		holder = new Stack();
 	}
 
-	private final Hashtable ctxTable;
-
 	final ContextService owningCsf;
 
 	private int		logSeverityLevel;
@@ -469,8 +517,6 @@
 
 	private boolean shutdown;
 	private LocaleFinder finder;
-
-	final Stack cmStack = new Stack();
 
 	Thread	activeThread;
 	int		activeCount;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=379265&r1=379264&r2=379265&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java Mon Feb 20 14:45:46 2006
@@ -82,6 +82,7 @@
 import org.apache.derby.iapi.db.TriggerExecutionContext;
 import org.apache.derby.iapi.reference.Property;
 
+import java.util.List;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -1141,7 +1142,7 @@
 			// reset the savepoints to the new
 			// location, since any outer nesting
 			// levels expect there to be a savepoint
-			resetSavepoints(statementContext);
+			resetSavepoints();
 		}
 	}
 
@@ -1317,40 +1318,26 @@
 			// reset the savepoints to the new
 			// location, since any outer nesting
 			// levels expet there to be a savepoint
-			resetSavepoints(statementContext);
+			resetSavepoints();
 		}
 	}
 
-	/*
-	** Reset all statement savepoints.  
-	*/
-	private void resetSavepoints(StatementContext statementContext)
-		 throws StandardException 
+	/**
+	 * Reset all statement savepoints. Traverses the StatementContext
+	 * stack from bottom to top, calling resetSavePoint()
+	 * on each element.
+	 *
+	 * @exception StandardException thrown if something goes wrong
+	 */
+	private void resetSavepoints() throws StandardException 
 	{
-		if (statementContext == null)
-			return;
-
-		ContextManager cm = getContextManager();
-		Stack stack = new Stack();
-
-		// build up a stack with all the statement
-		// contexts.
-		do
-		{
-			stack.push(statementContext);
-			statementContext.popMe();
-		}
-		while ((statementContext = ((StatementContext)cm.getContext(org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT))) != null);
-
-		while (!stack.empty())
-		{
-			statementContext = ((StatementContext)stack.pop());
-
-			// reset the savepoints to the new spot
-			statementContext.resetSavePoint();
-
-			// replace the contexts that we removed above
-			statementContext.pushMe();
+		final ContextManager cm = getContextManager();
+		final List stmts = cm.getContextStack(org.apache.derby.
+											  iapi.reference.
+											  ContextId.LANG_STATEMENT);
+		final int end = stmts.size();
+		for (int i = 0; i < end; ++i) {
+			((StatementContext)stmts.get(i)).resetSavePoint();
 		}
 	}