mirror of
https://github.com/joyieldInc/predixy.git
synced 2025-12-24 14:36:42 +08:00
251 lines
5.1 KiB
C++
251 lines
5.1 KiB
C++
/*
|
|
* predixy - A high performance and full features proxy for redis.
|
|
* Copyright (C) 2017 Joyield, Inc. <joyield.com@gmail.com>
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#ifndef _PREDIXY_ALLOC_H_
|
|
#define _PREDIXY_ALLOC_H_
|
|
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include "Sync.h"
|
|
#include "Exception.h"
|
|
#include "Util.h"
|
|
#include "Logger.h"
|
|
#include "Timer.h"
|
|
|
|
class AllocBase
|
|
{
|
|
public:
|
|
DefException(MemLimit);
|
|
public:
|
|
static void setMaxMemory(long m)
|
|
{
|
|
MaxMemory = m;
|
|
}
|
|
static long getMaxMemory()
|
|
{
|
|
return MaxMemory;
|
|
}
|
|
static long getUsedMemory()
|
|
{
|
|
return UsedMemory;
|
|
}
|
|
protected:
|
|
static long MaxMemory;
|
|
static AtomicLong UsedMemory;
|
|
};
|
|
|
|
template<class T>
|
|
inline int allocSize()
|
|
{
|
|
return sizeof(T);
|
|
}
|
|
|
|
template<class T, int CacheSize = 64>
|
|
class Alloc : public AllocBase
|
|
{
|
|
public:
|
|
template<class... Targs>
|
|
static T* create(Targs&&... args)
|
|
{
|
|
FuncCallTimer();
|
|
T* obj = nullptr;
|
|
if (Size > 0) {
|
|
obj = Free[--Size];
|
|
}
|
|
if (obj) {
|
|
try {
|
|
new ((void*)obj) T(args...);
|
|
} catch (...) {
|
|
bool del = true;
|
|
if (Size < CacheSize) {
|
|
Free[Size++] = obj;
|
|
del = false;
|
|
}
|
|
if (del) {
|
|
UsedMemory -= allocSize<T>();
|
|
::operator delete((void*)obj);
|
|
}
|
|
throw;
|
|
}
|
|
logVerb("alloc create object with old memory %d @%p", allocSize<T>(), obj);
|
|
return obj;
|
|
}
|
|
UsedMemory += allocSize<T>();
|
|
if (MaxMemory == 0 || UsedMemory <= MaxMemory) {
|
|
void* p = ::operator new(allocSize<T>());
|
|
if (p) {
|
|
try {
|
|
obj = new (p) T(args...);
|
|
logVerb("alloc create object with new memory %d @%p", allocSize<T>(), obj);
|
|
return obj;
|
|
} catch (...) {
|
|
UsedMemory -= allocSize<T>();
|
|
::operator delete(p);
|
|
throw;
|
|
}
|
|
} else {
|
|
UsedMemory -= allocSize<T>();
|
|
Throw(MemLimit, "system memory alloc fail");
|
|
}
|
|
} else {
|
|
UsedMemory -= allocSize<T>();
|
|
Throw(MemLimit, "maxmemory used");
|
|
}
|
|
return nullptr;
|
|
}
|
|
static void destroy(T* obj)
|
|
{
|
|
FuncCallTimer();
|
|
bool del = true;
|
|
obj->~T();
|
|
if (Size < CacheSize) {
|
|
Free[Size++] = obj;
|
|
del = false;
|
|
}
|
|
if (del) {
|
|
UsedMemory -= allocSize<T>();
|
|
::operator delete((void*)obj);
|
|
}
|
|
logVerb("alloc destroy object with size %d @%p delete %s", (int)allocSize<T>(), obj, del ? "true" : "false");
|
|
}
|
|
private:
|
|
thread_local static T* Free[CacheSize];
|
|
thread_local static int Size;
|
|
};
|
|
|
|
template<class T, int CacheSize>
|
|
thread_local T* Alloc<T, CacheSize>::Free[CacheSize];
|
|
template<class T, int CacheSize>
|
|
thread_local int Alloc<T, CacheSize>::Size = 0;
|
|
|
|
template<class T>
|
|
class RefCntObj
|
|
{
|
|
public:
|
|
RefCntObj():
|
|
mCnt(0)
|
|
{
|
|
}
|
|
RefCntObj(const RefCntObj&) = delete;
|
|
RefCntObj& operator=(const RefCntObj&) = delete;
|
|
int count() const
|
|
{
|
|
return mCnt;
|
|
}
|
|
void ref()
|
|
{
|
|
++mCnt;
|
|
}
|
|
void unref()
|
|
{
|
|
int n = --mCnt;
|
|
if (n == 0) {
|
|
Alloc<T>::destroy(static_cast<T*>(this));
|
|
} else if (n < 0) {
|
|
logError("unref object %p with cnt %d", this, n);
|
|
abort();
|
|
}
|
|
}
|
|
protected:
|
|
~RefCntObj()
|
|
{
|
|
mCnt = 0;
|
|
}
|
|
private:
|
|
AtomicInt mCnt;
|
|
};
|
|
|
|
template<class T>
|
|
class SharePtr
|
|
{
|
|
public:
|
|
SharePtr():
|
|
mObj(nullptr)
|
|
{
|
|
}
|
|
SharePtr(T* obj):
|
|
mObj(obj)
|
|
{
|
|
if (obj) {
|
|
obj->ref();
|
|
}
|
|
}
|
|
SharePtr(const SharePtr<T>& sp):
|
|
mObj(sp.mObj)
|
|
{
|
|
if (mObj) {
|
|
mObj->ref();
|
|
}
|
|
}
|
|
SharePtr(SharePtr<T>&& sp):
|
|
mObj(sp.mObj)
|
|
{
|
|
sp.mObj = nullptr;
|
|
}
|
|
~SharePtr()
|
|
{
|
|
if (mObj) {
|
|
mObj->unref();
|
|
mObj = nullptr;
|
|
}
|
|
}
|
|
operator T*() const
|
|
{
|
|
return mObj;
|
|
}
|
|
SharePtr& operator=(const SharePtr& sp)
|
|
{
|
|
if (this != &sp) {
|
|
T* obj = mObj;
|
|
mObj = sp.mObj;
|
|
if (mObj) {
|
|
mObj->ref();
|
|
}
|
|
if (obj) {
|
|
obj->unref();
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
T& operator*()
|
|
{
|
|
return *mObj;
|
|
}
|
|
const T& operator*() const
|
|
{
|
|
return *mObj;
|
|
}
|
|
T* operator->()
|
|
{
|
|
return mObj;
|
|
}
|
|
const T* operator->() const
|
|
{
|
|
return mObj;
|
|
}
|
|
bool operator!() const
|
|
{
|
|
return !mObj;
|
|
}
|
|
operator bool() const
|
|
{
|
|
return mObj;
|
|
}
|
|
bool operator==(const SharePtr& sp) const
|
|
{
|
|
return mObj == sp.mObj;
|
|
}
|
|
bool operator!=(const SharePtr& sp) const
|
|
{
|
|
return mObj != sp.mObj;
|
|
}
|
|
private:
|
|
T* mObj;
|
|
};
|
|
|
|
#endif
|