Beispiel #1
0
        /// <summary>
        /// Removes redundant nodes (that contain only an 'End' entry).
        /// </summary>
        /// <param name="entryIndex">The index of the entry that may have a redundant child.</param>
        /// <returns>An entry that needs to be promoted to the parent node (if any).</returns>
        private IndexEntry LiftNode(int entryIndex)
        {
            if ((_entries[entryIndex].Flags & IndexEntryFlags.Node) != 0)
            {
                IndexNode childNode = _index.GetSubBlock(_entries[entryIndex]).Node;
                if (childNode._entries.Count == 1)
                {
                    long freeBlock = _entries[entryIndex].ChildrenVirtualCluster;
                    _entries[entryIndex].Flags = (_entries[entryIndex].Flags & ~IndexEntryFlags.Node) |
                                                 (childNode._entries[0].Flags & IndexEntryFlags.Node);
                    _entries[entryIndex].ChildrenVirtualCluster = childNode._entries[0].ChildrenVirtualCluster;

                    _index.FreeBlock(freeBlock);
                }

                if ((_entries[entryIndex].Flags & (IndexEntryFlags.Node | IndexEntryFlags.End)) == 0)
                {
                    IndexEntry entry = _entries[entryIndex];
                    _entries.RemoveAt(entryIndex);

                    IndexNode nextNode = _index.GetSubBlock(_entries[entryIndex]).Node;
                    return(nextNode.AddEntry(entry));
                }
            }

            return(null);
        }
Beispiel #2
0
        public IndexNode(IndexNodeSaveFn store, int storeOverhead, Index index, IndexNode parent, byte[] buffer, int offset)
        {
            _store = store;
            _storageOverhead = storeOverhead;
            _index = index;
            _parent = parent;
            _header = new IndexHeader(buffer, offset + 0);
            _totalSpaceAvailable = _header.AllocatedSizeOfEntries;

            _entries = new List<IndexEntry>();
            int pos = (int)_header.OffsetToFirstEntry;
            while (pos < _header.TotalSizeOfEntries)
            {
                IndexEntry entry = new IndexEntry(index.IsFileIndex);
                entry.Read(buffer, offset + pos);
                _entries.Add(entry);

                if ((entry.Flags & IndexEntryFlags.End) != 0)
                {
                    break;
                }

                pos += entry.Size;
            }
        }
Beispiel #3
0
        public bool TryFindEntry(byte[] key, out IndexEntry entry, out IndexNode node)
        {
            foreach (IndexEntry focus in _entries)
            {
                if ((focus.Flags & IndexEntryFlags.End) != 0)
                {
                    if ((focus.Flags & IndexEntryFlags.Node) != 0)
                    {
                        IndexBlock subNode = _index.GetSubBlock(focus);
                        return(subNode.Node.TryFindEntry(key, out entry, out node));
                    }

                    break;
                }
                int compVal = _index.Compare(key, focus.KeyBuffer);
                if (compVal == 0)
                {
                    entry = focus;
                    node  = this;
                    return(true);
                }
                if (compVal < 0 && (focus.Flags & (IndexEntryFlags.End | IndexEntryFlags.Node)) != 0)
                {
                    IndexBlock subNode = _index.GetSubBlock(focus);
                    return(subNode.Node.TryFindEntry(key, out entry, out node));
                }
            }

            entry = null;
            node  = null;
            return(false);
        }
Beispiel #4
0
        public Index(File file, string name, BiosParameterBlock bpb, UpperCase upCase)
        {
            _file        = file;
            _name        = name;
            _bpb         = bpb;
            _isFileIndex = name == "$I30";

            _blockCache = new ObjectCache <long, IndexBlock>();

            _root     = _file.GetStream(AttributeType.IndexRoot, _name).GetContent <IndexRoot>();
            _comparer = _root.GetCollator(upCase);

            using (Stream s = _file.OpenStream(AttributeType.IndexRoot, _name, FileAccess.Read))
            {
                byte[] buffer = Utilities.ReadFully(s, (int)s.Length);
                _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, buffer, IndexRoot.HeaderOffset);

                // Give the attribute some room to breathe, so long as it doesn't squeeze others out
                // BROKEN, BROKEN, BROKEN - how to figure this out?  Query at the point of adding entries to the root node?
                _rootNode.TotalSpaceAvailable += _file.MftRecordFreeSpace(AttributeType.IndexRoot, _name) - 100;
            }

            if (_file.StreamExists(AttributeType.IndexAllocation, _name))
            {
                _indexStream = _file.OpenStream(AttributeType.IndexAllocation, _name, FileAccess.ReadWrite);
            }

            if (_file.StreamExists(AttributeType.Bitmap, _name))
            {
                _indexBitmap = new Bitmap(_file.OpenStream(AttributeType.Bitmap, _name, FileAccess.ReadWrite), long.MaxValue);
            }
        }
