Exemple #1
0
 private void SetIndexNode(IndexNode AIndexNode)
 {
     // This implements crabbing, because the new node is locked before the old node lock is released
     if (FIndexNode != null)
     {
         FIndexNode.Dispose();
     }
     FIndexNode = AIndexNode;
 }
Exemple #2
0
 /// <summary>Create is only called once to create a new stored instance of the index.</summary>
 public void Create(ServerProcess AProcess)
 {
     using (IndexNode LIndexNode = AllocateNode(AProcess, IndexNodeType.Data))
     {
         FRootID = LIndexNode.StreamID;
         FHeadID = FRootID;
         FTailID = FRootID;
         FHeight = 1;
     }
 }
Exemple #3
0
        private bool FindIndexKey(Stream AKey, object ACompareContext, out IndexNode AIndexNode, out int AEntryNumber)
        {
            SearchPath LSearchPath = new SearchPath();

            try
            {
                bool LResult = FAccessPath.FindKey(FProcess, AKey, ACompareContext, LSearchPath, out AEntryNumber);
                AIndexNode = LSearchPath.DisownAt(LSearchPath.Count - 1);
                return(LResult);
            }
            finally
            {
                LSearchPath.Dispose();
            }
        }
Exemple #4
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 #5
0
        public void Last()
        {
            CheckActive();

            FEOF = true;
            FBOF = false;
            bool LResult = false;

            if (FLastKey != null)
            {
                IndexNode LIndexNode;
                LResult = FindIndexKey(FLastKey.Stream, FLastKey.DataType, out LIndexNode, out FEntryNumber);
                SetIndexNode(LIndexNode);
            }
            else
            {
                if (FDirection == ScanDirection.Forward)
                {
                    SetIndexNode(new IndexNode(FProcess, FAccessPath, FAccessPath.TailID));
                    FEntryNumber = FIndexNode.EntryCount - 1;
                }
                else
                {
                    SetIndexNode(new IndexNode(FProcess, FAccessPath, FAccessPath.HeadID));
                    FEntryNumber = 0;
                }
            }

            if (!LResult)
            {
                // Determine FBOF
                IndexNode LSaveIndexNode   = new IndexNode(FProcess, FIndexNode.Index, FIndexNode.StreamID);
                int       LSaveEntryNumber = FEntryNumber;
                Prior();
                FEOF = true;
                if (FIndexNode != null)
                {
                    FIndexNode.Dispose();
                }
                FIndexNode   = LSaveIndexNode;
                FEntryNumber = LSaveEntryNumber;
            }
        }
Exemple #6
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;
                }
            }
        }