/// <summary> /// The recursive portion of the find key algorithm invoked by the FindKey method of the parent Index. /// </summary> public bool FindKey(Schema.IRowType keyRowType, NativeRow key, RowTreeSearchPath rowTreeSearchPath, out int entryNumber) { rowTreeSearchPath.Add(this); if (Node.NodeType == NativeRowTreeNodeType.Routing) { // Perform a binary search among the keys in this node to determine which streamid to follow for the next node bool result = NodeSearch(keyRowType, key, out entryNumber); // If the key was found, use the given entry number, otherwise, use the one before the given entry entryNumber = result ? entryNumber : (entryNumber - 1); return (new RowTreeNode ( Manager, Tree, RoutingNode.Nodes[entryNumber], LockMode.Shared ).FindKey ( keyRowType, key, rowTreeSearchPath, out entryNumber )); } 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(keyRowType, key, out entryNumber)); } }
// 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 override void Delete(IValueManager manager, NativeRow key) { int entryNumber; using (RowTreeSearchPath rowTreeSearchPath = new RowTreeSearchPath()) { bool result = FindKey(manager, KeyRowType, key, rowTreeSearchPath, out entryNumber); if (!result) { throw new IndexException(IndexException.Codes.KeyNotFound); } InternalDelete(manager, rowTreeSearchPath, entryNumber); } }
/// <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 override void Insert(IValueManager manager, NativeRow key, NativeRow data) { int entryNumber; using (RowTreeSearchPath rowTreeSearchPath = new RowTreeSearchPath()) { bool result = FindKey(manager, KeyRowType, key, rowTreeSearchPath, out entryNumber); if (result) { throw new IndexException(IndexException.Codes.DuplicateKey); } InternalInsert(manager, rowTreeSearchPath, entryNumber, key, data); } }
private bool FindIndexKey(Schema.IRowType keyRowType, NativeRow key, out RowTreeNode indexNode, out int entryNumber) { RowTreeSearchPath searchPath = new RowTreeSearchPath(); try { bool result = _accessPath.FindKey(_manager, keyRowType, key, searchPath, out entryNumber); indexNode = searchPath.DisownAt(searchPath.Count - 1); return(result); } finally { searchPath.Dispose(); } }
public void Delete(IValueManager manager, IRow row) { // Delete the row from all indexes Row clusteredKey = GetIndexData(manager, ClusteredIndex.KeyRowType, new IRow[] { row }); try { using (RowTreeSearchPath searchPath = new RowTreeSearchPath()) { int entryNumber; bool result = ClusteredIndex.FindKey(manager, ClusteredIndex.KeyRowType, (NativeRow)clusteredKey.AsNative, searchPath, out entryNumber); if (!result) { throw new IndexException(IndexException.Codes.KeyNotFound); } Row clusteredData = new Row(manager, ClusteredIndex.DataRowType, searchPath.DataNode.DataNode.Rows[entryNumber]); try { foreach (NativeRowTree bufferIndex in NonClusteredIndexes) { Row key = GetIndexData(manager, bufferIndex.KeyRowType, new IRow[] { clusteredKey, clusteredData }); try { bufferIndex.Delete(manager, (NativeRow)key.AsNative); } finally { key.Dispose(); } } } finally { clusteredData.Dispose(); } } ClusteredIndex.Delete(manager, (NativeRow)clusteredKey.AsNative); } finally { clusteredKey.Dispose(); } _rowCount--; }
public bool HasRow(IValueManager manager, IRow row) { IRow key = GetIndexData(manager, ClusteredIndex.KeyRowType, new IRow[] { row }); try { using (RowTreeSearchPath searchPath = new RowTreeSearchPath()) { int entryNumber; return(ClusteredIndex.FindKey(manager, ClusteredIndex.KeyRowType, (NativeRow)key.AsNative, searchPath, out entryNumber)); } } finally { key.Dispose(); } }
/// <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 override void Update(IValueManager manager, NativeRow oldKey, NativeRow newKey, NativeRow newData) { int entryNumber; using (RowTreeSearchPath rowTreeSearchPath = new RowTreeSearchPath()) { bool result = FindKey(manager, KeyRowType, oldKey, rowTreeSearchPath, out entryNumber); if (!result) { throw new IndexException(IndexException.Codes.KeyNotFound); } if (Compare(manager, KeyRowType, oldKey, KeyRowType, newKey) == 0) { if (newData != null) { rowTreeSearchPath.DataNode.UpdateData(newData, entryNumber); } } else { if (newData == null) { newData = rowTreeSearchPath.DataNode.DataNode.Rows[entryNumber]; rowTreeSearchPath.DataNode.DataNode.Delete(entryNumber); // Don't dispose here this is a move } else { InternalDelete(manager, rowTreeSearchPath, entryNumber); // Dispose here this is not a move } rowTreeSearchPath.Dispose(); result = FindKey(manager, KeyRowType, newKey, rowTreeSearchPath, out entryNumber); if (result) { throw new IndexException(IndexException.Codes.DuplicateKey); } InternalInsert(manager, rowTreeSearchPath, entryNumber, newKey, newData); } } }
/// <summary> /// Searches for the given key within the index. ARowTreeSearchPath 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="key">The key to be found.</param> /// <param name="rowTreeSearchPath">A <see cref="RowTreeSearchPath"/> which will contain the set of nodes along the search path to the key.</param> /// <param name="entryNumber">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(IValueManager manager, Schema.IRowType keyRowType, NativeRow key, RowTreeSearchPath rowTreeSearchPath, out int entryNumber) { return(new RowTreeNode(manager, this, Root, LockMode.Shared).FindKey(keyRowType, key, rowTreeSearchPath, out entryNumber)); }
private void InternalDelete(IValueManager manager, RowTreeSearchPath rowTreeSearchPath, int entryNumber) { rowTreeSearchPath.DataNode.DeleteData(entryNumber); }
private void InternalInsert(IValueManager manager, RowTreeSearchPath rowTreeSearchPath, int entryNumber, NativeRow key, NativeRow data) { // Walk back up the search path, inserting data and splitting pages as necessary RowTreeNode newRowTreeNode; NativeRowTreeNode splitNode = null; for (int index = rowTreeSearchPath.Count - 1; index >= 0; index--) { if (rowTreeSearchPath[index].Node.EntryCount >= Capacity) { // Allocate a new node using (newRowTreeNode = AllocateNode(manager, rowTreeSearchPath[index].Node.NodeType)) { // Thread it into the list of leaves, if necessary if (newRowTreeNode.Node.NodeType == NativeRowTreeNodeType.Data) { newRowTreeNode.Node.PriorNode = rowTreeSearchPath[index].Node; newRowTreeNode.Node.NextNode = rowTreeSearchPath[index].Node.NextNode; rowTreeSearchPath[index].Node.NextNode = newRowTreeNode.Node; if (newRowTreeNode.Node.NextNode == null) { Tail = newRowTreeNode.Node; } else { using (RowTreeNode nextRowTreeNode = new RowTreeNode(manager, this, newRowTreeNode.Node.NextNode, LockMode.Exclusive)) { nextRowTreeNode.Node.PriorNode = newRowTreeNode.Node; } } } int entryPivot = Split(rowTreeSearchPath[index].Node, newRowTreeNode.Node); // Insert the new entry into the appropriate node if (entryNumber >= entryPivot) { if (newRowTreeNode.Node.NodeType == NativeRowTreeNodeType.Data) { newRowTreeNode.InsertData(key, data, entryNumber - entryPivot); } else { newRowTreeNode.InsertRouting(key, splitNode, entryNumber - entryPivot); } } else if (newRowTreeNode.Node.NodeType == NativeRowTreeNodeType.Data) { rowTreeSearchPath[index].InsertData(key, data, entryNumber); } else { rowTreeSearchPath[index].InsertRouting(key, splitNode, entryNumber); } // Reset the AKey for the next round // The key for the entry one level up is the first key for the newly allocated node key = CopyKey(manager, newRowTreeNode.Node.Keys[0]); // Set LSplitNode to the newly allocated node splitNode = newRowTreeNode.Node; } if (index == 0) { // Allocate a new root node and grow the height of the tree by 1 using (newRowTreeNode = AllocateNode(manager, NativeRowTreeNodeType.Routing)) { newRowTreeNode.InsertRouting(null, rowTreeSearchPath[index].Node, 0); // 1st key of a routing node is not used newRowTreeNode.InsertRouting(key, splitNode, 1); Root = newRowTreeNode.Node; Height++; } } else { // reset AEntryNumber for the next round bool result = rowTreeSearchPath[index - 1].NodeSearch(KeyRowType, key, out entryNumber); // At this point we should be guaranteed to have a routing key which does not exist in the parent node if (result) { throw new IndexException(IndexException.Codes.DuplicateRoutingKey); } } } else { if (rowTreeSearchPath[index].Node.NodeType == NativeRowTreeNodeType.Data) { rowTreeSearchPath[index].InsertData(key, data, entryNumber); } else { rowTreeSearchPath[index].InsertRouting(key, splitNode, entryNumber); } break; } } }
public void Update(IValueManager manager, IRow oldRow, IRow newRow) { // AOldRow must have at least the columns of the clustered index key Row oldClusteredKey = GetIndexData(manager, ClusteredIndex.KeyRowType, new IRow[] { oldRow }); try { bool isClusteredIndexKeyAffected = GetIsIndexAffected(ClusteredIndex.KeyRowType, newRow); bool isClusteredIndexDataAffected = GetIsIndexAffected(ClusteredIndex.DataRowType, newRow); Row newClusteredKey = null; Row newClusteredData = null; try { // Update the row in each index using (RowTreeSearchPath searchPath = new RowTreeSearchPath()) { int entryNumber; bool result = ClusteredIndex.FindKey(manager, ClusteredIndex.KeyRowType, (NativeRow)oldClusteredKey.AsNative, searchPath, out entryNumber); if (!result) { throw new IndexException(IndexException.Codes.KeyNotFound); } Row oldClusteredData = new Row(manager, ClusteredIndex.DataRowType, searchPath.DataNode.DataNode.Rows[entryNumber]); try { bool isIndexAffected; foreach (NativeRowTree tree in NonClusteredIndexes) { isIndexAffected = GetIsIndexAffected(tree.KeyRowType, newRow); if (isClusteredIndexKeyAffected || isIndexAffected) { Row oldIndexKey = GetIndexData(manager, tree.KeyRowType, new Row[] { oldClusteredKey, oldClusteredData }); try { Row newIndexKey = null; Row newIndexData = null; try { if (isIndexAffected) { newIndexKey = GetIndexData(manager, tree.KeyRowType, new IRow[] { newRow, oldClusteredKey, oldClusteredData }); } if (isClusteredIndexKeyAffected) { newIndexData = GetIndexData(manager, tree.DataRowType, new IRow[] { newRow, oldClusteredKey, oldClusteredData }); } if (isIndexAffected && isClusteredIndexKeyAffected) { tree.Update(manager, (NativeRow)oldIndexKey.AsNative, (NativeRow)newIndexKey.AsNative, (NativeRow)newIndexData.AsNative); newIndexKey.ValuesOwned = false; newIndexData.ValuesOwned = false; } else if (isIndexAffected) { tree.Update(manager, (NativeRow)oldIndexKey.AsNative, (NativeRow)newIndexKey.AsNative); newIndexKey.ValuesOwned = false; } else if (isClusteredIndexKeyAffected) { tree.Update(manager, (NativeRow)oldIndexKey.AsNative, (NativeRow)oldIndexKey.AsNative, (NativeRow)newIndexData.AsNative); newIndexData.ValuesOwned = false; } } finally { if (newIndexKey != null) { newIndexKey.Dispose(); } if (newIndexData != null) { newIndexData.Dispose(); } } } finally { oldIndexKey.Dispose(); } } } if (isClusteredIndexKeyAffected) { newClusteredKey = GetIndexData(manager, ClusteredIndex.KeyRowType, new IRow[] { newRow, oldClusteredKey, oldClusteredData }); } if (isClusteredIndexDataAffected) { newClusteredData = GetIndexData(manager, ClusteredIndex.DataRowType, new IRow[] { newRow, oldClusteredData }); } } finally { oldClusteredData.Dispose(); } } if (isClusteredIndexKeyAffected && isClusteredIndexDataAffected) { ClusteredIndex.Update(manager, (NativeRow)oldClusteredKey.AsNative, (NativeRow)newClusteredKey.AsNative, (NativeRow)newClusteredData.AsNative); newClusteredKey.ValuesOwned = false; newClusteredData.ValuesOwned = false; } else if (isClusteredIndexKeyAffected) { ClusteredIndex.Update(manager, (NativeRow)oldClusteredKey.AsNative, (NativeRow)newClusteredKey.AsNative); newClusteredKey.ValuesOwned = false; } else if (isClusteredIndexDataAffected) { ClusteredIndex.Update(manager, (NativeRow)oldClusteredKey.AsNative, (NativeRow)oldClusteredKey.AsNative, (NativeRow)newClusteredData.AsNative); newClusteredData.ValuesOwned = false; } } finally { if (newClusteredKey != null) { newClusteredKey.Dispose(); } if (newClusteredData != null) { newClusteredData.Dispose(); } } } finally { oldClusteredKey.Dispose(); } }
public void GetRow(IRow row) { #if SAFETABLES CheckActive(); #endif CheckNotCrack(); if ((_accessPath.IsClustered) || IsSubset(row, _accessPath)) { Row localRow = new Row(_manager, _accessPath.KeyRowType, _indexNode.Node.Keys[_entryNumber]); try { localRow.CopyTo(row); } finally { localRow.Dispose(); } localRow = new Row(_manager, _accessPath.DataRowType, _indexNode.DataNode.Rows[_entryNumber]); try { localRow.CopyTo(row); } finally { localRow.Dispose(); } } else { using (RowTreeSearchPath searchPath = new RowTreeSearchPath()) { int entryNumber; bool result = _table.ClusteredIndex.FindKey(_manager, _table.ClusteredIndex.KeyRowType, _indexNode.DataNode.Rows[_entryNumber], searchPath, out entryNumber); if (result) { Row localRow = new Row(_manager, _table.ClusteredIndex.KeyRowType, searchPath.DataNode.Node.Keys[entryNumber]); try { localRow.CopyTo(row); } finally { localRow.Dispose(); } localRow = new Row(_manager, _table.ClusteredIndex.DataRowType, searchPath.DataNode.DataNode.Rows[entryNumber]); try { localRow.CopyTo(row); } finally { localRow.Dispose(); } } else { throw new ScanException(ScanException.Codes.ClusteredRowNotFound); } } } }