/// <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 byte[] this[byte[] key] { get { byte[] value; if (TryGetValue(key, out value)) { return(value); } throw new KeyNotFoundException(); } set { IndexEntry oldEntry; IndexNode node; _rootNode.TotalSpaceAvailable = _rootNode.CalcSize() + _file.MftRecordFreeSpace(AttributeType.IndexRoot, _name); if (_rootNode.TryFindEntry(key, out oldEntry, out node)) { node.UpdateEntry(key, value); } else { _rootNode.AddEntry(key, value); } } }
/// <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); }