变长引用计数型小对象池实现

class CTranBufPool : public CBufPoolV
{
	struct Handle {
		DLINK link;
		char* pBuffer;
        Handle* pRealHdl;
		int nRef;
        int nConsBuf;
	};
	typedef TLinkedList<Handle> FreeList;
	typedef std::map<char*, Handle*> BufferMap;

	FreeList m_FreeList;
	BufferMap m_BufferMap;

	int m_nBlockSize, m_nBufferSize, m_nBlockBase;
	int m_nAlloc, m_nMaxBuffers, m_nBuffers, m_nWaterMarks[3];
    int m_nMin, m_nMax;
	
	//分配m_nBufferSize字节的内存,该内存空间实际包含m_nAlloc个m_nBlockSize的单元;每个单元与一个Handle相关联,这些Handle入FreeList队列。
	bool AllocOnce() {
		char* pBuffer = (char*)AlignAlloc(m_nBlockSize, m_nBufferSize);
		//记录Block信息
		Handle* pHdl = (Handle*)ZeroAlloc(m_nAlloc * sizeof(Handle));
		if (pBuffer && pHdl) {
			m_BufferMap.insert(BufferMap::value_type(pBuffer, pHdl));
			//Buffer数
			m_nBuffers += m_nAlloc;

			//最后一个Block
            pBuffer += m_nBufferSize - m_nBlockSize;
            pHdl += m_nAlloc - 1;

			for (int i=0; i<m_nAlloc; i++) {
				pHdl->pBuffer = pBuffer;
				pHdl->nRef = 0;
				//
                pHdl->nConsBuf = i+1;
                pHdl->pRealHdl = pHdl;
				m_FreeList.push_back(pHdl);
				
				pBuffer -= m_nBlockSize;
				pHdl --;
			}
			return true;
		}
		if (pBuffer)
			free(pBuffer);
		if (pHdl)
			free(pHdl);
		return false;
	}

	Handle* GetHandle(char* pBuffer) {
		BufferMap::iterator it = m_BufferMap.upper_bound(pBuffer);
		if (it != m_BufferMap.begin()) {
			it --;
			
			char* pHead = it->first;
			ASSERT(pHead <= pBuffer);
			if (pBuffer < pHead + m_nBufferSize) {
				//2^m_nBlockBase
				int n = (pBuffer-pHead) >> m_nBlockBase;
                Handle* pHdl = it->second + n;
                ASSERT(pHdl->pBuffer == pHead + (((uint32)n) << m_nBlockBase));

				return pHdl;
			}
		}
		return NULL;
	}

    void Destroy() {
        m_FreeList.Init();
        m_nBuffers = 0;

        BufferMap::iterator it;
        for (it=m_BufferMap.begin(); it!=m_BufferMap.end(); it++) {
            free(it->first);
            free(it->second);
        }
        m_BufferMap.clear();
    }

public:
    CTranBufPool(const char* name, int nCategory) : CBufPoolV(name, nCategory) {
		m_nBuffers = 0;
		m_nBlockSize = m_nBufferSize = m_nAlloc = m_nMaxBuffers = m_nMin = 0;
        m_nWaterMarks[0] = m_nWaterMarks[1] = m_nWaterMarks[2] = 0;
	}

	bool Create(int nBlockSize, int nAlloc, int nMin, int nMax, double fRatio1, double fRatio2) {
        m_nUnitSize = nBlockSize;
		m_nBlockSize = nBlockSize;
		m_nBlockBase = Log_2(nBlockSize);
        if (-1 == m_nBlockBase) {
            TRACE0("Fatal: invalid block size of %d\n", nBlockSize);
            return false;
        }
		//Block数
        m_nAlloc = nAlloc;
		//最多Block数
		m_nMaxBuffers = nMax * nAlloc;
		//Buffer大小
		m_nBufferSize = m_nBlockSize * m_nAlloc;
		//当前Block数
		m_nBuffers = 0;
		//最大buffer数
        m_nMax = nMax;
#ifdef  _DEBUG

        m_nMin = 0;

#else
		//最少buffer数
        m_nMin = nMin;
#endif
        if (0!=fRatio1 && 0!=fRatio2) {
			//优先级1水位
		    m_nWaterMarks[0] = (int)((double)m_nMaxBuffers * fRatio1);
			//优先级2水位
		    m_nWaterMarks[1] = (int)((double)m_nMaxBuffers * fRatio2);
			//最大水位
		    m_nWaterMarks[2] = m_nMaxBuffers-1;
        }
		for (int i=0; i<m_nMin; i++) {
			if (!AllocOnce())
				return false;
		}
		return true;
	}

