Пример #1
0
        public void Initialize()
        {
            // recovery on edge crash
            if (File.Exists(TmpStorePath) && !File.Exists(_storePath))
            {
                File.Move(TmpStorePath, _storePath);
                _log.Log(LogSeverity.Warning, $"File recovered: {TmpStorePath}");
            }

            // Number of sectors is inferred from the file size.
            _firstNotAllocated = SectorIndex.First;
            if (File.Exists(_storePath))
            {
                var info = new FileInfo(_storePath);
                _firstNotAllocated = SectorIndex.OffsetInBytes(info.Length, _sectorSizeInBytes);
            }

            // hot stream does not apply to volatile store
            if (!File.Exists(_storePath))
            {
                _storeStream = new FileStream(_storePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
                _log?.Log(LogSeverity.Info, $"Empty file created: {_storePath}.");
                _firstNotAllocated = SectorIndex.First;

                _memoryStream = new MemoryStream();
            }
            else
            {
                _storeStream  = new FileStream(_storePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                _memoryStream = new MemoryStream((int)_storeStream.Length);
                _storeStream.CopyTo(_memoryStream);
            }
        }
Пример #2
0
        public void StoreAlternateWriteRead()
        {
            SectorIndex index = new SectorIndex(1);

            _store.Initialize();
            // manually make a sector
            var sector = new Sector(_sectorSize);

            var contentBytes = new byte[sector.Contents.Length];

            _rnd.NextBytes(contentBytes);
            contentBytes.AsSpan().CopyTo(sector.Contents);

            _store.AllocateSectors(4);
            _store.Write(index, sector);

            var storeProvided = _store.Read(index);

            // second write
            var contentBytes2 = new byte[sector.Contents.Length];

            _rnd.NextBytes(contentBytes2);
            contentBytes2.AsSpan().CopyTo(sector.Contents);

            SectorIndex otherIndex = new SectorIndex(2);

            _store.Write(otherIndex, sector);

            // read first sector
            storeProvided = _store.Read(index);

            Assert.True(storeProvided.Contents.SequenceEqual(contentBytes.AsSpan()));
        }
Пример #3
0
        public void EnsurePersistenceTest()
        {
            var numberOfSectorTesting = 5;

            _store.Initialize();
            // manually make a sector
            var sector = new Sector(_sectorSize);

            var contentBytes = new byte[sector.Contents.Length];

            for (var i = 0; i < numberOfSectorTesting; i++)
            {
                _rnd.NextBytes(contentBytes);
                contentBytes.AsSpan().CopyTo(sector.Contents);

                var index = _store.AllocateSectors(4);
                _store.Write(index, sector);
            }

            _store.EnsurePersistence();
            _store.Dispose();

            // reinit store
            _store = _storeFixiture.Create();

            _store.Initialize();
            var sectorIndex   = new SectorIndex((numberOfSectorTesting - 1) * 4);
            var storeProvided = _store.Read(sectorIndex);

            Assert.True(storeProvided.Contents.SequenceEqual(contentBytes.AsSpan()));
        }
Пример #4
0
        /// <summary>
        /// The returned 'Sector' is invalidated at the next call.
        /// </summary>
        public Sector Read(SectorIndex index)
        {
            _memoryStream.Seek(index.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);
            _sector.Read(_memoryStream, index.ByteIndex(_sectorSizeInBytes));

            return(_sector);
        }
Пример #5
0
        public SectorIndex AllocateSectors(int count)
        {
            if (count <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            var firstNewlyAllocated = _firstNotAllocated;

            _firstNotAllocated = _firstNotAllocated.GetNext(count);

            _storeStream.SetLength(_storeStream.Length + _sectorSizeInBytes * count);

            _sector.Clear();

            for (var idx = firstNewlyAllocated;
                 idx.IsWithinRange(_firstNotAllocated);
                 idx = idx.GetNext())
            {
                _sector.Write(_storeStream, idx.ByteIndex(_sectorSizeInBytes));
            }

            Debug.Assert(_storeStream.Length == _firstNotAllocated.ByteIndex(_sectorSizeInBytes));

            return(firstNewlyAllocated);
        }
Пример #6
0
        public void Initialize()
        {
            if (!File.Exists(_storePath))
            {
                _storeStream       = new FileStream(_storePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
                _firstNotAllocated = SectorIndex.First;
                _log?.Log(LogSeverity.Info, $"Empty file created: {_storePath}.");
            }
            else
            {
                _storeStream = new FileStream(_storePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }

            // Number of sectors is inferred from the file size.
            var info = new FileInfo(_storePath);

            _firstNotAllocated = SectorIndex.OffsetInBytes(info.Length, _sectorSizeInBytes);

            if (!File.Exists(_hotPath))
            {
                _hotStream = new FileStream(_hotPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
                _log?.Log(LogSeverity.Info, $"Empty file created: {_hotPath}.");
            }
            else
            {
                _hotStream = new FileStream(_hotPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                TryRecovery();
            }
        }
Пример #7
0
 public VolatileStore(int sectorSizeInBytes, string storePath, ILog log = null)
 {
     _sectorSizeInBytes = sectorSizeInBytes;
     _storePath         = storePath;
     _firstNotAllocated = SectorIndex.Unknown; // not initialized
     _log    = log;
     _sector = new Sector(_sectorSizeInBytes);
 }
Пример #8
0
 public TwoPhaseStore(int sectorSizeInBytes, string storePath, ILog log = null)
 {
     _sectorSizeInBytes = sectorSizeInBytes;
     _hotPath           = Path.Combine(Path.GetDirectoryName(storePath), @"hot-" + Path.GetFileName(storePath));
     _storePath         = storePath;
     _firstNotAllocated = SectorIndex.Unknown; // dummy initialization
     _log    = log;
     _sector = new Sector(_sectorSizeInBytes);
 }
Пример #9
0
        /// <summary>
        /// Deserialize a TxoPack from Sector.
        /// </summary>
        /// <param name="sector">Sector to deserialize</param>
        /// <param name="pack">TxoPack to fill</param>
        /// <param name="childSectorIndex">sectorIndex of child</param>
        /// <remarks>
        /// Life-time of the response lasts until the next call to 'Read'.
        /// Size of TxoPack should be large enough to not overflow.
        /// </remarks>
        public static void Deserialize(this Sector sector, TxoPack pack, out SectorIndex childSectorIndex)
        {
            var sectorContent = sector.Contents;

            childSectorIndex =
                new SectorIndex(BitConverter.ToInt32(sectorContent.Slice(ChildSectorIndexStart, ChildSectorIndexSizeInBytes)));
            var numberOfTxo = BitConverter.ToInt32(sectorContent.Slice(TxoCountStart, TxoCountSizeInBytes));
            var payloadLengthAccumulator = 0;

            ref var writer = ref pack.GetResetWriter();
Пример #10
0
        /// <remarks>
        /// The returned 'Sector' is invalidated at the next call.
        /// </remarks>
        public Sector Read(SectorIndex index)
        {
            if (!index.IsWithinRange(_firstNotAllocated))
            {
                throw new ArgumentOutOfRangeException(
                          $"Try to read from index {index} out of total {_firstNotAllocated.Value} sectors.");
            }

            _storeStream.Seek(index.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);
            _sector.Read(_storeStream, index.ByteIndex(_sectorSizeInBytes));

            return(_sector);
        }
Пример #11
0
        /// <summary>
        /// Write to hot storage first, then regular storage secondly.
        /// </summary>
        public void Write(SectorIndex index, Sector source)
        {
            if (!index.IsWithinRange(_firstNotAllocated))
            {
                throw new ArgumentOutOfRangeException(
                          $"Try to write to index {index.Value} out of total {_firstNotAllocated.Value} sectors.");
            }

            _hotStream.Seek(0, SeekOrigin.Begin);
            source.Write(_hotStream, index.ByteIndex(_sectorSizeInBytes));

            _storeStream.Seek(index.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);
            source.Write(_storeStream, index.ByteIndex(_sectorSizeInBytes));
        }
Пример #12
0
        public void StoreWriteRead()
        {
            SectorIndex index = new SectorIndex(3);

            _store.Initialize();
            // manually make a sector
            var sector = new Sector(_sectorSize);

            var rnd          = new Random(42);
            var contentBytes = new byte[sector.Contents.Length];

            rnd.NextBytes(contentBytes);
            contentBytes.AsSpan().CopyTo(sector.Contents);

            _store.AllocateSectors(4);
            _store.Write(index, sector);

            var storeProvided = _store.Read(index);

            Assert.True(storeProvided.Contents.SequenceEqual(contentBytes.AsSpan()));
        }
Пример #13
0
        public bool TryRead(SectorIndex index, out Sector sector)
        {
            sector = null;

            // upper layer saved -1 as sectorIndex if child sector doesn't exist.
            if (index.IsUnknown())
            {
                return(false);
            }

            var position = _storeStream.Seek(index.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);

            // seek a position beyond file length
            if (position == _storeStream.Length)
            {
                return(false);
            }

            _sector.Read(_storeStream, index.ByteIndex(_sectorSizeInBytes));
            sector = _sector;
            return(true);
        }
Пример #14
0
        /// <summary>
        /// Recover a halfway written sector.
        /// </summary>
        /// <remarks>
        /// TODO: verify this method does what it is supposed to do, after replacing TryRead with a Read that throws exceptions,
        /// instead of returning a bool.
        /// </remarks>
        private void TryRecovery()
        {
            try
            {
                var offset = _sector.Read(_hotStream); // hotstream is valid

                var deducedIndex = SectorIndex.OffsetInBytes(offset, _sectorSizeInBytes);
                try
                {
                    //try read last recorded sector

                    Read(deducedIndex);
                    // reach here means that both streams are ok
                }
                catch (SectorOperationException)
                {
                    // something went wrong in storeStream
                    _hotStream.Seek(0, SeekOrigin.Begin);
                    _sector.Read(_hotStream, offset);
                    // reach here means that hostream is ok

                    // copying '_hotstream' back to '_storeStream'
                    _storeStream.Seek(deducedIndex.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);
                    _sector.Write(_storeStream, deducedIndex.ByteIndex(_sectorSizeInBytes));

                    // TODO: add log to indicate successful recovery.
                }
            }
            catch (SectorOperationException)
            {
                // hotstream invalid
                // normally thanks to double writing, main store stream is valid
                _log?.Log(LogSeverity.Warning, "Hotstream error when trying to recover sector store.");

                throw;
            }
        }
Пример #15
0
 public void Write(SectorIndex index, Sector source)
 {
     _memoryStream.Seek(index.ByteIndex(_sectorSizeInBytes), SeekOrigin.Begin);
     source.Write(_memoryStream, index.ByteIndex(_sectorSizeInBytes));
 }