Exemplo n.º 1
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);
        }
Exemplo n.º 2
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);
        }
Exemplo n.º 3
0
        /// <summary>
        /// 检查文件结构
        /// </summary>
        /// <param name="chunksInUse">若指定使用中的块列表,则逐个匹配确认是否存在对应的块</param>
        /// <param name="throwExceptionWhenNotMatch">当发现未匹配的使用块时,是否抛出异常</param>
        private void CheckStructure(IDictionary <long, string> chunksInUse, bool throwExceptionWhenNotMatch)
        {
            Hashtable blockNumberToFlag = new Hashtable();
            Hashtable blockNumberToNext = new Hashtable();
            Hashtable visited           = new Hashtable();

            long lastBlockNumber = this.BlockFile.NextBlockNumber();

            for (long number = 0; number < lastBlockNumber; number++)
            {
                LinkedFileBlockFlag blockFlag;
                long nextBufferNumber;
                this.ReadBlock(number, out blockFlag, out nextBufferNumber);

                blockNumberToFlag[number] = blockFlag;
                blockNumberToNext[number] = nextBufferNumber;
            }

            // traverse the freelist
            long currentFreeBlockNumber = this.FreeBlockHead;

            while (currentFreeBlockNumber != StoredConstants.NullBlockNumber)
            {
                if (visited.ContainsKey(currentFreeBlockNumber))
                {
                    throw new LinkedFileException("cycle in free list " + currentFreeBlockNumber);
                }

                visited[currentFreeBlockNumber] = currentFreeBlockNumber;

                LinkedFileBlockFlag blockFlag = (LinkedFileBlockFlag)blockNumberToFlag[currentFreeBlockNumber];
                long nextBlockNumber          = (long)blockNumberToNext[currentFreeBlockNumber];

                if (blockFlag != LinkedFileBlockFlag.Free)
                {
                    throw new LinkedFileException("free list element not marked free " + currentFreeBlockNumber);
                }

                currentFreeBlockNumber = nextBlockNumber;
            }

            // traverse all nodes marked head
            Hashtable allChunks = new Hashtable();

            for (long number = 0; number < lastBlockNumber; number++)
            {
                LinkedFileBlockFlag blockFlag = (LinkedFileBlockFlag)blockNumberToFlag[number];
                if (blockFlag == LinkedFileBlockFlag.Head)
                {
                    if (visited.ContainsKey(number))
                    {
                        throw new LinkedFileException("head buffer already visited " + number);
                    }

                    allChunks[number] = number;
                    visited[number]   = number;

                    long bodyBlockNumber = (long)blockNumberToNext[number];
                    while (bodyBlockNumber != StoredConstants.NullBlockNumber)
                    {
                        LinkedFileBlockFlag bodyBlockFlag = (LinkedFileBlockFlag)blockNumberToFlag[bodyBlockNumber];
                        long nextBlockNumber = (long)blockNumberToNext[bodyBlockNumber];

                        if (visited.ContainsKey(bodyBlockNumber))
                        {
                            throw new LinkedFileException("body block visited twice " + bodyBlockNumber);
                        }

                        visited[bodyBlockNumber] = bodyBlockFlag;

                        if (bodyBlockFlag != LinkedFileBlockFlag.Body)
                        {
                            throw new LinkedFileException("body block not marked body " + blockFlag);
                        }

                        bodyBlockNumber = nextBlockNumber;
                    }

                    // check retrieval
                    this.GetChunk(number);
                }
            }

            // make sure all were visited
            for (long number = 0; number < lastBlockNumber; number++)
            {
                if (!visited.ContainsKey(number))
                {
                    throw new LinkedFileException("block not found either as data or free " + number);
                }
            }

            // check against in use list
            if (chunksInUse != null)
            {
                ArrayList notInUse = new ArrayList();

                foreach (var d in chunksInUse)
                {
                    long blockNumber = (long)d.Key;
                    if (!allChunks.ContainsKey(blockNumber))
                    {
                        throw new LinkedFileException("block in used list not found in linked file " + blockNumber + " " + d.Value);
                    }
                }
                foreach (DictionaryEntry d in allChunks)
                {
                    long blockNumber = (long)d.Key;
                    if (!chunksInUse.ContainsKey(blockNumber))
                    {
                        if (!throwExceptionWhenNotMatch)
                        {
                            throw new LinkedFileException("block in linked file not in used list " + blockNumber);
                        }
                        notInUse.Add(blockNumber);
                    }
                }

                notInUse.Sort();
                notInUse.Reverse();

                foreach (object item in notInUse)
                {
                    long blockNumber = (long)item;
                    this.ReleaseBlocks(blockNumber);
                }
            }
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 5
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;
    }
Exemplo n.º 6
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);
    }