Beispiel #5
0
        public Index(File file, string name, BiosParameterBlock bpb, UpperCase upCase)
        {
            _file = file;
            _name = name;
            _bpb = bpb;
            _isFileIndex = name == "$I30";

            _blockCache = new ObjectCache<long, IndexBlock>();

            _root = _file.GetStream(AttributeType.IndexRoot, _name).GetContent<IndexRoot>();
            _comparer = _root.GetCollator(upCase);

            using (Stream s = _file.OpenStream(AttributeType.IndexRoot, _name, FileAccess.Read))
            {
                byte[] buffer = Utilities.ReadFully(s, (int)s.Length);
                _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, buffer, IndexRoot.HeaderOffset);

                // Give the attribute some room to breathe, so long as it doesn't squeeze others out
                // BROKEN, BROKEN, BROKEN - how to figure this out?  Query at the point of adding entries to the root node?
                _rootNode.TotalSpaceAvailable += _file.MftRecordFreeSpace(AttributeType.IndexRoot, _name) - 100;
            }

            if (_file.StreamExists(AttributeType.IndexAllocation, _name))
            {
                _indexStream = _file.OpenStream(AttributeType.IndexAllocation, _name, FileAccess.ReadWrite);
            }

            if (_file.StreamExists(AttributeType.Bitmap, _name))
            {
                _indexBitmap = new Bitmap(_file.OpenStream(AttributeType.Bitmap, _name, FileAccess.ReadWrite), long.MaxValue);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Removes redundant nodes (that contain only an 'End' entry).
        /// </summary>
        /// <param name="entryIndex">The index of the entry that may have a redundant child</param>
        private void LiftNode(int entryIndex)
        {
            if ((_entries[entryIndex].Flags & IndexEntryFlags.Node) != 0)
            {
                IndexNode childNode = _index.GetSubBlock(this, _entries[entryIndex]).Node;
                if (childNode._entries.Count == 1)
                {
                    long freeBlock = _entries[entryIndex].ChildrenVirtualCluster;
                    _entries[entryIndex].Flags = (_entries[entryIndex].Flags & ~IndexEntryFlags.Node) | (childNode._entries[0].Flags & IndexEntryFlags.Node);
                    _entries[entryIndex].ChildrenVirtualCluster = childNode._entries[0].ChildrenVirtualCluster;
                    if ((_entries[entryIndex].Flags & IndexEntryFlags.Node) != 0)
                    {
                        IndexNode newChildNode = _index.GetSubBlock(this, _entries[entryIndex]).Node;
                        childNode._parent = this;
                    }
                    _index.FreeBlock(freeBlock);
                }

                if ((_entries[entryIndex].Flags & (IndexEntryFlags.Node | IndexEntryFlags.End)) == 0)
                {
                    IndexEntry entry = _entries[entryIndex];
                    _entries.RemoveAt(entryIndex);
                    AddEntry(entry, false);
                }
            }
        }
Beispiel #7
0
        public IndexNode(IndexNodeSaveFn store, int storeOverhead, Index index, IndexNode parent, byte[] buffer, int offset)
        {
            _store               = store;
            _storageOverhead     = storeOverhead;
            _index               = index;
            _parent              = parent;
            _header              = new IndexHeader(buffer, offset + 0);
            _totalSpaceAvailable = _header.AllocatedSizeOfEntries;

            _entries = new List <IndexEntry>();
            int pos = (int)_header.OffsetToFirstEntry;

            while (pos < _header.TotalSizeOfEntries)
            {
                IndexEntry entry = new IndexEntry(index.IsFileIndex);
                entry.Read(buffer, offset + pos);
                _entries.Add(entry);

                if ((entry.Flags & IndexEntryFlags.End) != 0)
                {
                    break;
                }

                pos += entry.Size;
            }
        }
Beispiel #8
0
 protected override void Read(byte[] buffer, int offset)
 {
     // Skip FixupRecord fields...
     LogSequenceNumber = Utilities.ToUInt64LittleEndian(buffer, offset + 0x08);
     IndexBlockVcn = Utilities.ToUInt64LittleEndian(buffer, offset + 0x10);
     _node = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, _parentNode, buffer, offset + FieldSize);
 }