	~CTranBufPool() {
		Destroy();
	}

    int GetFreePercent() const {
        int n = (int)m_FreeList.size();
        int n1 = m_nMaxBuffers-m_nBuffers+n;
        return (n1*100) / m_nMaxBuffers;
    }


#define _ALLOC_TRAN_BUF(p, how)                     \
    p = m_FreeList.how();                           \
    ASSERT(DLINK_IS_STANDALONE(&p->link));          \
    ASSERT(0 == p->nRef);                           \
    ASSERT(p->pRealHdl == p);                       \
    p->nRef = 1

	char* Allocate(uint32 nPriority, int count=1) {
		int n;
        ASSERT(0 != count);
		//最多两次重试
		for (int i=0; i<2; i++) {
			n = (int)m_FreeList.size();
			//使用的Block数大于这个优先级的水位
			if (m_nBuffers-n > m_nWaterMarks[nPriority]) {
				if (nPriority != 0) {
					static time_t last = 0;
					time_t now = time(NULL);
					//30秒打印一次
					if (now - last >= 30) {		// avoid too frequent print
						//可用的块
                        int n1 = m_nMaxBuffers-m_nBuffers+n;
						//阈值
                        int n2 = m_nMaxBuffers-m_nWaterMarks[nPriority];
						TRACE0("Warning: available tran buf (#%d) touches watermark(#%d, %.f%%)\n", 
								n1, n2, (double)(n1*100)/m_nMaxBuffers);
						last = now;
					}
				}
				return NULL;
			}
			//够用
            if (n >= count) {
                Handle *pHdl, *pTmp;
				//1个Block的情况
                if (1 == count) {
                    _ALLOC_TRAN_BUF(pHdl, pop_front);
				    return pHdl->pBuffer;
                }
                // Big block are formed by multiple consecutive blocks. 
                // We try from the tail of free list, which brings higher probability.
                _ALLOC_TRAN_BUF(pHdl, pop_back);
                int i = 1;
				//所在buffer后面有足够多的Block
                if (pHdl->nConsBuf >= count) {
                    for ( ; i<count; i++) {
                        pTmp = pHdl + i;
						//确保空间没有被使用
                        UNLIKELY_IF (0 != pTmp->nRef) {
                            break;
                        }
                        m_FreeList.remove(pTmp);
                        DLINK_INSERT_PREV(&pHdl->link, &pTmp->link);
                        pTmp->pRealHdl = pHdl;
                        pTmp->nRef = 1;
                    }
                }
                if (i == count) {
#if (defined(_DEBUG) && defined(_UNITTEST))

                    for (i=0 ; i<count; i++) {

                        pTmp = pHdl + i;

                        TRACE0("%d: %p <- %p -> %p\n", i, pTmp->link._prev, &pTmp->link, pTmp->link._next);

                    }

#endif
                    return pHdl->pBuffer;
                }
                else {
					//出错或是空间不够
                    for (int j=0; j<i; j++) {
                        pTmp = pHdl + j;
                        DLINK_INITIALIZE(&pTmp->link);
                        pTmp->pRealHdl = pTmp;
                        pTmp->nRef = 0;
                        m_FreeList.push_front(pTmp);
                    }
                }
            }
            if (m_nBuffers >= m_nMaxBuffers || !AllocOnce()) {
                return NULL;
            }
		}
		return NULL;
	}

	int AddRef(char* p, bool bCheck=false) {
		Handle* pHdl = GetHandle(p);
		if (NULL == pHdl) {
			if (!bCheck) {
                return -1;
            }
			RaiseError(Invalid_Block);
        }

        int n = ++ pHdl->pRealHdl->nRef;
        ASSERT(2 <= n);
        return n;
	}

#ifdef	_DEBUG
#define _FREE_TRAN_BUF(p, how)                              \
        memset(p->pBuffer, 0xCC, m_nBlockSize);             \
        m_FreeList.how(p)
#else
#define _FREE_TRAN_BUF(p, how)                              \
        m_FreeList.how(p)
#endif

