private void LoadStreamTable() { StorageStreamMetadata streamMetadata; stream.Position = 0; int index = 0; map.Clear(); items.Clear(); int cnt = (int)stream.Length / StorageStreamMetadata.StructureSize; for (int i = 0; i < cnt; i++) { streamMetadata = StorageStreamMetadata.Load(stream, i); if (streamMetadata.StreamId != Guid.Empty) { map.Set(index, true); items.Add(streamMetadata.StreamId, index); } index++; } }
/// <summary> /// Loads metadata /// </summary> public static StorageStreamMetadata Load(Stream streamTableStream, int streamTableIndex) { streamTableStream.Position = streamTableIndex * StorageStreamMetadata.StructureSize; streamTableStream.Read(Tools.Buffer, 0, StorageStreamMetadata.StructureSize); Tools.BufferReader.BaseStream.Position = 0; StorageStreamMetadata metadata = new StorageStreamMetadata(streamTableStream); metadata.StreamTableIndex = streamTableIndex; metadata.StreamId = new Guid(Tools.BufferReader.ReadBytes(16)); metadata.Length = Tools.BufferReader.ReadInt64(); metadata.InitializedLength = Tools.BufferReader.ReadInt64(); long firstSegmentPos = Tools.BufferReader.ReadInt64(); metadata.FirstSegmentPosition = firstSegmentPos != 0 ? firstSegmentPos : (long?)null; metadata.Tag = Tools.BufferReader.ReadInt32(); int hash = Tools.BufferReader.ReadInt32(); int calculatedHash = Tools.CalculateHash(metadata.StreamId, metadata.Length, metadata.InitializedLength, firstSegmentPos); if (hash != calculatedHash) { throw new StorageException("Error loading stream metadata"); } return(metadata); }
private void InternalRollbackTransaction() { if (transactionLevel > 0) { // Remove opened streams created during transaction lock (openedStreams) { foreach (Guid streamId in streamsCreatedDuringTransaction) { WeakReference <StorageStream> reference; if (openedStreams.TryGetValue(streamId, out reference)) { StorageStream tmpStream; if (reference.TryGetTarget(out tmpStream)) { if (tmpStream != null) { tmpStream.InternalClose(); } } openedStreams.Remove(streamId); } } streamsCreatedDuringTransaction.Clear(); // Rollback data transactionStream.RollbackTransaction(); MasterStream.RollbackTransaction(); streamsChangedDuringTransaction.Clear(); // Rollback changes in stream table streamTableStream.ReloadSegmentsOnRollback(streamTableStreamMetadata); streamTable.RollbackTransaction(); // Reload segments in system and opened streams because segments has changed foreach (var item in openedStreams.Values.ToList()) { StorageStream tmpStream; if (item.TryGetTarget(out tmpStream)) { if (streamTable.Contains(tmpStream.StreamId)) { StorageStreamMetadata tmpStreamMetadata = streamTable.Get(tmpStream.StreamId); tmpStream.ReloadSegmentsOnRollback(tmpStreamMetadata); } else { tmpStream.InternalClose(); } } } // Reload empty space segments var freeSpaceStreamMetadata = streamTable.Get(SystemStreamId.EmptySpace); FreeSpaceStream.ReloadSegmentsOnRollback(freeSpaceStreamMetadata); } } }
// Reloads segments from storage internal void ReloadSegmentsOnRollback(StorageStreamMetadata metadata) { CheckClosed(); changeNotified = false; // Reaload metadata and segments LoadStream(metadata); }
/// <summary> /// Creates a storage /// </summary> private void CreateStorage(Stream stream) { this.MasterStream = new MasterStream(stream, false); // Initialize storage metadata Segment metadataStreamSegment = Segment.Create(0, blockSize, null); metadataStreamSegment.Save(stream); StorageStream metadataStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = 0, InitializedLength = blockSize - Segment.StructureSize, Length = blockSize - Segment.StructureSize, StreamId = SystemStreamId.StorageMetadata, StreamTableIndex = -1 }, this); StorageMetadata storageMetadata = new StorageMetadata("[TmStorage 1.0]"); // Set metadata again because above, stream was not specified storageMetadata.Save(metadataStream); metadataStream.Close(); // Initialize stream table long streamTableSegmentSize = 1000 / ((int)blockSize / StorageStreamMetadata.StructureSize) * blockSize; Segment streamTableSegment = Segment.Create(blockSize, streamTableSegmentSize, null); stream.Position = metadataStreamSegment.DataAreaEnd; streamTableSegment.Save(stream); StorageStream streamTableStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = blockSize, InitializedLength = streamTableSegmentSize - Segment.StructureSize, Length = streamTableSegmentSize - Segment.StructureSize, StreamId = SystemStreamId.StreamTable, StreamTableIndex = -1 }, this); // Initialize empty space stream Segment emptyStreamSegment = Segment.Create(streamTableSegment.DataAreaEnd, long.MaxValue - streamTableSegment.DataAreaEnd, null); stream.Position = streamTableSegment.DataAreaEnd; emptyStreamSegment.Save(stream); // Write empty space stream metadata to stream table StorageStreamMetadata emptySpaceStreamMetadata = new StorageStreamMetadata(streamTableStream) { FirstSegmentPosition = emptyStreamSegment.Location, InitializedLength = emptyStreamSegment.DataAreaSize, Length = emptyStreamSegment.DataAreaSize, StreamId = SystemStreamId.EmptySpace, StreamTableIndex = 0 }; emptySpaceStreamMetadata.Save(); this.MasterStream = null; }
/// <summary> /// Constructor that loads the segments from master stream /// </summary> internal StorageStream(StorageStreamMetadata metadata, Storage storage) { if (storage == null) throw new ArgumentNullException("storage"); this.storage = storage; LoadStream(metadata); }
/// <summary> /// Constructor that loads the segments from master stream /// </summary> internal StorageStream(StorageStreamMetadata metadata, Storage storage) { if (storage == null) { throw new ArgumentNullException("storage"); } this.storage = storage; LoadStream(metadata); }
/// <summary> /// Returns table entries /// </summary> public IEnumerable <StorageStreamMetadata> Get() { StorageStreamMetadata streamMetadata; foreach (StorageStreamMetadata entry in entriesAddedInTransaction.Values) { yield return(entry); } for (int i = 0; i < stream.Length / StorageStreamMetadata.StructureSize; i++) { streamMetadata = StorageStreamMetadata.Load(stream, i); if (streamMetadata.StreamId != Guid.Empty) { yield return(streamMetadata); } } }
/// <summary> /// Gets first segment location for specified streamId or nulll if not found. /// </summary> public StorageStreamMetadata Get(Guid streamId) { StorageStreamMetadata result = null; int index; // Search through entries in memory if (!entriesAddedInTransaction.TryGetValue(streamId, out result)) { // Load it from stream table stream if (items.TryGetValue(streamId, out index)) { result = StorageStreamMetadata.Load(stream, index); } } return(result); }
/// <summary> /// Adds new entry /// </summary> public StorageStreamMetadata Add(Guid streamId, int tag = 0) { // Get the position of first empty entry int index = map.FindFirstEmptyEntry(); long streamPosition = index * StorageStreamMetadata.StructureSize; // Resize stream is needed if ((streamPosition + StorageStreamMetadata.StructureSize) > stream.Length) { int count = (int)stream.Length / StorageStreamMetadata.StructureSize; count += Math.Min(Math.Max((int)(count * 1.5), 512), 50000); long oldLength = stream.Length; stream.SetLength(count * StorageStreamMetadata.StructureSize); // Write zeros to newly allocated space long bytesToWrite = stream.Length - oldLength; stream.Position = oldLength; while (bytesToWrite > 0) { int amount = (int)Math.Min(bytesToWrite, Tools.EmptyBuffer.Length); stream.Write(Tools.EmptyBuffer, 0, amount); bytesToWrite -= amount; } stream.Save(); } StorageStreamMetadata streamMetadata = new StorageStreamMetadata(stream) { FirstSegmentPosition = null, StreamId = streamId, Tag = tag, StreamTableIndex = index }; entriesAddedInTransaction.Add(streamId, streamMetadata); //streamMetadata.Save(); map.Set(index, true); items.Add(streamId, index); return(streamMetadata); }
private void LoadStream(StorageStreamMetadata metadata) { // Load segments this.metadata = metadata; long? segmentPosition = metadata.FirstSegmentPosition; segments.Clear(); while (segmentPosition.HasValue) { Segment segment = Segment.Load(storage.MasterStream, segmentPosition.Value); segments.AddLast(segment); segmentPosition = segment.NextLocation; } // Manually adjust stream length and initializedSized for stream table stream if (metadata.StreamId == SystemStreamId.StreamTable) { metadata.Length = segments.Sum(x => x.DataAreaSize); metadata.InitializedLength = metadata.Length; } }
/// <summary> /// Loads metadata /// </summary> public static StorageStreamMetadata Load(Stream streamTableStream, int streamTableIndex) { streamTableStream.Position = streamTableIndex * StorageStreamMetadata.StructureSize; streamTableStream.Read(Tools.Buffer, 0, StorageStreamMetadata.StructureSize); Tools.BufferReader.BaseStream.Position = 0; StorageStreamMetadata metadata = new StorageStreamMetadata(streamTableStream); metadata.StreamTableIndex = streamTableIndex; metadata.StreamId = new Guid(Tools.BufferReader.ReadBytes(16)); metadata.Length = Tools.BufferReader.ReadInt64(); metadata.InitializedLength = Tools.BufferReader.ReadInt64(); long firstSegmentPos = Tools.BufferReader.ReadInt64(); metadata.FirstSegmentPosition = firstSegmentPos != 0 ? firstSegmentPos : (long?)null; metadata.Tag = Tools.BufferReader.ReadInt32(); int hash = Tools.BufferReader.ReadInt32(); int calculatedHash = Tools.CalculateHash(metadata.StreamId, metadata.Length, metadata.InitializedLength, firstSegmentPos); if (hash != calculatedHash) throw new StorageException("Error loading stream metadata"); return metadata; }
/// <summary> /// Opens the storage /// </summary> private void OpenStorage() { StartTransaction(); try { // For metadata assume block size of 512 because blockSize is unknown at this point. // 512 is the smallest block size so it will work as long as storage metadata is not // longer than 512 bytes storageMetadataStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = 0, InitializedLength = 512 - Segment.StructureSize, Length = 512 - Segment.StructureSize, StreamId = SystemStreamId.StorageMetadata, StreamTableIndex = -1 }, this); StorageMetadata = StorageMetadata.Load(storageMetadataStream); streamTableStreamMetadata = new StorageStreamMetadata(storageMetadataStream) { FirstSegmentPosition = blockSize, StreamId = SystemStreamId.StreamTable, StreamTableIndex = -1 }; streamTableStream = new StorageStream(streamTableStreamMetadata, this); streamTable = new StreamTable(streamTableStream); var freeSpaceStreamMetadata = streamTable.Get(SystemStreamId.EmptySpace); FreeSpaceStream = new StorageStream(freeSpaceStreamMetadata, this); CommitTransaction(); } catch { RollbackTransaction(); throw; } }
private void LoadStream(StorageStreamMetadata metadata) { // Load segments this.metadata = metadata; long?segmentPosition = metadata.FirstSegmentPosition; segments.Clear(); while (segmentPosition.HasValue) { Segment segment = Segment.Load(storage.MasterStream, segmentPosition.Value); segments.AddLast(segment); segmentPosition = segment.NextLocation; } // Manually adjust stream length and initializedSized for stream table stream if (metadata.StreamId == SystemStreamId.StreamTable) { metadata.Length = segments.Sum(x => x.DataAreaSize); metadata.InitializedLength = metadata.Length; } }
/// <summary> /// Adds new entry /// </summary> public StorageStreamMetadata Add(Guid streamId, int tag = 0) { // Get the position of first empty entry int index = map.FindFirstEmptyEntry(); long streamPosition = index * StorageStreamMetadata.StructureSize; // Resize stream is needed if ((streamPosition + StorageStreamMetadata.StructureSize) > stream.Length) { int count = (int)stream.Length / StorageStreamMetadata.StructureSize; count += Math.Min(Math.Max((int)(count * 1.5), 512), 50000); long oldLength = stream.Length; stream.SetLength(count * StorageStreamMetadata.StructureSize); // Write zeros to newly allocated space long bytesToWrite = stream.Length - oldLength; stream.Position = oldLength; while (bytesToWrite > 0) { int amount = (int)Math.Min(bytesToWrite, Tools.EmptyBuffer.Length); stream.Write(Tools.EmptyBuffer, 0, amount); bytesToWrite -= amount; } stream.Save(); } StorageStreamMetadata streamMetadata = new StorageStreamMetadata(stream) { FirstSegmentPosition = null, StreamId = streamId, Tag = tag, StreamTableIndex = index }; entriesAddedInTransaction.Add(streamId, streamMetadata); //streamMetadata.Save(); map.Set(index, true); items.Add(streamId, index); return streamMetadata; }
/// <summary> /// Creates a storage /// </summary> private void CreateStorage(Stream stream) { this.MasterStream = new MasterStream(stream, false); // Initialize storage metadata Segment metadataStreamSegment = Segment.Create(0, blockSize, null); metadataStreamSegment.Save(stream); StorageStream metadataStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = 0, InitializedLength = blockSize - Segment.StructureSize, Length = blockSize - Segment.StructureSize, StreamId = SystemStreamId.StorageMetadata, StreamTableIndex = -1 }, this); StorageMetadata storageMetadata = new StorageMetadata("[TmStorage 1.0]"); // Set metadata again because above, stream was not specified storageMetadata.Save(metadataStream); metadataStream.Close(); // Initialize stream table long streamTableSegmentSize = 1000 / ((int)blockSize / StorageStreamMetadata.StructureSize) * blockSize; Segment streamTableSegment = Segment.Create(blockSize, streamTableSegmentSize, null); stream.Position = metadataStreamSegment.DataAreaEnd; streamTableSegment.Save(stream); StorageStream streamTableStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = blockSize, InitializedLength = streamTableSegmentSize - Segment.StructureSize, Length = streamTableSegmentSize - Segment.StructureSize, StreamId = SystemStreamId.StreamTable, StreamTableIndex = -1 }, this); // Initialize empty space stream Segment emptyStreamSegment = Segment.Create(streamTableSegment.DataAreaEnd, long.MaxValue - streamTableSegment.DataAreaEnd, null); stream.Position = streamTableSegment.DataAreaEnd; emptyStreamSegment.Save(stream); // Write empty space stream metadata to stream table StorageStreamMetadata emptySpaceStreamMetadata = new StorageStreamMetadata(streamTableStream) { FirstSegmentPosition = emptyStreamSegment.Location, InitializedLength = emptyStreamSegment.DataAreaSize, Length = emptyStreamSegment.DataAreaSize, StreamId = SystemStreamId.EmptySpace, StreamTableIndex = 0 }; emptySpaceStreamMetadata.Save(); this.MasterStream = null; }
/// <summary> /// Opens the storage /// </summary> private void OpenStorage() { StartTransaction(); try { // For metadata assume block size of 512 because blockSize is unknown at this point. // 512 is the smallest block size so it will work as long as storage metadata is not // longer than 512 bytes storageMetadataStream = new StorageStream(new StorageStreamMetadata(null) { FirstSegmentPosition = 0, InitializedLength = 512 - Segment.StructureSize, Length = 512 - Segment.StructureSize, StreamId = SystemStreamId.StorageMetadata, StreamTableIndex = -1 }, this); StorageMetadata = StorageMetadata.Load(storageMetadataStream); streamTableStreamMetadata = new StorageStreamMetadata(storageMetadataStream) { FirstSegmentPosition = blockSize, StreamId = SystemStreamId.StreamTable, StreamTableIndex = -1 }; streamTableStream = new StorageStream(streamTableStreamMetadata, this); streamTable = new StreamTable(streamTableStream); var freeSpaceStreamMetadata = streamTable.Get(SystemStreamId.EmptySpace); FreeSpaceStream = new StorageStream(freeSpaceStreamMetadata, this); CommitTransaction(); } catch { RollbackTransaction(); throw; } }
// Reloads segments from storage internal void ReloadSegmentsOnRollback(StorageStreamMetadata metadata) { CheckClosed(); changeNotified = false; // Reaload metadata and segments LoadStream(metadata); }