Exemple #1
0
        /// <summary>
        /// The recursive portion of the find key algorithm invoked by the FindKey method of the parent Index.
        /// </summary>
        public bool FindKey(Stream AKey, object ACompareContext, SearchPath ASearchPath, out int AEntryNumber)
        {
            ASearchPath.Add(this);
            if (NodeType == IndexNodeType.Routing)
            {
                // Perform a binary search among the keys in this node to determine which streamid to follow for the next node
                bool LResult = NodeSearch(AKey, ACompareContext, out AEntryNumber);

                // If the key was found, use the given entry number, otherwise, use the one before the given entry
                AEntryNumber = LResult ? AEntryNumber : (AEntryNumber - 1);
                return
                    (new IndexNode
                     (
                         FProcess,
                         FIndex,
                         IndexUtility.GetStreamID(Data(AEntryNumber), 0)
                     ).FindKey
                     (
                         AKey,
                         ACompareContext,
                         ASearchPath,
                         out AEntryNumber
                     ));
            }
            else
            {
                // Perform a binary search among the keys in this node to determine which entry, if any, is equal to the given key
                return(NodeSearch(AKey, ACompareContext, out AEntryNumber));
            }
        }
Exemple #2
0
        private void DeallocateNode(ServerProcess AProcess, StreamID AStreamID)
        {
            using (IndexNode LIndexNode = new IndexNode(AProcess, this, AStreamID))
            {
                for (int LEntryIndex = LIndexNode.EntryCount - 1; LEntryIndex >= 0; LEntryIndex--)
                {
                    if (LIndexNode.NodeType == IndexNodeType.Routing)
                    {
                        if (LEntryIndex > 0)
                        {
                            DisposeKey(AProcess, LIndexNode.Key(LEntryIndex));
                        }
                        DeallocateNode(AProcess, IndexUtility.GetStreamID(LIndexNode.Data(LEntryIndex), 0));
                    }
                    else
                    {
                        DisposeKey(AProcess, LIndexNode.Key(LEntryIndex));
                        DisposeData(AProcess, LIndexNode.Data(LEntryIndex));

                        if (LIndexNode.NextNode == StreamID.Null)
                        {
                            FTailID = LIndexNode.PriorNode;
                        }
                        else
                        {
                            using (IndexNode LNextNode = new IndexNode(AProcess, this, LIndexNode.NextNode))
                            {
                                LNextNode.PriorNode = LIndexNode.PriorNode;
                            }
                        }

                        if (LIndexNode.PriorNode == StreamID.Null)
                        {
                            FHeadID = LIndexNode.NextNode;
                        }
                        else
                        {
                            using (IndexNode LPriorNode = new IndexNode(AProcess, this, LIndexNode.PriorNode))
                            {
                                LPriorNode.NextNode = LIndexNode.NextNode;
                            }
                        }
                    }
                }
            }

            AProcess.StreamManager.Deallocate(AStreamID);
        }
Exemple #3
0
        private unsafe void InternalInsert(ServerProcess AProcess, SearchPath ASearchPath, int AEntryNumber, Stream AKey, Stream AData)
        {
            // Walk back up the search path, inserting data and splitting pages as necessary
            IndexNode LNewIndexNode;

            for (int LIndex = ASearchPath.Count - 1; LIndex >= 0; LIndex--)
            {
                if (ASearchPath[LIndex].EntryCount >= ASearchPath[LIndex].MaxEntries)
                {
                    // Allocate a new node
                    using (LNewIndexNode = AllocateNode(AProcess, ASearchPath[LIndex].NodeType))
                    {
                        // Thread it into the list of leaves, if necessary
                        if (LNewIndexNode.NodeType == IndexNodeType.Data)
                        {
                            LNewIndexNode.PriorNode      = ASearchPath[LIndex].StreamID;
                            LNewIndexNode.NextNode       = ASearchPath[LIndex].NextNode;
                            ASearchPath[LIndex].NextNode = LNewIndexNode.StreamID;
                            if (LNewIndexNode.NextNode == StreamID.Null)
                            {
                                FTailID = LNewIndexNode.StreamID;
                            }
                            else
                            {
                                using (IndexNode LNextIndexNode = new IndexNode(AProcess, this, LNewIndexNode.NextNode))
                                {
                                    LNextIndexNode.PriorNode = LNewIndexNode.StreamID;
                                }
                            }
                        }

                        // Insert the upper half of the entries from ASearchPath[LIndex] into the new index node
                        int LEntryCount = ASearchPath[LIndex].EntryCount;
                        int LEntryPivot = LEntryCount / 2;
                        for (int LEntryIndex = LEntryPivot; LEntryIndex < LEntryCount; LEntryIndex++)
                        {
                            LNewIndexNode.InternalInsert(ASearchPath[LIndex].Key(LEntryIndex), ASearchPath[LIndex].Data(LEntryIndex), LEntryIndex - LEntryPivot);                             // The internal call prevents the RowsMoved event from being fired
                        }
                        // Remove the upper half of the entries from ASearchPath[LIndex]
                        for (int LEntryIndex = LEntryCount - 1; LEntryIndex >= LEntryPivot; LEntryIndex--)
                        {
                            ASearchPath[LIndex].InternalDelete(LEntryIndex);                             // The internal call prevents the data inside from being passed to the DisposeXXX methods, and prevents the RowDeleted event from being fired
                        }
                        // Notify index clients of the data change
                        RowsMoved(ASearchPath[LIndex].StreamID, LEntryPivot, LEntryCount - 1, LNewIndexNode.StreamID, -LEntryPivot);

                        // Insert the new entry into the appropriate node
                        if (AEntryNumber >= LEntryPivot)
                        {
                            LNewIndexNode.Insert(AKey, AData, AEntryNumber - LEntryPivot);
                        }
                        else
                        {
                            ASearchPath[LIndex].Insert(AKey, AData, AEntryNumber);
                        }

                        // Reset the AKey, AData and AEntryNumber variables for the next round
                        // The key for the entry one level up is the first key for the newly allocated node
                        AKey = new MemoryStream(KeyLength);
                        AKey.SetLength(KeyLength);
                        CopyKey(AProcess, LNewIndexNode.Key(0), AKey);

                        // The data is the StreamID of the newly allocated node
                        AData = new MemoryStream(sizeof(StreamID));
                        IndexUtility.SetStreamID(AData, 0, LNewIndexNode.StreamID);
                    }

                    if (LIndex == 0)
                    {
                        // Allocate a new root node and grow the height of the tree by 1
                        using (LNewIndexNode = AllocateNode(AProcess, IndexNodeType.Routing))
                        {
                            LNewIndexNode.Insert(AKey, AData, 0);
                            AKey = new MemoryStream(KeyLength);
                            AKey.SetLength(KeyLength);
                            AData = new MemoryStream(DataLength);
                            AData.SetLength(KeyLength);
                            IndexUtility.SetStreamID(AData, 0, ASearchPath[LIndex].StreamID);
                            LNewIndexNode.Insert(AKey, AData, 0);
                            FRootID = LNewIndexNode.StreamID;
                            FHeight++;
                        }
                    }
                    else
                    {
                        bool LResult = ASearchPath[LIndex - 1].NodeSearch(AKey, null, out AEntryNumber);
                        // At this point we should be guaranteed to have a routing key which does not exist in the parent node
                        if (LResult)
                        {
                            throw new IndexException(IndexException.Codes.DuplicateRoutingKey);
                        }
                    }
                }
                else
                {
                    ASearchPath[LIndex].Insert(AKey, AData, AEntryNumber);
                    break;
                }
            }
        }