Beispiel #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));
            }
        }
Beispiel #2
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();
            }
        }
Beispiel #3
0
        // TODO: Asynchronous collapsed node recovery
        /// <summary>Deletes the entry given by AKey.  The streams are disposed through the DisposeKey event, so it is the responsibility of the index user to dispose references within the streams.</summary>
        public void Delete(ServerProcess AProcess, Stream AKey)
        {
            int LEntryNumber;

            using (SearchPath LSearchPath = new SearchPath())
            {
                bool LResult = FindKey(AProcess, AKey, null, LSearchPath, out LEntryNumber);
                if (!LResult)
                {
                    throw new IndexException(IndexException.Codes.KeyNotFound);
                }

                InternalDelete(AProcess, LSearchPath, LEntryNumber);
            }
        }
Beispiel #4
0
        /// <summary>
        /// The given streams are copied into the index, so references within the streams
        /// are considered owned by the index after the insert.
        /// </summary>
        public void Insert(ServerProcess AProcess, Stream AKey, Stream AData)
        {
            int LEntryNumber;

            using (SearchPath LSearchPath = new SearchPath())
            {
                bool LResult = FindKey(AProcess, AKey, null, LSearchPath, out LEntryNumber);
                if (LResult)
                {
                    throw new IndexException(IndexException.Codes.DuplicateKey);
                }

                InternalInsert(AProcess, LSearchPath, LEntryNumber, AKey, AData);
            }
        }
Beispiel #5
0
        public void Delete(ServerProcess AProcess, Row ARow)
        {
            // Delete the row from all indexes
            Row LClusteredKey = GetIndexData(AProcess, FClusteredIndex.KeyRowType, new Row[] { ARow });

            try
            {
                using (SearchPath LSearchPath = new SearchPath())
                {
                    int  LEntryNumber;
                    bool LResult = FClusteredIndex.FindKey(AProcess, LClusteredKey.Stream, null, LSearchPath, out LEntryNumber);
                    if (!LResult)
                    {
                        throw new IndexException(IndexException.Codes.KeyNotFound);
                    }

                    Row LClusteredData = AProcess.RowManager.RequestRow(AProcess, FClusteredIndex.DataRowType, LSearchPath.DataNode.Data(LEntryNumber));
                    try
                    {
                        foreach (TableBufferIndex LBufferIndex in Indexes)
                        {
                            if (LBufferIndex != FClusteredIndex)
                            {
                                Row LKey = GetIndexData(AProcess, LBufferIndex.KeyRowType, new Row[] { LClusteredKey, LClusteredData });
                                try
                                {
                                    LBufferIndex.Delete(AProcess, LKey.Stream);
                                }
                                finally
                                {
                                    AProcess.RowManager.ReleaseRow(LKey);
                                }
                            }
                        }
                    }
                    finally
                    {
                        AProcess.RowManager.ReleaseRow(LClusteredData);
                    }
                }

                FClusteredIndex.Delete(AProcess, LClusteredKey.Stream);
            }
            finally
            {
                AProcess.RowManager.ReleaseRow(LClusteredKey);
            }
        }
Beispiel #6
0
        public bool HasRow(ServerProcess AProcess, Row ARow)
        {
            Row LKey = GetIndexData(AProcess, FClusteredIndex.KeyRowType, new Row[] { ARow });

            try
            {
                using (SearchPath LSearchPath = new SearchPath())
                {
                    int LEntryNumber;
                    return(FClusteredIndex.FindKey(AProcess, LKey.Stream, null, LSearchPath, out LEntryNumber));
                }
            }
            finally
            {
                AProcess.RowManager.ReleaseRow(LKey);
            }
        }
Beispiel #7
0
        /// <summary>Updates the entry given by AOldKey to the entry given by ANewKey and ANewData.  If AOldKey == ANewKey, the data for the entry is updated in place, otherwise it is moved to the location given by ANewKey.</summary>
        public void Update(ServerProcess AProcess, Stream AOldKey, Stream ANewKey, Stream ANewData)
        {
            int LEntryNumber;

            using (SearchPath LSearchPath = new SearchPath())
            {
                bool LResult = FindKey(AProcess, AOldKey, null, LSearchPath, out LEntryNumber);
                if (!LResult)
                {
                    throw new IndexException(IndexException.Codes.KeyNotFound);
                }

                if (Compare(AProcess, AOldKey, null, ANewKey, null) == 0)
                {
                    if (ANewData != null)
                    {
                        LSearchPath.DataNode.Update(ANewData, LEntryNumber);
                    }
                }
                else
                {
                    if (ANewData == null)
                    {
                        ANewData = new MemoryStream(DataLength);
                        ANewData.SetLength(DataLength);
                        CopyData(AProcess, LSearchPath.DataNode.Data(LEntryNumber), ANewData);
                    }
                    InternalDelete(AProcess, LSearchPath, LEntryNumber);
                    LSearchPath.Dispose();
                    LResult = FindKey(AProcess, ANewKey, null, LSearchPath, out LEntryNumber);
                    if (LResult)
                    {
                        throw new IndexException(IndexException.Codes.DuplicateKey);
                    }

                    InternalInsert(AProcess, LSearchPath, LEntryNumber, ANewKey, ANewData);
                }
            }
        }
