├── lib ├── readme ├── libshm.a └── libantisnow.a ├── src ├── antisnow │ ├── readme │ ├── makefile │ ├── antisnow.h │ ├── antisnow.cpp │ └── minSpinLock.h ├── list │ ├── time_list.h │ ├── list.h │ ├── list_head.h │ ├── readme.md │ └── doubly_linked_list.h ├── shm │ ├── readme.md │ ├── makefile │ ├── shm.h │ └── shm.cpp ├── monitor │ ├── makefile │ ├── monitor.h │ └── monitor.cpp ├── cache │ ├── cache.h │ └── cache.cpp ├── hash │ ├── hash.h │ └── hash.cpp ├── linktable │ ├── LinkTable.h │ ├── LinkTableDefine.h │ └── LinkTable.c ├── MultiHashTable │ ├── shm_adapter.h │ ├── link_table.h │ ├── shm_adapter.cc │ ├── multi_hash_table.h │ ├── link_table.cc │ └── multi_hash_table.cc └── net │ └── util.h ├── .gitignore ├── test ├── antisnow │ ├── makefile │ └── test.cpp └── shm │ ├── fork │ ├── makefile │ └── fork.cpp │ └── readwrite │ ├── makefile │ ├── comm.h │ ├── readme.md │ ├── read.cpp │ └── write.cpp └── include ├── antisnow.h └── shm.h /lib/readme: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/antisnow/readme: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/libshm.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiankonguse/shm-cache/HEAD/lib/libshm.a -------------------------------------------------------------------------------- /lib/libantisnow.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiankonguse/shm-cache/HEAD/lib/libantisnow.a -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | build/ 3 | file/ 4 | _drafts/ 5 | .DS_Store 6 | *.swp 7 | *~ 8 | .settings/ 9 | .svn/ 10 | .cproject 11 | .project 12 | ./lib/*.a 13 | *.o 14 | 15 | -------------------------------------------------------------------------------- /test/antisnow/makefile: -------------------------------------------------------------------------------- 1 | PRJ_PATH = ../.. 2 | 3 | all: 4 | g++ -o test test.cpp -I$(PRJ_PATH)/include -L$(PRJ_PATH)/lib -lantisnow -lshm -pthread 5 | clean: 6 | rm test 7 | -------------------------------------------------------------------------------- /test/shm/fork/makefile: -------------------------------------------------------------------------------- 1 | PRJ_PATH = ../../.. 2 | 3 | all: 4 | g++ -o fork fork.cpp -I$(PRJ_PATH)/include/ -L$(PRJ_PATH)/lib/ -static -lshm -pthread 5 | clean: 6 | rm fork 7 | -------------------------------------------------------------------------------- /test/shm/readwrite/makefile: -------------------------------------------------------------------------------- 1 | PRJ_PATH = ../../.. 2 | 3 | all: 4 | g++ -O0 -o read read.cpp -I$(PRJ_PATH)/include/ -L$(PRJ_PATH)/lib/ -static -lshm -pthread 5 | g++ -o write write.cpp -I$(PRJ_PATH)/include/ -L$(PRJ_PATH)/lib/ -static -lshm -pthread 6 | clean: 7 | rm read write 8 | -------------------------------------------------------------------------------- /src/list/time_list.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: time_list.h 3 | > Desc: time list 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2016年06月25日 7 | ***********************************************************************/ 8 | 9 | 10 | #include "list_head.h" 11 | 12 | #ifndef _TIME_LIST_H_ 13 | #define _TIME_LIST_H_ 14 | 15 | 16 | 17 | #endif 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/shm/readwrite/comm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * comm.h 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #ifndef COMM_H_ 9 | #define COMM_H_ 10 | 11 | const int TIME_NUM = 3; 12 | 13 | typedef struct { 14 | long long sec; 15 | long long usec; 16 | long long val; 17 | } Time; 18 | 19 | int generatesKey() { 20 | int key; 21 | char pathname[30]; 22 | strcpy(pathname, "/tmp"); 23 | 24 | key = ftok(pathname, 0x03); 25 | if (key == -1) { 26 | perror("ftok error"); 27 | return -1; 28 | } 29 | 30 | printf("key=%d\n", key); 31 | return key; 32 | } 33 | 34 | 35 | 36 | #endif /* COMM_H_ */ 37 | -------------------------------------------------------------------------------- /src/shm/readme.md: -------------------------------------------------------------------------------- 1 | # 相关函数手册 2 | 3 | 4 | 5 | ## shmget 6 | 7 | 申请一片共享内存. 8 | key 申请共享内存时的唯一标示. 9 | 如果key已存在, 但是和size大小不同, 则返回 -1, 正常则返回 shmid. 10 | 11 | ``` 12 | #include 13 | #include 14 | 15 | int shmget(key_t key, size_t size, int shmflg); 16 | ``` 17 | 18 | 19 | 20 | ## shmat 21 | 22 | 根据 shmid 得到共享内存地址(共享内存映射到进程内). 23 | 24 | ``` 25 | #include 26 | #include 27 | 28 | void *shmat(int shmid, const void *shmaddr, int shmflg); 29 | ``` 30 | 31 | ## shmctl 32 | 33 | 根据 shmid 和 cmd 操作共享内存, 常用的是删除共享内存. 34 | 35 | ``` 36 | #include 37 | #include 38 | 39 | int shmctl(int shmid, int cmd, struct shmid_ds *buf); 40 | ``` 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/shm/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CXX = g++ 3 | 4 | PRJ_PATH = ../.. 5 | 6 | C_FLAGS = -W 7 | C_FLAGS += -O2 8 | C_FLAGS += -fno-strict-aliasing 9 | C_FLAGS += -Wall 10 | C_FLAGS += -Wno-unused 11 | C_FLAGS += -Wno-missing-field-initializers 12 | C_FLAGS += -Wno-missing-braces 13 | C_FLAGS += -g 14 | C_FLAGS += -z 15 | C_FLAGS += -fPIC 16 | 17 | INC = -I../ 18 | LIB = -lz -lrt -lpthread 19 | 20 | SOURCE = $(wildcard *.cpp) 21 | OBJS = $(patsubst %.cpp,%.o,$(SOURCE)) 22 | 23 | OUTPUT := $(PRJ_PATH)/lib/libshm.a 24 | 25 | all: $(OUTPUT) 26 | 27 | .SUFFIXES: .o .cpp 28 | 29 | $(OUTPUT):$(OBJS) 30 | ar -rs $@ $(EX_LIB) $^ 31 | cp *.h $(PRJ_PATH)/include 32 | 33 | .cpp.o: 34 | g++ $(C_FLAGS) $(LIB) $(INC) -c $^ -o $(patsubst %.cpp,%.o,$^) 35 | 36 | clean: 37 | rm -f $(OBJS) 38 | -------------------------------------------------------------------------------- /src/antisnow/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CXX = g++ 3 | 4 | PRJ_PATH = ../.. 5 | 6 | C_FLAGS = -W 7 | C_FLAGS += -O2 8 | C_FLAGS += -fno-strict-aliasing 9 | C_FLAGS += -Wall 10 | C_FLAGS += -Wno-unused 11 | C_FLAGS += -Wno-missing-field-initializers 12 | C_FLAGS += -Wno-missing-braces 13 | C_FLAGS += -g 14 | C_FLAGS += -z 15 | C_FLAGS += -fPIC 16 | 17 | INC = -I../ 18 | INC += -I$(PRJ_PATH)/include/ 19 | LIB = -lz -lrt -lpthread 20 | LIB += -L$(PRJ_PATH)/lib/ -lshm 21 | 22 | SOURCE = $(wildcard *.cpp) 23 | OBJS = $(patsubst %.cpp,%.o,$(SOURCE)) 24 | 25 | OUTPUT := $(PRJ_PATH)/lib/libantisnow.a 26 | 27 | all: $(OUTPUT) 28 | 29 | .SUFFIXES: .o .cpp 30 | 31 | $(OUTPUT):$(OBJS) 32 | ar -rs $@ $(EX_LIB) $^ 33 | cp *.h $(PRJ_PATH)/include 34 | 35 | .cpp.o: 36 | g++ $(C_FLAGS) $(LIB) $(INC) -c $^ -o $(patsubst %.cpp,%.o,$^) 37 | 38 | clean: 39 | rm -f $(OBJS) 40 | -------------------------------------------------------------------------------- /src/monitor/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CXX = g++ 3 | 4 | PRJ_PATH = ../.. 5 | 6 | C_FLAGS = -W 7 | C_FLAGS += -O2 8 | C_FLAGS += -fno-strict-aliasing 9 | C_FLAGS += -Wall 10 | C_FLAGS += -Wno-unused 11 | C_FLAGS += -Wno-missing-field-initializers 12 | C_FLAGS += -Wno-missing-braces 13 | C_FLAGS += -g 14 | C_FLAGS += -z 15 | C_FLAGS += -fPIC 16 | 17 | INC = -I../ 18 | INC += -I$(PRJ_PATH)/include/ 19 | LIB = -lz -lrt -lpthread 20 | LIB += -L$(PRJ_PATH)/lib/ -lshm 21 | 22 | SOURCE = $(wildcard *.cpp) 23 | OBJS = $(patsubst %.cpp,%.o,$(SOURCE)) 24 | 25 | OUTPUT := $(PRJ_PATH)/lib/libmonitor.a 26 | 27 | all: $(OUTPUT) 28 | 29 | .SUFFIXES: .o .cpp 30 | 31 | $(OUTPUT):$(OBJS) 32 | ar -rs $@ $(EX_LIB) $^ 33 | cp *.h $(PRJ_PATH)/include 34 | 35 | .cpp.o: 36 | g++ $(C_FLAGS) $(LIB) $(INC) -c $^ -o $(patsubst %.cpp,%.o,$^) 37 | 38 | clean: 39 | rm -f $(OBJS) 40 | -------------------------------------------------------------------------------- /test/shm/readwrite/readme.md: -------------------------------------------------------------------------------- 1 | 2 | 当我们调整共享内存的大小之后, 发现运行失败了. 这时需要自己先手动删除 3 | 4 | ``` 5 | tiankonguse:readwrite $ ./write 6 | key=50462721 7 | iShmID = 7766027 8 | tiankonguse:readwrite $ ./read 9 | key=50462721 10 | iShmID = 7766027 11 | i=0 sec=1441278904 usec=644289 12 | i=1 sec=1441278904 usec=644299 13 | i=2 sec=1441278904 usec=644299 14 | 15 | tiankonguse:readwrite $ make -B 16 | g++ -o read read.cpp -I../../../include/ -L../../../lib/ -static -lshm -pthread 17 | g++ -o write write.cpp -I../../../include/ -L../../../lib/ -static -lshm -pthread 18 | tiankonguse:readwrite $ ./write 19 | key=50462721 20 | getShm error. err=shmget error. ret=22 21 | 22 | tiankonguse:readwrite $ ipcs -m | grep 7766027 23 | 0x03020001 7766027 tiankongus 666 24 0 24 | tiankonguse:readwrite $ ipcrm -m 7766027 25 | tiankonguse:readwrite $ ./write 26 | key=50462721 27 | iShmID = 7798795 28 | tiankonguse:readwrite $ ./read 29 | key=50462721 30 | iShmID = 7798795 31 | i=0 sec=1441279262 usec=344124 32 | i=1 sec=1441279263 usec=344291 33 | i=2 sec=1441279264 usec=34438 34 | ``` 35 | -------------------------------------------------------------------------------- /test/shm/readwrite/read.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * read.cpp 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "shm.h" 15 | #include "comm.h" 16 | 17 | int main(int argc, char** argv) { 18 | sleep(1); 19 | int key = generatesKey(); 20 | int size = sizeof(Time) * TIME_NUM; 21 | 22 | SHM_CACHE::Shm shm; 23 | shm.init(key, size); 24 | 25 | int iShmID = shm.getShmId(IPC_CREAT | 0666); 26 | if (iShmID == 0) { 27 | printf("getShm error. err=%s\n", shm.getLastError()); 28 | return -1; 29 | } 30 | printf("iShmID = %d\n", iShmID); 31 | 32 | Time *p_time; 33 | p_time = (Time *) shm.getAdr(); 34 | if (NULL == p_time) { 35 | printf("getAdr error. err=%s\n", shm.getLastError()); 36 | return -1; 37 | } 38 | 39 | for (int i = 0; i < TIME_NUM; i++) { 40 | printf("i=%d sec=%lld usec=%lld val=%lld\n", i, (p_time + i)->sec, 41 | (p_time + i)->usec, (p_time + i)->val); 42 | } 43 | 44 | shm.delShm(); 45 | 46 | return 0; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /test/antisnow/test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fork.cpp 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "shm.h" 14 | #include "antisnow.h" 15 | 16 | void test(SHM_CACHE::AntiSnow& antiSnow) { 17 | 18 | int n = 10000000 * 10; 19 | int N = 1000000; 20 | int ret = antiSnow.report(1, 1); 21 | if (ret < 0) { 22 | printf("ret=%d errormsg=%s\n", ret, antiSnow.getLastError().c_str()); 23 | return; 24 | } 25 | for (int i = 0; i < n; i++) { 26 | int ret = antiSnow.report(1, 1); 27 | if (i % N == 0) { 28 | printf("time=%d getpid=%d ret=%d \n", (int) time(NULL), 29 | (int) getpid(), ret); 30 | } 31 | } 32 | 33 | } 34 | 35 | int main() { 36 | 37 | SHM_CACHE::AntiSnow antiSnow; 38 | 39 | int pid; 40 | pid = fork(); 41 | 42 | if (pid == 0) { 43 | test(antiSnow); 44 | return 0; 45 | 46 | } else if (pid > 0) { 47 | test(antiSnow); 48 | } else { 49 | printf("fork error\n"); 50 | } 51 | 52 | return 0; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /test/shm/readwrite/write.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * write.cpp 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "shm.h" 17 | #include "comm.h" 18 | 19 | int main(int argc, char** argv) { 20 | 21 | int key = generatesKey(); 22 | int size = sizeof(Time) * TIME_NUM; 23 | 24 | SHM_CACHE::Shm shm; 25 | shm.init(key, size); 26 | 27 | int iShmID = shm.getShmId(IPC_CREAT | 0666); 28 | if (iShmID == 0) { 29 | printf("getShm error. err=%s\n", shm.getLastError()); 30 | return -1; 31 | } 32 | printf("iShmID = %d\n", iShmID); 33 | 34 | Time *p_time; 35 | p_time = (Time *) shm.getAdr(); 36 | if (NULL == p_time) { 37 | printf("getAdr error. err=%s\n", shm.getLastError()); 38 | return -1; 39 | } 40 | srand(time(NULL)); 41 | for (int i = 0; i < TIME_NUM; i++) { 42 | struct timeval start; 43 | gettimeofday(&start, NULL); 44 | (p_time + i)->sec = start.tv_sec; 45 | (p_time + i)->usec = start.tv_usec; 46 | (p_time + i)->val = rand() % 100; 47 | } 48 | 49 | return 0; 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /include/antisnow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * antisnow.h 3 | * 4 | * Created on: 2016-9-17 5 | * Author: tiankonguse 6 | */ 7 | 8 | #ifndef ANTISNOW_H_ 9 | #define ANTISNOW_H_ 10 | 11 | #include "shm.h" 12 | #include 13 | 14 | namespace SHM_CACHE { 15 | 16 | const int ANTISNOW_SHM_ID = 456719; 17 | const int MAX_ANTISNOW_NODE = 100; 18 | 19 | class AntiSnow { 20 | typedef struct AntiSnowNode { 21 | unsigned int iNum; 22 | unsigned int iMax; 23 | unsigned int iTime; 24 | AntiSnowNode() { 25 | iNum = 0; 26 | iMax = 0; 27 | iTime = 0; 28 | } 29 | } AntiSnowNode; 30 | 31 | int iErrorNo; 32 | int iAntiSnowShmSize; 33 | AntiSnowNode *pstNode; 34 | Shm shm; 35 | std::string strLastError; 36 | char lastErrorBuf[LAST_ERROR_SIZE]; 37 | 38 | public: 39 | 40 | AntiSnow(); 41 | 42 | /* 43 | * 上报数值, 为 iKey 加上 iValue. 44 | */ 45 | int report(int iKey, int iValue); 46 | 47 | int getErrorNo() { 48 | return iErrorNo; 49 | } 50 | 51 | std::string getLastError() { 52 | return strLastError; 53 | } 54 | }; 55 | 56 | } 57 | 58 | #endif /* ANTISNOW_H_ */ 59 | -------------------------------------------------------------------------------- /src/antisnow/antisnow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * antisnow.h 3 | * 4 | * Created on: 2016-9-17 5 | * Author: tiankonguse 6 | */ 7 | 8 | #ifndef ANTISNOW_H_ 9 | #define ANTISNOW_H_ 10 | 11 | #include "shm.h" 12 | #include 13 | 14 | namespace SHM_CACHE { 15 | 16 | const int ANTISNOW_SHM_ID = 456719; 17 | const int MAX_ANTISNOW_NODE = 100; 18 | 19 | class AntiSnow { 20 | typedef struct AntiSnowNode { 21 | unsigned int iNum; 22 | unsigned int iLock; 23 | unsigned int iTime; 24 | AntiSnowNode() { 25 | iNum = 0; 26 | iLock = 0; 27 | iTime = 0; 28 | } 29 | } AntiSnowNode; 30 | 31 | int iErrorNo; 32 | int iAntiSnowShmSize; 33 | AntiSnowNode *pstNode; 34 | Shm shm; 35 | std::string strLastError; 36 | char lastErrorBuf[LAST_ERROR_SIZE]; 37 | 38 | public: 39 | 40 | AntiSnow(); 41 | 42 | /* 43 | * 上报数值, 为 iKey 加上 iValue. 44 | */ 45 | int report(int iKey, int iValue); 46 | 47 | int getErrorNo() { 48 | return iErrorNo; 49 | } 50 | 51 | std::string getLastError() { 52 | return strLastError; 53 | } 54 | }; 55 | 56 | } 57 | 58 | #endif /* ANTISNOW_H_ */ 59 | -------------------------------------------------------------------------------- /src/cache/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cache.h 3 | * 4 | * Created on: 2015-9-5 5 | * Author: tiankonguse 6 | */ 7 | 8 | #ifndef CACHE_H_ 9 | #define CACHE_H_ 10 | 11 | #include 12 | 13 | #include "shm.h" 14 | #include "hash.h" 15 | 16 | namespace SHM_CACHE { 17 | 18 | #define MAX_KEY_LEN 128 19 | #define MAX_VALUE_LEN 1024 20 | #pragma pack(1) 21 | typedef struct { 22 | char cTimeOutFlag; 23 | uint8_t cKeyLen; 24 | uint32_t dwValueLen; 25 | uint32_t dwAccessTime; 26 | char cKey[0]; 27 | char sData[0]; 28 | } Node; 29 | #pragma Node() 30 | 31 | class Cache { 32 | Node* _node; 33 | //hash 函数操作类 34 | Hash _hash; 35 | 36 | //共享内存操作类 37 | Shm _shm; 38 | 39 | //超时时间 40 | int iTimeOut; 41 | int maxKeyLen; 42 | int maxValueLen; 43 | int iNodeSize; 44 | private: 45 | uint32_t HashKey(const char *sKey, int iSize); 46 | 47 | uint32_t fCompare(const void *, int, const void *); 48 | uint32_t fElinemate(const void *pKey, int ikeyLen, const void *pNode, 49 | uint32_t iTimeOut); 50 | public: 51 | Cache(); 52 | Cache::~Cache(); 53 | /* 54 | * 初始化, 指定共享内存的key, hash的bucket大小,以及cache超时时间 55 | */ 56 | int init(int _iKey, int _bucket, int _iTimeOut); 57 | 58 | int getCache(const std::string &strKey, std::string &strValue); 59 | 60 | int setCache(const std::string &strKey, const std::string &strValue); 61 | 62 | int delCache(const std::string &strKey); 63 | }; 64 | } 65 | 66 | #endif /* CACHE_H_ */ 67 | -------------------------------------------------------------------------------- /src/antisnow/antisnow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * antisnow.cpp 3 | * 4 | * Created on: 2016-9-17 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include "antisnow.h" 9 | #include "minSpinLock.h" 10 | 11 | namespace SHM_CACHE { 12 | 13 | AntiSnow::AntiSnow() { 14 | pstNode = NULL; 15 | iErrorNo = 0; 16 | iAntiSnowShmSize = sizeof(AntiSnowNode) * MAX_ANTISNOW_NODE; 17 | shm.init(ANTISNOW_SHM_ID, iAntiSnowShmSize); 18 | } 19 | 20 | int AntiSnow::report(int iPos, int iValue) { 21 | 22 | if (unlikely(iPos >= MAX_ANTISNOW_NODE)) { 23 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 24 | "iPos=[%d]>=MAX_ANTISNOW_NODE[%d] pos too max", iPos, 25 | MAX_ANTISNOW_NODE); 26 | strLastError = lastErrorBuf; 27 | return -__LINE__; 28 | } 29 | 30 | //第一次创建 31 | if (unlikely(pstNode == NULL)) { 32 | iErrorNo = shm.getShmInit((void**) &pstNode, 0666 | IPC_CREAT); 33 | if (iErrorNo < 0) { 34 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), "ret=[%d] msg[%s]", 35 | iErrorNo, shm.getLastError()); 36 | strLastError = lastErrorBuf; 37 | return -__LINE__; 38 | } 39 | iErrorNo = 0; 40 | } 41 | 42 | int retNum = 0; 43 | unsigned int iTime = time(NULL); 44 | MINLOCK(pstNode[iPos].iLock); 45 | if (pstNode[iPos].iTime < iTime) { 46 | pstNode[iPos].iTime = iTime; 47 | pstNode[iPos].iNum = iValue; 48 | } else { 49 | pstNode[iPos].iNum += iValue; 50 | } 51 | retNum = pstNode[iPos].iNum; 52 | MINUNLOCK(pstNode[iPos].iLock); 53 | return retNum; 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/list/list.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: list.h 3 | > Desc: c++ doubly linked list 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2016年06月25日 7 | ***********************************************************************/ 8 | 9 | #ifndef _LIST_H_ 10 | #define _LIST_H_ 11 | 12 | struct List{ 13 | struct List *prev; 14 | struct List *next; 15 | 16 | List(){ 17 | Init(); 18 | }; 19 | 20 | ~List() { 21 | Remove(); 22 | }; 23 | 24 | void Init(){ 25 | next = this; 26 | prev = this; 27 | } 28 | 29 | static void Add(struct List *n, struct List *prev, struct List *next){ 30 | next->prev = n; 31 | n->next = next; 32 | n->prev = prev; 33 | prev->next = n; 34 | } 35 | 36 | static void Remove(struct List *prev, struct List *next){ 37 | next->prev = prev; 38 | prev->next = next; 39 | } 40 | 41 | void AddTail(struct List *head){ 42 | Add(this, head->prev, head); 43 | } 44 | 45 | void Add(struct List *head){ 46 | Add(this, head, head->next); 47 | } 48 | 49 | void Remove(){ 50 | Remove(prev, next); 51 | Init(); 52 | } 53 | 54 | void Reset(){ 55 | Init(); 56 | } 57 | 58 | bool IsEmpty(){ 59 | return next == this && prev == this; 60 | } 61 | private: 62 | struct List & operator= (const struct List &a); 63 | }; 64 | 65 | 66 | #endif -------------------------------------------------------------------------------- /src/monitor/monitor.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: monitor.h 3 | > Desc: 统计监听库 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2016年06月19日 星期日 21时54分18秒 7 | ***********************************************************************/ 8 | 9 | #ifndef _MONITOR_H_ 10 | #define _MONITOR_H_ 11 | 12 | #include "shm.h" 13 | #include 14 | 15 | namespace SHM_CACHE { 16 | 17 | const int MONITOR_SHM_ID = 45678; 18 | const int MAX_MONITOR_NODE = 21000; 19 | 20 | class Monitor { 21 | typedef struct { 22 | int iUse; 23 | int iKey; 24 | int iValue; 25 | } MonitorNode; 26 | 27 | int iErrorNo; 28 | int iMonitorShmSize; 29 | MonitorNode *pstNode; 30 | Shm shm; 31 | std::string strLastError; 32 | 33 | private: 34 | 35 | /* 36 | * 查找位置. 37 | * 0 未找到, iPos 为第一个未使用的位置 38 | * 1 找到, iPos 为找到的位置 39 | * -1 空间不足 40 | */ 41 | int find(int iKey, int& iPos); 42 | 43 | public: 44 | 45 | Monitor(); 46 | 47 | /* 48 | * 上报数值, 为 iKey 加上 iValue. 49 | */ 50 | int report(int iKey, int iValue); 51 | 52 | int getErrorNo() { 53 | return iErrorNo; 54 | } 55 | 56 | std::string getLastError() { 57 | return strLastError; 58 | } 59 | }; 60 | 61 | } 62 | ; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /test/shm/fork/fork.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fork.cpp 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "shm.h" 14 | 15 | #define SIZE 1024 16 | 17 | int main() { 18 | 19 | SHM_CACHE::Shm shm; 20 | 21 | shm.init(IPC_PRIVATE, SIZE); 22 | 23 | int iShmID = shm.getShmId(IPC_CREAT | 0666); 24 | if (iShmID == 0) { 25 | printf("getShm error. err=%s\n", shm.getLastError()); 26 | return -1; 27 | } 28 | printf("iShmID = %d\n", iShmID); 29 | 30 | int pid; 31 | pid = fork(); 32 | 33 | if (pid == 0) { 34 | char *shmaddr = shm.getAdr(); 35 | if (NULL == shmaddr) { 36 | printf("getAdr error. err=%s\n", shm.getLastError()); 37 | return -1; 38 | } 39 | 40 | snprintf(shmaddr, SIZE, "this is parent, but will print in child !"); 41 | 42 | printf("father end\n"); 43 | return 0; 44 | 45 | } else if (pid > 0) { 46 | sleep(3); 47 | char *shmaddr = shm.getAdr(); 48 | if (NULL == shmaddr) { 49 | printf("getAdr error. err=%s\n", shm.getLastError()); 50 | return -1; 51 | } 52 | 53 | printf("%s\n", shmaddr); 54 | printf("child end\n"); 55 | shm.delShm(); 56 | } else { 57 | printf("fork error\n"); 58 | shm.delShm(); 59 | } 60 | 61 | return 0; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/monitor/monitor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * monitor.cpp 3 | * 4 | * Created on: 2016-6-19 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include "monitor.h" 9 | 10 | namespace SHM_CACHE { 11 | 12 | Monitor::Monitor(){ 13 | pstNode = NULL; 14 | iErrorNo = 0; 15 | iMonitorShmSize = sizeof(MonitorNode)*MAX_MONITOR_NODE; 16 | shm.init(MONITOR_SHM_ID, iMonitorShmSize); 17 | } 18 | 19 | int Monitor::find(int iKey, int& iPos){ 20 | iPos = 0; 21 | while(pstNode[iPos].iUse){ 22 | if(pstNode[iPos].iKey == iKey){ 23 | return 1; 24 | } 25 | ++iPos; 26 | if(iPos >= MAX_MONITOR_NODE){ 27 | iPos = 0; 28 | return -1; 29 | } 30 | } 31 | return 0; 32 | } 33 | 34 | int Monitor::report(int iKey, int iValue){ 35 | int iPos; 36 | 37 | //第一次创建 38 | if(pstNode == NULL){ 39 | iErrorNo = shm.getShmInit((void**)&pstNode, 0666); 40 | if(iErrorNo < 0){ 41 | strLastError = shm.getLastError(); 42 | return iErrorNo; 43 | } 44 | iErrorNo = 0; 45 | } 46 | 47 | iErrorNo = find(iKey, iPos); 48 | if(iErrorNo == 0){ 49 | pstNode[iPos].iUse = 1; 50 | pstNode[iPos].iKey = iKey; 51 | pstNode[iPos].iValue = iValue; 52 | }else if(iErrorNo < 0){ 53 | strLastError = "no space"; 54 | return -1; 55 | }else{ 56 | pstNode[iPos].iValue += iValue; 57 | } 58 | 59 | return 0; 60 | 61 | } 62 | 63 | 64 | }; 65 | -------------------------------------------------------------------------------- /src/hash/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hash.h 3 | * 4 | * Created on: 2015-9-5 5 | * Author: tiankonguse 6 | * desc: 第一个版本, 不考虑冲突问题 7 | */ 8 | 9 | #ifndef HASH_H_ 10 | #define HASH_H_ 11 | 12 | #include 13 | #include 14 | 15 | namespace SHM_CACHE { 16 | 17 | const uint32_t MAX_BUCKET = 2048; 18 | typedef uint32_t (*FCompare)(const void *, int ikeyLen, const void *); 19 | typedef uint32_t (*FElinemate)(const void *pKey, int ikeyLen, const void *pNode, 20 | uint32_t iTimeOut); 21 | 22 | typedef struct HashInfo { 23 | uint32_t uBucket; //实际的bucket大小 24 | uint32_t uShmSize; //申请内存的总大小 25 | uint32_t uNodeSize; //一个节点的大小 26 | char pHash[0]; //代表节点内存的起始位置 27 | } HashInfo; 28 | 29 | class Hash { 30 | HashInfo* shmHashInfo; 31 | HashInfo localHashInfo; 32 | const uint32_t maxBucket; 33 | FCompare _fCompare; 34 | FElinemate _fElinemate; 35 | uint32_t _inited; 36 | public: 37 | 38 | Hash(const uint32_t maxBucket = MAX_BUCKET); 39 | 40 | /* 41 | * 使用者传入预计bucket大小, 一个节点的大小, 42 | * 返回一个需要申请的内存大小 43 | * 返回0 代表参数非法,或者节点过大 44 | */ 45 | int EvalHashSize(uint32_t uSize, const uint32_t uNodeSize); 46 | 47 | /* 48 | * 传入内存起始地址, 比较函数, 淘汰函数来初始化hash 49 | * 初始化前会比较内存是第一次使用, 还是复用 50 | * 第一次使用需要初始化, 复用需要检查配置是否一致 51 | */ 52 | int init(void* pHash, FCompare fCompare, FElinemate fElinemate); 53 | 54 | /* 55 | * 传入key的字符串,key的长度 56 | * 返回值会付给node指针 57 | */ 58 | int Hash::get(const void *pKey, uint32_t uKeyLen, void *&pNode); 59 | 60 | /* 61 | * 传入key的字符串,key的长度, 以及超时时间 62 | * 搜索到的空节点和淘汰都会放在pNode节点中 63 | */ 64 | int getAll(const void *pKey, uint32_t uKeyLen, void *&pNode, int iTimeOut); 65 | 66 | private: 67 | 68 | /* 69 | * 根据传入的bucket, 计算出一个合适的bucket 70 | * 目前算法: 找到大于等于uSize的第一个素数 71 | */ 72 | void calcPrime(uint32_t uSize, uint32_t& uBucket); 73 | 74 | uint32_t hash(uint32_t uHashKey); 75 | 76 | uint32_t hash(const char *sKey, int iSize); 77 | 78 | }; 79 | 80 | } 81 | 82 | #endif /* HASH_H_ */ 83 | -------------------------------------------------------------------------------- /src/linktable/LinkTable.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: LinkTable.h 4 | 5 | DESCRIPTION: 数组索引+链表方式内存结构接口声明 6 | 7 | LinkTable的数据结构: 8 | IndexHeadList -- 一级索引表,也是主索引表,通过主索引Index(或者叫Unit)可以索引到二级索引表的起始位置 9 | IndexNodeList -- 二级索引表,也是次索引表,以主索引和次索引Offset共同索引Key(UIN)在ElementList中的下标 10 | ElementList -- 元素数组 11 | 12 | 注意: 13 | LinkTable有两类Index 14 | 1, 外部看到的Index,就是UDC的UnitID,从0开始,记为dwIndex 15 | 2, 内部看到的Index=UnitID+1,写作idx,或者IndexID 16 | 所有API的Index参数都是外部Index,也就是UnitID 17 | 18 | 19 | ******************************************************************************/ 20 | 21 | #ifndef _LINK_TABLE_H_ 22 | #define _LINK_TABLE_H_ 23 | 24 | //初始化链式表 25 | //返回LinkTable的句柄 26 | int LtInit(uint32_t dwIndexCount, uint64_t ddwIndexRowCount, 27 | uint64_t ddwElementCount, uint64_t ddwElementSize, int iKey, 28 | int iCreateFlag, int nodisplay); 29 | 30 | // 如果主索引表为空,则将LinkTable的IndexHeadList初始化为相应的IndexList 31 | // 否则,比较IndexHeadList和IndexList,如果不相对应则返回失败 32 | // dwIndexList必须是已经排好序的 33 | // 成功返回0,否则返回负数 34 | int LtSetIndexes(int lt, uint32_t dwIndexList[], int iIndexNum); 35 | 36 | // 判断初始化的时候是不是调用了LtSetIndexes()来设置UnitId 37 | // 如果是,则不允许增加或删除UnitId, 函数返回 1,否则返回0 38 | int LtIsIndexesLocked(int lt); 39 | 40 | //取得用户数据 41 | int LtGetData(int lt, uint64_t ddwKey, char *sDataBuf, int *piDataLen); 42 | 43 | //打印用户数据的链表指针 44 | int LtPrintData(int lt, uint64_t ddwKey); 45 | 46 | //设置数据,如果存在删除已有数据 47 | int LtSetData(int lt, uint64_t ddwKey, char *sDataBuf, int iDataLen); 48 | 49 | //删除指定索引下的所有数据包括索引定义 50 | int LtClearIndexData(int lt, uint32_t dwIndex); 51 | 52 | //清除某个Key对应的数据 53 | int LtClearKeyData(int lt, uint64_t ddwKey); 54 | 55 | // 允许用户改变预回收池的大小,sz必须在1到LT_MAX_PREFREE_POOL_SIZE之间 56 | int LtSetPrefreePoolSize(int lt, int sz); 57 | 58 | int LtGetHeaderData(int lt, void *pBuff, int iSize); 59 | int LtSetHeaderData(int lt, const void *pData, int iLen); 60 | 61 | int LtGetIndexData(int lt, uint32_t dwIndex, void *pBuff, int iSize); 62 | int LtSetIndexData(int lt, uint32_t dwIndex, const void *pData, int iLen); 63 | 64 | //释放头部 65 | int LtRemoveIndex(int lt, uint32_t dwIndex); 66 | int LtPrintInfo(int lt); 67 | int LtPrintElements(int lt); 68 | 69 | //关闭链式表共享内存 70 | int LtClose(int lt); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/shm/shm.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: shm.h 3 | > Desc: 面向对象共享内存库(非进程安全,由上层业务保证) 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2015年09月03日 星期四 17时14分18秒 7 | ***********************************************************************/ 8 | 9 | #ifndef _SHM_H_ 10 | #define _SHM_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef likely 20 | #define likely(x) __builtin_expect( (x), 1) 21 | #define unlikely(x) __builtin_expect( (x), 0) 22 | #endif 23 | 24 | namespace SHM_CACHE { 25 | 26 | const int LAST_ERROR_SIZE = 128; 27 | 28 | class Shm { 29 | int iShmID; 30 | int iKey; 31 | int iSize; 32 | char lastErrorBuf[LAST_ERROR_SIZE]; 33 | 34 | public: 35 | 36 | Shm(); 37 | 38 | /* 39 | * 初始化key和内存大小 40 | */ 41 | void init(int iKey, int iSize); 42 | 43 | /* 44 | * @desc 基础操作: 根据iKey, 查询或创建iSize大小的共享内存 45 | * 46 | * @return iShmID 47 | */ 48 | int getShmId(int iFlag); 49 | 50 | /* 51 | * @desc 基础操作: 根据iShmID, 映射到进程内地址 52 | * 53 | * @return 映射到进程内的地址 54 | */ 55 | char* getAdr(); 56 | 57 | /* 58 | * @desc 根据iKey, 查询或创建iSize大小的共享内存 59 | * 60 | * @param iFlag 标志位,常用标志位是 (0666 | IPC_CREAT) 61 | * 62 | * @return 返回共享内存的指针,失败时返回 NULL 63 | */ 64 | char* getShm(int iFlag); 65 | 66 | /* 67 | * @desc 根据iShmID, 查询或创建iSize大小的共享内存, 第一次创建时初始化内存 68 | * 69 | * @param pstShm 返回的共享内存指针, 失败时未定义 70 | * @param iFlag 标志位,常用标志位是 (0666 | IPC_CREAT) 71 | * 72 | * @return 失败时返回负数. 73 | * 0 已存在, 查询成功 74 | * 1 创建成功 75 | * -1 共享内存不存在, flag没有 IPC_CREAT 标示位 76 | * -2 共享内存不一致或者不存在, 但是创建失败 77 | * 78 | */ 79 | int getShmInit(void * &pstShm, int iFlag); 80 | int getShmInit(void ** ppstShm, int iFlag); 81 | 82 | /* 83 | * 得到共享内存大小 84 | */ 85 | int getShmSize(); 86 | 87 | /* 88 | * @desc 根据iKey, 得到共享内存, 并检查Size大小 89 | * 如果 piSize 是0, 则赋值 90 | * 91 | * @return 返回共享内存的指针,失败时返回 NULL 92 | */ 93 | char* getShmNoCreateAndCheck(int iFlag, int *piSize); 94 | 95 | /* 96 | * @desc 根据shkey删除指定的共享内存 97 | * 98 | * @param shkey 我们分配的共享内存的唯一标识 99 | * 100 | * @return 成功返回0, 失败返回非0 101 | */ 102 | int delShm(); 103 | 104 | char* getLastError() { 105 | return lastErrorBuf; 106 | } 107 | }; 108 | 109 | } 110 | #endif 111 | 112 | -------------------------------------------------------------------------------- /src/MultiHashTable/shm_adapter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //共享内存类 10 | class shm_adapter { 11 | public: 12 | /* 13 | * 默认构造函数 14 | * 需要使用create/open函数创建或打开共享内存 15 | */ 16 | shm_adapter(); 17 | 18 | /* 19 | * 构造函数 20 | * 需要使用is_valid函数判断是否成功 21 | * 注: bLock锁住内存, 只有root用户可以使用 22 | */ 23 | shm_adapter(uint64_t ddwShmKey, uint64_t ddwShmSize, bool bCreate = true, 24 | bool bReadOnly = false, bool bLock = true, bool bHugePage = false, 25 | bool bInitClear = true); 26 | 27 | /* 28 | * 析构函数 29 | */ 30 | ~shm_adapter(); 31 | 32 | /* 33 | * 判断初始化是否成功 34 | */ 35 | bool is_valid() { 36 | return m_bIsValid; 37 | } 38 | 39 | /* 40 | * 获取创建/连接的共享内存 41 | */ 42 | void *get_shm() { 43 | return m_pShm; 44 | } 45 | 46 | /* 47 | * 刷新共享内存 48 | * 注: 调用该函数会使用shmdt, 反复调用会影响性能 49 | * 如果共享内存不会在程序运行期间被另外的程序重新创建/修改大小, 则不需要调用该函数 50 | */ 51 | bool refresh(); 52 | 53 | /* 54 | * 取出失败信息 55 | */ 56 | const std::string &get_err_msg() { 57 | return m_strErrMsg; 58 | } 59 | 60 | /* 61 | * 打开存在的共享内存 62 | */ 63 | bool open(uint64_t ddwShmKey, bool bReadOnly = false); 64 | 65 | /* 66 | * 只读打开存在的共享内存 67 | */ 68 | bool open_readonly(uint64_t ddwShmKey) { 69 | return open(ddwShmKey, true); 70 | } 71 | 72 | /* 73 | * 创建共享内存 74 | */ 75 | bool create(uint64_t ddwShmKey, uint64_t ddwShmSize, bool bHugePage = false, 76 | bool bInitClear = true); 77 | 78 | /* 79 | * 使用大页创建共享内存 80 | */ 81 | bool create_hugepage(uint64_t ddwShmKey, uint64_t ddwShmSize, 82 | bool bInitClear = true) { 83 | return create(ddwShmKey, ddwShmSize, true, bInitClear); 84 | } 85 | 86 | /* 87 | * 获取共享内存的大小 88 | */ 89 | uint64_t get_size() { 90 | return m_ddwShmSize; 91 | } 92 | 93 | /* 94 | * 获取共享内存的Key 95 | */ 96 | uint64_t get_key() { 97 | return m_ddwShmKey; 98 | } 99 | 100 | /* 101 | * 判断是否为新的共享内存 102 | */ 103 | bool is_new() { 104 | return m_bIsNewShm; 105 | } 106 | 107 | /* 108 | * 关闭共享内存 109 | */ 110 | bool close(); 111 | 112 | private: 113 | 114 | public: 115 | 116 | private: 117 | 118 | bool m_bIsNewShm; //是否是新创建的共享内存 119 | 120 | uint64_t m_ddwShmKey; //共享内存的Key 121 | uint64_t m_ddwShmSize; //共享内存的大小 122 | int m_nShmId; //共享内存的ID 123 | 124 | bool m_bIsValid; //共享内存是否可用 125 | 126 | void *m_pShm; //共享内存的指针 127 | 128 | std::string m_strErrMsg; //错误信息 129 | }; 130 | -------------------------------------------------------------------------------- /src/list/list_head.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: list_head.h 3 | > Desc: wrap dobly linked list 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2016年06月25日 7 | ***********************************************************************/ 8 | 9 | #include "doubly_linked_list.h" 10 | 11 | #ifndef _LIST_HEAD_H_ 12 | #define _LIST_HEAD_H_ 13 | 14 | 15 | class CListHead{ 16 | public: 17 | struct list_head objlist; 18 | 19 | void InitList(void) { 20 | INIT_LIST_HEAD(&objlist); 21 | } 22 | void ResetList(void) { 23 | list_del_init(&objlist); 24 | } 25 | int ListEmpty(void) const { 26 | return list_empty(&objlist); 27 | } 28 | CListHead *ListNext(void) { 29 | return list_entry(objlist.next, CListHead, objlist); 30 | } 31 | CListHead *ListPrev(void) { 32 | return list_entry(objlist.prev, CListHead, objlist); 33 | } 34 | 35 | void ListAdd(CListHead &n) { 36 | list_add(&objlist, &n.objlist); 37 | } 38 | void ListAdd(CListHead *n) { 39 | list_add(&objlist, &n->objlist); 40 | } 41 | void ListAddTail(CListHead &n) { 42 | list_add_tail(&objlist, &n.objlist); 43 | } 44 | void ListAddTail(CListHead *n) { 45 | list_add_tail(&objlist, &n->objlist); 46 | } 47 | void ListDel(void) { 48 | ResetList(); 49 | } 50 | void ListMove(CListHead &n) { 51 | list_move(&objlist, &n.objlist); 52 | } 53 | void ListMove(CListHead *n) { 54 | list_move(&objlist, &n->objlist); 55 | } 56 | void ListMoveTail(CListHead &n) { 57 | list_move_tail(&objlist, &n.objlist); 58 | } 59 | void ListMoveTail(CListHead *n) { 60 | list_move_tail(&objlist, &n->objlist); 61 | } 62 | void FreeList(void) { 63 | while (!ListEmpty()){ 64 | ListNext()->ResetList(); 65 | } 66 | } 67 | }; 68 | 69 | 70 | template 71 | class CListObject: public CListHead{ 72 | public: 73 | CListObject(void) { 74 | InitList(); 75 | } 76 | ~CListObject(void) { 77 | ResetList(); 78 | } 79 | CListObject *ListNext(void) { 80 | return (CListObject*)CListHead::ListNext(); 81 | } 82 | CListObject *ListPrev(void) { 83 | return (CListObject*)CListHead::ListPrev(); 84 | } 85 | // T *ListOwner(void) { return static_cast(this); } 86 | T *ListOwner(void) { 87 | return (T *)this; 88 | } 89 | T *NextOwner(void) { 90 | return ListNext()->ListOwner(); 91 | } 92 | T *PrevOwner(void) { 93 | return ListPrev()->ListOwner(); 94 | } 95 | }; 96 | 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /include/shm.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: shm.h 3 | > Desc: 面向对象共享内存库(非进程安全,由上层业务保证) 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2015年09月03日 星期四 17时14分18秒 7 | ***********************************************************************/ 8 | 9 | #ifndef _SHM_H_ 10 | #define _SHM_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace SHM_CACHE { 20 | 21 | const int LAST_ERROR_SIZE = 128; 22 | 23 | class Shm { 24 | int iShmID; 25 | int iKey; 26 | int iSize; 27 | char lastErrorBuf[LAST_ERROR_SIZE]; 28 | 29 | public: 30 | 31 | Shm(); 32 | 33 | /* 34 | * 初始化key和内存大小 35 | */ 36 | void init(int iKey, int iSize); 37 | 38 | /* 39 | * @desc 基础操作: 根据iKey, 查询或创建iSize大小的共享内存 40 | * 41 | * @return iShmID 42 | */ 43 | int getShmId(int iFlag); 44 | 45 | /* 46 | * @desc 基础操作: 根据iShmID, 映射到进程内地址 47 | * 48 | * @return 映射到进程内的地址 49 | */ 50 | char* getAdr(); 51 | 52 | /* 53 | * @desc 根据iKey, 查询或创建iSize大小的共享内存 54 | * 55 | * @param iFlag 标志位,常用标志位是 (0666 | IPC_CREAT) 56 | * 57 | * @return 返回共享内存的指针,失败时返回 NULL 58 | */ 59 | char* getShm(int iFlag); 60 | 61 | /* 62 | * @desc 根据iShmID, 查询或创建iSize大小的共享内存, 第一次创建时初始化内存 63 | * 64 | * @param pstShm 返回的共享内存指针, 失败时未定义 65 | * @param iFlag 标志位,常用标志位是 (0666 | IPC_CREAT) 66 | * 67 | * @return 失败时返回负数. 68 | * 0 已存在, 查询成功 69 | * 1 创建成功 70 | * -1 共享内存不存在, flag没有 IPC_CREAT 标示位 71 | * -2 共享内存不一致或者不存在, 但是创建失败 72 | * 73 | */ 74 | int getShmInit(void * &pstShm, int iFlag); 75 | int getShmInit(void ** ppstShm, int iFlag); 76 | 77 | /* 78 | * 得到共享内存大小 79 | */ 80 | int getShmSize(); 81 | 82 | /* 83 | * @desc 根据iKey, 得到共享内存, 并检查Size大小 84 | * 如果 piSize 是0, 则赋值 85 | * 86 | * @return 返回共享内存的指针,失败时返回 NULL 87 | */ 88 | char* getShmNoCreateAndCheck(int iFlag, int *piSize); 89 | 90 | /* 91 | * @desc 根据shkey删除指定的共享内存 92 | * 93 | * @param shkey 我们分配的共享内存的唯一标识 94 | * 95 | * @return 成功返回0, 失败返回非0 96 | */ 97 | int delShm(); 98 | 99 | char* getLastError() { 100 | return lastErrorBuf; 101 | } 102 | }; 103 | 104 | } 105 | #endif 106 | 107 | -------------------------------------------------------------------------------- /src/linktable/LinkTableDefine.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: LinkTableDefine.h 4 | 5 | DESCRIPTION: 数组索引+链表方式内存结构定义 6 | 7 | LinkTable的数据结构: 8 | IndexHeadList -- 一级索引表,也是主索引表,通过主索引Index(或者叫Unit)可以索引到二级索引表的起始位置 9 | IndexNodeList -- 二级索引表,也是次索引表,以主索引和次索引Offset共同索引Key(UIN)在ElementList中的下标 10 | ElementList -- 元素数组 11 | 12 | 13 | 注意: 14 | LinkTable有两类Index 15 | 1, 外部看到的Index,就是UDC的UnitID,从0开始,记为dwIndex 16 | 2, 内部看到的Index=UnitID+1,写作idx,或者IndexID 17 | 所有API的Index参数都是外部Index,也就是UnitID 18 | 19 | ******************************************************************************/ 20 | 21 | #ifndef _LINK_TABLE_DEFINE_H_ 22 | #define _LINK_TABLE_DEFINE_H_ 23 | 24 | #define MAX_SHM_SIZE (1024UL*1024*1024*120) 25 | #define MAX_BLOCK_COUNT (200) 26 | #define MAX_ELEMENT_SIZE (200) 27 | 28 | #define MAX_LT_NUM 128 29 | 30 | #define LT_MAX_IDXDATA_SIZE 1024 31 | 32 | typedef struct { 33 | unsigned long ddwPosition :63; 34 | unsigned long cFlag :1; // 0 - not used, 1 - in use 35 | } IndexNode; 36 | 37 | typedef struct { 38 | uint64_t ddwIndexId; 39 | int iIndex; 40 | uint32_t dwIndexDataLen; // 每个主索引允许有用户自定义的数据,最大不超过LT_MAX_IDXDATA_SIZE 41 | uint8_t abIndexData[LT_MAX_IDXDATA_SIZE]; 42 | } IndexHead; 43 | 44 | typedef struct { 45 | uint64_t ddwKey; 46 | uint64_t ddwNext; 47 | uint8_t bufData[0]; 48 | } Element; 49 | 50 | #define _GET_ELE_AT(elist, idx, sz) ((Element *)(((char *)(elist)) + ((idx) * (sz)))) 51 | 52 | // 返回索引所指向的Element 53 | #define LT_ELE_AT(pLT, idx) _GET_ELE_AT((pLT)->pstElementList, idx, (pLT)->pstTableHead->ddwElementSize) 54 | 55 | // 根据句柄返回LinkTable内部结构指针 56 | #define GET_LT(lt) (((lt)>=0 && (lt)next will not fault if p->next is not a valid address, but evaluation will fault if p is not a valid address. 82 | 83 | If the target does not support data prefetch, the address expression is evaluated if it includes side effects but no other code is generated and GCC does not issue a warning. 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/antisnow/minSpinLock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * minSpinLock.h 3 | * 4 | * Created on: 2016年10月18日 5 | * Author: skyyuan 6 | */ 7 | 8 | #ifndef MINSPINLOCK_H_ 9 | #define MINSPINLOCK_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #define LIKELY(x) (__builtin_expect((x),1)) 23 | #define UNLIKELY(x) (__builtin_expect((x),0)) 24 | #define UNLIKELY_IF(x) if (__builtin_expect((x),0)) 25 | 26 | #define MINLOCK(obj) spin_lock( &obj, getpid()) 27 | #define MINUNLOCK(obj) spin_unlock( &obj, getpid()) 28 | 29 | #define nop() __asm__ ("pause" ) 30 | 31 | // return old value 32 | static inline int atomic_comp_swap(volatile void *lockword, int exchange, 33 | int comperand) { 34 | __asm__ __volatile__( 35 | "lock cmpxchg %1, (%2)" 36 | :"=a"(comperand) 37 | :"d"(exchange), "r"(lockword), "a"(comperand) 38 | ); 39 | return comperand; 40 | } 41 | 42 | static int SplitString(char* pString, char c, char* pElements[], int n) { 43 | char *p1, *p2; 44 | int i = 0; 45 | 46 | for (p1 = p2 = pString; *p1; p1++) { 47 | if (*p1 == c) { 48 | *p1 = 0; 49 | if (i < n) 50 | pElements[i++] = p2; 51 | p2 = p1 + 1; 52 | } 53 | } 54 | if (i < n) 55 | pElements[i++] = p2; 56 | return i; 57 | } 58 | 59 | static inline uint64_t rdtsc() { 60 | unsigned int lo, hi; 61 | /* We cannot use "=A", since this would use %rax on x86_64 */ 62 | __asm__ __volatile__ ( 63 | "rdtsc" 64 | : "=a" (lo), "=d" (hi) 65 | ); 66 | return (uint64_t) hi << 32 | lo; 67 | } 68 | 69 | static inline int Sleep(unsigned int nMilliseconds) { 70 | struct timespec ts; 71 | ts.tv_sec = nMilliseconds / 1000; 72 | ts.tv_nsec = (nMilliseconds % 1000) * 1000000; 73 | 74 | return nanosleep(&ts, NULL); 75 | } 76 | 77 | static uint64_t CalcCpuFreq() { 78 | uint64_t t1; 79 | uint64_t t2; 80 | 81 | t1 = rdtsc(); 82 | Sleep(100); 83 | t2 = rdtsc(); 84 | return (t2 - t1) * 10; 85 | } 86 | static uint64_t GetCpuFreq() { 87 | static uint64_t freq = 0; 88 | char buf[1024], *p[2]; 89 | 90 | if (0 != freq) { 91 | return freq; 92 | } 93 | 94 | FILE* fp = fopen("/proc/cpuinfo", "rb"); 95 | if (fp != NULL) { 96 | while (fgets(buf, sizeof(buf), fp) != NULL) { 97 | if (2 == SplitString(buf, ':', p, 2) 98 | && 0 == strncasecmp(p[0], "cpu MHz", 7)) { 99 | double f = strtod(p[1], NULL); 100 | freq = (uint64_t) (f * 1000000.0); 101 | /*printf("p[1]=%s f=%f freq=%llu\n", p[1], f,freq);*/ 102 | break; 103 | } 104 | } 105 | fclose(fp); 106 | } 107 | if (0 == freq) { 108 | freq = CalcCpuFreq(); 109 | } 110 | return freq; 111 | } 112 | 113 | static inline void spin_lock(volatile int *lock, int id) { 114 | static unsigned long long ticks_per_second = 0; 115 | unsigned long long ticks_nop = 0; 116 | 117 | int l; 118 | int i = 50; 119 | UNLIKELY_IF(ticks_per_second == 0) { 120 | ticks_per_second = GetCpuFreq(); 121 | } 122 | for (l = atomic_comp_swap(lock, id, 0); l != 0 && l != id; l = 123 | atomic_comp_swap(lock, id, 0)) { 124 | if (i--) { 125 | nop(); 126 | ++ticks_nop; 127 | } else { 128 | if (ticks_nop > ticks_per_second / 50) 129 | *lock = 0; 130 | i = 50; 131 | sched_yield(); 132 | 133 | atomic_comp_swap(lock, 0, id); 134 | break; 135 | } 136 | 137 | } 138 | } 139 | 140 | static inline bool spin_unlock(volatile int *lock, int id) { 141 | return id == atomic_comp_swap(lock, 0, id); 142 | } 143 | 144 | #ifdef __cplusplus 145 | } 146 | #endif 147 | 148 | #endif /* MINSPINLOCK_H_ */ 149 | -------------------------------------------------------------------------------- /src/MultiHashTable/link_table.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: LinkTable.h 4 | 5 | DESCRIPTION: 链表方式内存结构接口声明 6 | 7 | 这里仅提取出数据存储动态数组部分,内存管理和索引组织由上层进行 8 | ******************************************************************************/ 9 | 10 | #ifndef _LINK_TABLE_H_ 11 | #define _LINK_TABLE_H_ 12 | 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | 18 | // 一个key最大允许的块数,仅用于错误检测 19 | #define MAX_BLOCK_COUNT 10000 20 | 21 | // 预回收池最多占用256K 22 | #define LT_MAX_RECYCLE_POOL_SIZE (256UL*1024/8) 23 | #define LT_DEF_RECYCLE_POOL_SIZE 100 24 | // 预留给数据结构扩展的空间 25 | #define LT_MAX_RESERVE_LEN (256UL*1024) 26 | #define LT_MAX_USRDATA_LEN ((512UL*1024)-4) 27 | 28 | // 空间不足的时候是否需要回收预回收池中的元素再重试 29 | //#define EMPTY_RECYCLE_ON_OUT_OF_SPACE 30 | 31 | typedef unsigned long long ull64_t; 32 | 33 | typedef struct { 34 | ull64_t ddwNext :48; 35 | ull64_t ddwLengthInBlock :16; // data length in the block, the block is empty if this is 0 36 | uint8_t bufData[0]; 37 | } LtBlock; 38 | 39 | typedef struct { 40 | ull64_t ddwAllBlockCount; 41 | ull64_t ddwFreeBlockCount; 42 | ull64_t ddwBlockSize; 43 | ull64_t ddwLastEmpty; // 顺序分配时最后分配的为空的索引 44 | ull64_t ddwFirstFreePos; // All free blocks are linked together by ddwNext 45 | ull64_t ddwRecycleIndex; // Current index to addwRecyclePool 46 | uint32_t dwRecyclePoolSize; // 预回收池的大小,可配置,不大于LT_MAX_RECYCLE_POOL_SIZE 47 | ull64_t addwRecyclePool[LT_MAX_RECYCLE_POOL_SIZE]; // All blocks to be deleted are put here for delayed deletion 48 | uint8_t sReserved2[LT_MAX_RESERVE_LEN]; // Reserved for future extension 49 | uint32_t dwUserDataLen; 50 | uint8_t sUserData[LT_MAX_USRDATA_LEN]; // Reserved for application use 51 | } LinkTableHead; 52 | 53 | class LinkTable { 54 | private: 55 | volatile LinkTableHead *header; 56 | void *blocks; 57 | 58 | char errmsg[1024]; 59 | 60 | public: 61 | LinkTable() : 62 | header(NULL), blocks(NULL) { 63 | errmsg[0] = 0; 64 | } 65 | ~LinkTable() { 66 | } 67 | 68 | ull64_t EvalBufferSize(ull64_t uBlockCount, ull64_t uBlockSize) { 69 | return sizeof(LinkTableHead) + (uBlockCount * uBlockSize); 70 | } 71 | ull64_t EvalBlockCount(ull64_t uBuffSize, ull64_t uBlockSize) { 72 | return (uBuffSize - sizeof(LinkTableHead)) / uBlockSize; 73 | } 74 | 75 | //初始化链式表,用户必须自己分配LinkTableHead和Block所需的buffer 76 | //可以调用EvalBufferSize根据块大小和块数计算链表需要的buffer大小 77 | int Init(void *pBuffer, ull64_t ddwBufferSize, ull64_t ddwBlockCount, 78 | ull64_t ddwBlockSize); 79 | int InitExisting(void *pBuffer, ull64_t ddwBufferSize, 80 | ull64_t ddwBlockCount, ull64_t ddwBlockSize); 81 | 82 | //返回ddwPos指向的用户数据 83 | int GetData(ull64_t ddwPos, void *sDataBuf, int &iDataLen); 84 | 85 | //设置数据,如果ddwPos执行的数据有效,删除已有数据 86 | //执行成功时,ddwPos 返回新插入的数据位置 87 | // 返回 -100 表示空间不足 88 | int SetData(ull64_t &ddwPos, const void *sDataBuf, int iDataLen); 89 | 90 | //清除某个由ddwPos开始的数据 91 | int EraseData(ull64_t ddwPos); 92 | 93 | // 允许用户改变预回收池的大小,sz必须在1到LT_MAX_RECYCLE_POOL_SIZE之间 94 | int SetRecyclePoolSize(int sz); 95 | 96 | // 访问头部预留的用户空间 97 | int GetHeaderData(void *pBuff, int iSize); 98 | int SetHeaderData(const void *pData, int iLen); 99 | 100 | //调试 101 | const char *GetErrorMsg() { 102 | return errmsg; 103 | } 104 | int PrintInfo(const string &prefix = ""); 105 | int ReportInfo(); 106 | 107 | // 返回0~100,表示当前使用百分比 108 | int GetUsage() { 109 | return header ? 110 | (100 111 | - ((header->ddwFreeBlockCount * 100) 112 | / header->ddwAllBlockCount)) : 113 | 0; 114 | } 115 | 116 | private: 117 | int FreeBlock(ull64_t ddwStartPos); // 回收链表并放到free链表中 118 | int RecycleBlock(ull64_t ddwStartPos); // 放入回收池 119 | void EmptyRecyclePool(); // 清空回收池,回收池里面的所有元素 120 | int GetEmptyBlock(int iCount, ull64_t &ddwStartPos); // 获取iCount个空节点,并返回起始位置 121 | }; 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/hash/hash.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * hash.cpp 3 | * 4 | * Created on: 2015-9-5 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include "hash.h" 9 | #include 10 | 11 | namespace SHM_CACHE { 12 | 13 | Hash::Hash(const uint32_t _maxBucket) : 14 | shmHashInfo(NULL) { 15 | maxBucket = _maxBucket; 16 | if (maxBucket <= 0) { 17 | maxBucket = MAX_BUCKET; 18 | } 19 | 20 | localHashInfo.uBucket = 0; 21 | localHashInfo.uNodeSize = 0; 22 | localHashInfo.uShmSize = 0; 23 | _fCompare = NULL; 24 | _fElinemate = NULL; 25 | _inited = 0; 26 | } 27 | 28 | void Hash::calcPrime(uint32_t uSize, uint32_t& uBucket) { 29 | for (uint32_t n = uSize;; n++) { 30 | uint32_t m = 1; 31 | uint32_t sqrtn = sqrt(n * 1.0); 32 | for (uint32_t j = 2; j <= sqrtn; ++j) { 33 | if (n % j) { 34 | m = 0; 35 | break; 36 | } 37 | } 38 | if (m) { 39 | uBucket = n; 40 | break; 41 | } 42 | } 43 | } 44 | 45 | int Hash::EvalHashSize(uint32_t uSize, const uint32_t uNodeSize) { 46 | //计算前就大于最大bucket, 直接返回 47 | if (maxBucket < uSize) { 48 | return -1; 49 | } 50 | 51 | //先去计算bucket大小 52 | calcPrime(uSize, localHashInfo.uBucket); 53 | 54 | //计算后发现大于最大bucket, 直接返回 55 | if (maxBucket < localHashInfo.uBucket) { 56 | return -2; 57 | } 58 | 59 | localHashInfo.uNodeSize = uNodeSize; 60 | localHashInfo.uShmSize = localHashInfo.uBucket * localHashInfo.uNodeSize 61 | + sizeof(HashInfo); 62 | 63 | return localHashInfo.uShmSize; 64 | } 65 | 66 | int Hash::init(void* pHash, FCompare fCompare, FElinemate fElinemate) { 67 | if (!pHash) { 68 | return -1; 69 | } 70 | 71 | shmHashInfo = (HashInfo*) pHash; 72 | 73 | //第一次申请,会初始化为0, 不为0,说明不是第一次, 需要安全验证 74 | if (shmHashInfo->uBucket || shmHashInfo->uNodeSize 75 | || shmHashInfo->uShmSize) { 76 | if (shmHashInfo->uBucket != localHashInfo.uBucket 77 | || shmHashInfo->uNodeSize != localHashInfo.uNodeSize 78 | || shmHashInfo->uShmSize != localHashInfo.uShmSize) { 79 | return -2; 80 | } 81 | } else { 82 | shmHashInfo->uBucket = localHashInfo.uBucket; 83 | shmHashInfo->uNodeSize = localHashInfo.uNodeSize; 84 | shmHashInfo->uShmSize = localHashInfo.uShmSize; 85 | } 86 | _fCompare = fCompare; 87 | _fElinemate = fElinemate; 88 | 89 | if (shmHashInfo->uShmSize 90 | != shmHashInfo->uNodeSize * shmHashInfo->uBucket 91 | + sizeof(HashInfo)) { 92 | return -3; 93 | } 94 | 95 | _inited = 1; 96 | 97 | return 0; 98 | } 99 | 100 | uint32_t Hash::hash(const char *sKey, int iSize) { 101 | uint32_t dwKey = 0; 102 | static const uint64_t seed = 17; 103 | uint32_t uHashKey = 0; 104 | for (size_t i = 0; i < iSize; i++) { 105 | dwKey = dwKey * seed + sKey[i]; 106 | } 107 | 108 | uHashKey = hash(dwKey); 109 | 110 | return uHashKey; 111 | } 112 | 113 | int Hash::get(const void *pKey, uint32_t uKeyLen, void *&pNode) { 114 | //参数简单检查 115 | if (pKey == NULL) { 116 | return -1; 117 | } 118 | 119 | //hash 必须初始化 120 | if (_inited == 0) { 121 | return -2; 122 | } 123 | 124 | char *pRow = NULL; 125 | uint32_t uHashKey = 0; 126 | 127 | //hash 找到对应的位置 128 | uHashKey = hash((const char *) pKey, uKeyLen); 129 | 130 | //定位到 hash 的位置 131 | pRow = (char*) (shmHashInfo->pHash) + uHashKey * shmHashInfo->uNodeSize; 132 | if (_fCompare(pKey, uKeyLen, pRow) == 0) { 133 | pNode = pRow; 134 | return 1; 135 | } 136 | return 0; 137 | } 138 | 139 | int Hash::getAll(const void *pKey, uint32_t uKeyLen, void *&pNode, 140 | int iTimeOut) { 141 | //参数简单检查 142 | if (pKey == NULL) { 143 | return -1; 144 | } 145 | 146 | //hash 必须初始化 147 | if (_inited == 0) { 148 | return -2; 149 | } 150 | 151 | char *pRow = NULL; 152 | uint32_t uHashKey = 0; 153 | 154 | //hash 找到对应的位置 155 | uHashKey = hash((const char *) pKey, uKeyLen); 156 | 157 | //定位到 hash 的位置 158 | pRow = (char*) (shmHashInfo->pHash) + uHashKey * shmHashInfo->uNodeSize; 159 | if (_fElinemate(pKey, uKeyLen, pRow, iTimeOut) == 0) { 160 | pNode = pRow; 161 | return 1; 162 | } 163 | return 0; 164 | } 165 | 166 | uint32_t Hash::hash(uint32_t uHashKey) { 167 | return uHashKey % shmHashInfo->uBucket; 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/shm/shm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * shm.cpp 3 | * 4 | * Created on: 2015-9-3 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include "shm.h" 9 | 10 | namespace SHM_CACHE { 11 | 12 | Shm::Shm() { 13 | iShmID = 0; 14 | iKey = 0; 15 | iSize = 0; 16 | } 17 | 18 | void Shm::init(int iKey, int iSize) { 19 | memset(lastErrorBuf, 0, sizeof(lastErrorBuf)); 20 | this->iKey = iKey; 21 | this->iSize = iSize; 22 | } 23 | 24 | int Shm::getShmId(int iFlag) { 25 | if (iShmID > 0) { 26 | return iShmID; 27 | } 28 | 29 | if (iKey == 0) { 30 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 31 | "getShmId error. key = 0"); 32 | return 0; 33 | } 34 | 35 | iShmID = shmget(iKey, iSize, iFlag); 36 | if (iShmID < 0) { 37 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 38 | "getShmId error. ret=%d", 39 | errno); 40 | return 0; 41 | } 42 | return iShmID; 43 | } 44 | 45 | char* Shm::getAdr() { 46 | if (iShmID == 0) { 47 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 48 | "getAdr error. iShmID is 0"); 49 | return NULL; 50 | } 51 | 52 | char* sShm = (char*) shmat(iShmID, NULL, 0); 53 | if ((char *) -1 == sShm) { 54 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), "shmat error. ret=%d", 55 | errno); 56 | return NULL; 57 | } 58 | return sShm; 59 | } 60 | 61 | char* Shm::getShm(int iFlag) { 62 | if (getShmId(iFlag) == 0) { 63 | return NULL; 64 | } 65 | return getAdr(); 66 | } 67 | 68 | int Shm::getShmSize() { 69 | struct shmid_ds stShmStat; 70 | if (shmctl(iShmID, IPC_STAT, &stShmStat) < 0) { 71 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 72 | "shmctl IPC_STAT error. ret=%d", errno); 73 | return -1; 74 | } 75 | return stShmStat.shm_segsz; 76 | } 77 | 78 | char* Shm::getShmNoCreateAndCheck(int iFlag, int *piSize) { 79 | int iRealShmSize = 0; 80 | 81 | if (getShmId(iFlag) == 0) { 82 | return NULL; 83 | } 84 | 85 | iRealShmSize = getShmSize(); 86 | if (iRealShmSize == 0) { 87 | return NULL; 88 | } 89 | 90 | if (*piSize != 0 && *piSize != iRealShmSize) { 91 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 92 | "*piSize[%d] != iRealShmSize[%d]", *piSize, iRealShmSize); 93 | return NULL; 94 | } 95 | 96 | if (*piSize == 0) { 97 | *piSize = iRealShmSize; 98 | } 99 | 100 | return getAdr(); 101 | } 102 | 103 | int Shm::getShmInit(void * &pstShm, int iFlag) { 104 | volatile char *sShm = NULL; 105 | sShm = getShm(iFlag & (~IPC_CREAT)); 106 | if (NULL == sShm) { 107 | if (!(iFlag & IPC_CREAT)) { 108 | return -__LINE__; 109 | } 110 | sShm = getShm(iFlag); 111 | if (!sShm) { 112 | return -__LINE__; 113 | } 114 | memset((char*) sShm, 0, iSize); 115 | 116 | pstShm = (void*) sShm; 117 | return -__LINE__; 118 | } 119 | pstShm = (void*) sShm; 120 | return 0; 121 | } 122 | int Shm::getShmInit(void ** ppstShm, int iFlag) { 123 | return getShmInit(*ppstShm, iFlag); 124 | } 125 | 126 | int Shm::delShm() { 127 | if (iShmID == 0) { 128 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), 129 | "delShm error. iShmID is 0"); 130 | return -__LINE__; 131 | } 132 | 133 | int iRet = shmctl(iShmID, IPC_RMID, NULL); 134 | if (iRet < 0) { 135 | snprintf(lastErrorBuf, sizeof(lastErrorBuf), "shmctl error. ret=%d", 136 | errno); 137 | return -__LINE__; 138 | } 139 | 140 | return 0; 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/cache/cache.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * cache.cpp 3 | * 4 | * Created on: 2015-9-6 5 | * Author: tiankonguse 6 | */ 7 | 8 | #include "cache.h" 9 | 10 | namespace SHM_CACHE { 11 | 12 | Cache::Cache() : 13 | iTimeOut(0), maxKeyLen(MAX_KEY_LEN), maxValueLen(MAX_VALUE_LEN), iNodeSize( 14 | sizeof(Node) + MAX_KEY_LEN + MAX_VALUE_LEN) { 15 | _node = NULL; 16 | } 17 | 18 | Cache::~Cache() { 19 | if (_node) { 20 | free(_node); 21 | _node = NULL; 22 | } 23 | } 24 | 25 | int Cache::init(int _iKey, int _bucket, int _iTimeOut) { 26 | uint64_t uShmSize = 0; 27 | volatile void * pHash = NULL; 28 | 29 | //简单的检查超时时间 30 | iTimeOut = _iTimeOut; 31 | if (iTimeOut <= 0) { 32 | return -1; 33 | } 34 | 35 | if (_node) { 36 | free(_node); 37 | _node = NULL; 38 | } 39 | _node = (Node*) malloc(iNodeSize * sizeof(char)); 40 | if (!_node) { 41 | return -5; 42 | } 43 | 44 | //计算内存大小 45 | uShmSize = _hash.EvalHashSize(_bucket, iNodeSize); 46 | if (uShmSize <= 0) { 47 | return -2; 48 | } 49 | 50 | _shm.init(_iKey, uShmSize); 51 | 52 | if (_shm.getShm2(pHash, (int) (0666 | IPC_CREAT)) < 0) { 53 | return -3; 54 | } 55 | 56 | if (_hash.init((void *) pHash, fCompare, NULL) < 0) { 57 | return -4; 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | uint32_t Cache::fCompare(const void * vKey, int ikeyLen, 64 | const void * vNode) { 65 | const char * pKey = (const char *) vKey; 66 | const Node * pNode = (const Node *) vNode; 67 | 68 | if (!pKey || !pNode) { 69 | return 1; 70 | } 71 | 72 | if (pNode->cKeyLen != ikeyLen) { 73 | return 2; 74 | } 75 | 76 | return memcmp(pNode->cKey, pKey, ikeyLen); 77 | } 78 | uint32_t Cache::fElinemate(const void *vKey, int ikeyLen, const void *vNode, 79 | uint32_t iTimeOut) { 80 | 81 | const char * pKey = (const char *) vKey; 82 | const Node * pNode = (const Node *) vNode; 83 | 84 | if (!pKey || !pNode) { 85 | return 1; 86 | } 87 | 88 | uint32_t dwNow = time(NULL); 89 | if (pNode->dwAccessTime + iTimeOut > dwNow) { 90 | return 3; 91 | } 92 | 93 | return 0; 94 | } 95 | int Cache::getCache(const std::string &strKey, std::string &strValue) { 96 | 97 | if (strKey.length() > maxKeyLen) { 98 | return -1; 99 | } 100 | 101 | void* vNode = NULL; 102 | int iRet = _hash.get((void*) strKey.c_str(), strKey.length(), vNode); 103 | if (iRet < 0) { 104 | return -2; 105 | } 106 | 107 | Node* pNode = (Node*) vNode; 108 | 109 | if (iRet == 0) { 110 | return 1; 111 | } 112 | 113 | char* pData = (pNode->sData + MAX_KEY_LEN); 114 | 115 | strValue.assign(pData, pNode->dwValueLen); 116 | 117 | return 0; 118 | } 119 | 120 | int Cache::setCache(const std::string &strKey, 121 | const std::string &strValue) { 122 | 123 | if (strKey.length() <= 0 || strValue.length() <= 0) { 124 | return -1; 125 | } 126 | 127 | if (strKey.length() > MAX_KEY_LEN) { 128 | return -2; 129 | } 130 | 131 | if (strValue.length() > MAX_VALUE_LEN) { 132 | return -3; 133 | } 134 | 135 | memset(_node, 0, iNodeSize); 136 | _node->cKeyLen = strKey.length(); 137 | _node->dwAccessTime = time(NULL); 138 | _node->dwValueLen = strValue.length(); 139 | memcpy(_node->sData, strKey.c_str(), strKey.length()); 140 | memcpy(_node->sData + MAX_KEY_LEN, strValue.c_str(), strValue.length()); 141 | 142 | uint8_t cKeyLen = strKey.length(); 143 | void* vNode = NULL; 144 | int iRet = _hash.getAll((void*) strKey.c_str(), strKey.length(), vNode, 145 | iTimeOut); 146 | if (iRet < 0) { 147 | return -4; 148 | } 149 | 150 | if (iRet == 0) { 151 | return 1; 152 | } 153 | memcpy(vNode, _node, iNodeSize); 154 | 155 | return 0; 156 | } 157 | 158 | int Cache::delCache(const std::string &strKey) { 159 | 160 | if (strKey.length() > maxKeyLen) { 161 | return -1; 162 | } 163 | 164 | void* vNode = NULL; 165 | int iRet = _hash.get((void*) strKey.c_str(), strKey.length(), vNode); 166 | if (iRet < 0) { 167 | return -2; 168 | } 169 | 170 | if (iRet == 0) { 171 | return 0; 172 | } 173 | 174 | memset(vNode, 0, iNodeSize); 175 | 176 | return 0; 177 | } 178 | 179 | } 180 | 181 | -------------------------------------------------------------------------------- /src/MultiHashTable/shm_adapter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "shm_adapter.h" 5 | 6 | /* 7 | * 默认构造函数 8 | */ 9 | shm_adapter::shm_adapter() { 10 | m_bIsNewShm = false; 11 | m_ddwShmKey = 0; 12 | m_ddwShmSize = 0; 13 | m_bIsValid = false; 14 | m_pShm = NULL; 15 | m_nShmId = 0; 16 | } 17 | 18 | /* 19 | * 构造函数 20 | */ 21 | shm_adapter::shm_adapter(uint64_t ddwShmKey, uint64_t ddwShmSize, bool bCreate, 22 | bool bReadOnly, bool bLock, bool bHugePage, bool bInitClear) { 23 | int iRet; 24 | m_bIsNewShm = false; 25 | m_ddwShmKey = ddwShmKey; 26 | m_ddwShmSize = ddwShmSize; 27 | m_bIsValid = false; 28 | m_pShm = NULL; 29 | int nFlag = 0666; //默认标志 30 | if (bCreate) { 31 | //增加创建标志 32 | nFlag |= IPC_CREAT; 33 | } else if (bReadOnly) { 34 | //非创建, 并且只读, 去除写标志 35 | nFlag &= 077777444; 36 | } 37 | if (bHugePage) { 38 | //增加大页标志 39 | nFlag |= SHM_HUGETLB; 40 | } 41 | //获取ShmId 42 | int iShmId = shmget(ddwShmKey, ddwShmSize, nFlag & (~IPC_CREAT)); 43 | if (iShmId < 0) { 44 | //连接失败, 并且是非创建的, 返回失败 45 | if (!(nFlag & IPC_CREAT)) { 46 | m_strErrMsg = "shmget without create failed - "; 47 | m_strErrMsg += strerror(errno); 48 | return; 49 | } 50 | //连接失败, 创建该共享内存 51 | m_bIsNewShm = true; 52 | iShmId = shmget(ddwShmKey, ddwShmSize, nFlag); 53 | if (iShmId < 0) { 54 | m_strErrMsg = "shmget with create failed - "; 55 | m_strErrMsg += strerror(errno); 56 | return; 57 | } 58 | //Attach 59 | m_pShm = shmat(iShmId, NULL, 0); 60 | if (m_pShm == (void *) -1) { 61 | m_strErrMsg = "shmat with create failed - "; 62 | m_strErrMsg += strerror(errno); 63 | m_pShm = NULL; 64 | return; 65 | } 66 | //创建成功后初始化为0 67 | if (bInitClear) { 68 | memset(m_pShm, 0, ddwShmSize); 69 | } 70 | } else { 71 | //共享内存存在, Attach 72 | m_pShm = shmat(iShmId, NULL, 0); 73 | if (m_pShm == (void *) -1) { 74 | m_strErrMsg = "shmat with exist shm failed - "; 75 | m_strErrMsg += strerror(errno); 76 | m_pShm = NULL; 77 | return; 78 | } 79 | } 80 | 81 | m_nShmId = iShmId; 82 | 83 | //锁住内存 84 | if (bLock) { 85 | iRet = mlock(m_pShm, m_ddwShmSize); 86 | if (iRet != 0) { 87 | m_strErrMsg = "mlock failed - "; 88 | m_strErrMsg += strerror(errno); 89 | //操作失败, dettach内存 90 | shmdt(m_pShm); 91 | m_pShm = NULL; 92 | return; 93 | } 94 | } 95 | m_bIsValid = true; 96 | } 97 | 98 | /* 99 | * 析构函数 100 | */ 101 | shm_adapter::~shm_adapter() { 102 | if (m_pShm) { 103 | shmdt(m_pShm); 104 | } 105 | } 106 | 107 | /* 108 | * 刷新共享内存 109 | */ 110 | bool shm_adapter::refresh() { 111 | if (!m_pShm) { 112 | m_strErrMsg = "shm is not init yet"; 113 | return false; 114 | } 115 | 116 | struct shmid_ds stShmStat; 117 | //重新连接共享内存 118 | int nShmId = shmget(m_ddwShmKey, 0, 0); 119 | if (nShmId < 0) { 120 | m_strErrMsg = "shmget failed - "; 121 | m_strErrMsg += strerror(errno); 122 | return false; 123 | } 124 | //ShmId一样, 共享内存没有发生变化 125 | if (nShmId == m_nShmId) { 126 | return true; 127 | } 128 | //获取共享内存大小 129 | int iRet = shmctl(nShmId, IPC_STAT, &stShmStat); 130 | if (iRet < 0) { 131 | m_strErrMsg = "shmctl failed - "; 132 | m_strErrMsg += strerror(errno); 133 | return false; 134 | } 135 | //大小一样, 没有发生变化 136 | if (m_ddwShmSize == stShmStat.shm_segsz) { 137 | return true; 138 | } 139 | 140 | //重新Attach共享内存 141 | void *pShm = shmat(nShmId, NULL, 0); 142 | if (pShm == (void *) -1) { 143 | m_strErrMsg = "shmat failed - "; 144 | m_strErrMsg += strerror(errno); 145 | return false; 146 | } 147 | 148 | //释放旧的共享内存连接 149 | shmdt(m_pShm); 150 | 151 | m_pShm = pShm; 152 | m_nShmId = nShmId; 153 | m_ddwShmSize = stShmStat.shm_segsz; 154 | 155 | return true; 156 | } 157 | 158 | /* 159 | * 打开共享内存 160 | */ 161 | bool shm_adapter::open(uint64_t ddwShmKey, bool bReadOnly) { 162 | if (m_pShm) { 163 | m_strErrMsg = "Shm is NOT null, you have opened one already"; 164 | return false; 165 | } 166 | struct shmid_ds stShmStat; 167 | //连接共享内存 168 | int nShmId = shmget(ddwShmKey, 0, 0); 169 | if (nShmId < 0) { 170 | m_strErrMsg = "shmget failed - "; 171 | m_strErrMsg += strerror(errno); 172 | return false; 173 | } 174 | //获取共享内存大小 175 | int iRet = shmctl(nShmId, IPC_STAT, &stShmStat); 176 | if (iRet < 0) { 177 | m_strErrMsg = "shmctl to get size failed - "; 178 | m_strErrMsg += strerror(errno); 179 | return false; 180 | } 181 | //Attach共享内存 182 | if (bReadOnly) { 183 | m_pShm = shmat(nShmId, NULL, SHM_RDONLY); 184 | } else { 185 | m_pShm = shmat(nShmId, NULL, 0); 186 | } 187 | if (m_pShm == (void *) -1) { 188 | m_strErrMsg = "shmat with exist shm failed - "; 189 | m_strErrMsg += strerror(errno); 190 | m_pShm = NULL; 191 | return false; 192 | } 193 | 194 | m_nShmId = nShmId; 195 | m_ddwShmSize = stShmStat.shm_segsz; 196 | m_ddwShmKey = ddwShmKey; 197 | 198 | m_bIsValid = true; 199 | return true; 200 | } 201 | 202 | /* 203 | * 创建共享内存 204 | */ 205 | bool shm_adapter::create(uint64_t ddwShmKey, uint64_t ddwShmSize, 206 | bool bHugePage, bool bInitClear) { 207 | if (m_pShm) { 208 | m_strErrMsg = "Shm is NOT null, you have opened one already"; 209 | return false; 210 | } 211 | //设置创建标志 212 | int nFlag = 0666 | IPC_CREAT; 213 | if (bHugePage) { 214 | nFlag |= SHM_HUGETLB; 215 | } 216 | //尝试连接共享内存 217 | int nShmId = shmget(ddwShmKey, 0, 0); 218 | if (nShmId < 0) { 219 | //连接失败, 创建共享内存 220 | nShmId = shmget(ddwShmKey, ddwShmSize, nFlag); 221 | if (nShmId < 0) { 222 | m_strErrMsg = "shmget with create failed - "; 223 | m_strErrMsg += strerror(errno); 224 | return false; 225 | } 226 | //Attach共享内存 227 | m_pShm = shmat(nShmId, NULL, 0); 228 | if (m_pShm == (void *) -1) { 229 | m_strErrMsg = "shmat failed - "; 230 | m_strErrMsg += strerror(errno); 231 | m_pShm = NULL; 232 | return false; 233 | } 234 | if (bInitClear) { 235 | memset(m_pShm, 0, ddwShmSize); 236 | } 237 | m_bIsNewShm = true; 238 | } else { 239 | //共享内存已经存在, 判断大小是否一致 240 | struct shmid_ds stShmStat; 241 | int iRet = shmctl(nShmId, IPC_STAT, &stShmStat); 242 | if (iRet < 0) { 243 | m_strErrMsg = "shmctl with size failed - "; 244 | m_strErrMsg += strerror(errno); 245 | return false; 246 | } 247 | //大小不一致 248 | if (stShmStat.shm_segsz != ddwShmSize) { 249 | m_strErrMsg = "shm exist, but size is not the same"; 250 | return false; 251 | } 252 | //Attach共享内存 253 | m_pShm = shmat(nShmId, NULL, 0); 254 | if (m_pShm == (void *) -1) { 255 | m_strErrMsg = "shmat failed - "; 256 | m_strErrMsg += strerror(errno); 257 | m_pShm = NULL; 258 | return false; 259 | } 260 | m_bIsNewShm = false; 261 | } 262 | m_nShmId = nShmId; 263 | m_ddwShmKey = ddwShmKey; 264 | m_ddwShmSize = ddwShmSize; 265 | m_bIsValid = true; 266 | return true; 267 | } 268 | 269 | /* 270 | * 关闭共享内存 271 | */ 272 | bool shm_adapter::close() { 273 | if (m_pShm) { 274 | //Dettach共享内存 275 | int iRet = shmdt(m_pShm); 276 | if (iRet < 0) { 277 | m_strErrMsg = "shmdt shm failed - "; 278 | m_strErrMsg += strerror(errno); 279 | return false; 280 | } 281 | m_pShm = NULL; 282 | } 283 | m_bIsValid = false; 284 | return true; 285 | } 286 | -------------------------------------------------------------------------------- /src/list/doubly_linked_list.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: doubly_linked_list.h 3 | > Desc: Simple doubly linked list implementation by c. 4 | > Author: tiankonguse(skyyuan) 5 | > Mail: i@tiankonguse.com 6 | > Created Time: 2016年06月24日 7 | ***********************************************************************/ 8 | 9 | #ifndef _DOUBLY_LINKED_LIST_H_ 10 | #define _DOUBLY_LINKED_LIST_H_ 11 | 12 | __BEGIN_DECLS 13 | 14 | struct list_head { 15 | struct list_head *next, *prev; 16 | }; 17 | typedef struct list_head list_head_t; 18 | 19 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 20 | 21 | #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) 22 | 23 | #define INIT_LIST_HEAD(ptr) do { \ 24 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 25 | } while (0) 26 | 27 | 28 | #ifndef offsetof 29 | #if __GNUC__ >= 4 30 | #define offsetof(type, member) __builtin_offsetof (type, member) 31 | #else 32 | #define offsetof(type, member) (unsigned long)(&((type *)0)->member) 33 | #endif 34 | #endif 35 | 36 | 37 | /** 38 | * list_entry - get the struct for this entry 39 | * @ptr: the &struct list_head pointer. 40 | * @type: the type of the struct this is embedded in. 41 | * @member: the name of the list_struct within the struct. 42 | */ 43 | #define list_entry(ptr, type, member) ((type *)((char *)(ptr)-offsetof(type, member))) 44 | 45 | /** 46 | * list_for_each - iterate over a list 47 | * @pos: the &struct list_head to use as a loop counter. 48 | * @head: the head for your list. 49 | */ 50 | #define list_for_each(pos, head) \ 51 | for (pos = (head)->next, __builtin_prefetch(pos->next,0,1); \ 52 | pos != (head); \ 53 | pos = pos->next, __builtin_prefetch(pos->next,0,1)) \ 54 | 55 | #define __list_for_each(pos, head) \ 56 | for (pos = (head)->next; pos != (head); pos = pos->next) 57 | 58 | /** 59 | * list_for_each_prev - iterate over a list backwards 60 | * @pos: the &struct list_head to use as a loop counter. 61 | * @head: the head for your list. 62 | */ 63 | #define list_for_each_prev(pos, head) \ 64 | for (pos = (head)->prev, __builtin_prefetch(pos->prev,0,1); \ 65 | pos != (head); \ 66 | pos = pos->prev, __builtin_prefetch(pos->prev,0,1)) 67 | 68 | #define __list_for_each_prev(pos, head) \ 69 | for (pos = (head)->prev; pos != (head); \ 70 | pos = pos->prev) 71 | 72 | /** 73 | * list_for_each_safe - iterate over a list safe against removal of list entry 74 | * @pos: the &struct list_head to use as a loop counter. 75 | * @n: another &struct list_head to use as temporary storage 76 | * @head: the head for your list. 77 | */ 78 | #define list_for_each_safe(pos, n, head) \ 79 | for (pos = (head)->next, n = pos->next; pos != (head); \ 80 | pos = n, n = pos->next) 81 | 82 | /** 83 | * list_for_each_entry - iterate over list of given type 84 | * @pos: the type * to use as a loop counter. 85 | * @head: the head for your list. 86 | * @member: the name of the list_struct within the struct. 87 | */ 88 | #define list_for_each_entry(pos, head, member) \ 89 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 90 | __builtin_prefetch(pos->member.next,0,1); \ 91 | &pos->member != (head); \ 92 | pos = list_entry(pos->member.next, typeof(*pos), member), \ 93 | __builtin_prefetch(pos->member.next,0,1)) 94 | 95 | 96 | /* 97 | * Insert a p entry between two known consecutive entries. 98 | * 99 | * This is only for internal list manipulation where we know 100 | * the prev/next entries already! 101 | */ 102 | static inline void __list_add(struct list_head *p, struct list_head *prev, struct list_head *next){ 103 | next->prev = p; 104 | p->next = next; 105 | p->prev = prev; 106 | prev->next = p; 107 | } 108 | 109 | /** 110 | * list_add - add a p entry 111 | * @p: p entry to be added 112 | * @head: list head to add it after 113 | * 114 | * Insert a p entry after the specified head. 115 | * This is good for implementing stacks. 116 | */ 117 | static inline void list_add(struct list_head *p, struct list_head *head){ 118 | __list_add(p, head, head->next); 119 | } 120 | 121 | /** 122 | * list_add_tail - add a p entry 123 | * @p: p entry to be added 124 | * @head: list head to add it before 125 | * 126 | * Insert a p entry before the specified head. 127 | * This is useful for implementing queues. 128 | */ 129 | static inline void list_add_tail(struct list_head *p, struct list_head *head){ 130 | __list_add(p, head->prev, head); 131 | } 132 | 133 | /* 134 | * Delete a list entry by making the prev/next entries 135 | * point to each other. 136 | * 137 | * This is only for internal list manipulation where we know 138 | * the prev/next entries already! 139 | */ 140 | static inline void __list_del(struct list_head *prev, struct list_head *next){ 141 | next->prev = prev; 142 | prev->next = next; 143 | } 144 | 145 | /** 146 | * list_del - deletes entry from list. 147 | * @entry: the element to delete from the list. 148 | * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 149 | */ 150 | static inline void list_del(struct list_head *entry){ 151 | __list_del(entry->prev, entry->next); 152 | entry->next = 0; 153 | entry->prev = 0; 154 | } 155 | 156 | /** 157 | * list_del_init - deletes entry from list and reinitialize it. 158 | * @entry: the element to delete from the list. 159 | */ 160 | static inline void list_del_init(struct list_head *entry){ 161 | __list_del(entry->prev, entry->next); 162 | INIT_LIST_HEAD(entry); 163 | } 164 | 165 | /** 166 | * list_move - delete from one list and add as another's head 167 | * @list: the entry to move 168 | * @head: the head that will precede our entry 169 | */ 170 | static inline void list_move(struct list_head *list, struct list_head *head){ 171 | __list_del(list->prev, list->next); 172 | list_add(list, head); 173 | } 174 | /** 175 | * list_move_tail - delete from one list and add as another's tail 176 | * @list: the entry to move 177 | * @head: the head that will follow our entry 178 | */ 179 | static inline void list_move_tail(struct list_head *list, struct list_head *head){ 180 | __list_del(list->prev, list->next); 181 | list_add_tail(list, head); 182 | } 183 | 184 | /** 185 | * list_empty - tests whether a list is empty 186 | * @head: the list to test. 187 | */ 188 | static inline int list_empty(const struct list_head *head){ 189 | return head->next == head; 190 | } 191 | 192 | 193 | /** 194 | * delete list entry(head) and meger other to head 195 | * @list the entry to splice 196 | * @head he head that will follow our list 197 | */ 198 | static inline void __list_splice(struct list_head *list, struct list_head *head){ 199 | struct list_head *first = list->next; 200 | struct list_head *last = list->prev; 201 | struct list_head *at = head->next; 202 | 203 | first->prev = head; 204 | head->next = first; 205 | 206 | last->next = at; 207 | at->prev = last; 208 | } 209 | 210 | /** 211 | * list_splice - join two lists 212 | * @list: the p list to add. 213 | * @head: the place to add it in the first list. 214 | */ 215 | static inline void list_splice(struct list_head *list, struct list_head *head){ 216 | if (!list_empty(list)){ 217 | __list_splice(list, head); 218 | } 219 | } 220 | 221 | /** 222 | * list_splice_init - join two lists and reinitialise the emptied list. 223 | * @list: the p list to add. 224 | * @head: the place to add it in the first list. 225 | * 226 | * The list at @list is reinitialised 227 | */ 228 | static inline void list_splice_init(struct list_head *list, struct list_head *head){ 229 | if (!list_empty(list)) { 230 | __list_splice(list, head); 231 | INIT_LIST_HEAD(list); 232 | } 233 | } 234 | 235 | 236 | 237 | 238 | 239 | __END_DECLS 240 | 241 | 242 | #endif -------------------------------------------------------------------------------- /src/net/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL_H__ 2 | #define __UTIL_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | class LockHelper 31 | { 32 | public: 33 | explicit LockHelper(pthread_mutex_t *lock){ 34 | pthread_mutex_lock(lock); 35 | _lock = lock; 36 | } 37 | 38 | ~LockHelper(){ 39 | pthread_mutex_unlock(_lock); 40 | } 41 | 42 | private: 43 | pthread_mutex_t *_lock; 44 | }; 45 | 46 | class StringTokenizer: public std::vector{ 47 | public: 48 | StringTokenizer(const std::string &str, const std::string &sep){ 49 | std::string::const_iterator n = str.begin(), b, e, end = str.end(); 50 | while (n != end) { 51 | while (n != end && isspace(*n)) 52 | ++n; 53 | b = n; 54 | while (b != end && sep.find(*b) == std::string::npos) 55 | ++b; 56 | e = b; 57 | if (e != n) { 58 | --e; 59 | while (e != n && isspace(*e)) 60 | --e; 61 | if (!isspace(*e)) 62 | ++e; 63 | } 64 | 65 | if (e != n) 66 | this->push_back(std::string(n, e)); 67 | n = b; 68 | if (n != end) 69 | ++n; 70 | } 71 | } 72 | }; 73 | 74 | class Clock { 75 | public: 76 | static uint64_t rdtsc(){ 77 | uint32_t low = 0, high = 0; 78 | __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); 79 | return (uint64_t) high << 32 | low; 80 | } 81 | 82 | static uint64_t NowWithUs(){ 83 | struct timeval tv; 84 | int rc = gettimeofday (&tv, NULL); 85 | assert(rc == 0); 86 | 87 | return tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec; 88 | } 89 | }; 90 | 91 | static inline bool is_innerip(unsigned int ip){ 92 | return (ip >= 0x0A000000 && ip < 0x0B000000) || // [10.0.0.0, 11.0.0.0) 93 | (ip >= 0xAC000000 && ip < 0xAD000000) || // [172.0.0.0, 173.0.0.0) 94 | (ip >= 0xC0000000 && ip < 0xC1000000) || // [192.0.0.0, 193.0.0.0) 95 | (ip == 0x7F000001); // 127.0.0.1 96 | } 97 | 98 | static inline int get_hostip(const std::string &interface, std::string &ipaddr){ 99 | struct sockaddr_in sin; 100 | struct ifreq ifr; 101 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 102 | strncpy(ifr.ifr_name, interface.c_str(), 10); 103 | if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) 104 | return -1; 105 | 106 | memcpy(&sin, &ifr.ifr_addr, sizeof(sin)); 107 | ipaddr = inet_ntoa(sin.sin_addr); 108 | close(sock); 109 | return 0; 110 | } 111 | 112 | static inline unsigned get_hostip(std::string *ipaddr=NULL){ 113 | char addr[64] = { 0 }; 114 | struct sockaddr_in sin; 115 | struct ifreq ifr; 116 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 117 | if (sock >= 0) { 118 | for (int i = 0; i < 5; i++) { 119 | snprintf(ifr.ifr_name, 10, "eth%d", i); 120 | if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) 121 | continue; 122 | memcpy(&sin, &ifr.ifr_addr, sizeof(sin)); 123 | snprintf(addr, sizeof(addr), "%s", inet_ntoa(sin.sin_addr)); 124 | 125 | unsigned ip = inet_addr(addr); 126 | if (is_innerip(ntohl(ip))) { 127 | close(sock); 128 | if (ipaddr) 129 | *ipaddr = addr; 130 | return ip; 131 | } 132 | } 133 | 134 | close(sock); 135 | } 136 | 137 | return -1; 138 | } 139 | 140 | // 测试一个fd[]是否可读 141 | static inline bool IsReadable(int fd[], size_t n, size_t timeout){ 142 | struct pollfd fds[n]; 143 | for (size_t i = 0; i < n; i++) { 144 | fds[i].fd = fd[i]; 145 | fds[i].events = POLLIN; 146 | fds[i].revents = 0; 147 | } 148 | 149 | return poll(fds, n, timeout); 150 | } 151 | 152 | static inline int TcpConnect(const char *ip, int port) 153 | { 154 | int s = 0, on = 1, flags = 0; 155 | struct sockaddr_in sa; 156 | 157 | sa.sin_family = AF_INET; 158 | sa.sin_port = htons(port); 159 | if (inet_aton(ip, &(sa.sin_addr)) == 0) 160 | return -1; 161 | 162 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) 163 | return -1; 164 | 165 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) 166 | goto ERR; 167 | 168 | if ((flags = fcntl(s, F_GETFL)) < 0 || fcntl(s, F_SETFL, flags|O_NONBLOCK) < 0) 169 | goto ERR; 170 | 171 | if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 172 | if (errno != EINPROGRESS) 173 | goto ERR; 174 | } 175 | 176 | return s; 177 | ERR: 178 | if (s >= 0) 179 | close(s); 180 | return -1; 181 | } 182 | 183 | static inline bool SocketIsAlive(int fd){ 184 | if (fd < 0) 185 | return false; 186 | char buff[1]; 187 | int len = recv(fd, buff, 1, MSG_PEEK); 188 | if (len == 0) 189 | return false; 190 | if (len > 0 || errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) 191 | return true; 192 | return false; 193 | } 194 | 195 | 196 | class PipeEvent 197 | { 198 | public: 199 | PipeEvent() 200 | { 201 | int rc = pipe(pipefd); 202 | assert(rc == 0); 203 | rc = SetNonBlock(pipefd[0]); 204 | assert(rc == 0); 205 | rc = SetNonBlock(pipefd[1]); 206 | assert(rc == 0); 207 | } 208 | 209 | ~PipeEvent() 210 | { 211 | if (pipefd[0] >= 0) { 212 | close(pipefd[0]); 213 | close(pipefd[1]); 214 | } 215 | } 216 | 217 | int SendEvent() 218 | { 219 | char cmd = 0; 220 | return write(pipefd[1], &cmd, 1) == 1 ? 0 : -1; 221 | } 222 | 223 | void ReadAll() 224 | { 225 | char buff[32]; 226 | int rc = 0; 227 | do { 228 | rc = read(pipefd[0], buff, 32); 229 | } while (rc > 0); 230 | } 231 | 232 | int GetFD() 233 | { 234 | return pipefd[0]; 235 | } 236 | 237 | private: 238 | static int SetNonBlock(int fd) 239 | { 240 | int flags; 241 | if ((flags = fcntl(fd, F_GETFL)) == -1) 242 | return -1; 243 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 244 | return -1; 245 | return 0; 246 | } 247 | 248 | private: 249 | int pipefd[2]; 250 | }; 251 | 252 | struct NetBuff 253 | { 254 | NetBuff() 255 | { 256 | buffer = NULL; 257 | capacity = 0; 258 | size = 0; 259 | } 260 | 261 | ~NetBuff() 262 | { 263 | if (buffer) 264 | free(buffer); 265 | } 266 | 267 | int Expand(size_t len) 268 | { 269 | if (len <= capacity) 270 | return 0; 271 | char *ptr = (char *)realloc(buffer, len); 272 | if (ptr == NULL) 273 | return -1; 274 | buffer = ptr, capacity = len; 275 | 276 | return 0; 277 | } 278 | 279 | void Clean() 280 | { 281 | size = 0; 282 | } 283 | 284 | int Append(const char *ptr, size_t len) 285 | { 286 | if (len + size > capacity) { 287 | size_t n = capacity * 2; 288 | while (n < len + size) 289 | n *= 2; 290 | 291 | if (Expand(n) < 0) 292 | return -1; 293 | } 294 | 295 | memcpy(buffer + size, ptr, len); 296 | size += len; 297 | 298 | return 0; 299 | } 300 | 301 | int Reserve(size_t len) 302 | { 303 | if (capacity - size >= len) 304 | return 0; 305 | size_t n = capacity ? capacity * 2 : 128; 306 | 307 | while (n < len + size) 308 | n *= 2; 309 | 310 | return Expand(n); 311 | } 312 | 313 | char *buffer; 314 | unsigned capacity; 315 | unsigned size; 316 | }; 317 | 318 | #endif // __UTIL_H__ 319 | 320 | -------------------------------------------------------------------------------- /src/MultiHashTable/multi_hash_table.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: multi_hash_table.h 4 | 5 | DESCRIPTION: 多阶Hash表的一种实现:索引和数据分离,数据层使用LinkTable存储 6 | 7 | ******************************************************************************/ 8 | #ifndef __MULTI_HASH_TABLE__ 9 | #define __MULTI_HASH_TABLE__ 10 | 11 | #include 12 | #include 13 | #include "link_table.h" 14 | 15 | #define HASH_MAX_ROW 100 16 | #define HASH_MAX_KEY_LENGTH 64 17 | #define HASH_MAX_DATA_LENGTH (10*1024*1024) 18 | 19 | typedef ull64_t MhtIterator; 20 | 21 | typedef struct { 22 | union { 23 | uint32_t access_time; 24 | uint32_t access_seq; 25 | }; 26 | 27 | uint32_t klen; 28 | uint8_t key[HASH_MAX_KEY_LENGTH]; 29 | 30 | uint32_t dlen; 31 | uint8_t data[HASH_MAX_DATA_LENGTH]; 32 | } MhtData; 33 | 34 | class shm_adapter; 35 | 36 | typedef struct { 37 | uint32_t dwHashKey; // 32 bit hash for acKey[cKeyLen] 38 | union { 39 | uint32_t dwAccessTime; 40 | volatile uint32_t dwAccessSeq; 41 | }; 42 | ull64_t ddwLtPos :48; // Position in LinkTable 43 | ull64_t cKeyLen :8; 44 | uint8_t acKey[0]; 45 | } MhtNode; 46 | 47 | typedef struct { 48 | ull64_t ddwTotalShmSize; // total size allocated in shm (used if created from shm) 49 | ull64_t ddwHashNodeNum; // used for validity checking 50 | ull64_t ddwHashNodeSize; // hash node size 51 | ull64_t ddwDataBlockSize; // data block size in link table 52 | ull64_t ddwDataBlockNum; // data block num in link table 53 | ull64_t ddwRowNum; 54 | ull64_t auRowsNodeNum[HASH_MAX_ROW]; // each row's node num 55 | ull64_t auRowsStartNode[HASH_MAX_ROW]; // each row's starting node index, pre-calculated to speed up searching 56 | ull64_t ddwMaxUsedRow; // max row index (start at 0) in use 57 | ull64_t ddwEraseIterator; // used to iterate through the hash table for erasing old key 58 | uint8_t cUseAccessSeq; // 0: use access_time for auto erasing, 1: use access_seq 59 | uint8_t acReserved[1024 * 1024 - 1]; 60 | } MhtHeader; 61 | 62 | #define DEFAULT_MAX_KEY_LENGTH 8 63 | #define DEFAULT_ROW_NUM 20 64 | #define DEFAULT_INDEX_RATIO 50 // 1 hash node - 2 data block 65 | #define DEFAULT_BLOCK_SIZE 128 66 | #define DEFAULT_USE_HUGEPAGE 0 // not using huge page 67 | 68 | extern "C" { 69 | unsigned int DefaultHashFunc(const void *, int); 70 | typedef unsigned int (*CalcHashKeyFunc)(const void *, int); 71 | } 72 | 73 | // Memset to use default values, and set the arguments you are interested in 74 | typedef struct { 75 | ull64_t ddwShmKey; // required: shm key 76 | ull64_t ddwBufferSize; // required: how much memory can be used by us 77 | uint8_t cMaxKeyLen; // optional: max key length, use as small value as possible to save index space (default to 8) 78 | uint16_t wRowNum; // optional: row num, level of MultiHashTable, in range [1-HASH_MAX_ROW] (default to 20) 79 | uint32_t dwIndexRatio; // optional: hash node num * 100 / data block num, controls the index-data ratio (default to 50) 80 | ull64_t ddwBlockSize; // optional: data block size in LinkTable (default to 128) 81 | bool bUseHugePage; // optional: whether use huge page to speed up attaching/detaching 82 | // you should make sure /proc/sys/vm/nr_hugepages has enough value (in tlinux, each page is 2MB) 83 | bool bUseAccessSeq; // optional: whether use seq for auto-erase instead of access time 84 | CalcHashKeyFunc HashFunc; 85 | } MhtInitParam; 86 | 87 | class MultiHashTable { 88 | private: 89 | // Buffer structure: MhtHeader + HtBody[] + LinkTableHead + LtBody[] 90 | MhtHeader *header; 91 | void *ht; 92 | LinkTable lt; 93 | shm_adapter *pShmAdpt; 94 | static __thread char errmsg[1024]; 95 | CalcHashKeyFunc hashfunc; 96 | pthread_mutex_t mutex; 97 | 98 | private: 99 | // HashNodeSize=MaxKeyLen+sizeof(MhtNode) 100 | ull64_t EvaluateHashNodeSize(ull64_t ddwMaxKeyLen) { 101 | return ddwMaxKeyLen + sizeof(MhtNode); 102 | } 103 | ull64_t EvaluateHashNodeNum(ull64_t ddwMemsize, ull64_t ddwHashNodeSize, 104 | ull64_t ddwHashMemRatio) { 105 | ull64_t ddwDataMemSize = ddwMemsize * 100 / (100 + ddwHashMemRatio); // mem size for link table part 106 | ull64_t hashsz = ddwMemsize - ddwDataMemSize; // mem size for hash table part 107 | return hashsz / ddwHashNodeSize; 108 | } 109 | ull64_t NodeNumRatio2MemSizeRatio(ull64_t ddwNodeSize, ull64_t ddwBlockSize, 110 | uint64_t ddwIndexRatio) { 111 | return ddwIndexRatio * ddwNodeSize / ddwBlockSize; 112 | } 113 | // calculate each row's node num, return the real total node num 114 | ull64_t CalcNodeNumForEachRow(ull64_t ddwRowNum, ull64_t ddwMaxNodeNum, 115 | ull64_t auRowsNodeNum[], ull64_t auRowsStartNode[]); 116 | 117 | // Search and return a node for pKey, if no such key found, returns NULL, optionally 118 | // ppEmptyNode returns the first empty node encountered 119 | // ppOldestNode returns the oldest node in the search path 120 | // piEmptyRow returns ppEmptyNode's row index 121 | MhtNode *Search(const void *pKey, int iKeyLen, uint32_t dwHashKey, 122 | MhtNode **ppEmptyNode = NULL, MhtNode **ppOldestNode = NULL, 123 | int *piEmptyRow = NULL); 124 | 125 | // A brutal method for cache replacement: 126 | // iterate through the hash table and find the oldest node in a thousand to erase, 127 | // repeat this operation until enough space is needed 128 | int SearchAndEraseOldestOne(MhtNode *pDataNode); 129 | 130 | public: 131 | MultiHashTable() : 132 | header(NULL), ht(NULL), lt(), pShmAdpt(NULL), hashfunc( 133 | DefaultHashFunc) { 134 | pthread_mutex_init(&mutex, NULL); // always successful 135 | } 136 | ~MultiHashTable(); 137 | 138 | // Note: before a MultiHashTable can be used, you are responsible to call one of the 3 init methods below 139 | // and check the returned values, all methods returning an int have the 140 | // same meaning: 141 | // < 0 -- failed, please get the reason by GetErrorMsg() 142 | // = 0 -- successful 143 | 144 | // Init from user supplied buffer 145 | // pBuffer -- user supplied buffer 146 | // ddwBufferSize -- size of pBuffer 147 | // cMaxKeyLen -- max key length, use as small value as possible to save index space 148 | // wRowNum -- hash table row num, level of MultiHashTable, should be in range [1-HASH_MAX_ROW] 149 | // dwIndexRatio -- hash node num * 100 / data block num, controlling the ratio between index and data spaces 150 | // ddwBlockSize -- data block size in LinkTable 151 | // HashFunc -- function entry for calculating the hash key 152 | // bUseAccessSeq -- whether use seq for auto-erase instead of access time 153 | int InitFromBuffer(void *pBuffer, 154 | ull64_t ddwBufferSize, // required arguments 155 | uint8_t cMaxKeyLen = DEFAULT_MAX_KEY_LENGTH, uint16_t wRowNum = 156 | DEFAULT_ROW_NUM, 157 | uint32_t dwIndexRatio = DEFAULT_INDEX_RATIO, ull64_t ddwBlockSize = 158 | DEFAULT_BLOCK_SIZE, CalcHashKeyFunc HashFunc = NULL, 159 | bool bUseAccessSeq = false); 160 | 161 | // Init from existing shm, parameters are read from shm 162 | int InitFromShm(ull64_t ddwShmKey, CalcHashKeyFunc HashFunc = NULL); 163 | 164 | // Create a shm and init hash table, paramenters(except ddwShmKey/bUseHugePage) have the same meaning as InitFromBuffer() 165 | int CreateFromShm(const MhtInitParam ¶m); 166 | 167 | // 获取指定key的数据 168 | // 参数: 169 | // pKey -- 指向key的指针 170 | // iKeyLen -- pKey 的长度 171 | // sDataBuf -- 用于返回数据的buffer 172 | // iDataLen -- 传入sDataBuf的大小,调用成功时返回数据的大小,注意:传入的大小必须不小于初始化时指定的BlockSize的大小 173 | // bUpdateAccessTime -- 访问成功时是否更新节点的访问时间 174 | // pdwLastAccessTime -- 如果不为NULL,用于返回节点上一次的访问时间 175 | // 返回: 176 | // 0 -- 成功 177 | // <0 -- 失败,请用 GetErrorMsg() 获取失败的原因 178 | int GetData(const void *pKey, int iKeyLen, char *sDataBuf, int &iDataLen, 179 | bool bUpdateAccessTime = true, time_t *pdwLastAccessTime = NULL); 180 | 181 | // 设置指定key的数据 182 | // 参数: 183 | // pKey -- 指向key的指针 184 | // iKeyLen -- pKey 的长度 185 | // sDataBuf -- 指向需要写入数据的buffer 186 | // iDataLen -- 需要写入数据的大小 187 | // bRemoveOldIfNoSpace -- 如果空间不够,是否允许淘汰旧数据 188 | // 返回: 189 | // 0 -- 成功 190 | // <0 -- 失败,请用 GetErrorMsg() 获取失败的原因 191 | int SetData(const void *pKey, int iKeyLen, const char *sDataBuf, 192 | int iDataLen, bool bRemoveOldIfNoSpace = false); 193 | 194 | // 195 | // Erase a given key, returns: 196 | // 1 -- erased successfully 197 | // 0 -- no key found 198 | // <0 -- error 199 | // 200 | int EraseData(const void *pKey, int iKeyLen); 201 | 202 | // get data without effecting access time 203 | int PeekData(const void *pKey, int iKeyLen, char *sDataBuf, int &iDataLen) { 204 | return GetData(pKey, iKeyLen, sDataBuf, iDataLen, false); 205 | } 206 | // set data with bRemoveOldIfNoSpace=true 207 | int ForceSetData(const void *pKey, int iKeyLen, char *sDataBuf, 208 | int iDataLen) { 209 | return SetData(pKey, iKeyLen, sDataBuf, iDataLen, true); 210 | } 211 | 212 | // Iteration interfaces 213 | MhtIterator Begin() { 214 | return Next(End()); 215 | } 216 | MhtIterator End() { 217 | return (MhtIterator) -1; 218 | } 219 | MhtIterator Next(MhtIterator it); 220 | int Get(MhtIterator it, MhtData &data); 221 | 222 | int GetMaxKeyLen(); 223 | int GetDataBlockSize(); 224 | int GetHashRowNum(); 225 | int PrintInfo(const string &prefix = ""); 226 | int ReportInfo(); // report current usage 227 | int EraseBadNode(const void *pKey, int iKeyLen); 228 | const char *GetErrorMsg() { 229 | return errmsg; 230 | } 231 | }; 232 | 233 | #endif 234 | -------------------------------------------------------------------------------- /src/MultiHashTable/link_table.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: link_table.cc 4 | 5 | DESCRIPTION: 链表方式内存结构实现 6 | 7 | 这里仅提取出数据存储动态数组部分,内存管理和索引组织由上层进行 8 | ******************************************************************************/ 9 | #include 10 | #include 11 | #include 12 | 13 | #include "link_table.h" 14 | 15 | // if you have Attr_API, please define HAS_ATTR_API in your makefile 16 | // if you don't have one, we won't blame it, you can download it 17 | #ifdef HAS_ATTR_API 18 | #include "Attr_API.h" 19 | #else 20 | #define Attr_API(a, b) 21 | #endif 22 | 23 | //初始化链式表,用户必须自己分配LinkTableHead和Block所需的buffer 24 | //可以调用EvalSize计算Block需要的buffer大小 25 | int LinkTable::Init(void *pBuffer, ull64_t ddwBufferSize, ull64_t ddwBlockCount, 26 | ull64_t ddwBlockSize) { 27 | if (pBuffer == NULL 28 | || ddwBufferSize < EvalBufferSize(ddwBlockCount, ddwBlockSize)) { 29 | snprintf(errmsg, sizeof(errmsg), "Bad argument: %s", 30 | pBuffer == NULL ? "buffer is null" : "not enough buffer size"); 31 | return -1; 32 | } 33 | 34 | header = (volatile LinkTableHead *) pBuffer; 35 | blocks = ((char*) pBuffer) + sizeof(LinkTableHead); 36 | 37 | memset((void*) header, 0, sizeof(*header)); 38 | header->ddwAllBlockCount = header->ddwFreeBlockCount = (ddwBlockCount - 1); 39 | header->ddwBlockSize = ddwBlockSize; 40 | header->ddwLastEmpty = 1; // the first block (pos==0) is not used 41 | header->dwRecyclePoolSize = LT_DEF_RECYCLE_POOL_SIZE; 42 | 43 | return 0; 44 | } 45 | 46 | int LinkTable::InitExisting(void *pBuffer, ull64_t ddwBufferSize, 47 | ull64_t ddwBlockCount, ull64_t ddwBlockSize) { 48 | if (pBuffer == NULL 49 | || ddwBufferSize < EvalBufferSize(ddwBlockCount, ddwBlockSize)) { 50 | snprintf(errmsg, sizeof(errmsg), "Bad argument: %s", 51 | pBuffer == NULL ? "buffer is null" : "not enough buffer size"); 52 | return -1; 53 | } 54 | 55 | header = (volatile LinkTableHead *) pBuffer; 56 | blocks = ((char*) pBuffer) + sizeof(LinkTableHead); 57 | 58 | if (header->ddwAllBlockCount != (ddwBlockCount - 1)) { 59 | snprintf(errmsg, sizeof(errmsg), 60 | "Total block count mismatched: existing %llu, expected %llu", 61 | header->ddwAllBlockCount, (ddwBlockCount - 1)); 62 | return -2; 63 | } 64 | 65 | if (header->ddwBlockSize != ddwBlockSize) { 66 | snprintf(errmsg, sizeof(errmsg), 67 | "Block size mismatched: existing %llu, expected %llu", 68 | header->ddwBlockSize, ddwBlockSize); 69 | return -3; 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | #define _GET_ELE_AT(elist, idx, sz) ((LtBlock *)(((char *)(elist)) + ((idx) * (sz)))) 76 | 77 | // 返回索引所指向的Block 78 | #define LT_ELE_AT(idx) _GET_ELE_AT(blocks, idx, header->ddwBlockSize) 79 | 80 | // 释放链表的元素并放到free链表中 81 | int LinkTable::FreeBlock(ull64_t ddwStartPos) { 82 | ull64_t ddwCurPos = 0, ddwNextPos = 0; 83 | int iCount = 0; 84 | LtBlock *pBlock; 85 | 86 | if (header == NULL || blocks == NULL) { 87 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 88 | return -1; 89 | } 90 | 91 | if ((ddwStartPos == 0) || (ddwStartPos >= header->ddwAllBlockCount)) { 92 | Attr_API(355929 , 1); // Position gone insane 93 | snprintf(errmsg, sizeof(errmsg), "Position %llu gone insane", 94 | ddwStartPos); 95 | return -2; 96 | } 97 | 98 | ddwNextPos = ddwStartPos; 99 | while ((ddwNextPos) && (iCount <= MAX_BLOCK_COUNT)) { 100 | ddwCurPos = ddwNextPos; 101 | if (ddwCurPos >= header->ddwAllBlockCount) { 102 | Attr_API(355929, 1); // Position gone insane 103 | snprintf(errmsg, sizeof(errmsg), "Position %llu gone insane", 104 | ddwStartPos); 105 | return -3; 106 | } 107 | 108 | pBlock = LT_ELE_AT(ddwCurPos); 109 | ddwNextPos = pBlock->ddwNext; 110 | memset(pBlock, 0, header->ddwBlockSize); 111 | 112 | // 把节点放入Free列表中 113 | pBlock->ddwNext = header->ddwFirstFreePos; 114 | header->ddwFirstFreePos = ddwCurPos; 115 | 116 | header->ddwFreeBlockCount++; 117 | iCount++; 118 | } 119 | 120 | if (ddwNextPos != 0) { 121 | Attr_API(355931 , 1); // Too many blocks 122 | snprintf(errmsg, sizeof(errmsg), "Too many blocks at %llu", 123 | ddwStartPos); 124 | return -4; 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | // 预回收池的主要算法实现: 131 | // 用一个游标dwRecycleIndex循环遍历预回收池指针数组addwRecyclePool,没次预回收遍历一个指针, 132 | // 将本次希望回收的起始地址挂到addwRecyclePool[ddwRecycleIndex]上,并回收上次挂到这的地方的元素链表 133 | int LinkTable::RecycleBlock(ull64_t ddwStartPos) { 134 | int iRet; 135 | ull64_t ddwOldPos, ddwIdx; 136 | 137 | if (header == NULL || blocks == NULL) { 138 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 139 | return -1; 140 | } 141 | 142 | ddwIdx = header->ddwRecycleIndex; 143 | if (ddwIdx >= header->dwRecyclePoolSize) { 144 | Attr_API(355950, 1); 145 | ddwIdx = 0; 146 | header->ddwRecycleIndex = 0; 147 | } 148 | 149 | // 先放到预回收池中,再回收同个位置中的旧数据 150 | ddwOldPos = header->addwRecyclePool[ddwIdx]; 151 | header->addwRecyclePool[ddwIdx] = ddwStartPos; 152 | header->ddwRecycleIndex = (ddwIdx + 1) % header->dwRecyclePoolSize; 153 | 154 | if (ddwOldPos) { 155 | iRet = FreeBlock(ddwOldPos); 156 | if (iRet < 0) { 157 | // 如果回收失败,将导致单元不能被重新利用,这里只上报,不处理 158 | Attr_API(355951, 1); 159 | } 160 | } 161 | 162 | return 0; 163 | } 164 | 165 | // 回收全部预回收池中的元素 166 | void LinkTable::EmptyRecyclePool() { 167 | int i; 168 | 169 | if (header == NULL || blocks == NULL) 170 | return; 171 | 172 | for (i = 0; i < (int) header->dwRecyclePoolSize; i++) { 173 | if (header->addwRecyclePool[i]) { 174 | int iRet; 175 | 176 | iRet = FreeBlock(header->addwRecyclePool[i]); 177 | if (iRet < 0) { 178 | // 如果回收失败,将导致单元不能被重新利用,这里只上报,不处理 179 | Attr_API(355951, 1); 180 | } 181 | 182 | header->addwRecyclePool[i] = 0; 183 | } 184 | } 185 | 186 | header->ddwRecycleIndex = 0; 187 | } 188 | 189 | // ---------- 下面的 ATTR_API 属性需要重新申请 190 | 191 | //使用数组方式管理自由空间,分配和使用自由空间采用步进方式 192 | // 返回 -100 表示空间不足 193 | int LinkTable::GetEmptyBlock(int iCount, ull64_t &ddwOutPos) { 194 | ull64_t ddwStartPos, ddwCurPos; 195 | int i, j; 196 | #ifdef EMPTY_RECYCLE_ON_OUT_OF_SPACE 197 | int iTrySecond=0; 198 | #endif 199 | float fUsedRate; 200 | LtBlock *pBlock; 201 | 202 | if (header == NULL || blocks == NULL) { 203 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 204 | return -1; 205 | } 206 | 207 | // 只要空闲块数小于预设比例就告警 208 | fUsedRate = (header->ddwFreeBlockCount * 100.0 / header->ddwAllBlockCount); 209 | if (fUsedRate < 20.0) 210 | Attr_API(355995, 1); 211 | if (fUsedRate < 15.0) 212 | Attr_API(355996, 1); 213 | if (fUsedRate < 10.0) 214 | Attr_API(355997, 1); 215 | if (fUsedRate < 5.0) 216 | Attr_API(355998, 1); 217 | 218 | #ifdef EMPTY_RECYCLE_ON_OUT_OF_SPACE 219 | restart: 220 | if(iTrySecond) // 清空预回收池后重新分配 221 | Attr_API(355999, 1); 222 | #endif 223 | if ((iCount < 0) || (iCount > MAX_BLOCK_COUNT) 224 | || (iCount > (int) header->ddwFreeBlockCount)) { 225 | // Not enough space 226 | #ifdef EMPTY_RECYCLE_ON_OUT_OF_SPACE 227 | if(iTrySecond==0) 228 | { 229 | iTrySecond = 1; 230 | EmptyRecyclePool(); 231 | goto restart; 232 | } 233 | #endif 234 | Attr_API(356005, 1); 235 | strncpy(errmsg, "Not enough space", sizeof(errmsg)); 236 | return -100; 237 | } 238 | 239 | // 先从Free列表搜索,搜不到再挨个搜索 240 | ddwStartPos = 0; 241 | ddwCurPos = header->ddwFirstFreePos; 242 | i = 0; 243 | while (i < iCount && ddwCurPos > 0 && ddwCurPos < header->ddwAllBlockCount 244 | && (pBlock = LT_ELE_AT(ddwCurPos))->ddwLengthInBlock == 0) { 245 | ull64_t ddwNext; 246 | i++; 247 | ddwNext = pBlock->ddwNext; 248 | if (i == iCount) // 把最后一个的Next置零 249 | pBlock->ddwNext = 0; 250 | ddwCurPos = ddwNext; 251 | } 252 | 253 | if (i == iCount) // 找到了 254 | { 255 | ddwOutPos = header->ddwFirstFreePos; 256 | header->ddwFirstFreePos = ddwCurPos; 257 | return 0; 258 | } 259 | 260 | // FIXME:这里存在一个不是很重要的问题:就是当从Free链表中找到一些节点,但无法满足请求的需要, 261 | // 这时需要通过遍历搜索来分配,而遍历搜索可能会找到free链表中的节点,这将导致free链表中的节点被 262 | // 遍历分配了,使得Free链表断链,断链后的链表就只能由遍历分配器来分配了 263 | 264 | // 从header->ddwLastEmpty开始进行挨个搜索 265 | ddwStartPos = 0; 266 | ddwCurPos = header->ddwLastEmpty; 267 | i = 0; 268 | for (j = 0; (i < iCount) && (j < (int) header->ddwAllBlockCount); j++) { 269 | if ((pBlock = LT_ELE_AT(ddwCurPos))->ddwLengthInBlock == 0) { 270 | pBlock->ddwNext = ddwStartPos; 271 | ddwStartPos = ddwCurPos; 272 | i++; 273 | } 274 | ddwCurPos++; 275 | 276 | // Wrap around 277 | if (ddwCurPos >= header->ddwAllBlockCount) { 278 | ddwCurPos = 1; 279 | } 280 | } 281 | 282 | if (i < iCount) { 283 | // Not enough space 284 | #ifdef EMPTY_RECYCLE_ON_OUT_OF_SPACE 285 | if(iTrySecond==0) 286 | { 287 | iTrySecond = 1; 288 | EmptyRecyclePool(); 289 | goto restart; 290 | } 291 | #endif 292 | Attr_API(356005, 1); 293 | strncpy(errmsg, "Not enough space", sizeof(errmsg)); 294 | return -100; 295 | } 296 | 297 | ddwOutPos = ddwStartPos; 298 | header->ddwLastEmpty = ddwCurPos; 299 | return 0; 300 | } 301 | 302 | #define BLOCK_DATA_LEN() (header->ddwBlockSize - (unsigned long)(((LtBlock*)0)->bufData)) 303 | 304 | //返回ddwPos指向的用户数据 305 | int LinkTable::GetData(ull64_t ddwPos, void *sDataBuf, int &iOutDataLen) { 306 | ull64_t ddwCurPos = 0, ddwNextPos = 0; 307 | int iDataLen = 0, iBufLen = iOutDataLen; 308 | LtBlock *pBlock; 309 | 310 | if (sDataBuf == NULL || iBufLen < (int) BLOCK_DATA_LEN()) // buffer大小不足一个块 311 | { 312 | strncpy(errmsg, "Bad argument", sizeof(errmsg)); 313 | return -1; 314 | } 315 | 316 | if (header == NULL || blocks == NULL) { 317 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 318 | return -1; 319 | } 320 | 321 | iDataLen = 0; 322 | 323 | ddwNextPos = ddwPos; 324 | while (ddwNextPos) { 325 | ddwCurPos = ddwNextPos; 326 | if (ddwCurPos >= header->ddwAllBlockCount) { 327 | Attr_API(355929, 1); 328 | strncpy(errmsg, "Position gone insane", sizeof(errmsg)); 329 | return -21; 330 | } 331 | if ((iDataLen + (int) BLOCK_DATA_LEN()) > iBufLen) { 332 | Attr_API(356018, 1); 333 | strncpy(errmsg, "Not enough space for data", sizeof(errmsg)); 334 | return -4; 335 | } 336 | pBlock = LT_ELE_AT(ddwCurPos); 337 | uint16_t wBlockLen; 338 | if (pBlock->ddwNext) // not the last block 339 | { 340 | wBlockLen = BLOCK_DATA_LEN(); 341 | } else // the last block 342 | { 343 | wBlockLen = pBlock->ddwLengthInBlock; 344 | if (wBlockLen > BLOCK_DATA_LEN()) 345 | wBlockLen = BLOCK_DATA_LEN(); 346 | } 347 | memcpy(((char*) sDataBuf) + iDataLen, pBlock->bufData, wBlockLen); 348 | iDataLen += wBlockLen; 349 | ddwNextPos = pBlock->ddwNext; 350 | } 351 | iOutDataLen = iDataLen; 352 | return 0; 353 | } 354 | 355 | //设置数据,如果ddwPos指向的数据有效,删除已有数据 356 | //执行成功时,ddwPos 返回新插入的数据位置 357 | // 返回 -100 表示空间不足 358 | int LinkTable::SetData(ull64_t &ddwPos, const void *sDataBuf, int iDataLen) { 359 | ull64_t ddwCurPos = 0, ddwNextPos = 0, ddwStartPos = 0, ddwOldPos = ddwPos; 360 | int iCount = 0, iLeftLen = 0, iCopyLen = 0; 361 | int iRet = 0; 362 | LtBlock *pBlock; 363 | 364 | if (sDataBuf == NULL || iDataLen < 0) { 365 | strncpy(errmsg, "Bad argument", sizeof(errmsg)); 366 | return -1; 367 | } 368 | 369 | if (header == NULL || blocks == NULL) { 370 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 371 | return -1; 372 | } 373 | 374 | iCount = (iDataLen + BLOCK_DATA_LEN() - 1) / BLOCK_DATA_LEN(); 375 | if (iCount > MAX_BLOCK_COUNT) { 376 | Attr_API(356019, 1); 377 | snprintf(errmsg, sizeof(errmsg), 378 | "Data too large to fit in max of %d blocks", MAX_BLOCK_COUNT); 379 | return -2; 380 | } 381 | 382 | //先构造新数据 383 | iRet = GetEmptyBlock(iCount, ddwStartPos); 384 | if (iRet < 0) { 385 | if (iRet == -100) 386 | return iRet; 387 | return -7; 388 | } 389 | 390 | ddwNextPos = ddwStartPos; 391 | iLeftLen = iDataLen - iCopyLen; 392 | while ((ddwNextPos) && (iLeftLen > 0)) { 393 | ddwCurPos = ddwNextPos; 394 | if (ddwCurPos >= header->ddwAllBlockCount) { 395 | Attr_API(355929, 1); 396 | strncpy(errmsg, "Next position is bad", sizeof(errmsg)); 397 | return -8; 398 | } 399 | 400 | pBlock = LT_ELE_AT(ddwCurPos); 401 | if (iLeftLen > (int) BLOCK_DATA_LEN()) { 402 | memcpy(pBlock->bufData, ((char*) sDataBuf) + iCopyLen, 403 | BLOCK_DATA_LEN()); 404 | iCopyLen += BLOCK_DATA_LEN(); 405 | pBlock->ddwLengthInBlock = BLOCK_DATA_LEN(); 406 | } else { 407 | memcpy(pBlock->bufData, ((char*) sDataBuf) + iCopyLen, 408 | (unsigned) iLeftLen); 409 | iCopyLen += iLeftLen; 410 | pBlock->ddwLengthInBlock = iLeftLen; 411 | } 412 | 413 | ddwNextPos = pBlock->ddwNext; 414 | header->ddwFreeBlockCount--; 415 | iLeftLen = iDataLen - iCopyLen; 416 | } 417 | 418 | if (iLeftLen != 0) { 419 | //bug 420 | Attr_API(356083, 1); 421 | snprintf(errmsg, sizeof(errmsg), 422 | "Allocated blocks(%d) not enough for data(len=%d, bs=%llu)", 423 | iCount, iDataLen, header->ddwBlockSize); 424 | return -9; 425 | } 426 | 427 | LT_ELE_AT(ddwCurPos)->ddwNext = 0; 428 | LT_ELE_AT(0)->ddwNext = ddwNextPos; 429 | ddwPos = ddwStartPos; 430 | 431 | //删除旧数据 432 | if (ddwOldPos != 0) { 433 | iRet = RecycleBlock(ddwOldPos); 434 | if (iRet < 0) { 435 | // No way of turning back 436 | Attr_API(356091, 1); 437 | } 438 | } 439 | 440 | return 0; 441 | } 442 | 443 | //清除某个Key对应的数据 444 | int LinkTable::EraseData(ull64_t ddwPos) { 445 | if (header == NULL || blocks == NULL) { 446 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 447 | return -1; 448 | } 449 | 450 | return RecycleBlock(ddwPos); 451 | } 452 | 453 | // 允许用户改变预回收池的大小,sz必须在1到LT_MAX_PREFREE_POOL_SIZE之间 454 | int LinkTable::SetRecyclePoolSize(int sz) { 455 | if (sz < 1 || (unsigned int) sz > LT_MAX_RECYCLE_POOL_SIZE) { 456 | strncpy(errmsg, "Invalid argument", sizeof(errmsg)); 457 | return -1; 458 | } 459 | if (header == NULL || blocks == NULL) { 460 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 461 | return -2; 462 | } 463 | 464 | EmptyRecyclePool(); 465 | header->dwRecyclePoolSize = sz; 466 | 467 | return 0; 468 | } 469 | 470 | // 访问头部预留的用户空间 471 | int LinkTable::GetHeaderData(void *pBuff, int iSize) { 472 | if (iSize <= 0 || pBuff == NULL) { 473 | strncpy(errmsg, "Invalid argument", sizeof(errmsg)); 474 | return -1; 475 | } 476 | if (header == NULL || blocks == NULL) { 477 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 478 | return -2; 479 | } 480 | 481 | if (iSize > (int) header->dwUserDataLen) 482 | iSize = (int) header->dwUserDataLen; 483 | 484 | memcpy(pBuff, (void*) header->sUserData, iSize); 485 | return iSize; 486 | } 487 | 488 | int LinkTable::SetHeaderData(const void *pData, int iLen) { 489 | if (iLen < 0 || (iLen && pData == NULL)) { 490 | strncpy(errmsg, "Invalid argument", sizeof(errmsg)); 491 | return -1; 492 | } 493 | if (header == NULL || blocks == NULL) { 494 | strncpy(errmsg, "LinkTable not initialized", sizeof(errmsg)); 495 | return -2; 496 | } 497 | if (iLen > (int) sizeof(header->sUserData)) 498 | iLen = (int) sizeof(header->sUserData); 499 | 500 | if (iLen > 0) 501 | memcpy((void*) header->sUserData, pData, iLen); 502 | 503 | header->dwUserDataLen = iLen; 504 | return iLen; 505 | } 506 | 507 | //调试 508 | int LinkTable::PrintInfo(const string &prefix) { 509 | long i = 0; 510 | unsigned long total = 0; 511 | 512 | if (header == NULL || blocks == NULL) { 513 | cout << prefix << "Linktable not initialized" << endl; 514 | return -1; 515 | } 516 | 517 | cout << prefix << "ddwAllBlockCount: " << header->ddwAllBlockCount << endl; 518 | cout << prefix << "ddwFreeBlockCount: " << header->ddwFreeBlockCount 519 | << endl; 520 | cout << prefix << "ddwBlockSize: " << header->ddwBlockSize << endl; 521 | cout << prefix << "ddwFirstFreePos: " << header->ddwFirstFreePos 522 | << endl; 523 | cout << prefix << "ddwRecycleIndex: " << header->ddwRecycleIndex 524 | << endl; 525 | 526 | for (total = 0, i = 0; i < header->dwRecyclePoolSize; i++) { 527 | if (header->addwRecyclePool[i]) 528 | total++; 529 | } 530 | cout << prefix << "dwRecycledCount: " << total << endl; 531 | cout << prefix << "dwTableUsage: " << GetUsage() << endl; 532 | 533 | return 0; 534 | } 535 | 536 | int LinkTable::ReportInfo() { 537 | unsigned long i, total = 0; 538 | 539 | if (header == NULL || blocks == NULL) 540 | return -1; 541 | 542 | Attr_API_Set(389162, header->ddwAllBlockCount); 543 | Attr_API_Set(389163, header->ddwFreeBlockCount); 544 | Attr_API_Set(389164, header->ddwBlockSize); 545 | Attr_API_Set(389165, header->ddwFirstFreePos); 546 | Attr_API_Set(389166, header->ddwRecycleIndex); 547 | for (total = 0, i = 0; i < header->dwRecyclePoolSize; i++) { 548 | if (header->addwRecyclePool[i]) 549 | total++; 550 | } 551 | Attr_API_Set(389167, total); 552 | Attr_API_Set(389168, GetUsage()); 553 | 554 | return 0; 555 | } 556 | 557 | -------------------------------------------------------------------------------- /src/MultiHashTable/multi_hash_table.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: multi_hash_table.cc 4 | 5 | DESCRIPTION: 多阶Hash表的一种实现:索引和数据分离,数据层使用LinkTable存储 6 | ******************************************************************************/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "multi_hash_table.h" 18 | #include "shm_adapter.h" 19 | 20 | // if you have Attr_API, please define HAS_ATTR_API in your makefile 21 | // if you don't have one, we won't blame it, you can download it at http://www.server.com/oss 22 | #ifdef HAS_ATTR_API 23 | #include "Attr_API.h" 24 | #else 25 | #define Attr_API(a, b) 26 | #endif 27 | 28 | static const char *errnotostr(int errnum) { 29 | static __thread char s[64]; 30 | return strerror_r(errno, s, sizeof(s)); 31 | } 32 | 33 | extern "C" unsigned int DefaultHashFunc(const void *key, int len) { 34 | int32_t i, h = 0; 35 | #define magic 131 36 | const unsigned char *p = (const unsigned char *) key; 37 | 38 | if (!key) 39 | return 0; 40 | 41 | for (i = 0; i < len; i++, p++) 42 | h = h * magic + *p; 43 | 44 | return h; 45 | } 46 | 47 | /* 48 | * 返回n以下(不包括n)的最大质数 49 | */ 50 | static ull64_t MaxPrime(ull64_t n) { 51 | while (n--) { 52 | int k; 53 | int sqr = ceil(sqrt(n)); 54 | for (k = 2; k <= sqr; ++k) 55 | if (n % k == 0) 56 | break; 57 | if (k == sqr + 1) 58 | return n; 59 | } 60 | return 0; 61 | } 62 | 63 | __thread char MultiHashTable::errmsg[1024]; 64 | 65 | MultiHashTable::~MultiHashTable() { 66 | if (pShmAdpt) 67 | delete pShmAdpt; 68 | } 69 | 70 | // calculate each row's node num, return the real total node num 71 | ull64_t MultiHashTable::CalcNodeNumForEachRow(ull64_t ddwRowNum, 72 | ull64_t ddwMaxNodeNum, ull64_t auRowsNodeNum[], 73 | ull64_t auRowsStartNode[]) { 74 | ull64_t uNodeNum = 0, uLeftNum = ddwMaxNodeNum, i, j; 75 | #define PD(i) printf("row %llu, num %llu, start %llu\n", (ull64_t)i, auRowsNodeNum[i], auRowsStartNode[i]) 76 | auRowsNodeNum[0] = MaxPrime( 77 | ddwRowNum == 1 ? uLeftNum : (uLeftNum * 70 / 100)); 78 | auRowsStartNode[0] = uNodeNum; 79 | uNodeNum += auRowsNodeNum[0]; 80 | uLeftNum -= auRowsNodeNum[0]; 81 | PD(0); 82 | if (ddwRowNum == 1) 83 | return uNodeNum; 84 | 85 | auRowsNodeNum[1] = MaxPrime( 86 | ddwRowNum == 2 ? uLeftNum : (uLeftNum * 10 / 100)); 87 | auRowsStartNode[1] = uNodeNum; 88 | uNodeNum += auRowsNodeNum[1]; 89 | uLeftNum -= auRowsNodeNum[1]; 90 | PD(1); 91 | if (ddwRowNum == 2) 92 | return uNodeNum; 93 | 94 | auRowsNodeNum[2] = MaxPrime( 95 | ddwRowNum == 3 ? uLeftNum : (uLeftNum * 5 / 100)); 96 | auRowsStartNode[2] = uNodeNum; 97 | uNodeNum += auRowsNodeNum[2]; 98 | uLeftNum -= auRowsNodeNum[2]; 99 | PD(2); 100 | if (ddwRowNum == 3) 101 | return uNodeNum; 102 | 103 | j = uLeftNum / (ddwRowNum - 3); 104 | for (i = 3; i < ddwRowNum; ++i) { 105 | auRowsNodeNum[i] = j = MaxPrime(j); 106 | auRowsStartNode[i] = uNodeNum; 107 | uNodeNum += j; 108 | PD(i); 109 | } 110 | printf("total %llu\n", uNodeNum); 111 | #undef PD 112 | return uNodeNum; 113 | } 114 | 115 | int MultiHashTable::InitFromBuffer(void *pBuffer, ull64_t ddwBufferSize, 116 | uint8_t cMaxKeyLen, uint16_t wRowNum, uint32_t dwIndexRatio, 117 | ull64_t ddwBlockSize, CalcHashKeyFunc HashFunc, bool bUseAccessSeq) { 118 | if (pBuffer == NULL || ddwBufferSize < 1024 * 1024 * 2 || cMaxKeyLen < 1 119 | || cMaxKeyLen > HASH_MAX_KEY_LENGTH || wRowNum < 1 120 | || wRowNum > HASH_MAX_ROW || dwIndexRatio < 1 || dwIndexRatio > 1000 121 | || ddwBlockSize < 32 || ddwBlockSize > 8192) { 122 | strncpy(errmsg, "Bad argument", sizeof(errmsg)); 123 | return -1; 124 | } 125 | ull64_t ddwNodeSize = EvaluateHashNodeSize(cMaxKeyLen); 126 | ull64_t ddwMemRatio = NodeNumRatio2MemSizeRatio(ddwNodeSize, ddwBlockSize, 127 | dwIndexRatio); 128 | ull64_t ddwHashNodeNum = EvaluateHashNodeNum(ddwBufferSize, ddwNodeSize, 129 | ddwMemRatio); 130 | header = (MhtHeader*) pBuffer; 131 | memset(header, 0, sizeof(*header)); 132 | header->ddwTotalShmSize = ddwBufferSize; 133 | header->ddwHashNodeSize = ddwNodeSize; 134 | header->ddwRowNum = wRowNum; 135 | header->ddwHashNodeNum = CalcNodeNumForEachRow(wRowNum, ddwHashNodeNum, 136 | header->auRowsNodeNum, header->auRowsStartNode); 137 | ht = header + 1; 138 | 139 | ull64_t ddwDataSize = ddwBufferSize - sizeof(*header) 140 | - (header->ddwHashNodeNum * ddwNodeSize); 141 | ull64_t ddwBlockCount = lt.EvalBlockCount(ddwDataSize, ddwBlockSize); 142 | header->ddwDataBlockSize = ddwBlockSize; 143 | header->ddwDataBlockNum = ddwBlockCount; 144 | header->cUseAccessSeq = bUseAccessSeq; 145 | 146 | int ret = lt.Init(((char *) ht) + (header->ddwHashNodeNum * ddwNodeSize), 147 | ddwDataSize, ddwBlockCount, ddwBlockSize); 148 | if (ret) { 149 | snprintf(errmsg, sizeof(errmsg), "LinkTable Init failed (ret=%d): %s", 150 | ret, lt.GetErrorMsg()); 151 | return -2; 152 | } 153 | if (HashFunc) 154 | hashfunc = HashFunc; 155 | else 156 | hashfunc = DefaultHashFunc; 157 | return 0; 158 | } 159 | 160 | int MultiHashTable::InitFromShm(ull64_t ddwShmKey, CalcHashKeyFunc HashFunc) { 161 | if (pShmAdpt) 162 | delete pShmAdpt; 163 | 164 | pShmAdpt = new shm_adapter; 165 | if (pShmAdpt == NULL) { 166 | snprintf(errmsg, sizeof(errmsg), 167 | "Failed to create shm adaptor: Out of memory"); 168 | return -1; 169 | } 170 | if (pShmAdpt->open(ddwShmKey) == false) { 171 | snprintf(errmsg, sizeof(errmsg), "Failed to open shm: %s", 172 | pShmAdpt->get_err_msg().c_str()); 173 | delete pShmAdpt; 174 | pShmAdpt = NULL; 175 | return -100; 176 | } 177 | 178 | header = (MhtHeader*) pShmAdpt->get_shm(); 179 | if (header == NULL) { 180 | snprintf(errmsg, sizeof(errmsg), 181 | "Bug: shm open successfully but shm pointer is NULL"); 182 | delete pShmAdpt; 183 | pShmAdpt = NULL; 184 | return -3; 185 | } 186 | 187 | if (header->ddwTotalShmSize != pShmAdpt->get_size()) { 188 | snprintf(errmsg, sizeof(errmsg), 189 | "Error: shm size %llu differs from size in header %llu", 190 | (ull64_t) pShmAdpt->get_size(), header->ddwTotalShmSize); 191 | delete pShmAdpt; 192 | pShmAdpt = NULL; 193 | return -4; 194 | } 195 | 196 | ht = header + 1; 197 | 198 | ull64_t ddwDataSize = lt.EvalBufferSize(header->ddwDataBlockNum, 199 | header->ddwDataBlockSize); 200 | 201 | int ret = lt.InitExisting( 202 | ((char *) ht) + (header->ddwHashNodeNum * header->ddwHashNodeSize), 203 | ddwDataSize, header->ddwDataBlockNum, header->ddwDataBlockSize); 204 | if (ret) { 205 | snprintf(errmsg, sizeof(errmsg), "LinkTable Init failed (ret=%d): %s", 206 | ret, lt.GetErrorMsg()); 207 | delete pShmAdpt; 208 | pShmAdpt = NULL; 209 | return -5; 210 | } 211 | 212 | if (HashFunc) 213 | hashfunc = HashFunc; 214 | else 215 | hashfunc = DefaultHashFunc; 216 | return 0; 217 | } 218 | 219 | int MultiHashTable::CreateFromShm(const MhtInitParam &user_param) { 220 | int iret; 221 | MhtInitParam param = user_param; 222 | 223 | if (param.ddwShmKey == 0 224 | || param.ddwBufferSize 225 | < sizeof(MhtHeader) + sizeof(LinkTableHead) + 1024) { 226 | snprintf(errmsg, sizeof(errmsg), 227 | "Bad argument, ShmKey and BufferSize must be given"); 228 | return -1; 229 | } 230 | if (param.cMaxKeyLen == 0) 231 | param.cMaxKeyLen = DEFAULT_MAX_KEY_LENGTH; 232 | if (param.wRowNum == 0) 233 | param.wRowNum = DEFAULT_ROW_NUM; 234 | if (param.dwIndexRatio == 0) 235 | param.dwIndexRatio = DEFAULT_INDEX_RATIO; 236 | if (param.ddwBlockSize == 0) 237 | param.ddwBlockSize = DEFAULT_BLOCK_SIZE; 238 | 239 | if ((iret = InitFromShm(param.ddwShmKey, param.HashFunc)) == 0) // shm exists, check against given parameters 240 | { 241 | if (param.ddwBufferSize != header->ddwTotalShmSize) { 242 | snprintf(errmsg, sizeof(errmsg), 243 | "Shm size mismatched: shm %llu, given %llu", 244 | header->ddwTotalShmSize, param.ddwBufferSize); 245 | return -2; 246 | } 247 | if ((int) param.cMaxKeyLen != GetMaxKeyLen()) { 248 | snprintf(errmsg, sizeof(errmsg), 249 | "Max key length mismatched: shm %d, given %d", 250 | GetMaxKeyLen(), (int) param.cMaxKeyLen); 251 | return -3; 252 | } 253 | if (param.wRowNum != header->ddwRowNum) { 254 | snprintf(errmsg, sizeof(errmsg), 255 | "Hash row num mismatched: shm %llu, given %hu", 256 | header->ddwRowNum, param.wRowNum); 257 | return -4; 258 | } 259 | if (param.ddwBlockSize != header->ddwDataBlockSize) { 260 | snprintf(errmsg, sizeof(errmsg), 261 | "Data block size mismatched: shm %llu, given %llu", 262 | header->ddwDataBlockSize, param.ddwBlockSize); 263 | return -5; 264 | } 265 | return 0; 266 | } 267 | 268 | if (iret && iret != -100) // open existing shm failed 269 | { 270 | return -6; 271 | } 272 | 273 | pShmAdpt = new shm_adapter; 274 | if (pShmAdpt == NULL) { 275 | snprintf(errmsg, sizeof(errmsg), 276 | "Failed to create shm adaptor: Out of memory"); 277 | return -1; 278 | } 279 | 280 | bool ret = pShmAdpt->create(param.ddwShmKey, param.ddwBufferSize, 281 | param.bUseHugePage); 282 | if (ret == false) { 283 | snprintf(errmsg, sizeof(errmsg), "Failed to create shm: %s", 284 | pShmAdpt->get_err_msg().c_str()); 285 | delete pShmAdpt; 286 | pShmAdpt = NULL; 287 | return -2; 288 | } 289 | 290 | void *pBuffer = pShmAdpt->get_shm(); 291 | if (pBuffer == NULL) { 292 | snprintf(errmsg, sizeof(errmsg), 293 | "Bug: shm created successfully but shm pointer is NULL"); 294 | delete pShmAdpt; 295 | pShmAdpt = NULL; 296 | return -3; 297 | } 298 | 299 | return InitFromBuffer(pBuffer, param.ddwBufferSize, param.cMaxKeyLen, 300 | param.wRowNum, param.dwIndexRatio, param.ddwBlockSize, 301 | param.HashFunc, param.bUseAccessSeq); 302 | } 303 | 304 | static bool is_hnode_empty(MhtNode *n) { 305 | return (n->ddwLtPos == 0); 306 | } 307 | 308 | static inline int hnode_cmp(const void *pKey, uint8_t cKeyLen, 309 | const MhtNode *pNode) { 310 | int k; 311 | if ((k = (cKeyLen - pNode->cKeyLen))) 312 | return k; 313 | return memcmp(pKey, pNode->acKey, cKeyLen); 314 | } 315 | 316 | #define HT_GET_AT(ht, idx, ns) (MhtNode *)(((char*)(ht))+(ns)*(idx)) 317 | 318 | // Search and return a node for pKey, if no such key found, returns NULL, optionally 319 | // ppEmptyNode returns the first empty node encountered 320 | // ppOldestNode returns the oldest node in the search path 321 | MhtNode *MultiHashTable::Search(const void *pKey, int iKeyLen, 322 | uint32_t dwHashKey, MhtNode **ppEmptyNode, MhtNode **ppOldestNode, 323 | int *piEmptyRow) { 324 | ull64_t i; 325 | void *pRow; 326 | MhtNode *pNode; 327 | ull64_t ddwMaxRow = header->ddwMaxUsedRow; 328 | ull64_t ddwNodeSize = header->ddwHashNodeSize; 329 | 330 | if (ppEmptyNode) 331 | *ppEmptyNode = NULL; 332 | if (ppOldestNode) 333 | *ppOldestNode = NULL; 334 | 335 | if (ddwMaxRow >= header->ddwRowNum) { 336 | // BUG 337 | Attr_API(358690, 1); 338 | header->ddwMaxUsedRow = header->ddwRowNum - 1; 339 | ddwMaxRow = header->ddwMaxUsedRow; 340 | } 341 | 342 | for (i = 0, pRow = ht; i <= ddwMaxRow; 343 | pRow = HT_GET_AT(pRow, header->auRowsNodeNum[i], ddwNodeSize), i++) { 344 | pNode = HT_GET_AT(pRow, dwHashKey % header->auRowsNodeNum[i], 345 | ddwNodeSize); 346 | if (is_hnode_empty(pNode)) { 347 | if (ppEmptyNode && *ppEmptyNode == NULL) { 348 | if (piEmptyRow) 349 | *piEmptyRow = i; 350 | *ppEmptyNode = pNode; 351 | } 352 | continue; 353 | } 354 | if (dwHashKey == pNode->dwHashKey 355 | && hnode_cmp(pKey, iKeyLen, pNode) == 0) { 356 | return pNode; 357 | } 358 | // keep oldest node 359 | if (ppOldestNode 360 | && (*ppOldestNode == NULL 361 | || (*ppOldestNode)->dwAccessTime > pNode->dwAccessTime)) { 362 | *ppOldestNode = pNode; 363 | } 364 | } 365 | // if no empty is found, return an empty after max row 366 | if (ppEmptyNode && *ppEmptyNode == NULL && i < header->ddwRowNum) { 367 | if (piEmptyRow) 368 | *piEmptyRow = i; 369 | *ppEmptyNode = HT_GET_AT(pRow, dwHashKey % header->auRowsNodeNum[i], 370 | ddwNodeSize); 371 | } 372 | return NULL; 373 | } 374 | 375 | int MultiHashTable::GetData(const void *pKey, int iKeyLen, char *sDataBuf, 376 | int &iDataLen, bool bUpdateAccessTime, time_t *pdwLastAccessTime) { 377 | MhtNode *pDataNode; 378 | 379 | if (pKey == NULL || iKeyLen <= 0 || sDataBuf == NULL || iDataLen < 1) { 380 | snprintf(errmsg, sizeof(errmsg), "Bad argument"); 381 | return -1; 382 | } 383 | if (header == NULL || ht == NULL) { 384 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 385 | return -2; 386 | } 387 | 388 | uint32_t dwHashKey = hashfunc(pKey, iKeyLen); 389 | 390 | pDataNode = Search(pKey, iKeyLen, dwHashKey); 391 | if (pDataNode == NULL) { 392 | iDataLen = 0; 393 | return 0; 394 | } 395 | 396 | // read/update access time before reading 397 | // in order to make sure that if read is successful, access time is also valid and updated 398 | if (pdwLastAccessTime) 399 | *pdwLastAccessTime = pDataNode->dwAccessTime; 400 | if (bUpdateAccessTime) { 401 | if (header->cUseAccessSeq == 0) 402 | pDataNode->dwAccessTime = time(NULL); 403 | else 404 | __sync_fetch_and_add(&pDataNode->dwAccessSeq, 1); 405 | } 406 | 407 | ull64_t ddwLtPos = pDataNode->ddwLtPos; // read the position before conflict detection 408 | 409 | // conflict detection: if key is changed, it must have been replaced by the write process 410 | // if so, returns an error, the caller(or the client) is expected to try again 411 | if (hnode_cmp(pKey, iKeyLen, pDataNode)) { 412 | snprintf(errmsg, sizeof(errmsg), 413 | "Key changed while trying to read, maybe r/w conflicted"); 414 | return -3; 415 | } 416 | 417 | int ret = lt.GetData(ddwLtPos, sDataBuf, iDataLen); 418 | if (ret < 0) { 419 | snprintf(errmsg, sizeof(errmsg), "LinkTable GetData failed: %s", 420 | lt.GetErrorMsg()); 421 | return -4; 422 | } 423 | 424 | return 0; 425 | } 426 | 427 | /* 428 | * erase bad node in mht, used to fix read/write error 429 | * for specific key caused by bug 430 | * FIXME: use with EXTREME CARE! 431 | */ 432 | int MultiHashTable::EraseBadNode(const void *pKey, int iKeyLen) { 433 | MhtNode *pDataNode; 434 | 435 | if (pKey == NULL || iKeyLen <= 0) { 436 | snprintf(errmsg, sizeof(errmsg), "Bad argument"); 437 | return -1; 438 | } 439 | if (header == NULL || ht == NULL) { 440 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 441 | return -2; 442 | } 443 | 444 | uint32_t dwHashKey = hashfunc(pKey, iKeyLen); 445 | 446 | pDataNode = Search(pKey, iKeyLen, dwHashKey); 447 | if (pDataNode == NULL) { 448 | return 0; 449 | } 450 | 451 | memset(pDataNode, 0, sizeof(*pDataNode)); 452 | return 1; 453 | } 454 | 455 | int MultiHashTable::SearchAndEraseOldestOne(MhtNode *pDataNode) { 456 | ull64_t ddwNodeSize = header->ddwHashNodeSize; 457 | MhtNode *oldest = NULL; 458 | uint32_t oldesttime = (uint32_t) - 1; 459 | 460 | ull64_t it = header->ddwEraseIterator; 461 | if (it >= header->ddwHashNodeNum) 462 | it = 0; 463 | 464 | for (int cnt = 0; cnt < 100;) { 465 | MhtNode *n = HT_GET_AT(ht, it, ddwNodeSize); 466 | if (n != pDataNode && !is_hnode_empty(n)) { 467 | if (n->dwAccessTime < oldesttime) { 468 | oldesttime = n->dwAccessTime; 469 | oldest = n; 470 | } 471 | cnt++; 472 | } 473 | 474 | it++; 475 | if (it >= header->ddwHashNodeNum) 476 | it = 0; 477 | 478 | if (it == header->ddwEraseIterator) // we have searched through the whole ht 479 | { 480 | break; 481 | } 482 | } 483 | header->ddwEraseIterator = it; 484 | 485 | if (oldest) // found an oldest 486 | { 487 | if (lt.EraseData(oldest->ddwLtPos) < 0) { 488 | snprintf(errmsg, sizeof(errmsg), "Error: Clear old data failed: %s", 489 | lt.GetErrorMsg()); 490 | return -6; 491 | } 492 | memset(oldest, 0, sizeof(*oldest)); 493 | return 0; 494 | } 495 | snprintf(errmsg, sizeof(errmsg), 496 | "Error: no more index node to be replaced"); 497 | return -7; 498 | } 499 | 500 | int MultiHashTable::SetData(const void *pKey, int iKeyLen, const char *sDataBuf, 501 | int iDataLen, bool bRemoveOldIfNoSpace) { 502 | if (pKey == NULL || iKeyLen <= 0 || sDataBuf == NULL || iDataLen < 0) { 503 | snprintf(errmsg, sizeof(errmsg), "Bad argument"); 504 | return -1; 505 | } 506 | if (header == NULL || ht == NULL) { 507 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 508 | return -2; 509 | } 510 | 511 | int ht_usage = header->ddwMaxUsedRow * 100 / header->ddwRowNum; 512 | if (ht_usage > 50) 513 | Attr_API(358676, 1); 514 | if (ht_usage > 80) 515 | Attr_API(358677, 1); 516 | if (ht_usage > 90) 517 | Attr_API(358678, 1); 518 | if (ht_usage > 95) 519 | Attr_API(358679, 1); 520 | 521 | int ret, emptyrow = 0; 522 | MhtNode *pDataNode, *pEmptyNode = NULL, *pOldestNode = NULL; 523 | uint32_t dwHashKey = hashfunc(pKey, iKeyLen); 524 | ull64_t ddwLtPos; 525 | 526 | ret = pthread_mutex_lock(&mutex); 527 | if (ret < 0) { 528 | Attr_API(391679, 1); 529 | snprintf(errmsg, sizeof(errmsg), "Mutex lock failed: %s", 530 | errnotostr(errno)); 531 | return -3; 532 | } 533 | 534 | pDataNode = Search(pKey, iKeyLen, dwHashKey, &pEmptyNode, &pOldestNode, 535 | &emptyrow); 536 | // erase condition 1: if data used space exceeds 95%, erase the oldest node in the search path 537 | if (bRemoveOldIfNoSpace && pOldestNode && lt.GetUsage() > 95) { 538 | Attr_API(358680, 1); 539 | if ((ret = lt.EraseData(pOldestNode->ddwLtPos)) < 0) { 540 | snprintf(errmsg, sizeof(errmsg), "Error: Clear old data failed: %s", 541 | lt.GetErrorMsg()); 542 | ret = -4; 543 | goto unlock_out; 544 | } 545 | memset(pOldestNode, 0, sizeof(*pOldestNode)); 546 | if (pEmptyNode == NULL) { 547 | pEmptyNode = pOldestNode; 548 | emptyrow = 0; 549 | } 550 | pOldestNode = NULL; // mark being used 551 | } 552 | if (pDataNode == NULL) { 553 | if (pEmptyNode == NULL) { 554 | if (!bRemoveOldIfNoSpace) { 555 | Attr_API(358681, 1); 556 | snprintf(errmsg, sizeof(errmsg), 557 | "Error: Hash table out of space"); 558 | ret = -5; 559 | goto unlock_out; 560 | } 561 | 562 | // erase condition 2: if index node is out of space, erase oldest in the search path 563 | if (pOldestNode == NULL) { 564 | // It is impossible to come here, if it does, there must be a bug in the code 565 | Attr_API(358684, 1); 566 | snprintf(errmsg, sizeof(errmsg), 567 | "Bug: could not find an oldest hash node for erasing."); 568 | ret = -6; 569 | goto unlock_out; 570 | } else // take position of pOldestNode 571 | { 572 | Attr_API(358689, 1); // Removing oldest node 573 | if ((ret = lt.EraseData(pOldestNode->ddwLtPos)) < 0) { 574 | snprintf(errmsg, sizeof(errmsg), 575 | "Error: Clear old data failed: %s", 576 | lt.GetErrorMsg()); 577 | ret = -7; 578 | goto unlock_out; 579 | } 580 | memset(pOldestNode, 0, sizeof(*pOldestNode)); 581 | pEmptyNode = pOldestNode; 582 | emptyrow = 0; 583 | pOldestNode = NULL; // mark being used 584 | } 585 | } 586 | pDataNode = pEmptyNode; 587 | } else { 588 | pEmptyNode = NULL; 589 | } 590 | 591 | do { 592 | ddwLtPos = pDataNode->ddwLtPos; 593 | ret = lt.SetData(ddwLtPos, sDataBuf, iDataLen); 594 | if (ret < 0) { 595 | if (ret != -100) { 596 | snprintf(errmsg, sizeof(errmsg), 597 | "Link table set data failed: %s", lt.GetErrorMsg()); 598 | ret = -8; 599 | goto unlock_out; 600 | } 601 | // Link table has not enough space 602 | if (!bRemoveOldIfNoSpace) { 603 | Attr_API(358691, 1); 604 | snprintf(errmsg, sizeof(errmsg), 605 | "Error: Link table out of space"); 606 | ret = -9; 607 | goto unlock_out; 608 | }Attr_API(358692, 1); // removing old data 609 | if (pOldestNode) { 610 | // ERROR: when free space < 5%, the oldest node should have been erased previously! 611 | Attr_API(358706, 1); 612 | if ((ret = lt.EraseData(pOldestNode->ddwLtPos)) < 0) { 613 | snprintf(errmsg, sizeof(errmsg), 614 | "Error: Clear old data failed: %s", 615 | lt.GetErrorMsg()); 616 | ret = -10; 617 | goto unlock_out; 618 | } 619 | memset(pOldestNode, 0, sizeof(*pOldestNode)); 620 | pOldestNode = NULL; 621 | continue; 622 | } 623 | // erase condition 3: when not enough data space, remove the oldest in a thousand nodes 624 | Attr_API(358707, 1); // removing one oldest in a thousand nodes 625 | if (SearchAndEraseOldestOne(pDataNode)) { 626 | ret = -11; 627 | goto unlock_out; 628 | } 629 | continue; 630 | } 631 | } while (ret < 0); 632 | 633 | pDataNode->ddwLtPos = ddwLtPos; 634 | 635 | // if pEmptyNode is not NULL, it must be same as pDataNode 636 | if (pEmptyNode) // we are storing new node to emptynode 637 | { 638 | pEmptyNode->dwHashKey = dwHashKey; 639 | if (header->cUseAccessSeq == 0) 640 | pDataNode->dwAccessTime = time(NULL); 641 | else 642 | pDataNode->dwAccessSeq = 0; 643 | pEmptyNode->cKeyLen = iKeyLen; 644 | memcpy(pEmptyNode->acKey, pKey, iKeyLen); 645 | if ((ull64_t) emptyrow > header->ddwMaxUsedRow) // inserting data at higher row 646 | { 647 | Attr_API(358708, 1); 648 | header->ddwMaxUsedRow = (ull64_t) emptyrow; 649 | } 650 | } 651 | ret = 0; 652 | unlock_out: if (pthread_mutex_unlock(&mutex) < 0) { 653 | Attr_API(391680, 1); 654 | snprintf(errmsg, sizeof(errmsg), "Mutex unlock failed: %s", 655 | errnotostr(errno)); 656 | } 657 | return ret; 658 | } 659 | 660 | // 661 | // Erase a given key, returns: 662 | // 1 -- erased successfully 663 | // 0 -- no key found 664 | // <0 -- error 665 | // 666 | int MultiHashTable::EraseData(const void *pKey, int iKeyLen) { 667 | if (pKey == NULL || iKeyLen <= 0) { 668 | snprintf(errmsg, sizeof(errmsg), "Bad argument"); 669 | return -1; 670 | } 671 | if (header == NULL || ht == NULL) { 672 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 673 | return -2; 674 | } 675 | 676 | int ret; 677 | MhtNode *pDataNode; 678 | uint32_t dwHashKey = hashfunc(pKey, iKeyLen); 679 | 680 | ret = pthread_mutex_lock(&mutex); 681 | if (ret < 0) { 682 | Attr_API(391679, 1); 683 | snprintf(errmsg, sizeof(errmsg), "Mutex lock failed: %s", 684 | errnotostr(errno)); 685 | return -3; 686 | } 687 | 688 | pDataNode = Search(pKey, iKeyLen, dwHashKey); 689 | if (pDataNode) { 690 | ret = lt.EraseData(pDataNode->ddwLtPos); 691 | if (ret) { 692 | snprintf(errmsg, sizeof(errmsg), "Link table erase failed: %s", 693 | lt.GetErrorMsg()); 694 | ret = -4; 695 | goto unlock_ret; 696 | } 697 | memset(pDataNode, 0, sizeof(*pDataNode)); 698 | ret = 1; 699 | goto unlock_ret; 700 | } 701 | ret = 0; 702 | unlock_ret: if (pthread_mutex_unlock(&mutex) < 0) { 703 | Attr_API(391680, 1); 704 | snprintf(errmsg, sizeof(errmsg), "Mutex unlock failed: %s", 705 | errnotostr(errno)); 706 | } 707 | return ret; 708 | } 709 | 710 | MhtIterator MultiHashTable::Next(MhtIterator it) { 711 | if (header == NULL || ht == NULL) { 712 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 713 | return -1; 714 | } 715 | 716 | ull64_t ddwMaxUsedNode = 717 | header->ddwMaxUsedRow < header->ddwRowNum ? 718 | header->auRowsStartNode[header->ddwMaxUsedRow] 719 | + header->auRowsNodeNum[header->ddwMaxUsedRow] : 720 | header->ddwHashNodeNum; 721 | if (ddwMaxUsedNode > header->ddwHashNodeNum) 722 | ddwMaxUsedNode = header->ddwHashNodeNum; 723 | 724 | ull64_t ddwNodeSize = header->ddwHashNodeSize; 725 | for (it++; it < ddwMaxUsedNode; ++it) { 726 | if (!is_hnode_empty(HT_GET_AT(ht, it, ddwNodeSize))) 727 | return it; 728 | } 729 | return End(); 730 | } 731 | 732 | int MultiHashTable::Get(MhtIterator it, MhtData &data) { 733 | if (header == NULL || ht == NULL) { 734 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 735 | return -1; 736 | } 737 | 738 | MhtNode *pDataNode = HT_GET_AT(ht, it, header->ddwHashNodeSize); 739 | data.klen = pDataNode->cKeyLen; 740 | if (data.klen > HASH_MAX_KEY_LENGTH) 741 | data.klen = HASH_MAX_KEY_LENGTH; 742 | memcpy(data.key, pDataNode->acKey, data.klen); 743 | 744 | data.access_time = pDataNode->dwAccessTime; 745 | 746 | int ret = lt.GetData(pDataNode->ddwLtPos, data.data, *(int*) &(data.dlen = 747 | sizeof(data.data))); 748 | if (ret < 0) { 749 | snprintf(errmsg, sizeof(errmsg), "LinkTable GetData failed: %s", 750 | lt.GetErrorMsg()); 751 | return -2; 752 | } 753 | 754 | return 0; 755 | } 756 | 757 | int MultiHashTable::GetMaxKeyLen() { 758 | if (header == NULL || ht == NULL) { 759 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 760 | return -1; 761 | } 762 | return (int) (header->ddwHashNodeSize - sizeof(MhtNode)); 763 | } 764 | 765 | int MultiHashTable::GetDataBlockSize() { 766 | if (header == NULL || ht == NULL) { 767 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 768 | return -1; 769 | } 770 | return (int) header->ddwDataBlockSize; 771 | } 772 | 773 | int MultiHashTable::GetHashRowNum() { 774 | if (header == NULL || ht == NULL) { 775 | snprintf(errmsg, sizeof(errmsg), "Hash table is not initialized"); 776 | return -1; 777 | } 778 | return (int) header->ddwRowNum; 779 | } 780 | 781 | int MultiHashTable::PrintInfo(const string &prefix) { 782 | if (header == NULL || ht == NULL) { 783 | cout << prefix << "Hash table is not initialized" << endl; 784 | return -1; 785 | } 786 | cout << prefix << "Hash table info:" << endl; 787 | cout << prefix << " ddwTotalShmSize: " << header->ddwTotalShmSize 788 | << endl; 789 | cout << prefix << " ddwHashNodeNum: " << header->ddwHashNodeNum 790 | << endl; 791 | cout << prefix << " ddwHashNodeSize: " << header->ddwHashNodeSize 792 | << endl; 793 | cout << prefix << " ddwDataBlockSize: " << header->ddwDataBlockSize 794 | << endl; 795 | cout << prefix << " ddwDataBlockNum: " << header->ddwDataBlockNum 796 | << endl; 797 | cout << prefix << " ddwRowNum: " << header->ddwRowNum << endl; 798 | for (int i = 0; i < (int) header->ddwRowNum; i++) 799 | cout << prefix << " auRowsNodeNum[" << i << "]:" 800 | << (i < 10 ? " " : (i < 100 ? " " : "")) 801 | << header->auRowsNodeNum[i] << endl; 802 | cout << prefix << " ddwMaxUsedRow: " << header->ddwMaxUsedRow 803 | << endl; 804 | cout << prefix << " ddwEraseIterator: " << header->ddwEraseIterator 805 | << endl; 806 | cout << prefix << "Link table info:" << endl; 807 | lt.PrintInfo(prefix + " "); 808 | return 0; 809 | } 810 | 811 | int MultiHashTable::ReportInfo() { 812 | if (header == NULL || ht == NULL) { 813 | return -1; 814 | } 815 | Attr_API_Set(389153, header->ddwTotalShmSize); 816 | Attr_API_Set(389154, header->ddwHashNodeNum); 817 | Attr_API_Set(389155, header->ddwHashNodeSize); 818 | Attr_API_Set(389156, header->ddwDataBlockSize); 819 | Attr_API_Set(389157, header->ddwDataBlockNum); 820 | Attr_API_Set(389158, header->ddwRowNum); 821 | Attr_API_Set(389159, header->ddwMaxUsedRow); 822 | return lt.ReportInfo(); 823 | } 824 | -------------------------------------------------------------------------------- /src/linktable/LinkTable.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | FILENAME: LinkTable.c 4 | 5 | DESCRIPTION: 数组索引+链表方式内存接口定义 6 | 7 | LinkTable的数据结构: 8 | IndexHeadList -- 一级索引表,也是主索引表,通过主索引Index(或者叫Unit)可以索引到二级索引表的起始位置 9 | IndexNodeList -- 二级索引表,也是次索引表,以主索引和次索引Offset共同索引Key(UIN)在ElementList中的下标 10 | ElementList -- 元素数组 11 | 12 | 注意: 13 | LinkTable有两类Index 14 | 1, 外部看到的Index,就是UDC的UnitID,从0开始,记为dwIndex 15 | 2, 内部看到的Index=UnitID+1,写作idx 16 | 所有API的Index参数都是外部Index,也就是UnitID 17 | 18 | ******************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | #include "common.h" 31 | #include "oi_shm.h" 32 | #include "oi_str2.h" 33 | #include "Attr_API.h" 34 | #include "oi_debug.h" 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #include "LinkTableDefine.h" 40 | #include "LinkTable.h" 41 | 42 | #ifdef ELEMENT_DATABUF_LEN 43 | #undef ELEMENT_DATABUF_LEN 44 | #endif 45 | #define ELEMENT_DATABUF_LEN(pTable) (pTable->pstTableHead->ddwElementSize - (unsigned long)(((Element*)0)->bufData)) 46 | 47 | int iMaxLtNum = 0; 48 | volatile LinkTable g_stTables[MAX_LT_NUM]; 49 | 50 | static int compare_indexid(const void *pa, const void *pb) { 51 | const IndexHead *a, *b; 52 | 53 | a = (const IndexHead *) pa; 54 | b = (const IndexHead *) pb; 55 | 56 | return a->ddwIndexId - b->ddwIndexId; 57 | } 58 | 59 | static int InsertIndexHead(volatile LinkTable *pTable, uint64_t idx, 60 | IndexHead *base, size_t nmemb, size_t nmaxmemb, IndexHead **ppPtr, 61 | int createFlag) { 62 | IndexHead ih; 63 | IndexHead *pSearch = NULL; 64 | 65 | int iEqual = 0; 66 | 67 | if (idx == 0 || base == NULL || nmaxmemb == 0 || pTable == NULL 68 | || pTable->pstTableHead == NULL) { 69 | return -1; 70 | } 71 | 72 | ih.ddwIndexId = idx; 73 | ih.iIndex = 0; 74 | 75 | pSearch = (IndexHead *) my_bsearch(&ih, base, nmemb, sizeof(IndexHead), 76 | &iEqual, compare_indexid); 77 | if (pSearch && iEqual) { 78 | if (ppPtr) { 79 | *ppPtr = pSearch; 80 | } 81 | return 0; 82 | } 83 | 84 | if (createFlag == 0 || 85 | // If IndexIds are loaded at init time, no further modification is allowed 86 | pTable->pstTableHead->bLockedIndexIds) { 87 | return -2; 88 | } 89 | 90 | if ((nmaxmemb - nmemb) < 1) { 91 | return -2; //特殊的返回码,注意保持 92 | } 93 | 94 | if (pSearch) { 95 | int iIndex = base[nmemb].iIndex; 96 | 97 | // move one element forwards 98 | memmove(pSearch + 1, pSearch, 99 | ((unsigned long) (base + nmemb)) - ((unsigned long) pSearch)); 100 | 101 | pSearch->iIndex = iIndex; 102 | } else { 103 | pSearch = base + nmemb; 104 | } 105 | 106 | pSearch->ddwIndexId = idx; 107 | 108 | // Can index go insane? 109 | if (pSearch->iIndex < 0 || (size_t) pSearch->iIndex >= nmaxmemb) { 110 | // BUG: insane index 111 | Attr_API(162204, 1); 112 | pSearch->iIndex = nmemb; 113 | } 114 | 115 | if (ppPtr) 116 | *ppPtr = pSearch; 117 | 118 | return 1; 119 | } 120 | 121 | static uint64_t CalShmSize(uint64_t ddwIndexCount, uint64_t ddwIndexRowCount, 122 | uint64_t ddwElementCount, uint64_t ddwElementSize) { 123 | uint64_t ddwShmSize = (sizeof(LinkTableHead) 124 | + sizeof(IndexHead) * ddwIndexCount 125 | + sizeof(IndexNode) * ddwIndexCount * ddwIndexRowCount 126 | + ddwElementSize * ddwElementCount); 127 | 128 | // 2M 对齐 129 | return (ddwShmSize + (2UL << 20) - 1) & (~((2UL << 20) - 1)); 130 | } 131 | 132 | // 这里重写一下,支持unsigned size,不打印出错,不mlock 133 | static void *LT_GetShm(int iKey, uint64_t ddwSize, int iFlag) { 134 | int iShmID; 135 | char *sShm; 136 | 137 | if ((iShmID = shmget(iKey, ddwSize, iFlag)) < 0) 138 | return 0; 139 | 140 | if ((sShm = (char *) shmat(iShmID, NULL, 0)) == (char *) -1) 141 | return 0; 142 | 143 | return sShm; 144 | } 145 | 146 | static char *CreateLinkTableShm(int iKey, uint64_t ddwShmSize, 147 | uint64_t ddwIndexCount, uint64_t ddwIndexRowCount, 148 | uint64_t ddwElementCount, uint64_t ddwElementSize) { 149 | unsigned long u, hdrsize = sizeof(LinkTableHead) 150 | + sizeof(IndexHead) * ddwIndexCount; 151 | LinkTableHead *pTableHead; 152 | 153 | pTableHead = (LinkTableHead *) GetShm(iKey, ddwShmSize, 154 | 0666 | IPC_CREAT | SHM_HUGETLB); 155 | if (pTableHead == NULL) 156 | return 0; 157 | 158 | memset(pTableHead, 0, hdrsize); 159 | 160 | // The first element is reserved 161 | pTableHead->ddwAllElementCount = ddwElementCount - 1; 162 | pTableHead->ddwFreeElementCount = ddwElementCount - 1; 163 | pTableHead->ddwElementSize = ddwElementSize; 164 | pTableHead->ddwIndexCount = ddwIndexCount; 165 | pTableHead->ddwIndexRowCount = ddwIndexRowCount; 166 | pTableHead->dwPreFreePoolSize = LT_DEF_PREFREE_POOL_SIZE; 167 | pTableHead->ddwLastEmpty = 1; 168 | 169 | // 初始化索引值为自身所在的索引 170 | for (u = 0; u < ddwIndexCount; u++) 171 | ((IndexHead *) (pTableHead + 1))[u].iIndex = (int) u; 172 | 173 | // memset大共享内存会比较耗时,初始化表头后再执行 174 | memset(((char*) pTableHead) + hdrsize, 0, ddwShmSize - hdrsize); 175 | return (char*) pTableHead; 176 | } 177 | 178 | static int VerifyLinkTableParam(LinkTableHead *pTableHead, 179 | uint64_t ddwIndexCount, uint64_t ddwIndexRowCount, 180 | uint64_t ddwElementCount, uint64_t ddwElementSize, int nodisp) { 181 | if ((pTableHead->ddwAllElementCount != (ddwElementCount - 1)) 182 | || (pTableHead->ddwIndexCount != ddwIndexCount) 183 | || (pTableHead->ddwIndexRowCount != ddwIndexRowCount) 184 | || (pTableHead->ddwElementSize != ddwElementSize)) { 185 | if (!nodisp) { 186 | printf("Error: shm parameters mismatched: \n"); 187 | printf("\tdwIndexCount: given %llu, got %llu\n", ddwIndexCount, 188 | pTableHead->ddwIndexCount); 189 | printf("\tdwIndexRwCnt: given %llu, got %llu\n", ddwIndexRowCount, 190 | pTableHead->ddwIndexRowCount); 191 | printf("\tdwElementCnt: given %llu, got %llu\n", ddwElementCount, 192 | pTableHead->ddwAllElementCount + 1); 193 | printf("\tdwElementSz: given %llu, got %llu\n", ddwElementSize, 194 | pTableHead->ddwElementSize); 195 | } 196 | return -1; 197 | } 198 | 199 | return 0; 200 | } 201 | 202 | // 验证SHM中的参数与配置的参数是否一致,不一致则返回失败 203 | // 返回值: 0 不存在 1 存在且参数合法 -1 参数错误 204 | static int VerifyLinkTableSize(uint64_t ddwIndexCount, 205 | uint64_t ddwIndexRowCount, uint64_t ddwElementCount, 206 | uint64_t ddwElementSize, int iKey, int nodisp) { 207 | LinkTableHead *pTableHead; 208 | int iRet; 209 | 210 | pTableHead = (LinkTableHead *) LT_GetShm(iKey, 211 | sizeof(LinkTable) + sizeof(LinkTableHead), 0666); 212 | if (pTableHead == 0) // shm does not exist 213 | return 0; 214 | 215 | iRet = VerifyLinkTableParam(pTableHead, ddwIndexCount, ddwIndexRowCount, 216 | ddwElementCount, ddwElementSize, nodisp); 217 | shmdt(pTableHead); 218 | 219 | if (iRet < 0) 220 | return -1; 221 | 222 | return 1; 223 | } 224 | 225 | static void RecycleAllPreFreeElements(volatile LinkTable *pTable); 226 | 227 | int LtInit(uint32_t dwIndexCount, uint64_t ddwIndexRowCount, 228 | uint64_t ddwElementCount, uint64_t ddwElementSize, int iKey, 229 | int iCreateFlag, int nodisp) { 230 | char * pTable = NULL; 231 | volatile LinkTable *pLT; 232 | uint64_t ddwShmSize; 233 | int iVerifyResult; 234 | 235 | if (iMaxLtNum >= MAX_LT_NUM) { 236 | fprintf(stderr, "Max linktable num reached.\n"); 237 | return -1; 238 | } 239 | 240 | pLT = &g_stTables[iMaxLtNum]; 241 | 242 | if (dwIndexCount < 10 || ddwIndexRowCount < 100 || ddwElementCount < 1000 243 | || ddwElementSize < 10 || ddwElementSize > MAX_ELEMENT_SIZE 244 | || (iCreateFlag != 0 && iCreateFlag != 1)) { 245 | fprintf(stderr, 246 | "Invalid parameters: " 247 | "ddwIndexCount=%u, ddwIndexRowCount=%llu, ddwElementCount=%llu, ddwElementSize=%llu(max=%llu), iCreateFlag=%d\n", 248 | dwIndexCount, ddwIndexRowCount, ddwElementCount, ddwElementSize, 249 | (uint64_t)MAX_ELEMENT_SIZE, iCreateFlag); 250 | return -1; 251 | } 252 | 253 | ddwShmSize = CalShmSize(dwIndexCount, ddwIndexRowCount, ddwElementCount, 254 | ddwElementSize); 255 | #if 0 256 | printf("dwIndexCount=%u, ddwIndexRowCount=%llu, ddwElementCount=%llu, ddwElementSize=%llu, shmsize=%lluU=%lldS\n", 257 | dwIndexCount, ddwIndexRowCount, ddwElementCount, ddwElementSize, ddwShmSize, (int64_t)ddwShmSize); 258 | #endif 259 | 260 | if (ddwShmSize == 0 || ddwShmSize > MAX_SHM_SIZE) { 261 | fprintf(stderr, "Invalid shm size %llu (max=%lu)\n", ddwShmSize, 262 | MAX_SHM_SIZE); 263 | return -2; 264 | } 265 | 266 | iVerifyResult = VerifyLinkTableSize(dwIndexCount, ddwIndexRowCount, 267 | ddwElementCount, ddwElementSize, iKey, nodisp); 268 | if (iVerifyResult < 0) { 269 | if (!nodisp) 270 | fprintf(stderr, "VerifyLinkTableSize() returns %d.\n", 271 | iVerifyResult); 272 | return -10; // DONOT changed this return value, it is used by the process init() for retry 273 | } 274 | if (iVerifyResult == 0) 275 | printf("LinkTable shm does not exist yet.\n"); 276 | 277 | if (iCreateFlag == 1 && iVerifyResult == 0) 278 | pTable = (char*) CreateLinkTableShm(iKey, ddwShmSize, dwIndexCount, 279 | ddwIndexRowCount, ddwElementCount, ddwElementSize); 280 | else 281 | pTable = GetShm(iKey, ddwShmSize, 0666); 282 | 283 | if (pTable == NULL) { 284 | if (!nodisp) 285 | fprintf(stderr, "Attach shm key=%u, size=%llu failed.\n", iKey, 286 | ddwShmSize); 287 | return -20; // DONOT changed 288 | } 289 | 290 | if (mlock(pTable, ddwShmSize) != 0) { 291 | shmdt(pTable); 292 | perror("mlock fail"); 293 | return -3; 294 | } 295 | 296 | pLT->pstTableHead = (LinkTableHead*) pTable; 297 | pLT->pstIndexHeadList = (IndexHead *) (pTable + sizeof(LinkTableHead)); 298 | pLT->pstIndexNodeList = (IndexNode *) (pTable + sizeof(LinkTableHead) 299 | + sizeof(IndexHead) * dwIndexCount); 300 | pLT->pstElementList = (Element *) (pTable + sizeof(LinkTableHead) 301 | + sizeof(IndexHead) * dwIndexCount 302 | + sizeof(IndexNode) * dwIndexCount * ddwIndexRowCount); 303 | 304 | // Reverify anyway 305 | if (VerifyLinkTableParam(pLT->pstTableHead, dwIndexCount, ddwIndexRowCount, 306 | ddwElementCount, ddwElementSize, nodisp)) { 307 | shmdt(pTable); 308 | memset((void*) pLT, 0, sizeof(*pLT)); 309 | return -4; 310 | } 311 | 312 | // 程序启动时将预回收池中的所有元素回收掉 313 | if (iCreateFlag == 1) 314 | RecycleAllPreFreeElements(pLT); 315 | 316 | return iMaxLtNum++; 317 | } 318 | 319 | // 如果pstIndexHeadList为空,则将LinkTable的pstIndexHeadList初始化为相应的UnitList 320 | // 否则,比较pstIndexHeadList和dwIndexList,如果不相对应则返回失败 321 | // ddwIndexList必须是已经排好序的 322 | // 成功返回0,否则返回负数 323 | int LtSetIndexes(int lt, uint32_t dwIndexList[], int iIndexNum) { 324 | int i; 325 | volatile LinkTable *pTable = GET_LT(lt); 326 | 327 | if (pTable == NULL || pTable->pstTableHead == NULL || dwIndexList == NULL 328 | || iIndexNum < 0 329 | || iIndexNum > (int) pTable->pstTableHead->ddwIndexCount) 330 | return -1; 331 | 332 | // 检查 ddwIndexList是否已经排好序 333 | for (i = 0; i < iIndexNum - 1; i++) { 334 | if (dwIndexList[i] >= dwIndexList[i + 1]) 335 | return -2; 336 | } 337 | 338 | if (pTable->pstTableHead->ddwUsedIndexCount > 0) // IndexHeadList不为空 339 | { 340 | if (pTable->pstTableHead->ddwUsedIndexCount != (uint64_t) iIndexNum) 341 | return -3; 342 | 343 | for (i = 0; i < iIndexNum; i++) { 344 | // IndexId has changed 345 | if (pTable->pstIndexHeadList[i].ddwIndexId 346 | != (uint64_t)(dwIndexList[i] + 1)) 347 | return -4; 348 | 349 | // Index has changed 350 | if (pTable->pstIndexHeadList[i].iIndex != i) 351 | return -5; 352 | } 353 | } else // IndexHeadList为空 354 | { 355 | for (i = 0; i < iIndexNum; i++) { 356 | pTable->pstIndexHeadList[i].iIndex = i; 357 | pTable->pstIndexHeadList[i].ddwIndexId = dwIndexList[i] + 1; 358 | } 359 | for (; i < (int) pTable->pstTableHead->ddwIndexCount; i++) { 360 | pTable->pstIndexHeadList[i].iIndex = i; 361 | pTable->pstIndexHeadList[i].ddwIndexId = 0; 362 | } 363 | pTable->pstTableHead->ddwUsedIndexCount = iIndexNum; 364 | 365 | // From now on, pstIndexHeadList should not be changed 366 | pTable->pstTableHead->bLockedIndexIds = 1; 367 | } 368 | 369 | return 0; 370 | } 371 | 372 | static int GetIndexHead(volatile LinkTable *pTable, uint64_t idx, 373 | IndexHead **ppih, int createFlag) { 374 | int ret; 375 | if (ppih == NULL) 376 | return -1; 377 | 378 | if (pTable->pstTableHead->ddwUsedIndexCount 379 | > pTable->pstTableHead->ddwIndexCount) { 380 | Attr_API(162204, 1); 381 | return -2; // BUG: index goes insane 382 | } 383 | 384 | ret = InsertIndexHead(pTable, idx, pTable->pstIndexHeadList, 385 | pTable->pstTableHead->ddwUsedIndexCount, 386 | pTable->pstTableHead->ddwIndexCount, ppih, createFlag); 387 | 388 | if (ret < 0 || *ppih == NULL) 389 | // createFlag=1: 没有空间了,需要马上扩容 390 | // createFlag=0: 找不到 391 | { 392 | return -3; 393 | } else if (ret == 0) // 找到存在的了 394 | { 395 | } else // 找不到,增加新的 396 | { 397 | pTable->pstTableHead->ddwUsedIndexCount++; 398 | } 399 | return ret; 400 | } 401 | 402 | static int RecycleElement(volatile LinkTable *pTable, uint64_t ddwStartPos) { 403 | uint64_t ddwCurPos = 0, ddwNextPos = 0; 404 | int iCount = 0; 405 | 406 | Attr_API(241995, 1); 407 | 408 | if (pTable == NULL || pTable->pstTableHead == NULL) { 409 | return -10; 410 | } 411 | 412 | if ((ddwStartPos == 0) 413 | || (ddwStartPos >= pTable->pstTableHead->ddwAllElementCount)) { 414 | // Position gone insane 415 | Attr_API(161639, 1); 416 | return -2; 417 | } 418 | 419 | ddwNextPos = ddwStartPos; 420 | while ((ddwNextPos) && (iCount <= MAX_BLOCK_COUNT)) { 421 | ddwCurPos = ddwNextPos; 422 | if (ddwCurPos >= pTable->pstTableHead->ddwAllElementCount) { 423 | // Position gone insane 424 | Attr_API(161639, 1); 425 | return -3; 426 | } 427 | 428 | ddwNextPos = LT_ELE_AT(pTable,ddwCurPos)->ddwNext; 429 | memset(LT_ELE_AT(pTable, ddwCurPos), 0, 430 | pTable->pstTableHead->ddwElementSize); 431 | 432 | // 把节点放入Free列表中 433 | LT_ELE_AT(pTable,ddwCurPos)->ddwNext = 434 | pTable->pstTableHead->ddwFirstFreePos; 435 | pTable->pstTableHead->ddwFirstFreePos = ddwCurPos; 436 | 437 | pTable->pstTableHead->ddwFreeElementCount++; 438 | iCount++; 439 | } 440 | 441 | if (ddwNextPos != 0) { 442 | // Too many blocks 443 | Attr_API(161640, 1); 444 | return -4; 445 | } 446 | 447 | return 0; 448 | } 449 | 450 | // 预回收池的主要算法实现: 451 | // 用一个游标dwPreFreeIndex循环遍历预回收池指针数组addwPreFreePool,没次预回收遍历一个指针, 452 | // 将本次希望回收的起始地址挂到addwPreFreePool[ddwPreFreeIndex]上,并回收上次挂到这的地方的元素链表 453 | static int PreRecycleElement(volatile LinkTable *pTable, uint64_t ddwStartPos) { 454 | int iRet; 455 | uint64_t ddwOldPos, ddwIdx; 456 | 457 | Attr_API(241972, 1); 458 | 459 | ddwIdx = pTable->pstTableHead->ddwPreFreeIndex; 460 | if (ddwIdx >= pTable->pstTableHead->dwPreFreePoolSize) { 461 | Attr_API(241911, 1); 462 | ddwIdx = 0; 463 | pTable->pstTableHead->ddwPreFreeIndex = 0; 464 | } 465 | 466 | // 先放到预回收池中,再回收同个位置中的旧数据 467 | ddwOldPos = pTable->pstTableHead->addwPreFreePool[ddwIdx]; 468 | pTable->pstTableHead->addwPreFreePool[ddwIdx] = ddwStartPos; 469 | pTable->pstTableHead->ddwPreFreeIndex = (ddwIdx + 1) 470 | % pTable->pstTableHead->dwPreFreePoolSize; 471 | 472 | if (ddwOldPos) { 473 | iRet = RecycleElement(pTable, ddwOldPos); 474 | if (iRet < 0) { 475 | // 如果回收失败,将导致单元不能被重新利用,这里只上报,不处理 476 | Attr_API(241914, 1); 477 | } 478 | } 479 | 480 | return 0; 481 | } 482 | 483 | // 回收全部预回收池中的元素 484 | static void RecycleAllPreFreeElements(volatile LinkTable *pTable) { 485 | int i, nr = 0; 486 | 487 | for (i = 0; i < (int) pTable->pstTableHead->dwPreFreePoolSize; i++) { 488 | if (pTable->pstTableHead->addwPreFreePool[i]) { 489 | int iRet; 490 | 491 | if (nr++ == 0) // 第一次执行回收操作就上报 492 | Attr_API(241908, 1); 493 | 494 | iRet = RecycleElement(pTable, 495 | pTable->pstTableHead->addwPreFreePool[i]); 496 | if (iRet < 0) { 497 | // 如果回收失败,将导致单元不能被重新利用,这里只上报,不处理 498 | Attr_API(241914, 1); 499 | } 500 | 501 | pTable->pstTableHead->addwPreFreePool[i] = 0; 502 | } 503 | } 504 | 505 | pTable->pstTableHead->ddwPreFreeIndex = 0; 506 | } 507 | 508 | int LtSetPrefreePoolSize(int lt, int sz) { 509 | volatile LinkTable *pTable = GET_LT(lt); 510 | 511 | if (pTable == NULL || pTable->pstTableHead == NULL) { 512 | return -10; 513 | } 514 | if (sz <= 0 || (unsigned long) sz > LT_MAX_PREFREE_POOL_SIZE) { 515 | return -20; 516 | } 517 | RecycleAllPreFreeElements(pTable); 518 | pTable->pstTableHead->dwPreFreePoolSize = (unsigned int) sz; 519 | return 0; 520 | } 521 | 522 | //使用数组方式管理自由空间,分配和使用自由空间采用步进方式 523 | static int GetEmptyElement(volatile LinkTable *pTable, int iCount, 524 | uint64_t *pddwStartPos) { 525 | uint64_t ddwStartPos, ddwCurPos; 526 | int i, j, iTrySecond = 0; 527 | float fUsedRate; 528 | 529 | if (pTable == NULL || pTable->pstTableHead == NULL) { 530 | return -1; 531 | } 532 | 533 | // 只要空闲块数小于预设比例就告警 534 | fUsedRate = (pTable->pstTableHead->ddwFreeElementCount * 100.0 535 | / pTable->pstTableHead->ddwAllElementCount); 536 | if (fUsedRate < 20.0) 537 | Attr_API(178992, 1); 538 | if (fUsedRate < 15.0) 539 | Attr_API(232399, 1); 540 | if (fUsedRate < 10.0) 541 | Attr_API(241997, 1); 542 | if (fUsedRate < 5.0) 543 | Attr_API(242000, 1); 544 | 545 | restart: if (iTrySecond) // 清空预回收池后重新分配 546 | Attr_API(242023, 1); 547 | 548 | if ((iCount < 0) || (pddwStartPos == NULL) || (iCount > MAX_BLOCK_COUNT) 549 | || (iCount > (int) pTable->pstTableHead->ddwFreeElementCount)) { 550 | // Not enough space 551 | if (iTrySecond == 0) { 552 | iTrySecond = 1; 553 | RecycleAllPreFreeElements(pTable); 554 | goto restart; 555 | } 556 | Attr_API(161647, 1); 557 | return -2; 558 | } 559 | 560 | // 先从Free列表搜索,搜不到再挨个搜索 561 | ddwStartPos = 0; 562 | ddwCurPos = pTable->pstTableHead->ddwFirstFreePos; 563 | i = 0; 564 | while (i < iCount && ddwCurPos > 0 565 | && ddwCurPos < pTable->pstTableHead->ddwAllElementCount && 566 | LT_ELE_AT(pTable,ddwCurPos)->ddwKey == 0) { 567 | uint64_t ddwNext; 568 | i++; 569 | ddwNext = LT_ELE_AT(pTable,ddwCurPos)->ddwNext; 570 | if (i == iCount) // 把最后一个的Next置零 571 | LT_ELE_AT(pTable,ddwCurPos)->ddwNext = 0; 572 | ddwCurPos = ddwNext; 573 | } 574 | 575 | if (i == iCount) // 找到了 576 | { 577 | *pddwStartPos = pTable->pstTableHead->ddwFirstFreePos; 578 | pTable->pstTableHead->ddwFirstFreePos = ddwCurPos; 579 | Attr_API(178921, 1); 580 | if (iTrySecond) 581 | Attr_API(242024, 1); 582 | return 0; 583 | } 584 | 585 | // FIXME:这里存在一个不是很重要的问题:就是当从Free链表中找到一些节点,但无法满足请求的需要, 586 | // 这时需要通过遍历搜索来分配,而遍历搜索可能会找到free链表中的节点,这将导致free链表中的节点被 587 | // 遍历分配了,使得Free链表断链,断链后的链表就只能由遍历分配器来分配了 588 | 589 | // 从pstTableHead->ddwLastEmpty开始进行挨个搜索 590 | ddwStartPos = 0; 591 | ddwCurPos = pTable->pstTableHead->ddwLastEmpty; 592 | i = 0; 593 | for (j = 0; 594 | (i < iCount) && (j < (int) pTable->pstTableHead->ddwAllElementCount); 595 | j++) { 596 | if (LT_ELE_AT(pTable,ddwCurPos)->ddwKey == 0) { 597 | LT_ELE_AT(pTable,ddwCurPos)->ddwNext = ddwStartPos; 598 | ddwStartPos = ddwCurPos; 599 | i++; 600 | } 601 | ddwCurPos++; 602 | 603 | // Wrap around 604 | if (ddwCurPos >= pTable->pstTableHead->ddwAllElementCount) { 605 | ddwCurPos = 1; 606 | } 607 | } 608 | 609 | if (i < iCount) { 610 | // Not enough space 611 | if (iTrySecond == 0) { 612 | iTrySecond = 1; 613 | RecycleAllPreFreeElements(pTable); 614 | goto restart; 615 | } 616 | Attr_API(161647, 1); 617 | return -4; 618 | } 619 | 620 | *pddwStartPos = ddwStartPos; 621 | pTable->pstTableHead->ddwLastEmpty = ddwCurPos; 622 | Attr_API(178922, 1); 623 | if (iTrySecond) 624 | Attr_API(242024, 1); 625 | return 0; 626 | } 627 | 628 | inline int TranslateIndexId(volatile LinkTable *pTable, uint64_t ddwKey, 629 | uint64_t *pidx) { 630 | if (pTable == NULL || pTable->pstTableHead == NULL || pidx == NULL) { 631 | return -10; 632 | } 633 | 634 | *pidx = (ddwKey / pTable->pstTableHead->ddwIndexRowCount + 1); 635 | return 0; 636 | } 637 | 638 | inline int TranslateIndexOffset(volatile LinkTable *pTable, uint64_t ddwKey, 639 | uint64_t *poffset) { 640 | if (pTable == NULL || pTable->pstTableHead == NULL || poffset == NULL) { 641 | return -10; 642 | } 643 | 644 | *poffset = ddwKey % pTable->pstTableHead->ddwIndexRowCount; 645 | return 0; 646 | } 647 | 648 | static int GetIndexNode(volatile LinkTable *pTable, uint64_t ddwKey, 649 | IndexNode **ppIndexNode, int createFlag) { 650 | uint64_t idx = 0, offset = 0; 651 | IndexHead *pih = NULL; 652 | 653 | if (pTable == NULL || pTable->pstTableHead == NULL) { 654 | return -10; 655 | } 656 | 657 | TranslateIndexId(pTable, ddwKey, &idx); 658 | TranslateIndexOffset(pTable, ddwKey, &offset); 659 | 660 | GetIndexHead(pTable, idx, &pih, createFlag); 661 | 662 | if (pih) 663 | *ppIndexNode = &(pTable->pstIndexNodeList[pih->iIndex 664 | * pTable->pstTableHead->ddwIndexRowCount + offset]); 665 | else 666 | *ppIndexNode = NULL; 667 | 668 | return 0; 669 | } 670 | 671 | //取得用户数据 672 | /* 673 | <0:错误 674 | =0:找到数据 675 | >0:不存在 676 | */ 677 | int LtGetData(int lt, uint64_t ddwKey, char *sDataBuf, int *piDataLen) { 678 | IndexNode *pIndexNode = NULL; 679 | uint64_t ddwCurPos = 0, ddwNextPos = 0; 680 | int iRet = 0; 681 | int iDataLen = 0, iBufLen = 0; 682 | volatile LinkTable *pTable = GET_LT(lt); 683 | 684 | if (pTable == NULL || pTable->pstTableHead == NULL) { 685 | return -10; 686 | } 687 | 688 | if (sDataBuf == NULL || piDataLen == NULL) { 689 | return -1; 690 | } 691 | 692 | iBufLen = *piDataLen; 693 | *piDataLen = 0; 694 | if (iBufLen < (int) ELEMENT_DATABUF_LEN(pTable)) { 695 | return -2; 696 | } 697 | 698 | iRet = GetIndexNode(pTable, ddwKey, &pIndexNode, 0); // do not create 699 | if (iRet < 0) { 700 | return -3; 701 | } 702 | 703 | //index不存在或者未初始化返回不存在 704 | if ((pIndexNode == NULL) || (pIndexNode->cFlag == 0)) { 705 | return 1; 706 | } 707 | 708 | ddwNextPos = pIndexNode->ddwPosition; 709 | while (ddwNextPos) { 710 | ddwCurPos = ddwNextPos; 711 | if (ddwCurPos >= pTable->pstTableHead->ddwAllElementCount) { 712 | Attr_API(161639, 1); 713 | return -21; 714 | } 715 | if ((iDataLen + (int) ELEMENT_DATABUF_LEN(pTable)) > iBufLen) { 716 | Attr_API(161640, 1); 717 | return -4; 718 | } 719 | if (LT_ELE_AT(pTable,ddwCurPos)->ddwKey != ddwKey) { 720 | Attr_API(161641, 1); 721 | return -5; 722 | } 723 | memcpy(sDataBuf + iDataLen, LT_ELE_AT(pTable,ddwCurPos)->bufData, 724 | ELEMENT_DATABUF_LEN(pTable)); 725 | iDataLen += ELEMENT_DATABUF_LEN(pTable); 726 | ddwNextPos = LT_ELE_AT(pTable,ddwCurPos)->ddwNext; 727 | } 728 | *piDataLen = iDataLen; 729 | 730 | return 0; 731 | } 732 | 733 | int LtPrintData(int lt, uint64_t ddwKey) { 734 | IndexNode *pIndexNode = NULL; 735 | uint64_t ddwCurPos = 0, ddwNextPos = 0; 736 | int iRet = 0; 737 | volatile LinkTable *pTable = GET_LT(lt); 738 | 739 | if (pTable == NULL || pTable->pstTableHead == NULL) { 740 | return -10; 741 | } 742 | 743 | iRet = GetIndexNode(pTable, ddwKey, &pIndexNode, 0); 744 | if (iRet < 0) { 745 | return -20; 746 | } 747 | 748 | //index不存在或者未初始化返回不存在 749 | if ((pIndexNode == NULL) || (pIndexNode->cFlag == 0)) { 750 | if (pIndexNode == NULL) 751 | printf("No index node found.\n"); 752 | else 753 | printf("cFlag is zero, ddwPosition=%lu.\n", 754 | (unsigned long) pIndexNode->ddwPosition); 755 | return 11; 756 | } 757 | 758 | ddwNextPos = pIndexNode->ddwPosition; 759 | printf("ddwPosition=%llu, ddwKey=%llu\n", ddwNextPos, ddwKey); 760 | while (ddwNextPos) { 761 | ddwCurPos = ddwNextPos; 762 | printf("ddwCurPos=%llu, ddwKey=%llu", ddwCurPos, 763 | LT_ELE_AT(pTable,ddwCurPos)->ddwKey); 764 | printf("\n%s", 765 | DumpMemory(LT_ELE_AT(pTable,ddwCurPos)->bufData, 0, 766 | ELEMENT_DATABUF_LEN(pTable))); 767 | ddwNextPos = LT_ELE_AT(pTable,ddwCurPos)->ddwNext; 768 | } 769 | 770 | return 0; 771 | } 772 | 773 | //设置数据,如果存在删除已有数据 774 | int LtSetData(int lt, uint64_t ddwKey, char *sDataBuf, int iDataLen) { 775 | IndexNode *pIndexNode = NULL; 776 | uint64_t ddwCurPos = 0, ddwNextPos = 0, ddwStartPos = 0, ddwOldPos = 0; 777 | int iCount = 0, iLeftLen = 0, iCopyLen = 0; 778 | int iRet = 0; 779 | volatile LinkTable *pTable = GET_LT(lt); 780 | 781 | if (pTable == NULL || pTable->pstTableHead == NULL) { 782 | return -10; 783 | } 784 | 785 | if (sDataBuf == NULL || iDataLen < 0) { 786 | return -1; 787 | } 788 | 789 | iCount = (iDataLen + ELEMENT_DATABUF_LEN(pTable) - 1) 790 | / ELEMENT_DATABUF_LEN(pTable); 791 | if (iCount > MAX_BLOCK_COUNT) { 792 | return -2; 793 | } 794 | 795 | //创建或取得 IndexNode 796 | iRet = GetIndexNode(pTable, ddwKey, &pIndexNode, 1); // create if not found 797 | if (iRet < 0) { 798 | return -3; 799 | } 800 | 801 | if (pIndexNode == NULL) //IndexHeadList空间不够,需要扩容 802 | { 803 | // 出现这种情况,很有可能是传入了非法的 UIN 所致 804 | return -4; 805 | } 806 | 807 | //先构造新数据 808 | iRet = GetEmptyElement(pTable, iCount, &ddwStartPos); 809 | if (iRet < 0) { 810 | return -7; 811 | } 812 | 813 | ddwNextPos = ddwStartPos; 814 | iLeftLen = iDataLen - iCopyLen; 815 | while ((ddwNextPos) && (iLeftLen > 0)) { 816 | ddwCurPos = ddwNextPos; 817 | if (ddwCurPos >= pTable->pstTableHead->ddwAllElementCount) { 818 | Attr_API(161639, 1); 819 | return -8; 820 | } 821 | 822 | if (iLeftLen > (int) ELEMENT_DATABUF_LEN(pTable)) { 823 | memcpy(LT_ELE_AT(pTable,ddwCurPos)->bufData, sDataBuf + iCopyLen, 824 | ELEMENT_DATABUF_LEN(pTable)); 825 | iCopyLen += ELEMENT_DATABUF_LEN(pTable); 826 | } else { 827 | memcpy(LT_ELE_AT(pTable,ddwCurPos)->bufData, sDataBuf + iCopyLen, 828 | (unsigned) iLeftLen); 829 | iCopyLen += iLeftLen; 830 | } 831 | 832 | ddwNextPos = LT_ELE_AT(pTable,ddwCurPos)->ddwNext; 833 | LT_ELE_AT(pTable,ddwCurPos)->ddwKey = ddwKey; 834 | pTable->pstTableHead->ddwFreeElementCount--; 835 | iLeftLen = iDataLen - iCopyLen; 836 | } 837 | 838 | if (iLeftLen != 0) { 839 | //bug 840 | return -9; 841 | } 842 | 843 | LT_ELE_AT(pTable,ddwCurPos)->ddwNext = 0; 844 | LT_ELE_AT(pTable,0)->ddwNext = ddwNextPos; 845 | ddwOldPos = pIndexNode->ddwPosition; 846 | pIndexNode->ddwPosition = ddwStartPos; 847 | pIndexNode->cFlag = 1; 848 | 849 | //删除旧数据 850 | if (ddwOldPos != 0) { 851 | iRet = PreRecycleElement(pTable, ddwOldPos); 852 | if (iRet < 0) { 853 | return -6; 854 | } 855 | } 856 | 857 | return 0; 858 | } 859 | 860 | //删除指定索引下的所有节点和节点数据(*删除整个Unit的接口*) 861 | int LtClearIndexData(int lt, uint32_t dwIndex) { 862 | int i = 0, iRet = 0, iIndex; 863 | uint64_t ddwIndexStart = 0, sz; 864 | IndexHead *pstIndexHead = NULL; 865 | IndexNode *pIndexNode = NULL; 866 | volatile LinkTable *pTable = GET_LT(lt); 867 | 868 | if (pTable == NULL || pTable->pstTableHead == NULL 869 | || dwIndex >= pTable->pstTableHead->ddwIndexCount) { 870 | return -10; 871 | } 872 | 873 | // If IndexIds are loaded at init time, no further modification is allowed 874 | if (pTable->pstTableHead->bLockedIndexIds) { 875 | return -9; 876 | } 877 | 878 | iRet = GetIndexHead(pTable, INDEX_TO_ID(dwIndex), &pstIndexHead, 0); 879 | if (iRet != 0 || pstIndexHead == NULL) // 找不到 880 | { 881 | return -1; 882 | } 883 | 884 | ddwIndexStart = pstIndexHead->iIndex 885 | * pTable->pstTableHead->ddwIndexRowCount; 886 | 887 | for (i = 0; i < (int) pTable->pstTableHead->ddwIndexRowCount; i++) { 888 | pIndexNode = &(pTable->pstIndexNodeList[ddwIndexStart + i]); 889 | if (pIndexNode->ddwPosition != 0) { 890 | iRet = RecycleElement(pTable, pIndexNode->ddwPosition); 891 | if (iRet < 0) { 892 | Attr_API(241914, 1); 893 | return -3; 894 | } 895 | pIndexNode->ddwPosition = 0; 896 | pIndexNode->cFlag = 0; 897 | } 898 | } 899 | 900 | sz = (unsigned long) (pTable->pstIndexHeadList 901 | + pTable->pstTableHead->ddwUsedIndexCount) 902 | - (unsigned long) (pstIndexHead + 1); 903 | iIndex = pstIndexHead->iIndex; 904 | if (sz > 0) // move one element backwards 905 | memmove(pstIndexHead, pstIndexHead + 1, sz); 906 | pTable->pstIndexHeadList[pTable->pstTableHead->ddwUsedIndexCount - 1].iIndex = 907 | iIndex; 908 | pTable->pstIndexHeadList[pTable->pstTableHead->ddwUsedIndexCount - 1].ddwIndexId = 909 | 0; 910 | pTable->pstTableHead->ddwUsedIndexCount--; 911 | 912 | return 0; 913 | } 914 | 915 | // 判断初始化的时候是不是调用了LtSetIndexes()来设置UnitId 916 | // 如果是,则不允许增加或删除UnitId, 函数返回 1,否则返回0 917 | int LtIsIndexesLocked(int lt) { 918 | volatile LinkTable *pTable = GET_LT(lt); 919 | if (pTable == NULL || pTable->pstTableHead == NULL) { 920 | return 0; 921 | } 922 | return pTable->pstTableHead->bLockedIndexIds ? 1 : 0; 923 | } 924 | 925 | //删除指定索引下的所有数据包括索引定义 926 | int LtRemoveIndex(int lt, uint32_t dwIndex) { 927 | int i = 0, iRet = 0; 928 | uint64_t ddwIndexStart = 0, sz; 929 | int iIndex; 930 | volatile LinkTable *pTable = GET_LT(lt); 931 | IndexHead *pstIndexHead = NULL; 932 | IndexNode *pIndexNode = NULL; 933 | 934 | if (pTable == NULL || pTable->pstTableHead == NULL 935 | || ((uint64_t) dwIndex) >= pTable->pstTableHead->ddwIndexCount) { 936 | return -10; 937 | } 938 | 939 | // If IndexIds are loaded at init time, no further modification is allowed 940 | if (pTable->pstTableHead->bLockedIndexIds) { 941 | return -9; 942 | } 943 | 944 | iRet = GetIndexHead(pTable, INDEX_TO_ID(dwIndex), &pstIndexHead, 0); 945 | if (iRet != 0 || pstIndexHead == NULL) // 找不到 946 | { 947 | return -1; 948 | } 949 | 950 | ddwIndexStart = pstIndexHead->iIndex 951 | * pTable->pstTableHead->ddwIndexRowCount; 952 | 953 | for (i = 0; i < (int) pTable->pstTableHead->ddwIndexRowCount; i++) { 954 | pIndexNode = &(pTable->pstIndexNodeList[ddwIndexStart + i]); 955 | if (pIndexNode->ddwPosition != 0) // 还有没有释放完毕的,返回错误 956 | { 957 | return 10; 958 | } 959 | } 960 | 961 | sz = (unsigned long) (pTable->pstIndexHeadList 962 | + pTable->pstTableHead->ddwUsedIndexCount) 963 | - (unsigned long) (pstIndexHead + 1); 964 | iIndex = pstIndexHead->iIndex; 965 | if (sz > 0) 966 | memmove(pstIndexHead, pstIndexHead + 1, sz); 967 | pTable->pstIndexHeadList[pTable->pstTableHead->ddwUsedIndexCount - 1].iIndex = 968 | iIndex; 969 | pTable->pstIndexHeadList[pTable->pstTableHead->ddwUsedIndexCount - 1].ddwIndexId = 970 | 0; 971 | pTable->pstTableHead->ddwUsedIndexCount--; 972 | 973 | return 0; 974 | } 975 | 976 | static int ValifyIndex(volatile LinkTable *pTable) { 977 | int i, j, dup = 0; 978 | 979 | for (i = 0; i < (int) pTable->pstTableHead->ddwIndexCount; i++) { 980 | for (j = 0; j < i; j++) { 981 | if (pTable->pstIndexHeadList[j].iIndex 982 | == pTable->pstIndexHeadList[i].iIndex) 983 | break; 984 | } 985 | 986 | if (j < i) // found duplicate 987 | { 988 | printf( 989 | "Warning: duplicate index found between %d and %d, value=%d.\n", 990 | i, j, pTable->pstIndexHeadList[i].iIndex); 991 | dup++; 992 | } 993 | } 994 | 995 | return dup; 996 | } 997 | 998 | #define PRINT_ALL_ELEMENTS 0 999 | 1000 | int LtPrintInfo(int lt) { 1001 | long i = 0; 1002 | unsigned long total = 0, unit_total; 1003 | volatile LinkTable *pTable = GET_LT(lt); 1004 | 1005 | if (pTable == NULL || pTable->pstTableHead == NULL) { 1006 | return -10; 1007 | } 1008 | 1009 | printf("ddwAllElementCount: %llu\n", 1010 | pTable->pstTableHead->ddwAllElementCount); 1011 | printf("ddwFreeElementCount: %llu\n", 1012 | pTable->pstTableHead->ddwFreeElementCount); 1013 | printf("ddwElementSize: %llu\n", pTable->pstTableHead->ddwElementSize); 1014 | printf("ddwIndexCount: %llu\n", pTable->pstTableHead->ddwIndexCount); 1015 | printf("ddwIndexRowCount: %llu\n", 1016 | pTable->pstTableHead->ddwIndexRowCount); 1017 | printf("ddwUsedIndexCount: %llu\n", 1018 | pTable->pstTableHead->ddwUsedIndexCount); 1019 | printf("ddwFirstFreePos: %llu\n", 1020 | pTable->pstTableHead->ddwFirstFreePos); 1021 | printf("ddwPreFreeIndex: %llu\n", 1022 | pTable->pstTableHead->ddwPreFreeIndex); 1023 | 1024 | for (total = 0, i = 0; i < pTable->pstTableHead->dwPreFreePoolSize; i++) { 1025 | if (pTable->pstTableHead->addwPreFreePool[i]) 1026 | total++; 1027 | } 1028 | printf("ddwPreFreeCount: %lu\n", total); 1029 | 1030 | total = 0; 1031 | 1032 | #if 0 1033 | for(i=0; i<(int)pTable->pstTableHead->ddwIndexCount; i++) 1034 | { 1035 | printf("%d: iIndex:%d, ddwIndexId:%llu\n", i, 1036 | pTable->pstIndexHeadList[i].iIndex, 1037 | pTable->pstIndexHeadList[i].ddwIndexId); 1038 | } 1039 | #else 1040 | ValifyIndex(pTable); 1041 | #endif 1042 | 1043 | for (i = 0; i < (long) pTable->pstTableHead->ddwIndexCount; i++) { 1044 | if (pTable->pstIndexHeadList[i].ddwIndexId != 0) { 1045 | uint64_t j; 1046 | uint64_t start_idx = pTable->pstIndexHeadList[i].iIndex 1047 | * pTable->pstTableHead->ddwIndexRowCount; 1048 | 1049 | #if PRINT_ALL_ELEMENTS 1050 | uint64_t start_uin=(pTable->pstIndexHeadList[i].ddwIndexId-1)*pTable->pstTableHead->ddwIndexRowCount; 1051 | 1052 | printf("ddwIndexId:%llu (UnitID:%llu) iIndex: %d\n", 1053 | pTable->pstIndexHeadList[i].ddwIndexId, pTable->pstIndexHeadList[i].ddwIndexId-1, 1054 | pTable->pstIndexHeadList[i].iIndex); 1055 | #endif 1056 | unit_total = 0; 1057 | for (j = 0; j < pTable->pstTableHead->ddwIndexRowCount; j++) { 1058 | if (pTable->pstIndexNodeList[start_idx + j].cFlag != 0) { 1059 | uint64_t pos = 1060 | pTable->pstIndexNodeList[start_idx + j].ddwPosition; 1061 | if (pos > pTable->pstTableHead->ddwAllElementCount) 1062 | printf( 1063 | "\tpstIndexNodeList[%llu].ddwPosition is invalid!\n", 1064 | start_idx + j); 1065 | #if PRINT_ALL_ELEMENTS 1066 | else 1067 | printf("\tpstElementList[%llu]: key=%llu, next=%llu, uin=%llu\n", 1068 | pos, LT_ELE_AT(pTable,pos)->ddwKey, 1069 | LT_ELE_AT(pTable,pos)->ddwNext, start_uin+(uint64_t)j); 1070 | #endif 1071 | total++; 1072 | unit_total++; 1073 | } 1074 | } 1075 | #if PRINT_ALL_ELEMENTS 1076 | printf("UINs in unit: %lu\n", unit_total); 1077 | #else 1078 | printf("ddwIndexId:%llu (UnitID:%llu), iIndex: %d, uins:%lu\n", 1079 | pTable->pstIndexHeadList[i].ddwIndexId, 1080 | pTable->pstIndexHeadList[i].ddwIndexId - 1, 1081 | pTable->pstIndexHeadList[i].iIndex, unit_total); 1082 | #endif 1083 | } 1084 | } 1085 | 1086 | printf("\nTotal UINs: %lu\n", total); 1087 | return 0; 1088 | } 1089 | 1090 | int LtPrintElements(int lt) { 1091 | long i = 0; 1092 | unsigned long total = 0; 1093 | volatile LinkTable *pTable = GET_LT(lt); 1094 | 1095 | if (pTable == NULL || pTable->pstTableHead == NULL) { 1096 | return -10; 1097 | } 1098 | 1099 | ValifyIndex(pTable); 1100 | 1101 | printf("ddwAllElementCount: %llu\n", 1102 | pTable->pstTableHead->ddwAllElementCount); 1103 | printf("ddwFreeElementCount: %llu\n", 1104 | pTable->pstTableHead->ddwFreeElementCount); 1105 | printf("ddwElementSize: %llu\n", pTable->pstTableHead->ddwElementSize); 1106 | printf("ddwIndexCount: %llu\n", pTable->pstTableHead->ddwIndexCount); 1107 | printf("ddwIndexRowCount: %llu\n", 1108 | pTable->pstTableHead->ddwIndexRowCount); 1109 | printf("ddwUsedIndexCount: %llu\n", 1110 | pTable->pstTableHead->ddwUsedIndexCount); 1111 | printf("ddwFirstFreePos: %llu\n", 1112 | pTable->pstTableHead->ddwFirstFreePos); 1113 | printf("ddwPreFreeIndex: %llu\n", 1114 | pTable->pstTableHead->ddwPreFreeIndex); 1115 | 1116 | for (total = 0, i = 0; i < pTable->pstTableHead->dwPreFreePoolSize; i++) { 1117 | if (pTable->pstTableHead->addwPreFreePool[i]) 1118 | total++; 1119 | } 1120 | printf("ddwPreFreeCount: %lu\n", total); 1121 | 1122 | total = 0; 1123 | 1124 | printf("\nElements:\n"); 1125 | for (i = 0; i <= (long) pTable->pstTableHead->ddwAllElementCount; i++) { 1126 | if (LT_ELE_AT(pTable,i)->ddwNext || LT_ELE_AT(pTable,i)->ddwKey) { 1127 | printf("\tpstElementList[%ld]: next=%llu, key=%llu\n", i, 1128 | LT_ELE_AT(pTable,i)->ddwNext, LT_ELE_AT(pTable,i)->ddwKey); 1129 | 1130 | if (LT_ELE_AT(pTable,i)->ddwKey) 1131 | total++; 1132 | } 1133 | } 1134 | 1135 | printf("\nTotal elements: %lu\n", total); 1136 | return 0; 1137 | } 1138 | 1139 | //删除指定索引下的所有数据包括索引定义 1140 | int LtClearKeyData(int lt, uint64_t ddwKey) { 1141 | volatile LinkTable *pTable = GET_LT(lt); 1142 | IndexNode *pIndexNode = NULL; 1143 | int iRet = 0; 1144 | 1145 | if (pTable == NULL || pTable->pstTableHead == NULL) { 1146 | return -11; 1147 | } 1148 | 1149 | iRet = GetIndexNode(pTable, ddwKey, &pIndexNode, 0); 1150 | if (iRet < 0) { 1151 | return -20; 1152 | } 1153 | 1154 | //index不存在或者未初始化返回不存在 1155 | if (pIndexNode == NULL || pIndexNode->cFlag == 0) { 1156 | return 10; 1157 | } 1158 | 1159 | if (pIndexNode->ddwPosition != 0) { 1160 | uint64_t ddwOldPos = pIndexNode->ddwPosition; 1161 | 1162 | // 注意这个顺序,程序有可能随时被killed,优先保证指针有效性 1163 | pIndexNode->cFlag = 0; 1164 | pIndexNode->ddwPosition = 0; 1165 | 1166 | iRet = PreRecycleElement(pTable, ddwOldPos); 1167 | if (iRet < 0) { 1168 | return -30; 1169 | } 1170 | } 1171 | 1172 | return 0; 1173 | } 1174 | 1175 | int LtGetHeaderData(int lt, void *pBuff, int iSize) { 1176 | volatile LinkTable *pTable = GET_LT(lt); 1177 | 1178 | if (iSize <= 0 || pBuff == NULL || pTable == NULL 1179 | || pTable->pstTableHead == NULL) 1180 | return -1; 1181 | 1182 | if (iSize > (int) pTable->pstTableHead->dwUserDataLen) 1183 | iSize = (int) pTable->pstTableHead->dwUserDataLen; 1184 | 1185 | memcpy(pBuff, pTable->pstTableHead->sUserData, iSize); 1186 | return iSize; 1187 | } 1188 | 1189 | int LtSetHeaderData(int lt, const void *pData, int iLen) { 1190 | volatile LinkTable *pTable = GET_LT(lt); 1191 | 1192 | if (iLen < 0 || (iLen && pData == NULL) || pTable == NULL 1193 | || pTable->pstTableHead == NULL) 1194 | return -1; 1195 | 1196 | if (iLen > (int) sizeof(pTable->pstTableHead->sUserData)) 1197 | iLen = (int) sizeof(pTable->pstTableHead->sUserData); 1198 | 1199 | if (iLen > 0) 1200 | memcpy(pTable->pstTableHead->sUserData, pData, iLen); 1201 | 1202 | pTable->pstTableHead->dwUserDataLen = iLen; 1203 | return iLen; 1204 | 1205 | } 1206 | 1207 | int LtGetIndexData(int lt, uint32_t dwIndex, void *pBuff, int iSize) { 1208 | int iRet; 1209 | volatile LinkTable *pTable = GET_LT(lt); 1210 | IndexHead *pstIndexHead; 1211 | 1212 | if (iSize <= 0 || pBuff == NULL || pTable == NULL 1213 | || pTable->pstTableHead == NULL) 1214 | return -1; 1215 | 1216 | iRet = GetIndexHead(pTable, INDEX_TO_ID(dwIndex), &pstIndexHead, 0); 1217 | if (iRet != 0 || pstIndexHead == NULL) // 找不到 1218 | return -2; 1219 | 1220 | if (iSize > (int) pstIndexHead->dwIndexDataLen) 1221 | iSize = pstIndexHead->dwIndexDataLen; 1222 | 1223 | memcpy(pBuff, pstIndexHead->abIndexData, iSize); 1224 | return iSize; 1225 | } 1226 | 1227 | int LtSetIndexData(int lt, uint32_t dwIndex, const void *pData, int iLen) { 1228 | int iRet; 1229 | volatile LinkTable *pTable = GET_LT(lt); 1230 | IndexHead *pstIndexHead; 1231 | 1232 | if (iLen < 0 || (iLen > 0 && pData == NULL) || pTable == NULL 1233 | || pTable->pstTableHead == NULL) 1234 | return -1; 1235 | 1236 | iRet = GetIndexHead(pTable, INDEX_TO_ID(dwIndex), &pstIndexHead, 0); 1237 | if (iRet != 0 || pstIndexHead == NULL) // 找不到 1238 | return -2; 1239 | 1240 | if (iLen > (int) sizeof(pstIndexHead->abIndexData)) 1241 | iLen = (int) sizeof(pstIndexHead->abIndexData); 1242 | 1243 | if (iLen > 0) 1244 | memcpy(pstIndexHead->abIndexData, pData, iLen); 1245 | 1246 | pstIndexHead->dwIndexDataLen = iLen; 1247 | return iLen; 1248 | } 1249 | 1250 | int LtClose(int lt) { 1251 | volatile LinkTable *pTable = GET_LT(lt); 1252 | if (pTable == NULL) 1253 | return -1; 1254 | 1255 | if (pTable->pstTableHead != NULL) 1256 | shmdt(pTable->pstTableHead); 1257 | 1258 | memset((void*) pTable, 0, sizeof(g_stTables[0])); 1259 | 1260 | if (lt == iMaxLtNum - 1) 1261 | iMaxLtNum--; 1262 | 1263 | return 0; 1264 | } 1265 | 1266 | volatile LinkTable *GetLinkTable(int lt) { 1267 | volatile LinkTable *pTable = GET_LT(lt); 1268 | if (pTable == NULL || pTable->pstTableHead == NULL) 1269 | return NULL; 1270 | return pTable; 1271 | } 1272 | 1273 | --------------------------------------------------------------------------------