Example #1
0
        static void AppendPoolSubPages(StringBuilder buf, PoolSubpage <T>[] subpages)
        {
            for (int i = 0; i < subpages.Length; i++)
            {
                PoolSubpage <T> head = subpages[i];
                if (head.Next == head)
                {
                    continue;
                }

                buf.Append(StringUtil.Newline)
                .Append(i)
                .Append(": ");
                PoolSubpage <T> s = head.Next;
                for (; ;)
                {
                    buf.Append(s);
                    s = s.Next;
                    if (s == head)
                    {
                        break;
                    }
                }
            }
        }
Example #2
0
        /**
         * Returns the bitmap index of the subpage allocation.
         */

        internal long Allocate()
        {
            if (this.ElemSize == 0)
            {
                return(this.ToHandle(0));
            }

            /**
             * Synchronize on the head of the SubpagePool stored in the {@link PoolArena. This is needed as we synchronize
             * on it when calling {@link PoolArena#allocate(PoolThreadCache, int, int)} und try to allocate out of the
             * {@link PoolSubpage} pool for a given size.
             */
            PoolSubpage <T> head = this.Chunk.Arena.FindSubpagePoolHead(this.ElemSize);

            lock (head)
            {
                if (this.numAvail == 0 || !this.DoNotDestroy)
                {
                    return(-1);
                }

                int bitmapIdx = this.GetNextAvail();
                int q         = bitmapIdx.RightUShift(6);
                int r         = bitmapIdx & 63;
                Contract.Assert((this.bitmap[q].RightUShift(r) & 1) == 0);
                this.bitmap[q] |= 1L << r;

                if (--this.numAvail == 0)
                {
                    this.RemoveFromPool();
                }

                return(this.ToHandle(bitmapIdx));
            }
        }
Example #3
0
        /**
         * Create/ initialize a new PoolSubpage of normCapacity
         * Any PoolSubpage created/ initialized here is added to subpage pool in the PoolArena that owns this PoolChunk
         *
         * @param normCapacity normalized capacity
         * @return index in memoryMap
         */

        long AllocateSubpage(int normCapacity)
        {
            int d  = this.maxOrder; // subpages are only be allocated from pages i.e., leaves
            int id = this.AllocateNode(d);

            if (id < 0)
            {
                return(id);
            }

            PoolSubpage <T>[] subPages = this.subpages;
            int size = this.pageSize;

            this.freeBytes -= size;

            int             subpageIdx = this.SubpageIdx(id);
            PoolSubpage <T> subpage    = subPages[subpageIdx];

            if (subpage == null)
            {
                subpage = new PoolSubpage <T>(this, id, this.RunOffset(id), size, normCapacity);
                subPages[subpageIdx] = subpage;
            }
            else
            {
                subpage.Init(normCapacity);
            }
            return(subpage.Allocate());
        }
Example #4
0
        /**
         * Free a subpage or a run of pages
         * When a subpage is freed from PoolSubpage, it might be added back to subpage pool of the owning PoolArena
         * If the subpage pool in PoolArena has at least one other PoolSubpage of given elemSize, we can
         * completely free the owning Page so it is available for subsequent allocations
         *
         * @param handle handle to free
         */

        internal void Free(long handle)
        {
            int memoryMapIdx = MemoryMapIdx(handle);
            int bitmapIdx    = BitmapIdx(handle);

            if (bitmapIdx != 0)
            {
                // free a subpage
                PoolSubpage <T> subpage = this.subpages[this.SubpageIdx(memoryMapIdx)];
                Debug.Assert(subpage != null && subpage.DoNotDestroy);

                // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it.
                // This is need as we may add it back and so alter the linked-list structure.
                PoolSubpage <T> head = this.Arena.FindSubpagePoolHead(subpage.ElemSize);
                lock (head)
                {
                    if (subpage.Free(head, bitmapIdx & 0x3FFFFFFF))
                    {
                        return;
                    }
                }
            }
            this.freeBytes += this.RunLength(memoryMapIdx);
            this.SetValue(memoryMapIdx, this.Depth(memoryMapIdx));
            this.UpdateParentsFree(memoryMapIdx);
        }
Example #5
0
        static IReadOnlyCollection <IPoolSubpageMetric> SubPageMetricList(IReadOnlyList <PoolSubpage <T> > pages)
        {
            var metrics = new List <IPoolSubpageMetric>();

            for (int i = 1; i < pages.Count; i++)
            {
                PoolSubpage <T> head = pages[i];
                if (head.Next == head)
                {
                    continue;
                }
                PoolSubpage <T> s = head.Next;
                for (;;)
                {
                    metrics.Add(s);
                    s = s.Next;
                    if (s == head)
                    {
                        break;
                    }
                }
            }

            return(metrics);
        }
Example #6
0
        /**
         * Create/ initialize a new PoolSubpage of normCapacity
         * Any PoolSubpage created/ initialized here is added to subpage pool in the PoolArena that owns this PoolChunk
         *
         * @param normCapacity normalized capacity
         * @return index in memoryMap
         */

        long AllocateSubpage(int normCapacity)
        {
            // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it.
            // This is need as we may add it back and so alter the linked-list structure.
            PoolSubpage <T> head = this.Arena.FindSubpagePoolHead(normCapacity);

            lock (head)
            {
                int d  = this.maxOrder; // subpages are only be allocated from pages i.e., leaves
                int id = this.AllocateNode(d);
                if (id < 0)
                {
                    return(id);
                }

                PoolSubpage <T>[] subpages = this.subpages;
                int pageSize = this.pageSize;

                this.freeBytes -= pageSize;

                int             subpageIdx = this.SubpageIdx(id);
                PoolSubpage <T> subpage    = subpages[subpageIdx];
                if (subpage == null)
                {
                    subpage = new PoolSubpage <T>(head, this, id, this.RunOffset(id), pageSize, normCapacity);
                    subpages[subpageIdx] = subpage;
                }
                else
                {
                    subpage.Init(head, normCapacity);
                }

                return(subpage.Allocate());
            }
        }
Example #7
0
        public void Init(int elemSize)
        {
            this.DoNotDestroy = true;
            this.ElemSize     = elemSize;
            if (elemSize != 0)
            {
                this.maxNumElems  = this.numAvail = this.pageSize / elemSize;
                this.nextAvail    = 0;
                this.bitmapLength = this.maxNumElems.RightUShift(6);
                if ((this.maxNumElems & 63) != 0)
                {
                    this.bitmapLength++;
                }

                for (int i = 0; i < this.bitmapLength; i++)
                {
                    this.bitmap[i] = 0;
                }
            }

            PoolSubpage <T> head = this.Chunk.Arena.FindSubpagePoolHead(elemSize);

            lock (head)
            {
                this.AddToPool(head);
            }
        }
Example #8
0
        static PoolSubpage <T> NewSubpagePoolHead(int pageSize)
        {
            var head = new PoolSubpage <T>(pageSize);

            head.Prev = head;
            head.Next = head;
            return(head);
        }
Example #9
0
        void AddToPool(PoolSubpage <T> head)
        {
            Contract.Assert(this.Prev == null && this.Next == null);

            this.Prev      = head;
            this.Next      = head.Next;
            this.Next.Prev = this;
            head.Next      = this;
        }
Example #10
0
        void RemoveFromPool()
        {
            Contract.Assert(this.Prev != null && this.Next != null);

            this.Prev.Next = this.Next;
            this.Next.Prev = this.Prev;
            this.Next      = null;
            this.Prev      = null;
        }
Example #11
0
 public PoolSubpage(PoolSubpage <T> head, PoolChunk <T> chunk, int memoryMapIdx, int runOffset, int pageSize, int elemSize)
 {
     this.Chunk        = chunk;
     this.memoryMapIdx = memoryMapIdx;
     this.runOffset    = runOffset;
     this.pageSize     = pageSize;
     this.bitmap       = new long[pageSize.RightUShift(10)]; // pageSize / 16 / 64
     this.Init(head, elemSize);
 }
Example #12
0
        void RemoveFromPool()
        {
            Contract.Assert(this.Prev != null && this.Next != null);

            // ReSharper disable PossibleNullReferenceException
            this.Prev.Next = this.Next;
            this.Next.Prev = this.Prev;
            // ReSharper restore PossibleNullReferenceException
            this.Next = null;
            this.Prev = null;
        }
Example #13
0
        /**
         * @return {@code true} if this subpage is in use.
         *         {@code false} if this subpage is not used by its chunk and thus it's OK to be released.
         */

        internal bool Free(int bitmapIdx)
        {
            if (this.ElemSize == 0)
            {
                return(true);
            }

            /**
             * Synchronize on the head of the SubpagePool stored in the {@link PoolArena. This is needed as we synchronize
             * on it when calling {@link PoolArena#allocate(PoolThreadCache, int, int)} und try to allocate out of the
             * {@link PoolSubpage} pool for a given size.
             */
            PoolSubpage <T> head = this.Chunk.Arena.FindSubpagePoolHead(this.ElemSize);

            lock (head)
            {
                int q = bitmapIdx.RightUShift(6);
                int r = bitmapIdx & 63;
                Contract.Assert((this.bitmap[q].RightUShift(r) & 1) != 0);
                this.bitmap[q] ^= 1L << r;

                this.SetNextAvail(bitmapIdx);

                if (this.numAvail++ == 0)
                {
                    this.AddToPool(head);
                    return(true);
                }

                if (this.numAvail != this.maxNumElems)
                {
                    return(true);
                }
                else
                {
                    // Subpage not in use (numAvail == maxNumElems)
                    if (this.Prev == this.Next)
                    {
                        // Do not remove if this subpage is the only one left in the pool.
                        return(true);
                    }

                    // Remove this subpage from the pool if there are other subpages left in the pool.
                    this.DoNotDestroy = false;
                    this.RemoveFromPool();
                    return(false);
                }
            }
        }
Example #14
0
        void InitBufWithSubpage(PooledByteBuffer <T> buf, long handle, int bitmapIdx, int reqCapacity)
        {
            Contract.Assert(bitmapIdx != 0);

            int memoryMapIdx = MemoryMapIdx(handle);

            PoolSubpage <T> subpage = this.subpages[this.SubpageIdx(memoryMapIdx)];

            Contract.Assert(subpage.DoNotDestroy);
            Contract.Assert(reqCapacity <= subpage.ElemSize);

            buf.Init(
                this, handle,
                this.RunOffset(memoryMapIdx) + (bitmapIdx & 0x3FFFFFFF) * subpage.ElemSize + this.Offset,
                reqCapacity, subpage.ElemSize, this.Arena.Parent.ThreadCache <T>());
        }
Example #15
0
        /**
         * @return {@code true} if this subpage is in use.
         *         {@code false} if this subpage is not used by its chunk and thus it's OK to be released.
         */

        internal bool Free(PoolSubpage <T> head, int bitmapIdx)
        {
            if (this.ElemSize == 0)
            {
                return(true);
            }

            int q = bitmapIdx.RightUShift(6);
            int r = bitmapIdx & 63;

            Contract.Assert((this.bitmap[q].RightUShift(r) & 1) != 0);
            this.bitmap[q] ^= 1L << r;

            this.SetNextAvail(bitmapIdx);

            if (this.NumAvailable++ == 0)
            {
                this.AddToPool(head);
                return(true);
            }

            if (this.NumAvailable != this.MaxNumElements)
            {
                return(true);
            }
            else
            {
                // Subpage not in use (numAvail == maxNumElems)
                if (this.Prev == this.Next)
                {
                    // Do not remove if this subpage is the only one left in the pool.
                    return(true);
                }

                // Remove this subpage from the pool if there are other subpages left in the pool.
                this.DoNotDestroy = false;
                this.RemoveFromPool();
                return(false);
            }
        }
Example #16
0
        public void Init(PoolSubpage <T> head, int elemSize)
        {
            this.DoNotDestroy = true;
            this.ElemSize     = elemSize;
            if (elemSize != 0)
            {
                this.MaxNumElements = this.NumAvailable = this.pageSize / elemSize;
                this.nextAvail      = 0;
                this.bitmapLength   = this.MaxNumElements.RightUShift(6);
                if ((this.MaxNumElements & 63) != 0)
                {
                    this.bitmapLength++;
                }

                for (int i = 0; i < this.bitmapLength; i++)
                {
                    this.bitmap[i] = 0;
                }
            }

            this.AddToPool(head);
        }
Example #17
0
        static List <IPoolSubpageMetric> SubPageMetricList(PoolSubpage <T>[] pages)
        {
            var metrics = new List <IPoolSubpageMetric>();

            foreach (PoolSubpage <T> head in pages)
            {
                if (head.Next == head)
                {
                    continue;
                }
                PoolSubpage <T> s = head.Next;
                for (; ;)
                {
                    metrics.Add(s);
                    s = s.Next;
                    if (s == head)
                    {
                        break;
                    }
                }
            }
            return(metrics);
        }
Example #18
0
        static List <IPoolSubpageMetric> SubPageMetricList(PoolSubpage <T>[] pages)
        {
            var metrics = new List <IPoolSubpageMetric>();

            for (int i = 1; i < pages.Length; i++)
            {
                PoolSubpage <T> head = pages[i];
                if (head.Next == head)
                {
                    continue;
                }
                PoolSubpage <T> s = head.Next;
                for (;;)
                {
                    metrics.Add(s);
                    s = s.Next;
                    if (s == head)
                    {
                        break;
                    }
                }
            }
            return(metrics);
        }
Example #19
0
        void Allocate(PoolThreadCache <T> cache, PooledArrayBuffer <T> buf, int reqCapacity)
        {
            int normCapacity = this.NormalizeCapacity(reqCapacity);

            if (this.IsTinyOrSmall(normCapacity))
            {
                // capacity < pageSize
                int tableIdx;
                PoolSubpage <T>[] table;
                bool tiny = IsTiny(normCapacity);
                if (tiny)
                {
                    // < 512
                    if (cache.AllocateTiny(this, buf, reqCapacity, normCapacity))
                    {
                        // was able to allocate out of the cache so move on
                        return;
                    }
                    tableIdx = TinyIdx(normCapacity);
                    table    = this.tinySubpagePools;
                }
                else
                {
                    if (cache.AllocateSmall(this, buf, reqCapacity, normCapacity))
                    {
                        // was able to allocate out of the cache so move on
                        return;
                    }
                    tableIdx = SmallIdx(normCapacity);
                    table    = this.smallSubpagePools;
                }

                PoolSubpage <T> head = table[tableIdx];

                /**
                 * Synchronize on the head. This is needed as {@link PoolSubpage#allocate()} and
                 * {@link PoolSubpage#free(int)} may modify the doubly linked list as well.
                 */
                lock (head)
                {
                    PoolSubpage <T> s = head.Next;
                    if (s != head)
                    {
                        Contract.Assert(s.DoNotDestroy && s.ElemSize == normCapacity);
                        long handle = s.Allocate();
                        Contract.Assert(handle >= 0);
                        s.Chunk.InitBufWithSubpage(buf, handle, reqCapacity);

                        if (tiny)
                        {
                            ++this.NumTinyAllocations;
                        }
                        else
                        {
                            ++this.NumSmallAllocations;
                        }
                        return;
                    }
                }

                this.AllocateNormal(buf, reqCapacity, normCapacity);
                return;
            }

            if (normCapacity <= this.ChunkSize)
            {
                if (cache.AllocateNormal(this, buf, reqCapacity, normCapacity))
                {
                    // was able to allocate out of the cache so move on
                    return;
                }
                this.AllocateNormal(buf, reqCapacity, normCapacity);
            }
            else
            {
                // Huge allocations are never served via the cache so just call allocateHuge
                this.AllocateHuge(buf, reqCapacity);
            }
        }
Example #20
0
        public override string ToString()
        {
            lock (this)
            {
                StringBuilder buf = new StringBuilder()
                                    .Append("Chunk(s) at 0~25%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.qInit)
                                    .Append(Environment.NewLine)
                                    .Append("Chunk(s) at 0~50%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.q000)
                                    .Append(Environment.NewLine)
                                    .Append("Chunk(s) at 25~75%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.q025)
                                    .Append(Environment.NewLine)
                                    .Append("Chunk(s) at 50~100%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.q050)
                                    .Append(Environment.NewLine)
                                    .Append("Chunk(s) at 75~100%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.q075)
                                    .Append(Environment.NewLine)
                                    .Append("Chunk(s) at 100%:")
                                    .Append(Environment.NewLine)
                                    .Append(this.q100)
                                    .Append(Environment.NewLine)
                                    .Append("tiny subpages:");
                for (int i = 1; i < this.tinySubpagePools.Length; i++)
                {
                    PoolSubpage <T> head = this.tinySubpagePools[i];
                    if (head.Next == head)
                    {
                        continue;
                    }

                    buf.Append(Environment.NewLine)
                    .Append(i)
                    .Append(": ");
                    PoolSubpage <T> s = head.Next;
                    for (;;)
                    {
                        buf.Append(s);
                        s = s.Next;
                        if (s == head)
                        {
                            break;
                        }
                    }
                }
                buf.Append(Environment.NewLine)
                .Append("small subpages:");
                for (int i = 1; i < this.smallSubpagePools.Length; i++)
                {
                    PoolSubpage <T> head = this.smallSubpagePools[i];
                    if (head.Next == head)
                    {
                        continue;
                    }

                    buf.Append(Environment.NewLine)
                    .Append(i)
                    .Append(": ");
                    PoolSubpage <T> s = head.Next;
                    for (;;)
                    {
                        buf.Append(s);
                        s = s.Next;
                        if (s == head)
                        {
                            break;
                        }
                    }
                }
                buf.Append(Environment.NewLine);

                return(buf.ToString());
            }
        }