	int Free(char* p, bool bCheck=false) {
		Handle* pHdl = GetHandle(p);
		if (NULL == pHdl) {
			if (bCheck) {
				RaiseError(Invalid_Block);
			}
			return -1;
		}
        
        pHdl = pHdl->pRealHdl;
        int n = -- pHdl->nRef;
		//没有被引用
        if (0 == n) {
            Handle* pTmp = dlink_get_prev(pHdl);
            if (pTmp == pHdl) {
                ASSERT_EQUAL(pHdl->pRealHdl, pHdl);
                ASSERT_EQUAL(0, pHdl->nRef);
                _FREE_TRAN_BUF(pHdl, push_front);
                return 0;
            }
            // here comes big block
            Handle* p = pHdl;
            do {
                pHdl = pTmp;
                pTmp = dlink_get_prev(pTmp);
                ASSERT_EQUAL(1, pHdl->nRef);

                ASSERT_EQUAL(p, pHdl->pRealHdl);
                pHdl->pRealHdl = pHdl;
                pHdl->nRef = 0;
                DLINK_INITIALIZE(&pHdl->link);
                _FREE_TRAN_BUF(pHdl, push_back);
            } while (p != pTmp);
            ASSERT_EQUAL(p, p->pRealHdl);
            ASSERT_EQUAL(0, p->nRef);
            DLINK_INITIALIZE(&p->link);
            _FREE_TRAN_BUF(p, push_back);
            return 0;
        }
		return n;
	}

	void Print() {
        char buf[128];

        if (0 != m_nBuffers) {
            int nFree = m_nMaxBuffers-m_nBuffers+m_FreeList.size();
            PrintSize((uint64)m_nMaxBuffers*m_nBlockSize, buf, sizeof(buf));
            TRACE0("%16s: #%d:%d:%d (%.1f%%), Max=%sB\n", m_name, m_FreeList.size(), m_nBuffers, m_nMaxBuffers, 
			    ((double)nFree * 100 / m_nMaxBuffers), buf);
        }
	}

    int GetAllocCount() { return m_nBuffers; }
    int GetFreeCount() { return m_FreeList.size(); }
    void GarbageCollect() {}
    void _GarbageCollect() {
        if (m_nBuffers!=m_nMin*m_nAlloc && (int)m_FreeList.size()==m_nBuffers) {
            Destroy();
            Create(m_nBlockSize, m_nAlloc, m_nMin, m_nMax, 0, 0);
        }
    }

    int GetBlockSize() const { return m_nBlockSize; }

	/* return the maximum capacity of the pool. */ 
	int GetTotalBufNum() const { return m_nMaxBuffers; }

	/* return the allocated buffers' number, including FREED or be USING.
	 * !!NOTICE: Make sure you know the meaning of 'm_nBuffers' when use. 
	 */
	int GetAllocatedBufNum() const { return m_nBuffers; }

	/* return the number of buffers free to use. */
	int GetFreeBufNum() const { 
		return m_nMaxBuffers-m_nBuffers+m_FreeList.size(); 
	}

#undef _ALLOC_TRAN_BUF
#undef _FREE_TRAN_BUF
};
template <class TLock=CNoLock>
class TBufPool : public CBufPoolV
{
    uint32 m_nAlloc, m_nCur, m_nMax, m_nStart;
    uint32 m_nSize;
    TLock m_Lock;

    #pragma pack(push, r1, 1)
    struct AllocUnit {
        SLINK link;
        char buf[0];
    };
    #pragma pack(pop, r1)

    //free block链表
    TSingleList<AllocUnit> m_FreeList;
    //buffer链表
    TSingleList<AllocUnit> m_Pointers;

    bool AllocOnce() {
        ASSERT(m_nAlloc != 0);
        ASSERT(m_nCur <= m_nMax);
        //m_nAlloc个block和一个buffer指针构成
        AllocUnit* pUnit = (AllocUnit*)malloc(m_nAlloc * m_nUnitSize + sizeof(SLINK));
#ifdef _DEBUG
        memset(pUnit, 0xCC, m_nAlloc * m_nUnitSize + sizeof(SLINK));
#endif
        if (pUnit) {
            m_Pointers.push(pUnit);
            //buffer个数
            m_nCur ++;

            pUnit = MAKE_PTR(AllocUnit*, pUnit, sizeof(SLINK));
            //加入free链
            m_FreeList.pushn(m_nAlloc, pUnit, m_nUnitSize);
            return true;
        }
        PERROR("malloc");
        return false;
    }

public:
    TBufPool(char* name, int nCategory, uint32 nSize) : CBufPoolV(name, nCategory) {
        m_nAlloc = m_nCur = 0;
        m_nMax = (uint32)-1;
        m_nSize = nSize;
        m_nStart = 0;
    }
    TBufPool(char* name, int nCategory, uint32 nSize, uint32 nAlloc, uint32 nStart, uint32 nMax=(uint32)-1) 
        : CBufPoolV(name, nCategory) 
    {
        //数据大小
        m_nSize = nSize;
        Create(nAlloc, nStart, nMax);
    }
    virtual ~TBufPool() { Destroy(false); }

