Beispiel #1
0
        /// <summary>
        /// 构造B+树存储头
        /// </summary>
        /// <returns></returns>
        private byte[] MakeHeader()
        {
            // 魔数前缀 | 版本 | 节点容量 | 键大小 | 根节点块序号 | 空闲块头序号
            // prefix | version | node size | key size | block number of root | block number of free list head
            byte[] header = new byte[HeaderSize];

            // 魔数前缀
            StoredConstants.TreeFileHeaderPrefix.CopyTo(header, 0);

            // 版本 1 Byte
            header[StoredConstants.TreeFileHeaderPrefix.Length] = Version;

            // 节点容量 4 Bytes
            int index = StoredConstants.TreeFileHeaderPrefix.Length + 1;

            StoredHelper.Store(this.NodeCapacity, header, index);
            index += StoredConstants.IntegerLength;

            // 键大小 4 Bytes
            StoredHelper.Store(this.KeyLength, header, index);
            index += StoredConstants.IntegerLength;

            // 根节点块序号 8 Bytes
            StoredHelper.Store(this.RootNodeBlockNumber, header, index);
            index += StoredConstants.LongLength;

            // 空闲块头序号 8 Bytes
            StoredHelper.Store(this.FreeBlockHeadNumber, header, index);
            index += StoredConstants.LongLength;

            return(header);
        }
Beispiel #2
0
        /// <summary>
        /// 读取块存储头部
        /// </summary>
        private void ReadFileHeader()
        {
            byte[] header = new byte[this.FileHeaderSize];

            this.Stream.Seek(this.SeekStart, SeekOrigin.Begin);
            this.Stream.Read(header, 0, this.FileHeaderSize);

            int index = 0;

            // 魔数前缀
            foreach (byte b in FileHeaderPrefix)
            {
                if (header[index] != b)
                {
                    throw new LinkedFileException("invalid header prefix");
                }
                index++;
            }

            // 块的大小
            this.BlockSize = StoredHelper.RetrieveInt(header, index);
            index         += StoredConstants.IntegerLength;

            // 空闲列表头序号
            this.FreeBlockHead = StoredHelper.RetrieveLong(header, index);
            index += StoredConstants.LongLength;

            this.IsHeaderDirty = false;

            if (this.BlockSize < StoredConstants.MinBlockSize)
            {
                throw new LinkedFileException("linked file block size too small " + this.BlockSize);
            }
        }
Beispiel #3
0
        /// <summary>
        /// 读取块存储头部
        /// </summary>
        private void ReadFileHeader()
        {
            // 魔数前缀长度 | 块的大小
            byte[] header = new byte[FileHeaderSize];
            this.Stream.Seek(this.SeekStart, SeekOrigin.Begin);
            this.Stream.Read(header, 0, FileHeaderSize);

            int index = 0;

            // 魔数前缀
            foreach (byte b in FileHeaderPrefix)
            {
                if (header[index] != b)
                {
                    throw new BlockFileException("Invalid block file header prefix.");
                }
                index++;
            }

            // 块的大小 4 Bytes
            this.BlockSize = StoredHelper.RetrieveInt(header, index);
            index         += StoredConstants.IntegerLength;

            if (this.BlockSize < StoredConstants.MinBlockSize)
            {
                throw new BlockFileException("Block size is too small " + this.BlockSize + ".");
            }
        }
Beispiel #4
0
        /// <summary>
        /// 获取指定头序号的大块数据
        /// </summary>
        /// <param name="headBlockNumber">指定头序号</param>
        /// <returns>大块数据</returns>
        public byte[] GetChunk(long headBlockNumber)
        {
            // get the head, interpret the length
            LinkedFileBlockFlag blockFlag;
            long nextBlockNumber;

            byte[] block = this.ReadBlock(headBlockNumber, out blockFlag, out nextBlockNumber);

            // 读取块长度
            int length = StoredHelper.RetrieveInt(block, 0);

            if (length < 0)
            {
                throw new LinkedFileException("negative length block? must be garbage: " + length);
            }

            if (blockFlag != LinkedFileBlockFlag.Head)
            {
                throw new LinkedFileException("first block not marked HEAD");
            }

            byte[] buffer = new byte[length];

            // 在第一个块中读取数据
            int firstLength = this.BlockSize - StoredConstants.IntegerLength;

            if (firstLength > length)
            {
                firstLength = length;
            }
            Array.Copy(block, StoredConstants.IntegerLength, buffer, 0, firstLength);

            // 在链接的其他块中读取数据
            int stored = firstLength;

            while (stored < length)
            {
                // get the next buffer
                long currentBlockNumber = nextBlockNumber;
                block = this.ReadBlock(currentBlockNumber, out blockFlag, out nextBlockNumber);

                int nextLength = this.BlockSize;
                if (length - stored < nextLength)
                {
                    nextLength = length - stored;
                }

                Array.Copy(block, 0, buffer, stored, nextLength);
                stored += nextLength;
            }

            return(buffer);
        }
