Beispiel #1
0
        /// <summary> Construct from a read-only file. </summary>
        /// <remarks>
        ///     Used when recovering files written by a previous program
        ///     instance from their locations.
        /// </remarks>
        public BlockFile(IFileMemory file, uint fileId)
        {
            _pinner = new Pinner();
            _file   = file ?? throw new ArgumentNullException(nameof(file));
            FileId  = fileId;

            _flags = new AppendList <ReadFlag>();

            var offset = 0L;

            while (offset < _file.Length)
            {
                var     block  = AtOffset(offset);
                ref var header = ref block.Header;

                if (header.Rank != _flags.Count || header.ContentLength < 0 ||
                    header.ContentLength + BlockHeader.Size > _file.Length)
                {
                    // The header of the block appears broken. Do not include
                    // it in the list, and stop scanning (since we don't know
                    // how far to jump ahead).
                    break;
                }

                var thisOffset = offset;
                _flags.Append(ReadFlag.Triggered(() => VerifyAtOffset(thisOffset)));

                offset += block.RelativeOffsetToNextBlock;
            }
Beispiel #2
0
        /// <summary>
        ///     Attempts to schedule a write of the specified length into the file.
        /// </summary>
        /// <returns>
        ///     A valid block address representing the location where the written
        ///     block will be found, or a 'None' address if the file does not
        ///     currently have enough room for this.
        /// </returns>
        /// <remarks>
        ///     The provided writer will be invoked at some point in the future.
        ///
        ///     Thread-safe.
        /// </remarks>
        public BlockAddress TryScheduleWrite(
            uint realm,
            Hash hash,
            int length,
            WithSpan.ReadWrite writer)
        {
            if (length < 0)
            {
                throw new ArgumentException($"Negative length: {length}", nameof(length));
            }
            int  rank;
            long offset;

            lock (_syncRoot)
            {
                offset  = _offset;
                _offset = BlockAddress.Ceiling(offset + BlockHeader.Size + length);

                if (_offset > _file.Length)
                {
                    // Since this file is about to be flushed and closed,
                    // because it's "full enough", we prevent additional writes.
                    _offset = _file.Length;
                    return(BlockAddress.None);
                }

                rank = _flags.Count;
                _flags.Append(ReadFlag.Triggered(() => PerformWrite(offset, writer)));
            }

            // We touched '_offset' and '_flags' in the critical section, the remaining
            // work on the actual byte span can be done without mutex.

            var     span   = _file.AsMemory(offset, BlockHeader.Size).Span;
            ref var header = ref MemoryMarshal.Cast <byte, BlockHeader>(span)[0];