    bool Create(uint32 nAlloc, uint32 nStart, uint32 nMax=(uint32)-1) {
        ASSERT2(nStart, <=, nMax);
        ASSERT2(0, !=, nAlloc);

        //每块buffer的block个数
        m_nAlloc = nAlloc;
        m_nMax = nMax;
#ifdef  _DEBUG
        m_nStart = 0;
        m_nUnitSize = m_nSize + sizeof(SLINK) + 4;    // signature after each unit
#else
        //初始buffer数
        m_nStart = nStart;
        //节点大小
        m_nUnitSize = m_nSize + sizeof(SLINK);
#endif
        //当前buf数
        for (m_nCur=0; m_nCur<m_nStart; ) {
            if (!AllocOnce()) {
                return false;
            }
        }
        return true;
    }

    bool Destroy(bool /*bCheck*/) {
        m_FreeList.Init();

        AllocUnit* pUnit;
        while (NULL != (pUnit=m_Pointers.pop())) {
            free(pUnit);
        }
        m_nCur = 0;
        return true;
    }

    void* Allocate() {
        ASSERT_NOT_EQUAL(0, m_nAlloc);
        m_Lock.Lock();
        for (int i=0; ; i++) {
            AllocUnit* pUnit = m_FreeList.pop();
            if (NULL != pUnit) {
#ifdef	_DEBUG
                *MAKE_PTR(uint32*, pUnit->buf, m_nSize) = 0xdeadbeefUL;
#endif
                m_Lock.Unlock();
                return &pUnit->buf;
            }
            if (m_nCur>=m_nMax || 0!=i || !AllocOnce()) {
                break;
            }
        }
        m_Lock.Unlock();
        return NULL;
    }

    void* ZeroAllocate() {
        void* pBuf = Allocate();
        if (pBuf) {
            ZeroMemory(pBuf, m_nSize);
        }
        return pBuf;
    }

    void Free(void* pBuf) {
        AllocUnit* pUnit = CONTAINING_RECORD(pBuf, AllocUnit, buf);
#ifdef	_DEBUG
        ASSERT_EQUAL(*MAKE_PTR(uint32*, pUnit->buf, m_nSize), 0xdeadbeefUL);
        memset(pUnit, 0xCC, m_nUnitSize);
#endif
        m_Lock.Lock();
        m_FreeList.push(pUnit);
        m_Lock.Unlock();
    }

    void PrintObjs() {

        TRACE0("Total Objects: ");

        m_Lock.Lock();

        SLINK* p = (SLINK*)m_Pointers.top();

        AllocUnit* pE = NULL;



        while(p) {

            pE = MAKE_PTR(AllocUnit*, p, sizeof(SLINK));

            for(uint32 i = 0; i < m_nAlloc; ++i) {

                TRACE0("%p ", pE);

                ++pE;

            }

            p = p->_next;

        }

        TRACE0("\n");



        TRACE0("Free  Objects: ");

        pE = m_FreeList.top();

        while(pE) {

            TRACE0("%p ", pE);      

            p = pE->link._next;

            pE = p ? CONTAINING_RECORD(p, AllocUnit, link) : NULL;

        }

        TRACE0("\n");

        m_Lock.Unlock();

    }


    int GetAllocCount() {
        return m_nAlloc * m_nCur;
    }

    int GetFreeCount() {
        int m;

        m_Lock.Lock();
        m = m_FreeList.size();
        m_Lock.Unlock();
        return m;
    }

    void GarbageCollect() {
        m_Lock.Lock();
        if (m_nCur!=m_nStart && (uint32)m_FreeList.size()==m_nAlloc*m_nCur) {
            Destroy(false);
            Create(m_nAlloc, m_nStart, m_nMax);
        }
        m_Lock.Unlock();
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值