Beispiel #9
0
 protected override void Read(byte[] buffer, int offset)
 {
     // Skip FixupRecord fields...
     LogSequenceNumber = Utilities.ToUInt64LittleEndian(buffer, offset + 0x08);
     IndexBlockVcn     = Utilities.ToUInt64LittleEndian(buffer, offset + 0x10);
     _node             = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, _parentNode, buffer, offset + FieldSize);
 }
Beispiel #10
0
        internal IndexBlock GetSubBlock(IndexNode parentNode, IndexEntry parentEntry)
        {
            IndexBlock block = _blockCache[parentEntry.ChildrenVirtualCluster];

            if (block == null)
            {
                block = new IndexBlock(this, parentNode, parentEntry, _bpb);
                _blockCache[parentEntry.ChildrenVirtualCluster] = block;
            }

            return(block);
        }
Beispiel #11
0
        public IndexBlock(Index index, IndexNode parentNode, IndexEntry parentEntry, BiosParameterBlock bpb)
            : base("INDX", bpb.BytesPerSector)
        {
            _index = index;
            _parentNode = parentNode;

            Stream stream = index.AllocationStream;
            _streamPosition = parentEntry.ChildrenVirtualCluster * bpb.BytesPerSector * bpb.SectorsPerCluster;
            stream.Position = _streamPosition;
            byte[] buffer = Utilities.ReadFully(stream, (int)index.IndexBufferSize);
            FromBytes(buffer, 0);
        }
Beispiel #12
0
        public IndexBlock(Index index, IndexNode parentNode, IndexEntry parentEntry, BiosParameterBlock bpb)
            : base("INDX", bpb.BytesPerSector)
        {
            _index      = index;
            _parentNode = parentNode;

            Stream stream = index.AllocationStream;

            _streamPosition = parentEntry.ChildrenVirtualCluster * bpb.BytesPerSector * bpb.SectorsPerCluster;
            stream.Position = _streamPosition;
            byte[] buffer = Utilities.ReadFully(stream, (int)index.IndexBufferSize);
            FromBytes(buffer, 0);
        }
Beispiel #13
0
        private IndexBlock(Index index, bool isRoot, long vcn, BiosParameterBlock bpb)
            : base("INDX", bpb.BytesPerSector, bpb.IndexBufferSize)
        {
            _index  = index;
            _isRoot = isRoot;

            _indexBlockVcn = (ulong)vcn;

            _streamPosition = vcn * bpb.BytesPerSector * bpb.SectorsPerCluster;

            _node = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, isRoot, (uint)bpb.IndexBufferSize - FieldSize);

            WriteToDisk();
        }
        private IndexBlock(Index index, bool isRoot, long vcn, BiosParameterBlock bpb)
            : base("INDX", bpb.BytesPerSector, bpb.IndexBufferSize)
        {
            _index = index;
            _isRoot = isRoot;

            _indexBlockVcn = (ulong)vcn;

            _streamPosition = vcn * bpb.BytesPerSector * bpb.SectorsPerCluster;

            _node = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, isRoot, (uint)bpb.IndexBufferSize - FieldSize);

            WriteToDisk();
        }
Beispiel #15
0
        private IEnumerable <IndexEntry> FindAllIn(IComparable <byte[]> query, IndexNode node)
        {
            lock (_lock)
            {
                foreach (IndexEntry focus in node.Entries)
                {
                    bool searchChildren = true;
                    bool matches        = false;
                    bool keepIterating  = true;

                    if ((focus.Flags & IndexEntryFlags.End) == 0)
                    {
                        int compVal = query.CompareTo(focus.KeyBuffer);
                        if (compVal == 0)
                        {
                            matches = true;
                        }
                        else if (compVal > 0)
                        {
                            searchChildren = false;
                        }
                        else if (compVal < 0)
                        {
                            keepIterating = false;
                        }
                    }

                    if (searchChildren && (focus.Flags & IndexEntryFlags.Node) != 0)
                    {
                        IndexBlock block = GetSubBlock(focus);
                        foreach (IndexEntry entry in FindAllIn(query, block.Node))
                        {
                            yield return(entry);
                        }
                    }

                    if (matches)
                    {
                        yield return(focus);
                    }

                    if (!keepIterating)
                    {
                        yield break;
                    }
                }
            }
        }
