Exemplo n.º 1
0
        /// <summary>
        ///     Write a block and return the offset after the block
        /// </summary>
        /// <param name="block"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        private long WriteBlock(PersistentBlock block, long offset)
        {
            StorageStream.Seek(offset, SeekOrigin.Begin);
            var writer = new BinaryWriter(StorageStream);

            block.Write(writer);
            writer.Flush();

            return(StorageStream.Position);
        }
Exemplo n.º 2
0
        /// <summary>
        ///     Add a new bloc or update an existing one (depending if the primary key is already stored)
        /// </summary>
        /// <param name="data"></param>
        /// <param name="primaryKey"></param>
        /// <param name="transactionId"></param>
        public void StoreBlock(byte[] data, string primaryKey, int transactionId)
        {
            var block = new PersistentBlock
            {
                RawData           = data,
                PrimaryKey        = primaryKey,
                BlockStatus       = BlockStatus.Active,
                LastTransactionId = transactionId,
                UsedDataSize      = data.Length
            };

            if (BlockInfoByPrimaryKey.TryGetValue(primaryKey, out var blockInfo))
            {
                // load the old version of the block
                StorageStream.Seek(blockInfo.Offset, SeekOrigin.Begin);

                var reader = new BinaryReader(StorageStream);

                var oldBlock = new PersistentBlock();
                oldBlock.Read(reader);

                // if enough space is available do in-place update
                if (oldBlock.ReservedDataSize > block.UsedDataSize)
                {
                    block.ReservedDataSize = oldBlock.ReservedDataSize;

                    WriteBlock(block, blockInfo.Offset);
                }
                else // the old block is marked as deleted and the new version is added at the end of the stream
                {
                    oldBlock.BlockStatus = BlockStatus.Dirty;

                    InactiveBlockCount++;

                    WriteBlock(oldBlock, blockInfo.Offset);

                    block.ReservedDataSize = (int)(block.UsedDataSize * 1.5);
                    StorageSize            = WriteBlock(block, StorageSize);

                    BlockInfoByPrimaryKey[primaryKey] = new BlockInfo(StorageSize, block.LastTransactionId);
                }
            }
            else // a new object not already in the persistent storage
            {
                // reserve some more space to allow for in-place updating
                block.ReservedDataSize = (int)(block.UsedDataSize * 1.5);

                var offset = StorageSize;
                StorageSize = WriteBlock(block, StorageSize);

                BlockInfoByPrimaryKey[primaryKey] = new BlockInfo(offset, block.LastTransactionId);
            }

            _backupStorage?.StoreBlock(data, primaryKey, transactionId);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Remove dirty blocks thus compacting the storage
        /// </summary>
        public void CleanStorage()
        {
            if (File.Exists(TempFileName))
            {
                File.Delete(TempFileName);
            }

            var fullPath = Path.Combine(DataPath, StorageFileName);
            var tempPath = Path.Combine(DataPath, TempFileName);

            using (var tempStream = new FileStream(tempPath, FileMode.Create))
            {
                var writer = new BinaryWriter(tempStream);
                StorageStream.Dispose();

                StorageStream = new FileStream(fullPath, FileMode.OpenOrCreate);

                var reader = new BinaryReader(StorageStream);

                var  block  = new PersistentBlock();
                long offset = 0;


                // read all the blocks
                while (block.Read(reader))
                {
                    if (block.BlockStatus == BlockStatus.Active)
                    {
                        offset = (int)StorageStream.Position;
                        block.Write(writer);
                    }
                }

                StorageSize = offset;

                writer.Flush();
                StorageStream.Dispose();
            }

            File.Delete(fullPath);

            File.Move(tempPath, fullPath);


            StorageStream = new FileStream(fullPath, FileMode.OpenOrCreate);

            InactiveBlockCount = 0;
        }
Exemplo n.º 4
0
        /// <summary>
        ///     For recovery tests only
        /// </summary>
        /// <param name="primaryKey"></param>
        public void MakeCorruptedBlock(string primaryKey)
        {
            if (BlockInfoByPrimaryKey.TryGetValue(primaryKey, out var info))
            {
                var block = new PersistentBlock();
                StorageStream.Seek(info.Offset, SeekOrigin.Begin);
                var reader = new BinaryReader(StorageStream);
                block.Read(reader);

                block.Hash = block.Hash + 1; // the hash will not match so the block is corrupted
                StorageStream.Seek(info.Offset, SeekOrigin.Begin);

                var writer = new BinaryWriter(StorageStream);
                block.Write(writer);
            }
        }
Exemplo n.º 5
0
        public PersistentBlock ReadBlock(string primaryKey)
        {
            if (BlockInfoByPrimaryKey.TryGetValue(primaryKey, out var info))
            {
                var block = new PersistentBlock();

                StorageStream.Seek(info.Offset, SeekOrigin.Begin);
                var reader = new BinaryReader(StorageStream);

                block.Read(reader);

                return(block);
            }

            throw new NotSupportedException("primary key not found in backup storage");
        }
Exemplo n.º 6
0
        private void MarkInvalidBlocksAsDirty(InvalidBlockException e)
        {
            var nextOffset = FindNextBeginMarker(e.Offset + PersistentBlock.MinSize);

            var size = nextOffset - e.Offset;

            var dirtyBlock = PersistentBlock.MakeDirtyBlock(size);

            StorageStream.Seek(e.Offset, SeekOrigin.Begin);

            var writer = new BinaryWriter(StorageStream);

            dirtyBlock.Write(writer);

            InactiveBlockCount++;

            CorruptedBlocks++;
        }
Exemplo n.º 7
0
        public void DeleteBlock(string primaryKey, int transactionId)
        {
            if (BlockInfoByPrimaryKey.TryGetValue(primaryKey, out var blockInfo))
            {
                StorageStream.Seek(blockInfo.Offset, SeekOrigin.Begin);

                var reader = new BinaryReader(StorageStream);
                var block  = new PersistentBlock();
                block.Read(reader);
                if (block.BlockStatus != BlockStatus.Active)
                {
                    // if the same id ok. We are re executing a transaction that was not marked as Processed.
                    // It happens if the server crashes during the update of persistence blocks. The transaction is simply played
                    // again when the server is restarted
                    if (block.LastTransactionId != transactionId)
                    {
                        throw new NotSupportedException(
                                  $"Trying to delete an inactive block for primary key {primaryKey}");
                    }
                }

                block.BlockStatus       = BlockStatus.Deleted;
                block.LastTransactionId = transactionId;

                StorageStream.Seek(blockInfo.Offset, SeekOrigin.Begin);
                var writer = new BinaryWriter(StorageStream);
                block.Write(writer);
                writer.Flush();

                BlockInfoByPrimaryKey.Remove(primaryKey);

                InactiveBlockCount++;

                _backupStorage?.DeleteBlock(primaryKey, transactionId);
            }
            else
            {
                throw new NotSupportedException($"Active block not found for primary key {primaryKey}");
            }
        }
Exemplo n.º 8
0
        private void LoadAll(bool useObjectProcessor)
        {
            var reader = new BinaryReader(StorageStream);

            var  block  = new PersistentBlock();
            long offset = 0;


            // read all the blocks
            while (block.Read(reader))
            {
                // get information for deleted blocks too as there may be an uncomplete delete transaction to
                // reprocess
                if (block.BlockStatus == BlockStatus.Active || block.BlockStatus == BlockStatus.Deleted)
                {
                    BlockInfoByPrimaryKey[block.PrimaryKey] =
                        new BlockInfo(offset, block.LastTransactionId);

                    // only active blocks contain objects
                    if (useObjectProcessor && block.BlockStatus == BlockStatus.Active)
                    {
                        ObjectProcessor.Process(block.RawData);
                    }
                }

                if (block.BlockStatus != BlockStatus.Active)
                {
                    InactiveBlockCount++;
                }

                offset = (int)StorageStream.Position;
            }

            if (useObjectProcessor)
            {
                ObjectProcessor.EndProcess(DataPath);
            }

            StorageSize = offset;
        }