Beispiel #8
0
        public void Update(ServerProcess AProcess, Row AOldRow, Row ANewRow)
        {
            // AOldRow must have at least the columns of the clustered index key
            Row LOldClusteredKey = GetIndexData(AProcess, FClusteredIndex.KeyRowType, new Row[] { AOldRow });

            try
            {
                bool LIsClusteredIndexKeyAffected  = GetIsIndexAffected(FClusteredIndex.KeyRowType, ANewRow);
                bool LIsClusteredIndexDataAffected = GetIsIndexAffected(FClusteredIndex.DataRowType, ANewRow);

                Row LNewClusteredKey  = null;
                Row LNewClusteredData = null;
                try
                {
                    // Update the row in each index
                    using (SearchPath LSearchPath = new SearchPath())
                    {
                        int  LEntryNumber;
                        bool LResult = FClusteredIndex.FindKey(AProcess, LOldClusteredKey.Stream, null, LSearchPath, out LEntryNumber);
                        if (!LResult)
                        {
                            throw new IndexException(IndexException.Codes.KeyNotFound);
                        }

                        Row LOldClusteredData = AProcess.RowManager.RequestRow(AProcess, FClusteredIndex.DataRowType, LSearchPath.DataNode.Data(LEntryNumber));
                        try
                        {
                            bool LIsIndexAffected;
                            foreach (TableBufferIndex LBufferIndex in Indexes)
                            {
                                if (LBufferIndex != FClusteredIndex)
                                {
                                    LIsIndexAffected = GetIsIndexAffected(LBufferIndex.KeyRowType, ANewRow);

                                    if (LIsClusteredIndexKeyAffected || LIsIndexAffected)
                                    {
                                        Row LOldIndexKey = GetIndexData(AProcess, LBufferIndex.KeyRowType, new Row[] { LOldClusteredKey, LOldClusteredData });
                                        try
                                        {
                                            Row LNewIndexKey  = null;
                                            Row LNewIndexData = null;
                                            try
                                            {
                                                if (LIsIndexAffected)
                                                {
                                                    LNewIndexKey = GetIndexData(AProcess, LBufferIndex.KeyRowType, new Row[] { ANewRow, LOldClusteredKey, LOldClusteredData });
                                                }

                                                if (LIsClusteredIndexKeyAffected)
                                                {
                                                    LNewIndexData = GetIndexData(AProcess, LBufferIndex.DataRowType, new Row[] { ANewRow, LOldClusteredKey, LOldClusteredData });
                                                }

                                                if (LIsIndexAffected && LIsClusteredIndexKeyAffected)
                                                {
                                                    LBufferIndex.Update(AProcess, LOldIndexKey.Stream, LNewIndexKey.Stream, LNewIndexData.Stream);
                                                    LNewIndexKey.ValuesOwned  = false;
                                                    LNewIndexData.ValuesOwned = false;
                                                }
                                                else if (LIsIndexAffected)
                                                {
                                                    LBufferIndex.Update(AProcess, LOldIndexKey.Stream, LNewIndexKey.Stream);
                                                    LNewIndexKey.ValuesOwned = false;
                                                }
                                                else if (LIsClusteredIndexKeyAffected)
                                                {
                                                    LBufferIndex.Update(AProcess, LOldIndexKey.Stream, LOldIndexKey.Stream, LNewIndexData.Stream);
                                                    LNewIndexData.ValuesOwned = false;
                                                }
                                            }
                                            finally
                                            {
                                                if (LNewIndexKey != null)
                                                {
                                                    AProcess.RowManager.ReleaseRow(LNewIndexKey);
                                                }

                                                if (LNewIndexData != null)
                                                {
                                                    AProcess.RowManager.ReleaseRow(LNewIndexData);
                                                }
                                            }
                                        }
                                        finally
                                        {
                                            AProcess.RowManager.ReleaseRow(LOldIndexKey);
                                        }
                                    }
                                }
                            }

                            if (LIsClusteredIndexKeyAffected)
                            {
                                LNewClusteredKey = GetIndexData(AProcess, FClusteredIndex.KeyRowType, new Row[] { ANewRow, LOldClusteredKey, LOldClusteredData });
                            }

                            if (LIsClusteredIndexDataAffected)
                            {
                                LNewClusteredData = GetIndexData(AProcess, FClusteredIndex.DataRowType, new Row[] { ANewRow, LOldClusteredData });
                            }
                        }
                        finally
                        {
                            AProcess.RowManager.ReleaseRow(LOldClusteredData);
                        }
                    }

                    if (LIsClusteredIndexKeyAffected && LIsClusteredIndexDataAffected)
                    {
                        FClusteredIndex.Update(AProcess, LOldClusteredKey.Stream, LNewClusteredKey.Stream, LNewClusteredData.Stream);
                        LNewClusteredKey.ValuesOwned  = false;
                        LNewClusteredData.ValuesOwned = false;
                    }
                    else if (LIsClusteredIndexKeyAffected)
                    {
                        FClusteredIndex.Update(AProcess, LOldClusteredKey.Stream, LNewClusteredKey.Stream);
                        LNewClusteredKey.ValuesOwned = false;
                    }
                    else if (LIsClusteredIndexDataAffected)
                    {
                        FClusteredIndex.Update(AProcess, LOldClusteredKey.Stream, LOldClusteredKey.Stream, LNewClusteredData.Stream);
                        LNewClusteredData.ValuesOwned = false;
                    }
                }
                finally
                {
                    if (LNewClusteredKey != null)
                    {
                        AProcess.RowManager.ReleaseRow(LNewClusteredKey);
                    }

                    if (LNewClusteredData != null)
                    {
                        AProcess.RowManager.ReleaseRow(LNewClusteredData);
                    }
                }
            }
            finally
            {
                AProcess.RowManager.ReleaseRow(LOldClusteredKey);
            }
        }
