public void Commit(int transactionID)
        {
            if (paused)
            {
                throw new Exception("Transaction handling is currently paused, can't commit!");
            }
#if LOG_TRANSACTION_HANDLING
            writer.WriteLine(new String(' ', transactionLevel) + "Commit to " + transactionID);
            writer.Flush();
            --transactionLevel;
#endif
#if CHECK_RINGLISTS
            procEnv.graph.CheckTypeRinglistsBroken();
#endif
            if (procEnv.Recorder != null)
            {
                procEnv.Recorder.TransactionCommit(transactionID);
            }

            // removes rollback information only if the transaction is outermost
            // otherwise we might need to undo it because a transaction enclosing this transaction failed
            if (transactionID == 0)
            {
                if (wasVisitedFreeRecorded && undoItems.Count > 0)
                {
                    if (wasGraphChanged)
                    {
                        undoing = true;
                        procEnv.SwitchToSubgraph(procEnv.Graph);
                    }

                    for (int i = undoItems.Count - 1; i >= 0; --i)
                    {
                        IUndoItem curItem = undoItems[i];
                        if (curItem is LGSPUndoVisitedFree)
                        {
                            procEnv.graph.UnreserveVisitedFlag(((LGSPUndoVisitedFree)curItem)._visitorID);
                        }
                        else if (curItem is LGSPUndoGraphChange)
                        {
                            curItem.DoUndo(procEnv);
                        }
                    }

                    if (wasGraphChanged)
                    {
                        procEnv.ReturnFromSubgraph();
                        undoing = false;
                    }
                }

                undoItems.Clear();
                UnsubscribeEvents();
                wasVisitedFreeRecorded = false;
                wasGraphChanged        = false;
            }
        }
        public void Rollback(int transactionID)
        {
            if (paused)
            {
                throw new Exception("Transaction handling is currently paused, can't roll back!");
            }
#if LOG_TRANSACTION_HANDLING
            writer.WriteLine(new String(' ', transactionLevel) + "Rollback to " + transactionID);
            writer.Flush();
#endif
            if (procEnv.Recorder != null)
            {
                procEnv.Recorder.TransactionRollback(transactionID, true);
            }

            undoing = true;
            if (wasGraphChanged)
            {
                procEnv.SwitchToSubgraph(procEnv.Graph);
            }

            while (undoItems.Count > transactionID)
            {
                IUndoItem lastItem = undoItems[undoItems.Count - 1];
#if LOG_TRANSACTION_HANDLING
                writer.Write(new String(' ', transactionLevel) + "rolling back " + undoItems.Count + " - ");
                if (lastItem is LGSPUndoTransactionStarted)
                {
                    writer.WriteLine("TransactionStarted");
                }
                else if (lastItem is LGSPUndoElemAdded)
                {
                    LGSPUndoElemAdded item = (LGSPUndoElemAdded)lastItem;
                    if (item._elem is INode)
                    {
                        INode node = (INode)item._elem;
                        writer.WriteLine("ElementAdded: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(node) + ":" + node.Type.Name);
                    }
                    else if (item._elem is IEdge)
                    {
                        IEdge edge = (IEdge)item._elem;
                        writer.WriteLine("ElementAdded: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge.Source) + " -" + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge) + ":" + edge.Type.Name + " ->" + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge.Target));
                    }
                    else
                    {
                        IObject obj = (IObject)item._elem;
                        writer.WriteLine("ElementAdded: hash" + obj.GetHashCode() + ":" + obj.Type.Name);
                    }
                }
                else if (lastItem is LGSPUndoElemRemoved)
                {
                    LGSPUndoElemRemoved item = (LGSPUndoElemRemoved)lastItem;
                    if (item._elem is INode)
                    {
                        INode node = (INode)item._elem;
                        writer.WriteLine("RemovingElement: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(node) + ":" + node.Type.Name);
                    }
                    else if (item._elem is IEdge)
                    {
                        IEdge edge = (IEdge)item._elem;
                        writer.WriteLine("RemovingElement: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge.Source) + " -" + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge) + ":" + edge.Type.Name + "-> " + ((LGSPNamedGraph)procEnv.graph).GetElementName(edge.Target));
                    }
                    else
                    {
                        IObject obj = (IObject)item._elem;
                        writer.WriteLine("RemovingElement: hash" + obj.GetHashCode() + ":" + obj.Type.Name);
                    }
                }
                else if (lastItem is LGSPUndoAttributeChanged)
                {
                    LGSPUndoAttributeChanged item = (LGSPUndoAttributeChanged)lastItem;
                    if (item._elem is IGraphElement)
                    {
                        writer.WriteLine("ChangingElementAttribute: " + ((LGSPNamedGraph)procEnv.graph).GetElementName((IGraphElement)item._elem) + ":" + item._elem.Type.Name + "." + item._attrType.Name);
                    }
                    else
                    {
                        writer.WriteLine("ChangingElementAttribute: hash" + ((IObject)item._elem).GetHashCode() + ":" + item._elem.Type.Name + "." + item._attrType.Name);
                    }
                }
                else if (lastItem is LGSPUndoElemRetyped)
                {
                    LGSPUndoElemRetyped item = (LGSPUndoElemRetyped)lastItem;
                    writer.WriteLine("RetypingElement: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(item._newElem) + ":" + item._newElem.Type.Name + "<" + ((LGSPNamedGraph)procEnv.graph).GetElementName(item._oldElem) + ":" + item._oldElem.Type.Name + ">");
                }
                else if (lastItem is LGSPUndoElemRedirecting)
                {
                    LGSPUndoElemRedirecting item = (LGSPUndoElemRedirecting)lastItem;
                    writer.WriteLine("RedirectingEdge: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(item._edge) + " before undoing removal");
                }
                else if (lastItem is LGSPUndoVisitedAlloc)
                {
                    LGSPUndoVisitedAlloc item = (LGSPUndoVisitedAlloc)lastItem;
                    writer.WriteLine("VisitedAlloc: " + item._visitorID);
                }
                else if (lastItem is LGSPUndoVisitedFree)
                {
                    LGSPUndoVisitedFree item = (LGSPUndoVisitedFree)lastItem;
                    writer.WriteLine("VisitedFree: " + item._visitorID);
                }
                else if (lastItem is LGSPUndoSettingVisited)
                {
                    LGSPUndoSettingVisited item = (LGSPUndoSettingVisited)lastItem;
                    writer.WriteLine("SettingVisited: " + ((LGSPNamedGraph)procEnv.graph).GetElementName(item._elem) + ".visited[" + item._visitorID + "]");
                }
                else if (lastItem is LGSPUndoGraphChange)
                {
                    LGSPUndoGraphChange item = (LGSPUndoGraphChange)lastItem;
                    writer.WriteLine("GraphChange: to previous " + item._oldGraph.Name);
                }
#endif
                if (wasGraphChanged)
                {
                    if (lastItem is LGSPUndoGraphChange)
                    {
                        if (undoItems.Count - 2 >= 0 && undoItems[undoItems.Count - 2] is LGSPUndoGraphChange)
                        {
                            undoItems.RemoveAt(undoItems.Count - 1);
                            continue; // skip graph change without effect to preceeding graph change
                        }
                    }
                }

                lastItem.DoUndo(procEnv);
                undoItems.RemoveAt(undoItems.Count - 1);
            }

            if (wasGraphChanged)
            {
                procEnv.ReturnFromSubgraph();
            }
            undoing = false;

            if (transactionID == 0)
            {
                UnsubscribeEvents();
                wasVisitedFreeRecorded = false;
                wasGraphChanged        = false;
            }

            if (procEnv.Recorder != null)
            {
                procEnv.Recorder.TransactionRollback(transactionID, false);
            }

#if LOG_TRANSACTION_HANDLING
            --transactionLevel;
            writer.Flush();
#endif
#if CHECK_RINGLISTS
            procEnv.graph.CheckTypeRinglistsBroken();
#endif
        }