Beispiel #16
0
        public IndexNode(IndexNodeSaveFn store, int storeOverhead, Index index, IndexNode parent, uint allocatedSize)
        {
            _store = store;
            _storageOverhead = storeOverhead;
            _index = index;
            _parent = parent;
            _header = new IndexHeader(allocatedSize);
            _totalSpaceAvailable = allocatedSize;

            IndexEntry endEntry = new IndexEntry(_index.IsFileIndex);
            endEntry.Flags |= IndexEntryFlags.End;

            _entries = new List<IndexEntry>();
            _entries.Add(endEntry);

            _header.OffsetToFirstEntry = (uint)(IndexHeader.Size + storeOverhead);
            _header.TotalSizeOfEntries = (uint)(_header.OffsetToFirstEntry + endEntry.Size);
        }
Beispiel #17
0
        public IndexNode(IndexNodeSaveFn store, int storeOverhead, Index index, IndexNode parent, uint allocatedSize)
        {
            _store               = store;
            _storageOverhead     = storeOverhead;
            _index               = index;
            _parent              = parent;
            _header              = new IndexHeader(allocatedSize);
            _totalSpaceAvailable = allocatedSize;

            IndexEntry endEntry = new IndexEntry(_index.IsFileIndex);

            endEntry.Flags |= IndexEntryFlags.End;

            _entries = new List <IndexEntry>();
            _entries.Add(endEntry);

            _header.OffsetToFirstEntry = (uint)(IndexHeader.Size + storeOverhead);
            _header.TotalSizeOfEntries = (uint)(_header.OffsetToFirstEntry + endEntry.Size);
        }
Beispiel #18
0
        protected IEnumerable <IndexEntry> Enumerate(IndexNode node)
        {
            foreach (IndexEntry focus in node.Entries)
            {
                if ((focus.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexBlock block = GetSubBlock(focus);
                    foreach (IndexEntry subEntry in Enumerate(block.Node))
                    {
                        yield return(subEntry);
                    }
                }

                if ((focus.Flags & IndexEntryFlags.End) == 0)
                {
                    yield return(focus);
                }
            }
        }
Beispiel #19
0
        private void NodeAsString(TextWriter writer, string prefix, IndexNode node, string id)
        {
            writer.WriteLine(prefix + id + ":");
            foreach (var entry in node.Entries)
            {
                if ((entry.Flags & IndexEntryFlags.End) != 0)
                {
                    writer.WriteLine(prefix + "      E");
                }
                else
                {
                    writer.WriteLine(prefix + "      " + EntryAsString(entry, _file.BestName, _name));
                }

                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    NodeAsString(writer, prefix + "        ", GetSubBlock(node, entry).Node, ":i" + entry.ChildrenVirtualCluster);
                }
            }
        }
Beispiel #20
0
        private Index(AttributeType attrType, AttributeCollationRule collationRule, File file, string name, BiosParameterBlock bpb, UpperCase upCase)
        {
            _file        = file;
            _name        = name;
            _bpb         = bpb;
            _isFileIndex = (name == "$I30");

            _blockCache = new ObjectCache <long, IndexBlock>();

            _file.CreateStream(AttributeType.IndexRoot, _name);

            _root = new IndexRoot()
            {
                AttributeType             = (uint)attrType,
                CollationRule             = collationRule,
                IndexAllocationSize       = (uint)bpb.IndexBufferSize,
                RawClustersPerIndexRecord = bpb.RawIndexBufferSize
            };

            _comparer = _root.GetCollator(upCase);

            _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, null, 32);
        }
Beispiel #21
0
        internal IndexBlock AllocateBlock(IndexNode parentNode, IndexEntry parentEntry)
        {
            if (_indexStream == null)
            {
                _file.CreateStream(AttributeType.IndexAllocation, _name);
                _indexStream = _file.OpenStream(AttributeType.IndexAllocation, _name, FileAccess.ReadWrite);
            }

            if (_indexBitmap == null)
            {
                _file.CreateStream(AttributeType.Bitmap, _name);
                _indexBitmap = new Bitmap(_file.OpenStream(AttributeType.Bitmap, _name, FileAccess.ReadWrite), long.MaxValue);
            }

            long idx = _indexBitmap.AllocateFirstAvailable(0);

            parentEntry.ChildrenVirtualCluster = idx * Utilities.Ceil(_bpb.IndexBufferSize, _bpb.SectorsPerCluster * _bpb.BytesPerSector);
            parentEntry.Flags |= IndexEntryFlags.Node;

            IndexBlock block = IndexBlock.Initialize(this, parentNode, parentEntry, _bpb);

            _blockCache[parentEntry.ChildrenVirtualCluster] = block;
            return(block);
        }
