/// <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); }
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); }
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); }
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; } } }
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); } } }
/// <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); }
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); }