Example #1
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);
        }
Example #2
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);
        }
Example #3
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);
        }
Example #4
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;
                }
            }
        }
Example #5
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);
                }
            }
        }
Example #6
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);
        }
Example #7
0
        internal IndexBlock AllocateBlock(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, false, parentEntry, _bpb);

            _blockCache[parentEntry.ChildrenVirtualCluster] = block;
            return(block);
        }