Beispiel #22
0
 internal static IndexBlock Initialize(Index index, IndexNode parentNode, IndexEntry parentEntry, BiosParameterBlock bpb)
 {
     return(new IndexBlock(index, parentNode, parentEntry.ChildrenVirtualCluster, bpb));
 }
Beispiel #23
0
        public bool RemoveEntry(byte[] key)
        {
            bool       exactMatch;
            int        entryIndex = GetEntry(key, out exactMatch);
            IndexEntry entry      = _entries[entryIndex];

            if (exactMatch)
            {
                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    // Get the next biggest entry in the index, which may be sibling or descendant of sibling
                    IndexEntry replacementLeaf = _entries[entryIndex + 1];
                    if ((replacementLeaf.Flags & (IndexEntryFlags.End | IndexEntryFlags.Node)) == IndexEntryFlags.End)
                    {
                        entry.KeyBuffer  = null;
                        entry.DataBuffer = null;
                        entry.Flags     |= IndexEntryFlags.End;
                        _entries.RemoveAt(entryIndex + 1);
                    }
                    else
                    {
                        if ((replacementLeaf.Flags & IndexEntryFlags.Node) != 0)
                        {
                            IndexNode giftingNode = _index.GetSubBlock(this, replacementLeaf).Node;
                            replacementLeaf = giftingNode.FindSmallestLeaf();
                        }

                        // Take a reference to the byte arrays because in the recursive case, these arrays
                        // may be changed as a new node is promoted.
                        byte[] newKey  = replacementLeaf.KeyBuffer;
                        byte[] newData = replacementLeaf.DataBuffer;

                        RemoveEntry(newKey);

                        // Just over-write our key & data with the replacement
                        entry.KeyBuffer  = newKey;
                        entry.DataBuffer = newData;

                        LiftNode(entryIndex + 1);
                    }
                }
                else
                {
                    _entries.RemoveAt(entryIndex);
                }

                _store();
                return(true);
            }
            else
            {
                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexNode childNode = _index.GetSubBlock(this, entry).Node;
                    if (childNode.RemoveEntry(key))
                    {
                        LiftNode(entryIndex);

                        _store();
                        return(true);
                    }
                }
                else
                {
                    return(false);
                }
            }

            return(false);
        }
Beispiel #24
0
 internal static IndexBlock Initialize(Index index, IndexNode parentNode, IndexEntry parentEntry, BiosParameterBlock bpb)
 {
     return new IndexBlock(index, parentNode, parentEntry.ChildrenVirtualCluster, bpb);
 }
Beispiel #25
0
        private Index(AttributeType attrType, AttributeCollationRule collationRule, File file, string name, BiosParameterBlock bpb, UpperCase upCase)
        {
            _file = file;
            _name = name;
            _bpb = bpb;
            _isFileIndex = name == "$I30";

            _blockCache = new ObjectCache<long, IndexBlock>();

            _file.CreateStream(AttributeType.IndexRoot, _name);

            _root = new IndexRoot()
            {
                AttributeType = (uint)attrType,
                CollationRule = collationRule,
                IndexAllocationSize = (uint)bpb.IndexBufferSize,
                RawClustersPerIndexRecord = bpb.RawIndexBufferSize
            };

            _comparer = _root.GetCollator(upCase);

            _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, 32);
        }
Beispiel #26
0
 private void NodeAsString(TextWriter writer, string prefix, IndexNode node, string id)
 {
     writer.WriteLine(prefix + id + ":");
     foreach (var entry in node.Entries)
     {
         if ((entry.Flags & IndexEntryFlags.End) != 0)
         {
             writer.WriteLine(prefix + "      E");
         }
         else
         {
             writer.WriteLine(prefix + "      " + EntryAsString(entry, _file.BestName, _name));
         }
         
         if ((entry.Flags & IndexEntryFlags.Node) != 0)
         {
             NodeAsString(writer, prefix + "        ", GetSubBlock(entry).Node, ":i" + entry.ChildrenVirtualCluster);
         }
     }
 }
