예제 #1
0
        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++;
            }
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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);
                }
            }
        }
예제 #4
0
        // Reloads segments from storage
        internal void ReloadSegmentsOnRollback(StorageStreamMetadata metadata)
        {
            CheckClosed();
            changeNotified = false;

            // Reaload metadata and segments
            LoadStream(metadata);
        }
예제 #5
0
        /// <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;
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        /// <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);
                }
            }
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        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;
            }
        }
예제 #12
0
        /// <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;
        }
예제 #13
0
        /// <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;
            }
        }
예제 #14
0
        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;
            }
        }
예제 #15
0
        /// <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;
        }
예제 #16
0
파일: Storage.cs 프로젝트: qq5013/TmStorage
        /// <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;
        }
예제 #17
0
파일: Storage.cs 프로젝트: qq5013/TmStorage
        /// <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;
            }
        }
예제 #18
0
        // Reloads segments from storage
        internal void ReloadSegmentsOnRollback(StorageStreamMetadata metadata)
        {
            CheckClosed();
            changeNotified = false;

            // Reaload metadata and segments
            LoadStream(metadata);
        }