Beispiel #5
0
        /// <summary>
        /// 构造存储头
        /// </summary>
        /// <returns></returns>
        public byte[] MakeFileHeader()
        {
            // 魔数前缀长度 | 块的大小
            byte[] header = new byte[FileHeaderSize];

            // 魔数前缀
            FileHeaderPrefix.CopyTo(header, 0);

            // 块的大小 4 Bytes
            StoredHelper.Store(this.BlockSize, header, FileHeaderPrefix.Length);

            return(header);
        }
Beispiel #6
0
        /// <summary>
        /// 读取B+树存储头
        /// </summary>
        private void ReadHeader()
        {
            // 魔数前缀 | 版本 | 节点容量 | 键大小 | 根节点块序号 | 空闲块头序号
            // prefix | version | node size | key size | block number of root | block number of free list head
            byte[] header = new byte[HeaderSize];

            this.Stream.Seek(this.SeekStart, SeekOrigin.Begin);
            this.Stream.Read(header, 0, HeaderSize);

            // 验证头前缀魔数
            int index = 0;

            foreach (byte b in StoredConstants.TreeFileHeaderPrefix)
            {
                if (header[index] != b)
                {
                    throw new BlockFileException("invalid header prefix");
                }
                index++;
            }

            // 版本
            this.Version = header[index];
            index       += 1;

            // 节点容量
            this.NodeCapacity = StoredHelper.RetrieveInt(header, index);
            index            += StoredConstants.IntegerLength;

            // 键大小
            this.KeyLength = StoredHelper.RetrieveInt(header, index);
            index         += StoredConstants.IntegerLength;

            // 根节点块序号
            this.RootNodeBlockNumber = StoredHelper.RetrieveLong(header, index);
            index += StoredConstants.LongLength;

            // 空闲块头序号
            this.FreeBlockHeadNumber = StoredHelper.RetrieveLong(header, index);
            index += StoredConstants.LongLength;

            if (this.NodeCapacity < 2)
            {
                throw new BPlusTreeException("node size must be larger than 2");
            }
            if (this.KeyLength < 5)
            {
                throw new BPlusTreeException("Key length must be larger than 5");
            }
        }
Beispiel #7
0
        /// <summary>
        /// 在指定的块序号之后,查找新的空闲块头序号
        /// </summary>
        /// <param name="blockNumber">指定的块序号</param>
        /// <returns>新的空闲块头序号</returns>
        private long ParseFreeBlock(long blockNumber)
        {
            int freeSize = 1 + StoredConstants.LongLength;

            byte[] block = new byte[freeSize];

            this.BlockFile.ReadBlock(blockNumber, block, 0, freeSize);
            if (block[0] != (byte)BPlusTreeNodeIndicator.Free)
            {
                throw new BPlusTreeException("free block not marked free");
            }

            long newHead = StoredHelper.RetrieveLong(block, 1);

            return(newHead);
        }
Beispiel #8
0
        /// <summary>
        /// 读取块
        /// </summary>
        /// <param name="blockNumber">块序号</param>
        /// <param name="blockFlag">块标记</param>
        /// <param name="nextBlockNumber">链接的下一个块</param>
        /// <returns>块数据</returns>
        private byte[] ReadBlock(long blockNumber, out LinkedFileBlockFlag blockFlag, out long nextBlockNumber)
        {
            byte[] fullBuffer = new byte[LinkedBlockOverhead + this.BlockSize];
            this.BlockFile.ReadBlock(blockNumber, fullBuffer, 0, fullBuffer.Length);

            // 读取块标记
            blockFlag = (LinkedFileBlockFlag)fullBuffer[0];

            // 读取链接的下一个块的序号
            nextBlockNumber = StoredHelper.RetrieveLong(fullBuffer, 1);

            // 读取数据
            byte[] buffer = new byte[this.BlockSize];
            Array.Copy(fullBuffer, LinkedBlockOverhead, buffer, 0, this.BlockSize);

            return(buffer);
        }
Beispiel #9
0
        /// <summary>
        /// 构造存储头
        /// </summary>
        /// <returns></returns>
        public byte[] MakeFileHeader()
        {
            // 魔数前缀长度 | 块的大小 | 空闲列表头序号
            byte[] header = new byte[this.FileHeaderSize];

            // 魔数前缀
            FileHeaderPrefix.CopyTo(header, 0);
            int index = FileHeaderPrefix.Length;

            // 块的大小
            StoredHelper.Store(this.BlockSize, header, index);
            index += StoredConstants.IntegerLength;

            // 空闲列表头序号
            StoredHelper.Store(this.FreeBlockHead, header, index);
            index += StoredConstants.LongLength;

            return(header);
        }
