Exemplo n.º 1
0
        /// <summary>
        /// Drains chunks to the given stream and notifies the given promise when it's done.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="promise"></param>
        private void DrainToStream(Stream stream, Promise <ChunkedBuffer> promise)
        {
            MemoryChunkNode currentChunk = null;

            lock (_syncRoot)
            {
                currentChunk = rootChunk;

                if (currentChunk == null)
                {
                    promise.CreateFulfiller().Fulfill(this);

                    return;
                }

                rootChunk = rootChunk.next;
            }

            stream.BeginWrite(currentChunk.pooledBytes, currentChunk.offset, currentChunk.count, new AsyncCallback(OnDrainToStreamWriteComplete),
                              new DrainChunksState()
            {
                currentChunk = currentChunk,
                stream       = stream,
                promise      = promise
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// Appeds the given chunk to this stream.
        /// </summary>
        /// <param name="chunk"></param>
        private void AppendChunk(MemoryChunkNode chunk)
        {
            lock (_syncRoot)
            {
                if (rootChunk == null)
                {
                    rootChunk = chunk;
                }
                else
                {
                    MemoryChunkNode currentChunk = rootChunk;

                    while (currentChunk != null)
                    {
                        if (currentChunk.next == null)
                        {
                            currentChunk.next = chunk;
                            break;
                        }
                        else
                        {
                            currentChunk = currentChunk.next;
                        }
                    }
                }

                WritePosition += chunk.count;
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Affers a pooled memory chunk to this stream.
        /// </summary>
        /// <param name="pooledBytes"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public ChunkedBuffer OfferChunk(PooledObject <byte[]> pooledObject, int offset, int count)
        {
            ValidateBuffer();

            if (pooledObject == null)
            {
                throw new ArgumentNullException("'data' cannot be null");
            }

            if (pooledObject.State != PooledObjectState.USED)
            {
                throw new Exception("This pooled object is not active.");
            }

            if (pooledObject.Pool != pool)
            {
                throw new Exception("The given pooled object does not belong to the pool that is assigned to this stream: " + pooledObject.Pool);
            }

            MemoryChunkNode chunk = new MemoryChunkNode()
            {
                pooledObject = pooledObject,
                pooledBytes  = pooledObject.Value,
                offset       = offset,
                count        = count,
                next         = null
            };

            pooledObject.RefCount.Increment();

            AppendChunk(chunk);

            return(this);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Flushes this stream and clears any read pooled memory chunks.
        /// </summary>
        public void Flush()
        {
            lock (_syncRoot)
            {
                ValidateBuffer();

                MemoryChunkNode currentChunk = rootChunk;

                while (currentChunk != null)
                {
                    if (currentChunk.count > ReadPosition)
                    {
                        break;
                    }

                    if (currentChunk.pooledObject != null && currentChunk.pooledObject.RefCount.Decrement() < 1)
                    {
                        if (currentChunk.pooledObject.State == PooledObjectState.USED)
                        {
                            currentChunk.pooledObject.Return();
                        }
                        else
                        {
                            SockNetLogger.Log(SockNetLogger.LogLevel.WARN, this, "Potential resource leak found.");
                        }
                    }
                    rootChunk     = currentChunk.next;
                    ReadPosition -= currentChunk.count;
                    WritePosition = Math.Max(0, WritePosition - currentChunk.count);
                    currentChunk  = currentChunk.next;
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Reads data into the given buffer from the current position.
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public int Read(byte[] buffer, int offset, int count)
        {
            lock (_syncRoot)
            {
                ValidateBuffer();

                if (WritePosition == ReadPosition)
                {
                    return(0);
                }

                int bytesScanned = 0;
                int bytesRead    = 0;

                MemoryChunkNode currentChunk = rootChunk;

                while (currentChunk != null && bytesRead < count)
                {
                    if (bytesScanned >= ReadPosition)
                    {
                        int bytesToCopy = Math.Min(currentChunk.count, count - bytesRead);

                        Buffer.BlockCopy(currentChunk.pooledBytes, currentChunk.offset, buffer, offset + bytesRead, bytesToCopy);

                        bytesRead += bytesToCopy;
                    }
                    else if (currentChunk.count + bytesScanned >= ReadPosition)
                    {
                        int sourceChunkOffset = (int)(ReadPosition - bytesScanned);
                        int bytesToCopy       = Math.Min(currentChunk.count - sourceChunkOffset, count - bytesRead);

                        Buffer.BlockCopy(currentChunk.pooledBytes, currentChunk.offset + sourceChunkOffset, buffer, offset + bytesRead, bytesToCopy);

                        bytesRead += bytesToCopy;
                    }

                    bytesScanned += currentChunk.count;
                    currentChunk  = currentChunk.next;
                }

                ReadPosition += bytesRead;

                return(bytesRead);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Synchronously drains the buffer into the stream.
        /// </summary>
        /// <param name="stream"></param>
        public ChunkedBuffer DrainToStreamSync(Stream stream)
        {
            lock (_syncRoot)
            {
                while (rootChunk != null)
                {
                    stream.Write(rootChunk.pooledBytes, rootChunk.offset, rootChunk.count);

                    if (rootChunk.pooledObject != null && rootChunk.pooledObject.Pool != null && rootChunk.pooledObject.RefCount.Decrement() < 1)
                    {
                        rootChunk.pooledObject.Return();
                    }

                    rootChunk = rootChunk.next;
                }
            }

            return(this);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Offers the following raw buffer.
        /// </summary>
        /// <param name="data"></param>
        public ChunkedBuffer OfferRaw(byte[] data, int offset, int count)
        {
            ValidateBuffer();

            if (data == null)
            {
                throw new ArgumentNullException("'data' cannot be null");
            }

            MemoryChunkNode chunk = new MemoryChunkNode()
            {
                pooledObject = null,
                pooledBytes  = data,
                offset       = offset,
                count        = count,
                next         = null
            };

            AppendChunk(chunk);

            return(this);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Drains chunks to the given stream and notifies the given promise when it's done.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="promise"></param>
        private void DrainToStream(Stream stream, Promise<ChunkedBuffer> promise)
        {
            MemoryChunkNode currentChunk = null;

            lock (_syncRoot)
            {
                currentChunk = rootChunk;

                if (currentChunk == null)
                {
                    promise.CreateFulfiller().Fulfill(this);

                    return;
                }

                rootChunk = rootChunk.next;
            }

            stream.BeginWrite(currentChunk.pooledBytes, currentChunk.offset, currentChunk.count, new AsyncCallback(OnDrainToStreamWriteComplete),
                new DrainChunksState()
                {
                    currentChunk = currentChunk,
                    stream = stream,
                    promise = promise
                });
        }
Exemplo n.º 9
0
        /// <summary>
        /// Appeds the given chunk to this stream.
        /// </summary>
        /// <param name="chunk"></param>
        private void AppendChunk(MemoryChunkNode chunk)
        {
            lock (_syncRoot)
            {
                if (rootChunk == null)
                {
                    rootChunk = chunk;
                }
                else
                {
                    MemoryChunkNode currentChunk = rootChunk;

                    while (currentChunk != null)
                    {
                        if (currentChunk.next == null)
                        {
                            currentChunk.next = chunk;
                            break;
                        }
                        else
                        {
                            currentChunk = currentChunk.next;
                        }
                    }
                }

                WritePosition += chunk.count;
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Offers the following raw buffer.
        /// </summary>
        /// <param name="data"></param>
        public ChunkedBuffer OfferRaw(byte[] data, int offset, int count)
        {
            ValidateBuffer();

            if (data == null)
            {
                throw new ArgumentNullException("'data' cannot be null");
            }

            MemoryChunkNode chunk = new MemoryChunkNode()
            {
                pooledObject = null,
                pooledBytes = data,
                offset = offset,
                count = count,
                next = null
            };

            AppendChunk(chunk);

            return this;
        }
Exemplo n.º 11
0
        /// <summary>
        /// Affers a pooled memory chunk to this stream.
        /// </summary>
        /// <param name="pooledBytes"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public ChunkedBuffer OfferChunk(PooledObject<byte[]> pooledObject, int offset, int count)
        {
            ValidateBuffer();

            if (pooledObject == null)
            {
                throw new ArgumentNullException("'data' cannot be null");
            }

            if (pooledObject.State != PooledObjectState.USED)
            {
                throw new Exception("This pooled object is not active.");
            }

            if (pooledObject.Pool != pool)
            {
                throw new Exception("The given pooled object does not belong to ths pool that is assigned to this stream: " + pooledObject.Pool);
            }

            MemoryChunkNode chunk = new MemoryChunkNode()
            {
                pooledObject = pooledObject,
                pooledBytes = pooledObject.Value,
                offset = offset,
                count = count,
                next = null
            };
            pooledObject.RefCount.Increment();

            AppendChunk(chunk);

            return this;
        }
Exemplo n.º 12
0
        /// <summary>
        /// Flushes this stream and clears any read pooled memory chunks.
        /// </summary>
        public void Flush()
        {
            lock (_syncRoot)
            {
                ValidateBuffer();

                MemoryChunkNode currentChunk = rootChunk;

                while (currentChunk != null)
                {
                    if (currentChunk.count > ReadPosition)
                    {
                        break;
                    }

                    if (currentChunk.pooledObject != null && currentChunk.pooledObject.RefCount.Decrement() < 1)
                    {
                        if (currentChunk.pooledObject.State == PooledObjectState.USED)
                        {
                            currentChunk.pooledObject.Return();
                        }
                        else
                        {
                            SockNetLogger.Log(SockNetLogger.LogLevel.WARN, this, "[Flush] Potential resource leak found.");
                        }
                    }
                    rootChunk = currentChunk.next;
                    ReadPosition -= currentChunk.count;
                    WritePosition = Math.Max(0, WritePosition - currentChunk.count);
                    currentChunk = currentChunk.next;
                }
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Synchronously drains the buffer into the stream.
        /// </summary>
        /// <param name="stream"></param>
        public ChunkedBuffer DrainToStreamSync(Stream stream)
        {
            lock (_syncRoot)
            {
                while (rootChunk != null)
                {
                    stream.Write(rootChunk.pooledBytes, rootChunk.offset, rootChunk.count);

                    if (rootChunk.pooledObject != null && rootChunk.pooledObject.Pool != null && rootChunk.pooledObject.RefCount.Decrement() < 1)
                    {
                        rootChunk.pooledObject.Return();
                    }

                    rootChunk = rootChunk.next;
                }
            }

            return this;
        }