예제 #1
0
        internal IndexBlock AllocateBlock(IndexEntry parentEntry)
        {
            if (AllocationStream == null)
            {
                _file.CreateStream(AttributeType.IndexAllocation, _name);
                AllocationStream = _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, false, parentEntry, _bpb);

            _blockCache[parentEntry.ChildrenVirtualCluster] = block;
            return(block);
        }
예제 #2
0
        /// <summary>
        /// Only valid on the root node, this method moves all entries into a
        /// single child node.
        /// </summary>
        /// <returns>Whether any changes were made.</returns>
        internal bool Depose()
        {
            if (!_isRoot)
            {
                throw new InvalidOperationException("Only valid on root node");
            }

            if (_entries.Count == 1)
            {
                return(false);
            }

            IndexEntry newRootEntry = new IndexEntry(_index.IsFileIndex);

            newRootEntry.Flags = IndexEntryFlags.End;

            IndexBlock newBlock = _index.AllocateBlock(newRootEntry);

            // Set the deposed entries into the new node.  Note we updated the parent
            // pointers first, because it's possible SetEntries may need to further
            // divide the entries to fit into nodes.  We mustn't overwrite any changes.
            newBlock.Node.SetEntries(_entries, 0, _entries.Count);

            _entries.Clear();
            _entries.Add(newRootEntry);

            return(true);
        }
예제 #3
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);
        }
예제 #4
0
        internal IndexBlock GetSubBlock(IndexEntry parentEntry)
        {
            IndexBlock block = _blockCache[parentEntry.ChildrenVirtualCluster];

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

            return(block);
        }
예제 #5
0
        /// <summary>
        /// Only valid on non-root nodes, this method divides the node in two,
        /// adding the new node to the current parent.
        /// </summary>
        private void Divide()
        {
            int        midEntryIdx = _entries.Count / 2;
            IndexEntry midEntry    = _entries[midEntryIdx];

            // The terminating entry (aka end) for the new node
            IndexEntry newTerm = new IndexEntry(_index.IsFileIndex);

            newTerm.Flags |= IndexEntryFlags.End;

            // The set of entries in the new node
            List <IndexEntry> newEntries = new List <IndexEntry>(midEntryIdx + 1);

            for (int i = 0; i < midEntryIdx; ++i)
            {
                newEntries.Add(_entries[i]);
            }
            newEntries.Add(newTerm);

            // Copy the node pointer from the elected 'mid' entry to the new node
            if ((midEntry.Flags & IndexEntryFlags.Node) != 0)
            {
                newTerm.ChildrenVirtualCluster = midEntry.ChildrenVirtualCluster;
                newTerm.Flags |= IndexEntryFlags.Node;
            }

            // Set the new entries into the new node
            IndexBlock newBlock = _index.AllocateBlock(_parent, midEntry);

            newBlock.Node.SetEntries(newEntries, 0, newEntries.Count);

            // All of the nodes that used to be referenced by an entry that's just gone
            // into the new block, need to have their parent references updated to point
            // to the new block.
            foreach (var entry in newEntries)
            {
                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexBlock block = _index.GetSubBlockIfCached(entry);
                    if (block != null)
                    {
                        block.Node._parent = newBlock.Node;
                    }
                }
            }

            // Forget about the entries moved into the new node, and the entry about
            // to be promoted as the new node's pointer
            _entries.RemoveRange(0, midEntryIdx + 1);

            // Promote the old mid entry
            _parent.AddEntry(midEntry, true);
        }
예제 #6
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;
                    }
                }
            }
        }
예제 #7
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);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Only valid on non-root nodes, this method divides the node in two,
        /// adding the new node to the current parent.
        /// </summary>
        /// <returns>An entry that needs to be promoted to the parent node (if any).</returns>
        private IndexEntry Divide()
        {
            int        midEntryIdx = _entries.Count / 2;
            IndexEntry midEntry    = _entries[midEntryIdx];

            // The terminating entry (aka end) for the new node
            IndexEntry newTerm = new IndexEntry(_index.IsFileIndex);

            newTerm.Flags |= IndexEntryFlags.End;

            // The set of entries in the new node
            List <IndexEntry> newEntries = new List <IndexEntry>(midEntryIdx + 1);

            for (int i = 0; i < midEntryIdx; ++i)
            {
                newEntries.Add(_entries[i]);
            }

            newEntries.Add(newTerm);

            // Copy the node pointer from the elected 'mid' entry to the new node
            if ((midEntry.Flags & IndexEntryFlags.Node) != 0)
            {
                newTerm.ChildrenVirtualCluster = midEntry.ChildrenVirtualCluster;
                newTerm.Flags |= IndexEntryFlags.Node;
            }

            // Set the new entries into the new node
            IndexBlock newBlock = _index.AllocateBlock(midEntry);

            // Set the entries into the new node.  Note we updated the parent
            // pointers first, because it's possible SetEntries may need to further
            // divide the entries to fit into nodes.  We mustn't overwrite any changes.
            newBlock.Node.SetEntries(newEntries, 0, newEntries.Count);

            // Forget about the entries moved into the new node, and the entry about
            // to be promoted as the new node's pointer
            _entries.RemoveRange(0, midEntryIdx + 1);

            // Promote the old mid entry
            return(midEntry);
        }
예제 #9
0
        /// <summary>
        /// Only valid on the root node, this method moves all entries into a
        /// single child node.
        /// </summary>
        internal bool Depose()
        {
            if (_parent != null)
            {
                throw new InvalidOperationException("Only valid on root node");
            }

            if (_entries.Count == 1)
            {
                return(false);
            }

            IndexEntry newRootEntry = new IndexEntry(_index.IsFileIndex);

            newRootEntry.Flags = IndexEntryFlags.End;

            IndexBlock newBlock = _index.AllocateBlock(this, newRootEntry);

            newBlock.Node.SetEntries(_entries, 0, _entries.Count);

            // All of the nodes that used to be one layer beneath us, are now two layers
            // beneath, they need their parent pointers updating.
            foreach (var entry in _entries)
            {
                if ((entry.Flags & IndexEntryFlags.Node) != 0)
                {
                    IndexBlock block = _index.GetSubBlockIfCached(entry);
                    if (block != null)
                    {
                        block.Node._parent = newBlock.Node;
                    }
                }
            }

            _entries.Clear();
            _entries.Add(newRootEntry);

            return(true);
        }
예제 #10
0
파일: Index.cs 프로젝트: alexcmd/DiscUtils
        internal IndexBlock GetSubBlock(IndexEntry parentEntry)
        {
            IndexBlock block = _blockCache[parentEntry.ChildrenVirtualCluster];
            if (block == null)
            {
                block = new IndexBlock(this, false, parentEntry, _bpb);
                _blockCache[parentEntry.ChildrenVirtualCluster] = block;
            }

            return block;
        }