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