TryAllocate() public method

Attempts to allocate a memory block of a specified length.
public TryAllocate ( long length, IMemoryBlock &allocatedBlock ) : bool
length long Length, in bytes, of memory block
allocatedBlock IMemoryBlock Allocated memory block
return bool
Exemplo n.º 1
0
        /// <summary>
        /// Creates a buffer of the specified size, filled with the contents of a specified byte array
        /// </summary>
        /// <param name="size">Buffer size, in bytes</param>
        /// <param name="filledWith">Byte array to copy to buffer</param>
        /// <returns>IBuffer object of requested size</returns>
        public IBuffer GetBuffer(long size, byte[] filledWith)
        {
            if (size < 0) throw new ArgumentException("size must be greater than 0");

            //TODO: If size is larger than 16 * SlabSize (or MaxNumberOfSegments * SlabSize) then throw exception saying you can't have a buffer greater than 16 times Slab size
            //Write test for this

            //Make sure filledWith can fit into the requested buffer, so that we do not allocate a buffer and then
            //an exception is thrown (when IBuffer.FillWith() is called) before the buffer is returned.
            if (filledWith != null)
            {
                if (filledWith.LongLength > size) throw new ArgumentException("Length of filledWith array cannot be larger than desired buffer size");
                if (filledWith.LongLength == 0) filledWith = null;

                //TODO: Write test that will test that IBuffer.FillWith() doesn't throw an exception (and that buffers aren't allocated) in this method
            }

            if (size == 0)
            {
                //Return an empty buffer
                return new ManagedBuffer(firstSlab);
            }

            List<IMemoryBlock> allocatedBlocks = new List<IMemoryBlock>();

            //TODO: Consider the performance penalty involved in making the try-catch below a constrained region
            //RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                IMemorySlab[] slabArr;
                long allocdLengthTally = 0;

                if (GetSingleSlabPool())
                {
                    //Optimization: Chances are that there'll be just one slab in a pool, so access it directly 
                    //and avoid the lock statement involved while creating an array of slabs.

                    //Note that even if singleSlabPool is inaccurate, this method will still work properly.
                    //The optimization is effective because singleSlabPool will be accurate majority of the time.

                    slabArr = new IMemorySlab[] { firstSlab };
                    allocdLengthTally = TryAllocateBlocksInSlabs(size, MAX_SEGMENTS_PER_BUFFER, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //We got the entire length we are looking for, so leave
                        return GetFilledBuffer(allocatedBlocks, filledWith);
                    }

                    SetSingleSlabPool(false); // Slab count will soon be incremented
                }
                else
                {
                    lock (syncSlabList)
                    {
                        slabArr = slabs.ToArray();
                    }

                    allocdLengthTally = TryAllocateBlocksInSlabs(size, MAX_SEGMENTS_PER_BUFFER, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //We got the entire length we are looking for, so leave
                        return GetFilledBuffer(allocatedBlocks, filledWith);
                    }
                }


                //Try to create new slab
                lock (syncNewSlab)
                {
                    //Look again for free block
                    lock (syncSlabList)
                    {
                        slabArr = slabs.ToArray();
                    }

                    allocdLengthTally += TryAllocateBlocksInSlabs(size - allocdLengthTally, MAX_SEGMENTS_PER_BUFFER - allocatedBlocks.Count, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //found it -- leave
                        return GetFilledBuffer(allocatedBlocks, filledWith);
                    }

                    List<IMemorySlab> newSlabList = new List<IMemorySlab>();
                    do
                    {
                        //Unable to find available free space, so create new slab
                        MemorySlab newSlab = new MemorySlab(slabSize, this);

                        IMemoryBlock allocdBlk;
                        if (slabSize > size - allocdLengthTally)
                        {
                            //Allocate remnant
                            newSlab.TryAllocate(size - allocdLengthTally, out allocdBlk);
                        }
                        else
                        {
                            //Allocate entire slab
                            newSlab.TryAllocate(slabSize, out allocdBlk);
                        }

                        newSlabList.Add(newSlab);
                        allocatedBlocks.Add(allocdBlk);
                        allocdLengthTally += allocdBlk.Length;
                    }
                    while (allocdLengthTally < size);

                    lock (syncSlabList)
                    {
                        //Add new slabs to collection
                        slabs.AddRange(newSlabList);

                        //Add extra slabs as requested in object properties
                        for (int i = 0; i < subsequentSlabs - 1; i++)
                        {
                            slabs.Add(new MemorySlab(slabSize, this));
                        }
                    }

                }

                return GetFilledBuffer(allocatedBlocks, filledWith);
            }
            catch
            {
                //OOM, Thread abort exceptions and other ugly things can happen so roll back any allocated blocks.
                //This will prevent a limbo situation where those blocks are allocated but caller is unaware and can't deallocate them.

                //NOTE: This try-catch block should not be within a lock as it calls MemorySlab.Free which takes locks,
                //and in turn calls BufferPool.TryFreeSlabs which takes other locks and can lead to a dead-lock/race condition.

                //TODO: Write rollback test.

                for (int b = 0; b < allocatedBlocks.Count; b++)
                {
                    allocatedBlocks[b].Slab.Free(allocatedBlocks[b]);
                }

                throw;
            }

        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a buffer of the specified size
        /// </summary>
        /// <param name="size">Buffer size, in bytes</param>
        /// <returns>IBuffer object of requested size</returns>        
        public IBuffer GetBuffer(long size)
        {
            if (size < 0) throw new ArgumentException("Length must be greater than 0");

            if (size == 0) return new ManagedBuffer(firstSlab); //Return an empty buffer

            IMemoryBlock allocatedBlock;
            IMemorySlab[] slabArr;

            if (singleSlabPool == -1)
            {
                //Optimization: Chances are that there'll be just one slab in a pool, so access it directly
                //and avoid the lock statement involved while creating an array of slabs.

                //Note that even if singleSlabPool is inaccurate, this method will still work properly.
                //The optimization is effective because singleSlabPool will be accurate majority of the time.

                slabArr = new IMemorySlab[] { firstSlab };
                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    return new ManagedBuffer(allocatedBlock);
                }

                Interlocked.Exchange(ref singleSlabPool, 0); // Slab count will soon be incremented
            }
            else
            {

                lock (sync_slabList)
                {
                    slabArr = slabs.ToArray();
                }

                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    return new ManagedBuffer(allocatedBlock);
                }
            }

            lock (sync_newSlab)
            {
                //Look again for free block
                lock (sync_slabList)
                {
                    slabArr = slabs.ToArray();
                }

                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    //found it -- leave
                    return new ManagedBuffer(allocatedBlock);
                }

                //Unable to find available free space, so create new slab
                MemorySlab newSlab = new MemorySlab(slabSize, this);

                newSlab.TryAllocate(size, out allocatedBlock);

                lock (sync_slabList)
                {
                    //Add new Slab to collection

                    slabs.Add(newSlab);

                    //Add extra slabs as requested in object properties
                    for (int i = 0; i < subsequentSlabs - 1; i++)
                    {
                        slabs.Add(new MemorySlab(slabSize, this));
                    }
                }

            }

            return new ManagedBuffer(allocatedBlock);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a buffer of the specified size
        /// </summary>
        /// <param name="size">Buffer size, in bytes</param>
        /// <returns>IBuffer object of requested size</returns>
        public IBuffer GetBuffer(long size)
        {
            if (size < 0)
            {
                throw new ArgumentException("Length must be greater than 0");
            }

            if (size == 0)
            {
                return(new ManagedBuffer(firstSlab));           //Return an empty buffer
            }
            IMemoryBlock allocatedBlock;

            IMemorySlab[] slabArr;

            if (singleSlabPool == -1)
            {
                //Optimization: Chances are that there'll be just one slab in a pool, so access it directly
                //and avoid the lock statement involved while creating an array of slabs.

                //Note that even if singleSlabPool is inaccurate, this method will still work properly.
                //The optimization is effective because singleSlabPool will be accurate majority of the time.

                slabArr = new IMemorySlab[] { firstSlab };
                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    return(new ManagedBuffer(allocatedBlock));
                }

                Interlocked.Exchange(ref singleSlabPool, 0); // Slab count will soon be incremented
            }
            else
            {
                lock (sync_slabList)
                {
                    slabArr = slabs.ToArray();
                }

                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    return(new ManagedBuffer(allocatedBlock));
                }
            }


            lock (sync_newSlab)
            {
                //Look again for free block
                lock (sync_slabList)
                {
                    slabArr = slabs.ToArray();
                }

                if (TryAllocateBlockInSlabs(size, slabArr, out allocatedBlock))
                {
                    //found it -- leave
                    return(new ManagedBuffer(allocatedBlock));
                }

                //Unable to find available free space, so create new slab
                MemorySlab newSlab = new MemorySlab(slabSize, this);

                newSlab.TryAllocate(size, out allocatedBlock);

                lock (sync_slabList)
                {
                    //Add new Slab to collection

                    slabs.Add(newSlab);

                    //Add extra slabs as requested in object properties
                    for (int i = 0; i < subsequentSlabs - 1; i++)
                    {
                        slabs.Add(new MemorySlab(slabSize, this));
                    }
                }
            }

            return(new ManagedBuffer(allocatedBlock));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates a buffer of the specified size, filled with the contents of a specified byte array
        /// </summary>
        /// <param name="size">Buffer size, in bytes</param>
        /// <param name="filledWith">Byte array to copy to buffer</param>
        /// <returns>IBuffer object of requested size</returns>
        public IBuffer GetBuffer(long size, byte[] filledWith)
        {
            if (size < 0)
            {
                throw new ArgumentException("size must be greater than 0");
            }

            //TODO: If size is larger than 16 * SlabSize (or MaxNumberOfSegments * SlabSize) then throw exception saying you can't have a buffer greater than 16 times Slab size
            //Write test for this

            //Make sure filledWith can fit into the requested buffer, so that we do not allocate a buffer and then
            //an exception is thrown (when IBuffer.FillWith() is called) before the buffer is returned.
            if (filledWith != null)
            {
                if (filledWith.LongLength > size)
                {
                    throw new ArgumentException("Length of filledWith array cannot be larger than desired buffer size");
                }
                if (filledWith.LongLength == 0)
                {
                    filledWith = null;
                }

                //TODO: Write test that will test that IBuffer.FillWith() doesn't throw an exception (and that buffers aren't allocated) in this method
            }

            if (size == 0)
            {
                //Return an empty buffer
                return(new ManagedBuffer(firstSlab));
            }

            List <IMemoryBlock> allocatedBlocks = new List <IMemoryBlock>();

            //TODO: Consider the performance penalty involved in making the try-catch below a constrained region
            //RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                IMemorySlab[] slabArr;
                long          allocdLengthTally = 0;

                if (GetSingleSlabPool())
                {
                    //Optimization: Chances are that there'll be just one slab in a pool, so access it directly
                    //and avoid the lock statement involved while creating an array of slabs.

                    //Note that even if singleSlabPool is inaccurate, this method will still work properly.
                    //The optimization is effective because singleSlabPool will be accurate majority of the time.

                    slabArr           = new IMemorySlab[] { firstSlab };
                    allocdLengthTally = TryAllocateBlocksInSlabs(size, MAX_SEGMENTS_PER_BUFFER, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //We got the entire length we are looking for, so leave
                        return(GetFilledBuffer(allocatedBlocks, filledWith));
                    }

                    SetSingleSlabPool(false); // Slab count will soon be incremented
                }
                else
                {
                    lock (syncSlabList)
                    {
                        slabArr = slabs.ToArray();
                    }

                    allocdLengthTally = TryAllocateBlocksInSlabs(size, MAX_SEGMENTS_PER_BUFFER, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //We got the entire length we are looking for, so leave
                        return(GetFilledBuffer(allocatedBlocks, filledWith));
                    }
                }


                //Try to create new slab
                lock (syncNewSlab)
                {
                    //Look again for free block
                    lock (syncSlabList)
                    {
                        slabArr = slabs.ToArray();
                    }

                    allocdLengthTally += TryAllocateBlocksInSlabs(size - allocdLengthTally, MAX_SEGMENTS_PER_BUFFER - allocatedBlocks.Count, slabArr, ref allocatedBlocks);

                    if (allocdLengthTally == size)
                    {
                        //found it -- leave
                        return(GetFilledBuffer(allocatedBlocks, filledWith));
                    }

                    List <IMemorySlab> newSlabList = new List <IMemorySlab>();
                    do
                    {
                        //Unable to find available free space, so create new slab
                        MemorySlab newSlab = new MemorySlab(slabSize, this);

                        IMemoryBlock allocdBlk;
                        if (slabSize > size - allocdLengthTally)
                        {
                            //Allocate remnant
                            newSlab.TryAllocate(size - allocdLengthTally, out allocdBlk);
                        }
                        else
                        {
                            //Allocate entire slab
                            newSlab.TryAllocate(slabSize, out allocdBlk);
                        }

                        newSlabList.Add(newSlab);
                        allocatedBlocks.Add(allocdBlk);
                        allocdLengthTally += allocdBlk.Length;
                    }while (allocdLengthTally < size);

                    lock (syncSlabList)
                    {
                        //Add new slabs to collection
                        slabs.AddRange(newSlabList);

                        //Add extra slabs as requested in object properties
                        for (int i = 0; i < subsequentSlabs - 1; i++)
                        {
                            slabs.Add(new MemorySlab(slabSize, this));
                        }
                    }
                }

                return(GetFilledBuffer(allocatedBlocks, filledWith));
            }
            catch
            {
                //OOM, Thread abort exceptions and other ugly things can happen so roll back any allocated blocks.
                //This will prevent a limbo situation where those blocks are allocated but caller is unaware and can't deallocate them.

                //NOTE: This try-catch block should not be within a lock as it calls MemorySlab.Free which takes locks,
                //and in turn calls BufferPool.TryFreeSlabs which takes other locks and can lead to a dead-lock/race condition.

                //TODO: Write rollback test.

                for (int b = 0; b < allocatedBlocks.Count; b++)
                {
                    allocatedBlocks[b].Slab.Free(allocatedBlocks[b]);
                }

                throw;
            }
        }