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