/// <summary>
        /// NonPersistentDiskQueueSegmentFactory constructor
        /// </summary>
        /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
        /// <param name="fileNamePrefix">Prefix for the segment file name</param>
        /// <param name="serializer">Items serializing/deserializing logic</param>
        /// <param name="writeBufferSize">Determines the number of items, that are stored in memory before save them to disk (-1 - set to default value, 0 - disable write buffer)</param>
        /// <param name="cachedMemoryWriteStreamSize">Maximum size of the cached byte stream that used to serialize items in memory (-1 - set to default value, 0 - disable byte stream caching)</param>
        /// <param name="readBufferSize">Determines the number of items, that are stored in memory for read purposes (-1 - set to default value, 0 - disable read buffer)</param>
        /// <param name="cachedMemoryReadStreamSize">Maximum size of the cached byte stream that used to deserialize items in memory (-1 - set to default value, 0 - disable byte stream caching)</param>
        public NonPersistentDiskQueueSegmentFactory(int capacity, string fileNamePrefix, IDiskQueueItemSerializer <T> serializer,
                                                    int writeBufferSize, int cachedMemoryWriteStreamSize, int readBufferSize, int cachedMemoryReadStreamSize)
        {
            if (capacity <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity should be positive");
            }
            if (string.IsNullOrEmpty(fileNamePrefix))
            {
                throw new ArgumentNullException(nameof(fileNamePrefix));
            }
            if (serializer == null)
            {
                throw new ArgumentNullException(nameof(serializer));
            }

            _capacity       = capacity;
            _fileNamePrefix = fileNamePrefix;
            _serializer     = serializer;

            _writeBufferSize             = writeBufferSize;
            _cachedMemoryWriteStreamSize = cachedMemoryWriteStreamSize;
            _readBufferSize             = readBufferSize;
            _cachedMemoryReadStreamSize = cachedMemoryReadStreamSize;
        }
 /// <summary>
 /// NonPersistentDiskQueueSegmentFactory constructor
 /// </summary>
 /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
 /// <param name="fileNamePrefix">Prefix for the segment file name</param>
 /// <param name="serializer">Items serializing/deserializing logic</param>
 public NonPersistentDiskQueueSegmentFactory(int capacity, string fileNamePrefix, IDiskQueueItemSerializer <T> serializer)
     : this(capacity, fileNamePrefix, serializer, -1, -1, -1, -1)
 {
 }
 /// <summary>
 /// NonPersistentDiskQueueSegmentFactory constructor
 /// </summary>
 /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
 /// <param name="fileNamePrefix">Prefix for the segment file name</param>
 /// <param name="serializer">Items serializing/deserializing logic</param>
 /// <param name="writeBufferSize">Determines the number of items, that are stored in memory before save them to disk (-1 - set to default value, 0 - disable write buffer)</param>
 /// <param name="readBufferSize">Determines the number of items, that are stored in memory for read purposes (-1 - set to default value, 0 - disable read buffer)</param>
 public NonPersistentDiskQueueSegmentFactory(int capacity, string fileNamePrefix, IDiskQueueItemSerializer <T> serializer,
                                             int writeBufferSize, int readBufferSize)
     : this(capacity, fileNamePrefix, serializer, writeBufferSize, -1, readBufferSize, -1)
 {
 }
 /// <summary>
 /// NonPersistentDiskQueueSegment constructor
 /// </summary>
 /// <param name="segmentNumber">Segment number</param>
 /// <param name="fileName">Full file name for the segment</param>
 /// <param name="serializer">Items serializing/deserializing logic</param>
 /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
 public NonPersistentDiskQueueSegment(long segmentNumber, string fileName, IDiskQueueItemSerializer <T> serializer, int capacity)
     : this(segmentNumber, fileName, serializer, capacity, -1, -1, -1, -1)
 {
 }
 /// <summary>
 /// NonPersistentDiskQueueSegment constructor
 /// </summary>
 /// <param name="segmentNumber">Segment number</param>
 /// <param name="fileName">Full file name for the segment</param>
 /// <param name="serializer">Items serializing/deserializing logic</param>
 /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
 /// <param name="writeBufferSize">Determines the number of items, that are stored in memory before save them to disk (-1 - set to default value, 0 - disable write buffer)</param>
 /// <param name="readBufferSize">Determines the number of items, that are stored in memory for read purposes (-1 - set to default value, 0 - disable read buffer)</param>
 public NonPersistentDiskQueueSegment(long segmentNumber, string fileName, IDiskQueueItemSerializer <T> serializer, int capacity,
                                      int writeBufferSize, int readBufferSize)
     : this(segmentNumber, fileName, serializer, capacity, writeBufferSize, -1, readBufferSize, -1)
 {
 }
        /// <summary>
        /// NonPersistentDiskQueueSegment constructor
        /// </summary>
        /// <param name="segmentNumber">Segment number</param>
        /// <param name="fileName">Full file name for the segment</param>
        /// <param name="serializer">Items serializing/deserializing logic</param>
        /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
        /// <param name="writeBufferSize">Determines the number of items, that are stored in memory before save them to disk (-1 - set to default value, 0 - disable write buffer)</param>
        /// <param name="cachedMemoryWriteStreamSize">Maximum size of the cached byte stream that used to serialize items in memory (-1 - set to default value, 0 - disable byte stream caching)</param>
        /// <param name="readBufferSize">Determines the number of items, that are stored in memory for read purposes (-1 - set to default value, 0 - disable read buffer)</param>
        /// <param name="cachedMemoryReadStreamSize">Maximum size of the cached byte stream that used to deserialize items in memory (-1 - set to default value, 0 - disable byte stream caching)</param>
        public NonPersistentDiskQueueSegment(long segmentNumber, string fileName, IDiskQueueItemSerializer <T> serializer, int capacity,
                                             int writeBufferSize, int cachedMemoryWriteStreamSize, int readBufferSize, int cachedMemoryReadStreamSize)
            : base(segmentNumber, capacity, 0, 0)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }
            if (serializer == null)
            {
                throw new ArgumentNullException(nameof(serializer));
            }
            if (File.Exists(fileName))
            {
                throw new ArgumentException($"Can't create NonPersistentDiskQueueSegment on existing file '{fileName}'", nameof(fileName));
            }

            _fileName   = fileName;
            _serializer = serializer;

            try
            {
                _writeStream = new FileStream(_fileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read);
                _readStream  = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                _writeLock = new object();
                _readLock  = new object();

                _writeBufferSize    = 0;
                _maxWriteBufferSize = writeBufferSize >= 0 ? writeBufferSize : DefaultWriteBufferSize;
                if (writeBufferSize < 0 && serializer.ExpectedSizeInBytes > 0)
                {
                    _maxWriteBufferSize = checked (Math.Max(DefaultWriteBufferSize, 4096 / Math.Min(serializer.ExpectedSizeInBytes + ItemHeaderSize, MaxChacheSizePerItem)));
                }

                if (_maxWriteBufferSize > 0)
                {
                    _writeBuffer = new ConcurrentQueue <T>();
                }

                _cachedMemoryWriteStream        = null;
                _maxCachedMemoryWriteStreamSize = cachedMemoryWriteStreamSize;
                if (cachedMemoryWriteStreamSize < 0)
                {
                    checked
                    {
                        int expectedItemSize = MaxChacheSizePerItem;
                        if (serializer.ExpectedSizeInBytes > 0)
                        {
                            expectedItemSize = Math.Min(serializer.ExpectedSizeInBytes + ItemHeaderSize, MaxChacheSizePerItem);
                        }
                        _maxCachedMemoryWriteStreamSize = Math.Min(MaxCachedMemoryStreamSize, (_maxWriteBufferSize + 1) * expectedItemSize);
                    }
                }


                _maxReadBufferSize = readBufferSize >= 0 ? readBufferSize : Math.Max(_writeBufferSize / 2, DefaultReadBufferSize);
                if (_maxReadBufferSize > 0)
                {
                    _readBuffer = new ConcurrentQueue <T>();
                }

                _cachedMemoryReadStream        = null;
                _maxCachedMemoryReadStreamSize = cachedMemoryReadStreamSize;
                if (cachedMemoryReadStreamSize < 0)
                {
                    checked
                    {
                        int expectedItemSize = MaxChacheSizePerItem;
                        if (serializer.ExpectedSizeInBytes > 0)
                        {
                            expectedItemSize = Math.Min(serializer.ExpectedSizeInBytes + ItemHeaderSize, MaxChacheSizePerItem);
                        }
                        _maxCachedMemoryReadStreamSize = Math.Min(MaxCachedMemoryStreamSize, expectedItemSize);
                    }
                }


                // Prepare file header
                WriteSegmentHeader(_writeStream, Number, Capacity);
                _readStream.Seek(0, SeekOrigin.End); // Offset readStream after the header

                _isDisposed = false;

                Debug.Assert(_maxWriteBufferSize >= 0);
                Debug.Assert(_maxCachedMemoryWriteStreamSize >= 0);
                Debug.Assert(_maxReadBufferSize >= 0);
                Debug.Assert(_maxCachedMemoryReadStreamSize >= 0);
                Debug.Assert(_writeStream.Position == _readStream.Position);
            }
            catch
            {
                // Should close streams to make created files available to delete
                if (_writeStream != null)
                {
                    _writeStream.Dispose();
                }
                if (_readStream != null)
                {
                    _readStream.Dispose();
                }

                throw;
            }
        }
 /// <summary>
 /// Creates new instance of <see cref="NonPersistentDiskQueueSegmentFactory{T}"/>
 /// </summary>
 /// <param name="capacity">Maximum number of stored items inside the segement (overall capacity)</param>
 /// <param name="fileNamePrefix">Prefix for the segment file name</param>
 /// <param name="serializer">Items serializing/deserializing logic</param>
 /// <returns>Created <see cref="NonPersistentDiskQueueSegmentFactory{T}"/></returns>
 public static NonPersistentDiskQueueSegmentFactory <T> CreateFactory(int capacity, string fileNamePrefix, IDiskQueueItemSerializer <T> serializer)
 {
     return(new NonPersistentDiskQueueSegmentFactory <T>(capacity, fileNamePrefix, serializer));
 }