Beispiel #27
0
        private IEnumerable<IndexEntry> FindAllIn(IComparable<byte[]> query, IndexNode node)
        {
            foreach (var focus in node.Entries)
            {
                bool searchChildren = true;
                bool matches = false;
                bool keepIterating = true;

                if ((focus.Flags & IndexEntryFlags.End) == 0)
                {
                    int compVal = query.CompareTo(focus.KeyBuffer);
                    if (compVal == 0)
                    {
                        matches = true;
                    }
                    else if (compVal > 0)
                    {
                        searchChildren = false;
                    }
                    else if (compVal < 0)
                    {
                        keepIterating = false;
                    }
                }

                if (searchChildren && (focus.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexBlock block = GetSubBlock(focus);
                    foreach (var entry in FindAllIn(query, block.Node))
                    {
                        yield return entry;
                    }
                }

                if (matches)
                {
                    yield return focus;
                }

                if (!keepIterating)
                {
                    yield break;
                }
            }
        }
Beispiel #28
0
        protected IEnumerable<IndexEntry> Enumerate(IndexNode node)
        {
            foreach (var focus in node.Entries)
            {
                if ((focus.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexBlock block = GetSubBlock(focus);
                    foreach (var subEntry in Enumerate(block.Node))
                    {
                        yield return subEntry;
                    }
                }

                if ((focus.Flags & IndexEntryFlags.End) == 0)
                {
                    yield return focus;
                }
            }
        }
Beispiel #29
0
        public bool RemoveEntry(byte[] key, out IndexEntry newParentEntry)
        {
            bool       exactMatch;
            int        entryIndex = GetEntry(key, out exactMatch);
            IndexEntry entry      = _entries[entryIndex];

            if (exactMatch)
            {
                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexNode  childNode = _index.GetSubBlock(entry).Node;
                    IndexEntry rLeaf     = childNode.FindLargestLeaf();

                    byte[] newKey  = rLeaf.KeyBuffer;
                    byte[] newData = rLeaf.DataBuffer;

                    IndexEntry newEntry;
                    childNode.RemoveEntry(newKey, out newEntry);
                    entry.KeyBuffer  = newKey;
                    entry.DataBuffer = newData;

                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    newEntry = LiftNode(entryIndex);
                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    newEntry = PopulateEnd();
                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    // New entry could be larger than old, so may need
                    // to divide this node...
                    newParentEntry = EnsureNodeSize();
                }
                else
                {
                    _entries.RemoveAt(entryIndex);
                    newParentEntry = null;
                }

                _store();
                return(true);
            }
            else if ((entry.Flags & IndexEntryFlags.Node) != 0)
            {
                IndexNode  childNode = _index.GetSubBlock(entry).Node;
                IndexEntry newEntry;
                if (childNode.RemoveEntry(key, out newEntry))
                {
                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    newEntry = LiftNode(entryIndex);
                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    newEntry = PopulateEnd();
                    if (newEntry != null)
                    {
                        InsertEntryThisNode(newEntry);
                    }

                    // New entry could be larger than old, so may need
                    // to divide this node...
                    newParentEntry = EnsureNodeSize();

                    _store();
                    return(true);
                }
            }

            newParentEntry = null;
            return(false);
        }
Beispiel #30
0
        public bool TryFindEntry(byte[] key, out IndexEntry entry, out IndexNode node)
        {
            foreach (var focus in _entries)
            {
                if ((focus.Flags & IndexEntryFlags.End) != 0)
                {
                    if ((focus.Flags & IndexEntryFlags.Node) != 0)
                    {
                        IndexBlock subNode = _index.GetSubBlock(focus);
                        return subNode.Node.TryFindEntry(key, out entry, out node);
                    }

                    break;
                }
                else
                {
                    int compVal = _index.Compare(key, focus.KeyBuffer);
                    if (compVal == 0)
                    {
                        entry = focus;
                        node = this;
                        return true;
                    }
                    else if (compVal < 0 && (focus.Flags & (IndexEntryFlags.End | IndexEntryFlags.Node)) != 0)
                    {
                        IndexBlock subNode = _index.GetSubBlock(focus);
                        return subNode.Node.TryFindEntry(key, out entry, out node);
                    }
                }
            }

            entry = null;
            node = null;
            return false;
        }