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);
                    }
                }
            }
        }
Example #3
0
        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);
        }
Example #5
0
        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;
            }
        }
Example #10
0
        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);
        }