Пример #1
0
        public void RemoveEntry(byte[] key)
        {
            if (!m_rootRecord.IsParentNode)
            {
                int index = CollationHelper.FindIndexInLeafNode(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    m_rootRecord.IndexEntries.RemoveAt(index);
                }
                m_volume.UpdateFileRecord(m_fileRecord);
            }
            else
            {
                int indexOfEntryToRemove;
                KeyValuePairList <int, IndexRecord> path = FindRemovalPath(key, out indexOfEntryToRemove);
                if (path == null)
                {
                    return;
                }

                if ((path.Count > 0 && path[path.Count - 1].Value.IsParentNode) || path.Count == 0)
                {
                    // We find the rightmost leaf entry in the left branch and put it instead.
                    // Note: Excluding the root of the branch, the rightmost leaf entry in the branch collates last.
                    KeyValuePairList <int, IndexRecord> pathToLeaf = FindPathToRightmostLeaf(path, indexOfEntryToRemove);
                    IndexRecord leaf = pathToLeaf[pathToLeaf.Count - 1].Value;
                    IndexEntry  entryToRemoveFromLeaf = leaf.IndexEntries[leaf.IndexEntries.Count - 1];
                    leaf.IndexEntries.RemoveAt(leaf.IndexEntries.Count - 1);
                    long leafRecordIndex = ConvertToRecordIndex(leaf.RecordVBN);
                    // Note: CHKDSK does not accept an empty IndexRecord, however, we must not call RemovePointer just yet because it might affect the parent as well.
                    WriteIndexRecord(leafRecordIndex, leaf);

                    if (path.Count == 0)
                    {
                        m_rootRecord.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference;
                        m_rootRecord.IndexEntries[indexOfEntryToRemove].Key           = entryToRemoveFromLeaf.Key;
                        m_volume.UpdateFileRecord(m_fileRecord);
                    }
                    else
                    {
                        path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference;
                        path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].Key           = entryToRemoveFromLeaf.Key;
                        long recordIndex = ConvertToRecordIndex(path[path.Count - 1].Value.RecordVBN);
                        WriteIndexRecord(recordIndex, path[path.Count - 1].Value);
                    }

                    if (leaf.IndexEntries.Count == 0)
                    {
                        int indexOfLeafPointer = pathToLeaf[pathToLeaf.Count - 1].Key;
                        RemovePointer(pathToLeaf.GetRange(0, pathToLeaf.Count - 1), indexOfLeafPointer);
                        DeallocateIndexRecord(leafRecordIndex);
                    }
                }
                else
                {
                    int         indexInParentRecord = path[path.Count - 1].Key;
                    IndexRecord leaf = path[path.Count - 1].Value;

                    leaf.IndexEntries.RemoveAt(indexOfEntryToRemove);
                    long recordIndex = ConvertToRecordIndex(leaf.RecordVBN);
                    if (leaf.IndexEntries.Count > 0)
                    {
                        WriteIndexRecord(recordIndex, leaf);
                    }
                    else
                    {
                        path.RemoveAt(path.Count - 1);
                        RemovePointer(path, indexInParentRecord);
                        DeallocateIndexRecord(recordIndex);
                    }
                }
            }
        }
Пример #2
0
        /// <param name="path">Key is index in parent node</param>
        private void SplitIndexRecord(KeyValuePairList <int, IndexRecord> path)
        {
            int indexInParentRecord = path[path.Count - 1].Key;
            // We will treat the record we want to split as the right node, and create a left node
            IndexRecord       rightNode        = path[path.Count - 1].Value;
            long              rightNodeVBN     = rightNode.RecordVBN;
            long              rightNodeIndex   = ConvertToRecordIndex(rightNodeVBN);
            List <IndexEntry> rightNodeEntries = rightNode.IndexEntries;
            int         splitIndex             = rightNodeEntries.Count / 2;
            IndexEntry  middleEntry            = rightNodeEntries[splitIndex];
            IndexRecord leftNode = new IndexRecord();

            leftNode.IsParentNode = rightNode.IsParentNode;
            leftNode.IndexEntries = rightNodeEntries.GetRange(0, splitIndex);
            rightNodeEntries.RemoveRange(0, splitIndex + 1);
            if (rightNode.IsParentNode)
            {
                // A parent node has n keys and points to (n + 1) subnodes,
                // When splitting it to two nodes we will take the pointer from the entry we wish to push to the parent node,
                // and use it as the last pointer in the left node.
                IndexEntry leftNodeLastEntry = new IndexEntry();
                leftNodeLastEntry.ParentNodeForm = true;
                leftNodeLastEntry.IsLastEntry    = true;
                leftNodeLastEntry.SubnodeVBN     = middleEntry.SubnodeVBN;
                leftNode.IndexEntries.Add(leftNodeLastEntry);
            }
            long leftNodeIndex = AllocateIndexRecord();

            leftNode.RecordVBN = ConvertToVirtualBlockNumber(leftNodeIndex);
            IndexEntry newParentEntry = new IndexEntry(middleEntry.FileReference, middleEntry.Key);

            newParentEntry.ParentNodeForm = true;
            newParentEntry.SubnodeVBN     = leftNode.RecordVBN;
            WriteIndexRecord(rightNodeIndex, rightNode);
            WriteIndexRecord(leftNodeIndex, leftNode);
            if (path.Count > 1)
            {
                IndexRecord       parentRecord      = path[path.Count - 2].Value;
                long              parentRecordIndex = ConvertToRecordIndex(parentRecord.RecordVBN);
                List <IndexEntry> parentEntries     = parentRecord.IndexEntries;
                parentEntries.Insert(indexInParentRecord, newParentEntry);
                if (parentRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord))
                {
                    WriteIndexRecord(parentRecordIndex, parentRecord);
                }
                else
                {
                    // Split parent index record
                    path.RemoveAt(path.Count - 1);
                    SplitIndexRecord(path);
                }
            }
            else
            {
                m_rootRecord.IndexEntries.Insert(indexInParentRecord, newParentEntry);
                if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident)
                {
                    SplitRootIndexRecord();
                }
                else
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
        }