Beispiel #9
0
        public void GetRow(Row ARow)
        {
            CheckActive();
            CheckNotCrack();

            if ((FAccessPath.IsClustered) || IsSubset(ARow, FAccessPath))
            {
                Row LRow = FProcess.RowManager.RequestRow(FProcess, FAccessPath.KeyRowType, FIndexNode.Key(FEntryNumber));
                try
                {
                    LRow.CopyTo(ARow);
                }
                finally
                {
                    FProcess.RowManager.ReleaseRow(LRow);
                }

                LRow = FProcess.RowManager.RequestRow(FProcess, FAccessPath.DataRowType, FIndexNode.Data(FEntryNumber));
                try
                {
                    LRow.CopyTo(ARow);
                }
                finally
                {
                    FProcess.RowManager.ReleaseRow(LRow);
                }
            }
            else
            {
                using (SearchPath LSearchPath = new SearchPath())
                {
                    int  LEntryNumber;
                    bool LResult = FTable.ClusteredIndex.FindKey(FProcess, FIndexNode.Data(FEntryNumber), null, LSearchPath, out LEntryNumber);
                    if (LResult)
                    {
                        Row LRow = FProcess.RowManager.RequestRow(FProcess, FTable.ClusteredIndex.KeyRowType, LSearchPath.DataNode.Key(LEntryNumber));
                        try
                        {
                            LRow.CopyTo(ARow);
                        }
                        finally
                        {
                            FProcess.RowManager.ReleaseRow(LRow);
                        }

                        LRow = FProcess.RowManager.RequestRow(FProcess, FTable.ClusteredIndex.DataRowType, LSearchPath.DataNode.Data(LEntryNumber));
                        try
                        {
                            LRow.CopyTo(ARow);
                        }
                        finally
                        {
                            FProcess.RowManager.ReleaseRow(LRow);
                        }
                    }
                    else
                    {
                        throw new ScanException(ScanException.Codes.ClusteredRowNotFound);
                    }
                }
            }
        }
Beispiel #10
0
 /// <summary>
 /// Searches for the given key within the index.  ASearchPath and AEntryNumber together give the
 /// location of the key in the index.  If the search is successful, the entry exists, otherwise
 /// the EntryNumber indicates where the entry should be placed for an insert.
 /// </summary>
 /// <param name="AKey">The key to be found.</param>
 /// <param name="ACompareContext">Context information which will passed to the compare handler.  May be null.</param>
 /// <param name="ASearchPath">A <see cref="SearchPath"/> which will contain the set of nodes along the search path to the key.</param>
 /// <param name="AEntryNumber">The EntryNumber where the key either is, or should be, depending on the result of the find.</param>
 /// <returns>A boolean value indicating the success or failure of the find.</returns>
 public bool FindKey(ServerProcess AProcess, Stream AKey, object ACompareContext, SearchPath ASearchPath, out int AEntryNumber)
 {
     return(new IndexNode(AProcess, this, FRootID).FindKey(AKey, ACompareContext, ASearchPath, out AEntryNumber));
 }
Beispiel #11
0
 private void InternalDelete(ServerProcess AProcess, SearchPath ASearchPath, int AEntryNumber)
 {
     ASearchPath.DataNode.Delete(AEntryNumber);
 }
Beispiel #12
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;
                }
            }
        }