public void UpdateSubnodeEntry(NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree) { SubnodeLeafEntry entry = GetLeafEntry(subnodeID.Value); if (entry != null) { entry.bidData = new BlockID(0); if (dataTree != null && dataTree.RootBlock != null) { entry.bidData = dataTree.RootBlock.BlockID; } entry.bidSub = new BlockID(0); if (subnodeBTree != null && subnodeBTree.RootBlock != null) { entry.bidSub = subnodeBTree.RootBlock.BlockID; } // We have to store the new leaf block, and cascade the changes up to the root block SubnodeLeafBlock leafBlock = FindLeafBlock(entry.nid.Value); // leafBlock cannot be null int index = leafBlock.IndexOfLeafEntry(subnodeID.Value); leafBlock.rgentries[index] = entry; UpdateBlockAndReferences(leafBlock); } }
public void DeleteSubnodeEntry(NodeID subnodeID) { SubnodeLeafBlock leafBlock = FindLeafBlock(subnodeID.Value); if (leafBlock != null) { int index = leafBlock.IndexOfLeafEntry(subnodeID.Value); if (index >= 0) { leafBlock.rgentries.RemoveAt(index); if (leafBlock.rgentries.Count == 0) { // We will only delete the root during SaveChanges() // [We want to avoid setting the root to null, because we may still use it before changes are saved] if (m_rootBlock is SubnodeIntermediateBlock) { int indexOfBlock = ((SubnodeIntermediateBlock)m_rootBlock).GetIndexOfBlockID(leafBlock.BlockID.Value); ((SubnodeIntermediateBlock)m_rootBlock).rgentries.RemoveAt(indexOfBlock); UpdateBlock(m_rootBlock); DeleteBlock(leafBlock); } else { UpdateBlockAndReferences(leafBlock); } } else { UpdateBlockAndReferences(leafBlock); } } } }
public override Block Clone() { SubnodeLeafBlock result = (SubnodeLeafBlock)MemberwiseClone(); result.rgentries = new List <SubnodeLeafEntry>(); foreach (SubnodeLeafEntry entry in rgentries) { result.rgentries.Add(entry.Clone()); } return(result); }
public List <SubnodeLeafBlock> GetLeafBlocks() { List <SubnodeLeafBlock> result = new List <SubnodeLeafBlock>(); for (int blockIndex = 0; blockIndex < NumberOfLeafBlocks; blockIndex++) { SubnodeLeafBlock block = GetLeafBlock(blockIndex); result.Add(block); } return(result); }
public SubnodeLeafBlock Split() { int newBlockStartIndex = rgentries.Count / 2; SubnodeLeafBlock newBlock = new SubnodeLeafBlock(); // BlockID will be given when the block will be added for (int index = newBlockStartIndex; index < rgentries.Count; index++) { newBlock.rgentries.Add(rgentries[index]); } rgentries.RemoveRange(newBlockStartIndex, rgentries.Count - newBlockStartIndex); return(newBlock); }
public SubnodeLeafEntry GetLeafEntry(uint subnodeID) { Block block = FindLeafBlock(subnodeID); if (block is SubnodeLeafBlock) { SubnodeLeafBlock leafBlock = (SubnodeLeafBlock)block; int index = leafBlock.IndexOfLeafEntry(subnodeID); if (index >= 0) { return(leafBlock.rgentries[index]); } } return(null); }
public uint GetNextNodeIndex() { uint nextIndex = 0; for (int blockIndex = 0; blockIndex < this.NumberOfLeafBlocks; blockIndex++) { SubnodeLeafBlock leafBlock = GetLeafBlock(blockIndex); foreach (SubnodeLeafEntry entry in leafBlock.rgentries) { if (entry.nid.nidIndex >= nextIndex) { nextIndex = entry.nid.nidIndex + 1; } } } return(nextIndex); }
public void InsertSubnodeEntry(SubnodeLeafEntry entry) { if (m_rootBlock == null) { m_rootBlock = new SubnodeLeafBlock(); AddBlock(m_rootBlock); } SubnodeLeafBlock leafBlock = FindLeafBlock(entry.nid.Value); if (leafBlock.rgentries.Count < SubnodeLeafBlock.MaximumNumberOfEntries) { leafBlock.InsertSorted(entry); UpdateBlockAndReferences(leafBlock); } else { // Instead of splitting, it might be better to move entries around so blocks will remain packed SubnodeLeafBlock newLeafBlock = leafBlock.Split(); if (newLeafBlock.BlockKey < entry.nid.Value) { newLeafBlock.InsertSorted(entry); } else { int insertIndex = leafBlock.InsertSorted(entry); if (insertIndex == 0 && m_rootBlock is SubnodeIntermediateBlock) { // block key has been modified, we must update the parent UpdateIntermediateEntry((SubnodeIntermediateBlock)m_rootBlock, leafBlock.BlockID, leafBlock.BlockKey); } } UpdateBlockAndReferences(leafBlock); AddBlock(newLeafBlock); if (m_rootBlock is SubnodeLeafBlock) { // this is a root page and it's full, we have to create a new root CreateNewRoot(); } InsertIntermediateEntry((SubnodeIntermediateBlock)m_rootBlock, newLeafBlock.BlockKey, newLeafBlock.BlockID); } }
private void UpdateBlockAndReferences(SubnodeLeafBlock leafBlock) { ulong existingBlockID = leafBlock.BlockID.Value; UpdateBlock(leafBlock); if (m_rootBlock is SubnodeIntermediateBlock) { if (leafBlock.BlockID.Value != existingBlockID) { // A new block has been written instead of the old one, update the root block SubnodeIntermediateBlock rootBlock = (SubnodeIntermediateBlock)m_rootBlock; int index = rootBlock.GetIndexOfBlockID(existingBlockID); rootBlock.rgentries[index].bid = leafBlock.BlockID; UpdateBlock(m_rootBlock); } } else if (m_rootBlock is SubnodeLeafBlock) { m_rootBlock = leafBlock; } }
public static Block ReadFromStream(Stream stream, BlockRef blockRef, int dataLength, bCryptMethodName bCryptMethod) { long offset = (long)blockRef.ib; int totalLength = GetTotalBlockLength(dataLength); stream.Seek(offset, SeekOrigin.Begin); byte[] buffer = new byte[totalLength]; stream.Read(buffer, 0, totalLength); BlockTrailer trailer = BlockTrailer.ReadFromEndOfBuffer(buffer); Block block; if (trailer.bid.Internal) { // XBlock or XXBlock byte btype = buffer[0]; byte cLevel = buffer[1]; if (btype == (byte)BlockType.XBlock && cLevel == 0x01) { // XBLOCK block = new XBlock(buffer); } else if (btype == (byte)BlockType.XXBlock && cLevel == 0x02) { // XXBLOCK block = new XXBlock(buffer); } else if (btype == (byte)BlockType.SLBLOCK && cLevel == 0x00) { // SLBLock block = new SubnodeLeafBlock(buffer); } else if (btype == (byte)BlockType.SIBLOCK && cLevel == 0x01) { // SIBLock block = new SubnodeIntermediateBlock(buffer); } else { throw new Exception("Internal block, but not XBLOCK, XXBlock, SLBLOCK or SIBLOCK"); } } else { block = new DataBlock(buffer, bCryptMethod); } // See question 3 at: // http://social.msdn.microsoft.com/Forums/en-CA/os_binaryfile/thread/923f5964-4a89-4811-86c2-06a553c34510 // However, so far all tests suggest that there should be no problem to use BlockID.Value for both arguments if (blockRef.bid.LookupValue != block.BlockID.LookupValue) { throw new InvalidBlockIDException(); } if (dataLength != trailer.cb) { throw new Exception("Invalid block length"); } uint crc = PSTCRCCalculation.ComputeCRC(buffer, dataLength); if (block.BlockTrailer.dwCRC != crc) { throw new InvalidChecksumException(); } uint signature = BlockTrailer.ComputeSignature(blockRef.ib, blockRef.bid.Value); if (block.BlockTrailer.wSig != signature) { throw new InvalidChecksumException(); } return(block); }