Beispiel #10
0
        /// <summary>
        /// 回收再利用指定序号的块
        /// </summary>
        /// <param name="blockNumber">指定序号</param>
        public void ReclaimBlock(long blockNumber)
        {
            int freeSize = 1 + StoredConstants.LongLength;

            byte[] block = new byte[freeSize];

            // it better not already be marked free
            this.BlockFile.ReadBlock(blockNumber, block, 0, 1);
            if (block[0] == (byte)BPlusTreeNodeIndicator.Free)
            {
                throw new BPlusTreeException("attempt to re-free free block not allowed");
            }
            block[0] = (byte)BPlusTreeNodeIndicator.Free;

            // 将指定序号的块置为空闲
            StoredHelper.Store(this.FreeBlockHeadNumber, block, 1);
            this.BlockFile.WriteBlock(blockNumber, block, 0, freeSize);
            this.FreeBlockHeadNumber = blockNumber;
        }
Beispiel #11
0
        /// <summary>
        /// 写入块
        /// </summary>
        /// <param name="blockNumber">块序号</param>
        /// <param name="blockFlag">块标记</param>
        /// <param name="fromArray">读取至此数组</param>
        /// <param name="startAt">读取起始点</param>
        /// <param name="length">读取长度</param>
        /// <param name="nextBlockNumber">链接的下一个块</param>
        private void WriteBlock(long blockNumber, LinkedFileBlockFlag blockFlag, byte[] fromArray, int startAt, int length, long nextBlockNumber)
        {
            if (this.BlockSize < length)
            {
                throw new LinkedFileException("block size too small " + this.BlockSize + "<" + length);
            }

            byte[] buffer = new byte[LinkedBlockOverhead + length];

            // 写入块标记
            buffer[0] = (byte)blockFlag; // 1 Byte

            // 写入链接的下一个块的序号
            StoredHelper.Store(nextBlockNumber, buffer, 1); // 8 Bytes

            // 写入数据
            if (fromArray != null)
            {
                Array.Copy(fromArray, startAt, buffer, LinkedBlockOverhead, length);
            }

            this.BlockFile.WriteBlock(blockNumber, buffer, 0, buffer.Length);
        }
Beispiel #12
0
        /// <summary>
        /// 存储新的大块数据,返回头序号。
        /// </summary>
        /// <param name="chunk">读取至此数组</param>
        /// <param name="startAt">读取起始点</param>
        /// <param name="length">读取长度</param>
        /// <returns>存储数据的头序号</returns>
        public long StoreChunk(byte[] chunk, int startAt, int length)
        {
            if (length < 0 || startAt < 0)
            {
                throw new LinkedFileException("cannot store negative length chunk (" + startAt + "," + length + ")");
            }

            // 分配用于存储的块 并标记为头块
            long currentBlockNumber = this.AllocateBlock();
            LinkedFileBlockFlag currentBlockFlag = LinkedFileBlockFlag.Head;

            // 存储数据的头序号
            long headBlockNumber = currentBlockNumber;

            int endAt = startAt + length;

            // special case: zero length chunk
            if (endAt > chunk.Length)
            {
                throw new LinkedFileException("array doesn't have this much data: " + endAt);
            }

            // store header with length information
            byte[] block = new byte[this.BlockSize];

            // 存储块长度
            StoredHelper.Store(length, block, 0);

            int fromIndex        = startAt;
            int firstBlockLength = this.BlockSize - StoredConstants.IntegerLength;
            int storedLength     = 0;

            if (firstBlockLength > length)
            {
                firstBlockLength = length;
            }

            // 存储数据
            Array.Copy(chunk, fromIndex, block, StoredConstants.IntegerLength, firstBlockLength);

            storedLength += firstBlockLength;
            fromIndex    += firstBlockLength;

            // 存储剩余数据
            while (storedLength < length)
            {
                // 获取下一个块序号
                long nextBlockNumber = this.AllocateBlock();

                // 存储当前数据
                this.WriteBlock(currentBlockNumber, currentBlockFlag, block, 0, block.Length, nextBlockNumber);

                currentBlockNumber = nextBlockNumber;
                currentBlockFlag   = LinkedFileBlockFlag.Body; // 下一个块则为Body

                int nextLength = this.BlockSize;
                if (storedLength + nextLength > length)
                {
                    nextLength = length - storedLength;
                }

                Array.Copy(chunk, fromIndex, block, 0, nextLength);

                storedLength += nextLength;
                fromIndex    += nextLength;
            }

            // 存储最终块
            this.WriteBlock(currentBlockNumber, currentBlockFlag, block, 0, block.Length, StoredConstants.NullBlockNumber);

            return(headBlockNumber);
        }