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