mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 11:46:50 +00:00
- Implement a linear search in CmpFindSubKeyInRoot (until cells are stored in a lexically sorted way).
- Implement Leaf->Root index conversion (leaf selecting algorithm, splitting the leaf if necessary). See issue #3418 for more details. svn path=/trunk/; revision=36053
This commit is contained in:
parent
c63c067562
commit
73f4cc9691
1 changed files with 387 additions and 6 deletions
|
@ -145,13 +145,12 @@ CmpFindSubKeyInRoot(IN PHHIVE Hive,
|
|||
IN PCUNICODE_STRING SearchName,
|
||||
IN PHCELL_INDEX SubKey)
|
||||
{
|
||||
ULONG High, Low = 0, i, ReturnIndex;
|
||||
ULONG High, Low = 0, i = 0, ReturnIndex;
|
||||
HCELL_INDEX LeafCell;
|
||||
PCM_KEY_INDEX Leaf;
|
||||
LONG Result;
|
||||
|
||||
/* Verify Index for validity */
|
||||
ASSERTMSG("We don't do a linear search yet!\n", FALSE);
|
||||
ASSERT(Index->Count != 0);
|
||||
ASSERT(Index->Signature == CM_KEY_INDEX_ROOT);
|
||||
|
||||
|
@ -160,7 +159,9 @@ CmpFindSubKeyInRoot(IN PHHIVE Hive,
|
|||
while (TRUE)
|
||||
{
|
||||
/* Choose next entry */
|
||||
#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
|
||||
i = ((High - Low) / 2) + Low;
|
||||
#endif
|
||||
|
||||
/* Get the leaf cell and then the leaf itself */
|
||||
LeafCell = Index->List[i];
|
||||
|
@ -190,6 +191,7 @@ CmpFindSubKeyInRoot(IN PHHIVE Hive,
|
|||
goto Return;
|
||||
}
|
||||
|
||||
#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
|
||||
/* Check for negative result */
|
||||
if (Result < 0)
|
||||
{
|
||||
|
@ -228,6 +230,7 @@ CmpFindSubKeyInRoot(IN PHHIVE Hive,
|
|||
/* Update the base to this index, since we know it's not lower. */
|
||||
Low = i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -242,6 +245,16 @@ Big:
|
|||
|
||||
/* Release the leaf cell */
|
||||
HvReleaseCell(Hive, LeafCell);
|
||||
|
||||
#ifndef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
|
||||
/* Go to the next index, and return failure if we reach the end */
|
||||
if (++i > High)
|
||||
{
|
||||
/* Return failure */
|
||||
*SubKey = HCELL_NIL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure we got here for the right reasons */
|
||||
|
@ -1116,6 +1129,366 @@ CmpAddToLeaf(IN PHHIVE Hive,
|
|||
return NewCell;
|
||||
}
|
||||
|
||||
HCELL_INDEX
|
||||
NTAPI
|
||||
CmpSplitLeaf(IN PHHIVE Hive,
|
||||
IN HCELL_INDEX RootCell,
|
||||
IN ULONG RootSelect,
|
||||
IN HSTORAGE_TYPE Type)
|
||||
{
|
||||
PCM_KEY_INDEX IndexKey, LeafKey, NewKey;
|
||||
PCM_KEY_FAST_INDEX FastLeaf;
|
||||
HCELL_INDEX LeafCell, NewCell;
|
||||
ULONG FirstHalf, LastHalf;
|
||||
ULONG EntrySize, TotalSize;
|
||||
|
||||
/* Get the cell */
|
||||
IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell);
|
||||
|
||||
/* Check if we've got valid IndexKey */
|
||||
if (!IndexKey) return HCELL_NIL;
|
||||
|
||||
/* Get the leaf cell and key */
|
||||
LeafCell = IndexKey->List[RootSelect];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Check if we've got valid LeafKey */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* We are going to divide this leaf into two halves */
|
||||
FirstHalf = (LeafKey->Count / 2);
|
||||
LastHalf = LeafKey->Count - FirstHalf;
|
||||
|
||||
/* Now check what kind of hive we're dealing with,
|
||||
* and compute entry size
|
||||
*/
|
||||
if (Hive->Version >= 5)
|
||||
{
|
||||
/* XP Hive: Use hash leaf */
|
||||
ASSERT(LeafKey->Signature == CM_KEY_HASH_LEAF);
|
||||
EntrySize = sizeof(CM_INDEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use index leaf */
|
||||
ASSERT(LeafKey->Signature == CM_KEY_INDEX_LEAF);
|
||||
EntrySize = sizeof(HCELL_INDEX);
|
||||
}
|
||||
|
||||
/* Compute the total size */
|
||||
TotalSize = (EntrySize * LastHalf) + FIELD_OFFSET(CM_KEY_INDEX, List) + 1;
|
||||
|
||||
/* Mark the leaf cell dirty */
|
||||
HvMarkCellDirty(Hive, LeafCell, FALSE);
|
||||
|
||||
/* Make sure its type is the same */
|
||||
ASSERT(HvGetCellType(LeafCell) == Type);
|
||||
|
||||
/* Allocate the cell, fail in case of error */
|
||||
NewCell = HvAllocateCell(Hive, TotalSize, Type, LeafCell);
|
||||
if (NewCell == HCELL_NIL) return NewCell;
|
||||
|
||||
/* Get the key */
|
||||
NewKey = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell);
|
||||
if (!NewKey)
|
||||
{
|
||||
/* Free the cell and exit - should not happen! */
|
||||
ASSERT(FALSE);
|
||||
HvFreeCell(Hive, NewCell);
|
||||
return HCELL_NIL;
|
||||
}
|
||||
|
||||
/* Release the newly created cell */
|
||||
HvReleaseCell(Hive, NewCell);
|
||||
|
||||
/* Set its signature according to the version of the hive */
|
||||
if (Hive->Version >= 5)
|
||||
{
|
||||
/* XP Hive: Use hash leaf signature */
|
||||
NewKey->Signature = CM_KEY_HASH_LEAF;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use index leaf signature */
|
||||
NewKey->Signature = CM_KEY_INDEX_LEAF;
|
||||
}
|
||||
|
||||
/* Calculate the size of the free entries in the root key */
|
||||
TotalSize = HvGetCellSize(Hive, IndexKey) -
|
||||
(IndexKey->Count * sizeof(HCELL_INDEX)) -
|
||||
FIELD_OFFSET(CM_KEY_INDEX, List);
|
||||
|
||||
/* Check if we're out of space */
|
||||
if (TotalSize / sizeof(HCELL_INDEX) < 1)
|
||||
{
|
||||
/* Grow the leaf by one more entry */
|
||||
TotalSize = HvGetCellSize(Hive, IndexKey) + sizeof(HCELL_INDEX);
|
||||
|
||||
/* Re-allocate the root */
|
||||
RootCell = HvReallocateCell(Hive, RootCell, TotalSize);
|
||||
if (RootCell == HCELL_NIL)
|
||||
{
|
||||
/* Free the cell and exit */
|
||||
HvFreeCell(Hive, NewCell);
|
||||
return HCELL_NIL;
|
||||
}
|
||||
|
||||
/* Get the leaf cell */
|
||||
IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell);
|
||||
if (!IndexKey)
|
||||
{
|
||||
/* This shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
return HCELL_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Splitting is done, now we need to copy the contents,
|
||||
* according to the hive version
|
||||
*/
|
||||
if (Hive->Version >= 5)
|
||||
{
|
||||
/* Copy the fast indexes */
|
||||
FastLeaf = (PCM_KEY_FAST_INDEX)LeafKey;
|
||||
RtlMoveMemory(&NewKey->List[0],
|
||||
&FastLeaf->List[FirstHalf],
|
||||
LastHalf * EntrySize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the indexes themselves */
|
||||
RtlMoveMemory(&NewKey->List[0],
|
||||
&LeafKey->List[FirstHalf],
|
||||
LastHalf * EntrySize);
|
||||
}
|
||||
|
||||
/* Shift the data inside the root key */
|
||||
if (RootSelect < (IndexKey->Count - 1))
|
||||
{
|
||||
RtlMoveMemory(&IndexKey->List[RootSelect + 2],
|
||||
&IndexKey->List[RootSelect + 1],
|
||||
IndexKey->Count -
|
||||
(RootSelect + 1) * sizeof(HCELL_INDEX));
|
||||
}
|
||||
|
||||
/* Make sure both old and new computed counts are valid */
|
||||
ASSERT(FirstHalf != 0);
|
||||
ASSERT(LastHalf != 0);
|
||||
|
||||
/* Update the count value of old and new keys */
|
||||
LeafKey->Count = FirstHalf;
|
||||
NewKey->Count = LastHalf;
|
||||
|
||||
/* Increase the count value of the root key */
|
||||
IndexKey->Count++;
|
||||
|
||||
/* Set the new cell in root's list */
|
||||
IndexKey->List[RootSelect + 1] = NewCell;
|
||||
|
||||
/* Return the root cell */
|
||||
return RootCell;
|
||||
}
|
||||
|
||||
HCELL_INDEX
|
||||
NTAPI
|
||||
CmpSelectLeaf(IN PHHIVE Hive,
|
||||
IN PCM_KEY_NODE KeyNode,
|
||||
IN PUNICODE_STRING Name,
|
||||
IN HSTORAGE_TYPE Type,
|
||||
IN PHCELL_INDEX *RootCell)
|
||||
{
|
||||
PCM_KEY_INDEX IndexKey, LeafKey;
|
||||
PCM_KEY_FAST_INDEX FastLeaf;
|
||||
HCELL_INDEX LeafCell, CurrentCell;
|
||||
ULONG SubKeyIndex;
|
||||
LONG Result;
|
||||
|
||||
/* Mark it as dirty */
|
||||
HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Type], FALSE);
|
||||
|
||||
/* Get the cell */
|
||||
IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]);
|
||||
|
||||
/* Check if we've got a valid key */
|
||||
if (!IndexKey)
|
||||
{
|
||||
/* Should not happen! */
|
||||
ASSERTMSG("IndexKey = NULL!, it should not happen!\n", FALSE);
|
||||
return HCELL_NIL;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
ASSERT(IndexKey->Signature == CM_KEY_INDEX_ROOT);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
/* Find subkey */
|
||||
SubKeyIndex = CmpFindSubKeyInRoot(Hive, IndexKey, Name, &LeafCell);
|
||||
|
||||
/* Make sure we found something valid */
|
||||
if (SubKeyIndex & 0x80000000) return HCELL_NIL;
|
||||
|
||||
/* Try to fit it into the LeafCell, if it was found */
|
||||
if (LeafCell != HCELL_NIL)
|
||||
{
|
||||
/* Get the leaf key */
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Check for failure */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Check if it fits into this leaf and break */
|
||||
if (LeafKey->Count < CmpMaxIndexPerHblock)
|
||||
{
|
||||
/* Fill in the result and return it */
|
||||
*RootCell = &IndexKey->List[SubKeyIndex];
|
||||
return LeafCell;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the leaf cell at the very end */
|
||||
LeafCell = IndexKey->List[SubKeyIndex];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Return an error in case of problems */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Choose the cell to search from depending on the key type */
|
||||
if ((LeafKey->Signature == CM_KEY_FAST_LEAF) ||
|
||||
(LeafKey->Signature == CM_KEY_HASH_LEAF))
|
||||
{
|
||||
FastLeaf = (PCM_KEY_FAST_INDEX)LeafKey;
|
||||
CurrentCell = FastLeaf->List[0].Cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure it's an index leaf */
|
||||
ASSERT(LeafKey->Signature == CM_KEY_INDEX_LEAF);
|
||||
CurrentCell = LeafKey->List[0];
|
||||
}
|
||||
|
||||
/* Do a name compare */
|
||||
Result = CmpDoCompareKeyName(Hive, Name, CurrentCell);
|
||||
|
||||
/* Check for failure */
|
||||
if (Result == 2) return HCELL_NIL;
|
||||
|
||||
/* Names can't be equal, ensure that */
|
||||
ASSERT(Result != 0);
|
||||
|
||||
/* Check if it's above */
|
||||
if (Result >= 0)
|
||||
{
|
||||
/* Get the first cell in the index */
|
||||
LeafCell = IndexKey->List[0];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Return an error in case of problems */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Check if it fits into this leaf and break */
|
||||
if (LeafKey->Count < CmpMaxIndexPerHblock)
|
||||
{
|
||||
/* Fill in the result and return the cell */
|
||||
*RootCell = &IndexKey->List[SubKeyIndex + 1];
|
||||
return LeafCell;
|
||||
}
|
||||
|
||||
/* No, it doesn't fit, check the other leaf */
|
||||
if (SubKeyIndex < (IndexKey->Count - 1))
|
||||
{
|
||||
/* Yes, there is space */
|
||||
LeafCell = IndexKey->List[SubKeyIndex + 1];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Return an error in case of problems */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Check if it fits and break */
|
||||
if (LeafKey->Count < CmpMaxIndexPerHblock)
|
||||
{
|
||||
/* Fill in the result and return the cell */
|
||||
*RootCell = &IndexKey->List[SubKeyIndex + 1];
|
||||
return LeafCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, it's below, check the subkey index */
|
||||
if (SubKeyIndex > 0)
|
||||
{
|
||||
/* There should be space at the leaf one before that */
|
||||
LeafCell = IndexKey->List[SubKeyIndex - 1];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Return an error in case of problems */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Check if it fits and break */
|
||||
if (LeafKey->Count < CmpMaxIndexPerHblock)
|
||||
{
|
||||
/* Decrement the subkey index */
|
||||
SubKeyIndex--;
|
||||
|
||||
/* Fill in the result and return the cell */
|
||||
*RootCell = &IndexKey->List[SubKeyIndex];
|
||||
return LeafCell;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the first leaf, if possible */
|
||||
LeafCell = IndexKey->List[0];
|
||||
LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||
|
||||
/* Return an error in case of problems */
|
||||
if (!LeafKey) return HCELL_NIL;
|
||||
|
||||
/* Check if it fits and break */
|
||||
if (LeafKey->Count < CmpMaxIndexPerHblock)
|
||||
{
|
||||
/* Fill in the result and return the cell */
|
||||
*RootCell = &IndexKey->List[0];
|
||||
return LeafCell;
|
||||
}
|
||||
}
|
||||
|
||||
/* It didn't fit into either, so proceed to splitting */
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to split */
|
||||
CurrentCell = CmpSplitLeaf(Hive,
|
||||
KeyNode->SubKeyLists[Type],
|
||||
SubKeyIndex,
|
||||
Type);
|
||||
|
||||
/* Return failure in case splitting failed */
|
||||
if (CurrentCell == HCELL_NIL) return CurrentCell;
|
||||
|
||||
/* Set the SubKeyLists value with the new key */
|
||||
KeyNode->SubKeyLists[Type] = CurrentCell;
|
||||
|
||||
/* Get the new cell */
|
||||
IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]);
|
||||
|
||||
/* Return in case of failure */
|
||||
if (!IndexKey) return HCELL_NIL;
|
||||
|
||||
/* Make sure the new key became index root */
|
||||
ASSERT(IndexKey->Signature == CM_KEY_INDEX_ROOT);
|
||||
|
||||
/* Now loop over with the new IndexKey value, which definately
|
||||
* has the space now
|
||||
*/
|
||||
}
|
||||
|
||||
/* Shouldn't come here */
|
||||
return HCELL_NIL;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CmpAddSubKey(IN PHHIVE Hive,
|
||||
|
@ -1253,7 +1626,7 @@ CmpAddSubKey(IN PHHIVE Hive,
|
|||
/* Convert */
|
||||
OldIndex = (PCM_KEY_FAST_INDEX)Index;
|
||||
|
||||
for (i=0; i < OldIndex->Count; i++)
|
||||
for (i = 0; i < OldIndex->Count; i++)
|
||||
{
|
||||
Index->List[i] = OldIndex->List[i].Cell;
|
||||
}
|
||||
|
@ -1299,9 +1672,17 @@ CmpAddSubKey(IN PHHIVE Hive,
|
|||
/* Check if we turned the index into a root */
|
||||
if (Index->Signature == CM_KEY_INDEX_ROOT)
|
||||
{
|
||||
/* Not handled yet */
|
||||
DPRINT1("Leaf->Root Index Conversion not yet implemented!\n");
|
||||
ASSERT(FALSE);
|
||||
DPRINT("Leaf->Root Index Conversion\n");
|
||||
|
||||
/* Get the leaf where to add the new entry (the routine will do
|
||||
* the splitting if necessary)
|
||||
*/
|
||||
LeafCell = CmpSelectLeaf(Hive, KeyNode, &Name, Type, &RootPointer);
|
||||
if (LeafCell == HCELL_NIL)
|
||||
{
|
||||
/* Not handled */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add our leaf cell */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue