Exemple #1
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);
        }
        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;
                    }
                }
            }
        }
Exemple #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)
        {
            // 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());
            }
        }
        PoolSubpage <T> NewSubpagePoolHead(int pageSize)
        {
            var head = new PoolSubpage <T>(pageSize);

            head.Prev = head;
            head.Next = head;
            return(head);
        }
 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);
 }
        void RemoveFromPool()
        {
            Debug.Assert(this.Prev != null && this.Next != null);

            this.Prev.Next = this.Next;
            this.Next.Prev = this.Prev;
            this.Next      = null;
            this.Prev      = null;
        }
        void AddToPool(PoolSubpage <T> head)
        {
            Debug.Assert(this.Prev == null && this.Next == null);

            this.Prev      = head;
            this.Next      = head.Next;
            this.Next.Prev = this;
            head.Next      = this;
        }
Exemple #8
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>());
        }
        /**
         * @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;

            Debug.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);
            }
        }
        public void Init(PoolSubpage <T> head, 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;
                }
            }

            this.AddToPool(head);
        }
        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);
        }
        void Allocate(PoolThreadCache <T> cache, PooledByteBuffer <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)
                    {
                        Debug.Assert(s.DoNotDestroy && s.ElemSize == normCapacity);
                        long handle = s.Allocate();
                        Debug.Assert(handle >= 0);
                        s.Chunk.InitBufWithSubpage(buf, handle, reqCapacity);
                        this.IncTinySmallAllocation(tiny);
                        return;
                    }
                }

                lock (this)
                {
                    this.AllocateNormal(buf, reqCapacity, normCapacity);
                }

                this.IncTinySmallAllocation(tiny);
                return;
            }
            if (normCapacity <= this.ChunkSize)
            {
                if (cache.AllocateNormal(this, buf, reqCapacity, normCapacity))
                {
                    // was able to allocate out of the cache so move on
                    return;
                }

                lock (this)
                {
                    this.AllocateNormal(buf, reqCapacity, normCapacity);
                    this.allocationsNormal++;
                }
            }
            else
            {
                // Huge allocations are never served via the cache so just call allocateHuge
                this.AllocateHuge(buf, reqCapacity);
            }
        }