Add some temp AVL debugging code: In case an AVL table gets unbalanced, dump the table and a backtrace.

svn path=/trunk/; revision=56249
This commit is contained in:
Timo Kreuzer 2012-03-27 17:19:53 +00:00
parent 6fcb5fd53c
commit 98a00b314d

View file

@ -140,7 +140,7 @@ RtlpRebalanceAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
{ {
/* This performs the rotation described in Knuth A8-A10 for Case 1 */ /* This performs the rotation described in Knuth A8-A10 for Case 1 */
RtlPromoteAvlTreeNode(ChildNode); RtlPromoteAvlTreeNode(ChildNode);
/* The nodes are now balanced */ /* The nodes are now balanced */
RtlSetBalance(ChildNode, RtlBalancedAvlTree); RtlSetBalance(ChildNode, RtlBalancedAvlTree);
RtlSetBalance(Node, RtlBalancedAvlTree); RtlSetBalance(Node, RtlBalancedAvlTree);
@ -189,20 +189,60 @@ RtlpRebalanceAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
RtlSetBalance(SubChildNode, RtlBalancedAvlTree); RtlSetBalance(SubChildNode, RtlBalancedAvlTree);
return FALSE; return FALSE;
} }
/* /*
* The case that remains is that the child was already balanced, so this is * The case that remains is that the child was already balanced, so this is
* This is the rotation required for Case 3 in Knuth A8-A10 * This is the rotation required for Case 3 in Knuth A8-A10
*/ */
RtlPromoteAvlTreeNode(ChildNode); RtlPromoteAvlTreeNode(ChildNode);
/* Now the child has the opposite weight of the node */ /* Now the child has the opposite weight of the node */
RtlSetBalance(ChildNode, -Balance); RtlSetBalance(ChildNode, -Balance);
/* This only happens on deletion, so we return TRUE to terminate the delete */ /* This only happens on deletion, so we return TRUE to terminate the delete */
return TRUE; return TRUE;
} }
void
FORCEINLINE
Indent(ULONG Level)
{
while (Level--)
{
DbgPrint(" ");
}
}
VOID
FORCEINLINE
DbgDumpAvlNodes(
PRTL_BALANCED_LINKS Node,
ULONG Level)
{
#ifdef PRTL_BALANCED_LINKS
if (Level == 0)
{
DbgPrint("++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
DbgPrint("Root = %p\n", Node);
}
Indent(Level+1); DbgPrint("LetChid = %p", Node->LeftChild);
if (Node->LeftChild)
{
DbgPrint("(%lx, %lx)\n", Node->LeftChild->StartingVpn,Node->LeftChild->EndingVpn);
DbgDumpAvlNodes(Node->LeftChild, Level+1);
}
else DbgPrint("\n");
Indent(Level+1); DbgPrint("RightChild = %p\n", Node->RightChild);
if (Node->RightChild)
{
DbgPrint("(%lx, %lx)\n", Node->RightChild->StartingVpn,Node->RightChild->EndingVpn);
DbgDumpAvlNodes(Node->RightChild, Level+1);
}
#endif
}
VOID VOID
FORCEINLINE FORCEINLINE
RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table, RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
@ -211,7 +251,7 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
IN OUT TABLE_SEARCH_RESULT SearchResult) IN OUT TABLE_SEARCH_RESULT SearchResult)
{ {
CHAR Balance; CHAR Balance;
/* Initialize the new inserted element */ /* Initialize the new inserted element */
MI_ASSERT(SearchResult != TableFoundNode); MI_ASSERT(SearchResult != TableFoundNode);
NewNode->LeftChild = NewNode->RightChild = NULL; NewNode->LeftChild = NewNode->RightChild = NULL;
@ -225,8 +265,15 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
/* This is the new root node */ /* This is the new root node */
RtlInsertAsRightChildAvl(&Table->BalancedRoot, NewNode); RtlInsertAsRightChildAvl(&Table->BalancedRoot, NewNode);
//MI_ASSERT(RtlBalance(NewNode) == RtlBalancedAvlTree); //MI_ASSERT(RtlBalance(NewNode) == RtlBalancedAvlTree);
if (RtlBalance(NewNode) != RtlBalancedAvlTree) DPRINT1("Warning: Root node unbalanced?\n"); if (RtlBalance(NewNode) != RtlBalancedAvlTree)
{
DPRINT1("Warning: Root node unbalanced?\n");
DbgDumpAvlNodes(&Table->BalancedRoot, 0);
#ifdef PRTL_BALANCED_LINKS
KeRosDumpStackFrames(NULL, 0);
#endif
}
/* On AVL trees, we also update the depth */ /* On AVL trees, we also update the depth */
ASSERT(Table->DepthOfTree == 0); ASSERT(Table->DepthOfTree == 0);
Table->DepthOfTree = 1; Table->DepthOfTree = 1;
@ -245,7 +292,14 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
/* Little cheat to save on loop processing, taken from Timo */ /* Little cheat to save on loop processing, taken from Timo */
//MI_ASSERT(RtlBalance(NewNode) == RtlBalancedAvlTree); //MI_ASSERT(RtlBalance(NewNode) == RtlBalancedAvlTree);
if (RtlBalance(NewNode) != RtlBalancedAvlTree) DPRINT1("Warning: Root node unbalanced?\n"); if (RtlBalance(NewNode) != RtlBalancedAvlTree)
{
DPRINT1("Warning: Root node unbalanced?\n");
DbgDumpAvlNodes(&Table->BalancedRoot, 0);
#ifdef PRTL_BALANCED_LINKS
KeRosDumpStackFrames(NULL, 0);
#endif
}
RtlSetBalance(&Table->BalancedRoot, RtlLeftHeavyAvlTree); RtlSetBalance(&Table->BalancedRoot, RtlLeftHeavyAvlTree);
/* /*
@ -258,13 +312,13 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
{ {
/* Calculate which side to balance on */ /* Calculate which side to balance on */
Balance = RtlIsLeftChildAvl(NewNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree; Balance = RtlIsLeftChildAvl(NewNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
/* Check if the parent node was balanced */ /* Check if the parent node was balanced */
if (RtlBalance(NodeOrParent) == RtlBalancedAvlTree) if (RtlBalance(NodeOrParent) == RtlBalancedAvlTree)
{ {
/* It's not balanced anymore (heavy on one side) */ /* It's not balanced anymore (heavy on one side) */
RtlSetBalance(NodeOrParent, Balance); RtlSetBalance(NodeOrParent, Balance);
/* Move up */ /* Move up */
NewNode = NodeOrParent; NewNode = NodeOrParent;
NodeOrParent = RtlParentAvl(NodeOrParent); NodeOrParent = RtlParentAvl(NodeOrParent);
@ -273,14 +327,14 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
{ {
/* The parent's balance is opposite, so the tree is balanced now */ /* The parent's balance is opposite, so the tree is balanced now */
RtlSetBalance(NodeOrParent, RtlBalancedAvlTree); RtlSetBalance(NodeOrParent, RtlBalancedAvlTree);
/* Check if this is the root (the cheat applied earlier gets us here) */ /* Check if this is the root (the cheat applied earlier gets us here) */
if (RtlBalance(&Table->BalancedRoot) == RtlBalancedAvlTree) if (RtlBalance(&Table->BalancedRoot) == RtlBalancedAvlTree)
{ {
/* The depth has thus increased */ /* The depth has thus increased */
Table->DepthOfTree++; Table->DepthOfTree++;
} }
/* We reached the root or a balanced node, so we're done */ /* We reached the root or a balanced node, so we're done */
break; break;
} }
@ -301,10 +355,10 @@ RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
PRTL_BALANCED_LINKS DeleteNode = NULL, ParentNode; PRTL_BALANCED_LINKS DeleteNode = NULL, ParentNode;
PRTL_BALANCED_LINKS *Node1, *Node2; PRTL_BALANCED_LINKS *Node1, *Node2;
CHAR Balance; CHAR Balance;
/* Take one of the children if possible */ /* Take one of the children if possible */
if (!(RtlLeftChildAvl(Node)) || !(RtlRightChildAvl(Node))) DeleteNode = Node; if (!(RtlLeftChildAvl(Node)) || !(RtlRightChildAvl(Node))) DeleteNode = Node;
/* Otherwise, check if one side is longer */ /* Otherwise, check if one side is longer */
if (!(DeleteNode) && (RtlBalance(Node) >= RtlBalancedAvlTree)) if (!(DeleteNode) && (RtlBalance(Node) >= RtlBalancedAvlTree))
{ {
@ -316,34 +370,34 @@ RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
{ {
/* Pick the predecessor which will be the longest side in this case */ /* Pick the predecessor which will be the longest side in this case */
DeleteNode = RtlLeftChildAvl(Node); DeleteNode = RtlLeftChildAvl(Node);
while (RtlRightChildAvl(DeleteNode)) DeleteNode = RtlRightChildAvl(DeleteNode); while (RtlRightChildAvl(DeleteNode)) DeleteNode = RtlRightChildAvl(DeleteNode);
} }
/* Get the parent node */ /* Get the parent node */
ParentNode = RtlParentAvl(DeleteNode); ParentNode = RtlParentAvl(DeleteNode);
DPRINT("Parent: %p\n", ParentNode); DPRINT("Parent: %p\n", ParentNode);
/* Pick which now to use based on whether or not we have a left child */ /* Pick which now to use based on whether or not we have a left child */
Node1 = RtlLeftChildAvl(DeleteNode) ? &DeleteNode->LeftChild : &DeleteNode->RightChild; Node1 = RtlLeftChildAvl(DeleteNode) ? &DeleteNode->LeftChild : &DeleteNode->RightChild;
DPRINT("Node 1: %p %p\n", Node1, *Node1); DPRINT("Node 1: %p %p\n", Node1, *Node1);
/* Pick which node to swap based on if we're already a left child or not */ /* Pick which node to swap based on if we're already a left child or not */
Node2 = RtlIsLeftChildAvl(DeleteNode) ? &ParentNode->LeftChild : &ParentNode->RightChild; Node2 = RtlIsLeftChildAvl(DeleteNode) ? &ParentNode->LeftChild : &ParentNode->RightChild;
DPRINT("Node 2: %p %p\n", Node2, *Node2); DPRINT("Node 2: %p %p\n", Node2, *Node2);
/* Pick the correct balance depending on which side will get heavier */ /* Pick the correct balance depending on which side will get heavier */
Balance = RtlIsLeftChildAvl(DeleteNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree; Balance = RtlIsLeftChildAvl(DeleteNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
DPRINT("Balance: %lx\n", Balance); DPRINT("Balance: %lx\n", Balance);
/* Swap the children nodes, making one side heavier */ /* Swap the children nodes, making one side heavier */
*Node2 = *Node1; *Node2 = *Node1;
/* If the node has a child now, update its parent */ /* If the node has a child now, update its parent */
if (*Node1) RtlSetParent(*Node1, ParentNode); if (*Node1) RtlSetParent(*Node1, ParentNode);
/* Assume balanced root for loop optimization */ /* Assume balanced root for loop optimization */
RtlSetBalance(&Table->BalancedRoot, RtlBalancedAvlTree); RtlSetBalance(&Table->BalancedRoot, RtlBalancedAvlTree);
/* Loop up the tree by parents */ /* Loop up the tree by parents */
while (TRUE) while (TRUE)
{ {
@ -374,7 +428,7 @@ RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
/* Choose which balance factor to use based on which side we're on */ /* Choose which balance factor to use based on which side we're on */
Balance = RtlIsRightChild(ParentNode) ? Balance = RtlIsRightChild(ParentNode) ?
RtlRightHeavyAvlTree : RtlLeftHeavyAvlTree; RtlRightHeavyAvlTree : RtlLeftHeavyAvlTree;
/* Iterate up the tree */ /* Iterate up the tree */
ParentNode = RtlParentAvl(ParentNode); ParentNode = RtlParentAvl(ParentNode);
} }
@ -384,7 +438,7 @@ RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
/* Copy the deleted node itself */ /* Copy the deleted node itself */
RtlpCopyAvlNodeData(DeleteNode, Node); RtlpCopyAvlNodeData(DeleteNode, Node);
/* Pick the right node to unlink */ /* Pick the right node to unlink */
Node1 = RtlIsLeftChildAvl(Node) ? Node1 = RtlIsLeftChildAvl(Node) ?
&(RtlParentAvl(DeleteNode))->LeftChild : &(RtlParentAvl(DeleteNode))->RightChild; &(RtlParentAvl(DeleteNode))->LeftChild : &(RtlParentAvl(DeleteNode))->RightChild;