简易分析myicq的内存池模型

myicq 1.0中实现了一个内存池的模型,可以自动分配和回收对象内存。下面看下其实现方式。

首先内存池使用了双向链表来链接的,链表的实现也就是linux中常见的list_head形式,不过是其自己实现的。

有点不解的是,既然用list_head,如果是在linux实现,可以自己调用linux里内建好的list_head,而且还是C的呢,而不是myicq里自己实现的还是类的形式的。又如果如果说是在windows下,那windows下的vc也有类似的形式如:FILED_OFFSET宏就是这样。

感觉在这里用刻意使用list_head,而又是以类的形式使用,我感觉还不如直接使用stl来得方便,或者说代码阅读性好很多。

不多说了,看代码。

myicq里的ListHead

list.h

view plaincopy to clipboardprint?
01./*************************************************************************** 
02. *                                                                         * 
03. *   This program is free software; you can redistribute it and/or modify  * 
04. *   it under the terms of the GNU General Public License as published by  * 
05. *   the Free Software Foundation; either version 2 of the License, or     * 
06. *   (at your option) any later version.                                   * 
07. *                                                                         * 
08. *   copyright            : (C) 2002 by Zhang Yong                         * 
09. *   email                : z-yong163@163.com                              * 
10. ***************************************************************************/ 
11.#ifndef _LIST_H_  
12.#define _LIST_H_  
13.#include "icqtypes.h"  
14.#define LIST_ENTRY(ptr, type, member) /  
15.    ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))  
16.#define LIST_FOR_EACH(pos, head) /  
17.    for (pos = (head)->next; pos != (head); pos = pos->next)  
18./* 
19. * 这是一个循环链表 
20. */ 
21.class ListHead {  
22.public:  
23.    ListHead() {  
24.        prev = next = this;  
25.    }  
26.    bool isEmpty() {  
27.        return (next == this);  
28.    }  
29.    ListHead *removeHead();  
30.    void add(ListHead *item);  
31.    void addHead(ListHead *item);  
32.    void remove();  
33.    ListHead *prev, *next;  
34.};  
35.#endif 
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/
#ifndef _LIST_H_
#define _LIST_H_
#include "icqtypes.h"
#define LIST_ENTRY(ptr, type, member) /
 ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
#define LIST_FOR_EACH(pos, head) /
 for (pos = (head)->next; pos != (head); pos = pos->next)
/*
 * 这是一个循环链表
 */
class ListHead {
public:
 ListHead() {
  prev = next = this;
 }
 bool isEmpty() {
  return (next == this);
 }
 ListHead *removeHead();
 void add(ListHead *item);
 void addHead(ListHead *item);
 void remove();
 ListHead *prev, *next;
};
#endif

list.cpp

view plaincopy to clipboardprint?
01./*************************************************************************** 
02. *                                                                         * 
03. *   This program is free software; you can redistribute it and/or modify  * 
04. *   it under the terms of the GNU General Public License as published by  * 
05. *   the Free Software Foundation; either version 2 of the License, or     * 
06. *   (at your option) any later version.                                   * 
07. *                                                                         * 
08. *   copyright            : (C) 2002 by Zhang Yong                         * 
09. *   email                : z-yong163@163.com                              * 
10. ***************************************************************************/ 
11.#include "list.h"  
12./* 
13. * 让this节点孤立起来 
14. */ 
15.void ListHead::remove()  
16.{  
17.    prev->next = next;  
18.    next->prev = prev;  
19.    prev = next = this;  
20.}  
21./* 
22. * 将this后面的节点孤立起来,并返回这个节点 
23. */ 
24.ListHead *ListHead::removeHead()  
25.{  
26.    ListHead *t = next;  
27.    next->remove();  
28.    return t;  
29.}  
30./* 
31. * 在this前加入item 
32. */ 
33.void ListHead::add(ListHead *item)  
34.{  
35.    item->prev = prev;  
36.    item->next = this;  
37.    prev->next = item;  
38.    prev = item;  
39.}  
40./* 
41. * 在this后面加入节点item 
42. */ 
43.void ListHead::addHead(ListHead *item)  
44.{  
45.    item->prev = this;  
46.    item->next = next;  
47.    next->prev = item;  
48.    next = item;  
49.} 
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/
#include "list.h"
/*
 * 让this节点孤立起来
 */
void ListHead::remove()
{
 prev->next = next;
 next->prev = prev;
 prev = next = this;
}
/*
 * 将this后面的节点孤立起来,并返回这个节点
 */
ListHead *ListHead::removeHead()
{
 ListHead *t = next;
 next->remove();
 return t;
}
/*
 * 在this前加入item
 */
void ListHead::add(ListHead *item)
{
 item->prev = prev;
 item->next = this;
 prev->next = item;
 prev = item;
}
/*
 * 在this后面加入节点item
 */
void ListHead::addHead(ListHead *item)
{
 item->prev = this;
 item->next = next;
 next->prev = item;
 next = item;
}

这样就实现了一个简单的双向链表,如果对list_head机制不熟的可以看我的文章《深入浅出linux内核源代码之双向链表list_head(上)》 和《 深入浅出linux内核源代码之双向链表list_head(下) 》。

下面是一个内存池的实现方式:

slab.h

view plaincopy to clipboardprint?
01./*************************************************************************** 
02. *                                                                         * 
03. *   This program is free software; you can redistribute it and/or modify  * 
04. *   it under the terms of the GNU General Public License as published by  * 
05. *   the Free Software Foundation; either version 2 of the License, or     * 
06. *   (at your option) any later version.                                   * 
07. *                                                                         * 
08. *   copyright            : (C) 2002 by Zhang Yong                         * 
09. *   email                : z-yong163@163.com                              * 
10. ***************************************************************************/ 
11.#ifndef _SLAB_H  
12.#define _SLAB_H  
13.#include "list.h"  
14.#include <stdio.h>  
15.struct SLAB;  
16.struct OBJ {  
17.    OBJ *next;  
18.    SLAB *slab;  
19.};  
20.struct SLAB {  
21.    ListHead item;  
22.    int inuse;  
23.    OBJ *free;  
24.};  
25.class Cache {  
26.public:  
27.    Cache(int size, int n);  
28.    ~Cache();  
29.    void *allocObj();  
30.    void freeObj(void *p);  
31.    static int reclaimAll();  
32.private:  
33.    SLAB *newSlab();  
34.    int reclaim(int n = 0xffff);  
35.    Cache *nextCache;  
36.    ListHead slabList;  
37.    ListHead *firstNotFull;  
38.    int objSize;  
39.    int numObjs;  
40.    int numFreeSlabs;  
41.    int slabSize;  
42.    static Cache *cacheList;  
43.};  
44.#define DECLARE_SLAB(type)      /  
45.private:    /  
46.    static Cache type##_cache;  /  
47.public: /  
48.    void *operator new(size_t) {    /  
49.        return type##_cache.allocObj(); /  
50.    }   /  
51.    void operator delete(void *p) { /  
52.        type##_cache.freeObj(p);    /  
53.    }  
54.#define IMPLEMENT_SLAB(type, num)   /  
55.    Cache type::type##_cache(sizeof(type), num);  
56.#endif 
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/
#ifndef _SLAB_H
#define _SLAB_H
#include "list.h"
#include <stdio.h>
struct SLAB;
struct OBJ {
 OBJ *next;
 SLAB *slab;
};
struct SLAB {
 ListHead item;
 int inuse;
 OBJ *free;
};
class Cache {
public:
 Cache(int size, int n);
 ~Cache();
 void *allocObj();
 void freeObj(void *p);
 static int reclaimAll();
private:
 SLAB *newSlab();
 int reclaim(int n = 0xffff);
 Cache *nextCache;
 ListHead slabList;
 ListHead *firstNotFull;
 int objSize;
 int numObjs;
 int numFreeSlabs;
 int slabSize;
 static Cache *cacheList;
};
#define DECLARE_SLAB(type)  /
private: /
 static Cache type##_cache; /
public: /
 void *operator new(size_t) { /
  return type##_cache.allocObj(); /
 } /
 void operator delete(void *p) { /
  type##_cache.freeObj(p); /
 }
#define IMPLEMENT_SLAB(type, num) /
 Cache type::type##_cache(sizeof(type), num);
#endif

slab.cpp

view plaincopy to clipboardprint?
01./*************************************************************************** 
02. *                                                                         * 
03. *   This program is free software; you can redistribute it and/or modify  * 
04. *   it under the terms of the GNU General Public License as published by  * 
05. *   the Free Software Foundation; either version 2 of the License, or     * 
06. *   (at your option) any later version.                                   * 
07. *                                                                         * 
08. *   copyright            : (C) 2002 by Zhang Yong                         * 
09. *   email                : z-yong163@163.com                              * 
10. ***************************************************************************/ 
11.#include "slab.h"  
12.#include <stdlib.h>  
13.#include <memory.h>  
14.#define MAX_FREE_SLABS      8  
15.Cache *Cache::cacheList = NULL;  
16.int Cache::reclaimAll()  
17.{  
18.    int ret = 0;  
19.    for (Cache *p = cacheList; p; p = p->nextCache)  
20.        ret += p->reclaim();  
21.    return ret;  
22.}  
23.Cache::Cache(int size, int n)  
24.{  
25.    objSize = size + sizeof(OBJ);  
26.    numObjs = n;  
27.    numFreeSlabs = 0;  
28.    firstNotFull = &slabList;  
29.    slabSize = sizeof(SLAB) + objSize * n;  
30.    // Add it to the cache chain  
31.    nextCache = cacheList;  
32.    cacheList = this;  
33.}  
34.Cache::~Cache()  
35.{  
36.    while (!slabList.isEmpty()) {  
37.        ListHead *pos = slabList.removeHead();  
38.        SLAB *slab = LIST_ENTRY(pos, SLAB, item);  
39.        free(slab);  
40.    }  
41.}  
42./* 
43. * Reclaim empty slabs in this cache 
44. */ 
45.int Cache::reclaim(int n)  
46.{  
47.    SLAB *slab;  
48.    ListHead *pos, *t = firstNotFull;  
49.    int i = 0;  
50.    while (i < n && (pos = slabList.prev) != &slabList) {  
51.        slab = LIST_ENTRY(pos, SLAB, item);  
52.        if (slab->inuse)  
53.            break;  
54.        i++;  
55.        if (firstNotFull == pos)  
56.            firstNotFull = pos->prev;  
57.        pos->remove();  
58.        free(slab);  
59.    }  
60.    if (firstNotFull != t && firstNotFull != &slabList) {  
61.        slab = LIST_ENTRY(firstNotFull, SLAB, item);  
62.        if (slab->inuse == numObjs)  
63.            firstNotFull = &slabList;  
64.    }  
65.    numFreeSlabs += i;  
66.    return i;  
67.}  
68./* 
69. * Alloc a new slab 
70. */ 
71.SLAB *Cache::newSlab()  
72.{  
73.    SLAB *slab = (SLAB *) malloc(slabSize);  
74.    if (!slab) {  
75.        if (reclaimAll() > 0) {  
76.            slab = (SLAB *) malloc(slabSize);  
77.            if (!slab)  
78.                return NULL;  
79.        }  
80.    }  
81.    slab->inuse = 0;  
82.    OBJ *obj = (OBJ *) (slab + 1);  
83.    slab->free = obj;  
84.    for (int i = 0; i < numObjs - 1; ++i) {  
85.        OBJ *next = (OBJ *) ((char *) obj + objSize);  
86.        obj->next = next;  
87.        obj->slab = slab;  
88.        obj = next;  
89.    }  
90.    obj->next = NULL;  
91.    obj->slab = slab;  
92.    slabList.add(&slab->item);  
93.    firstNotFull = &slab->item;  
94.    return slab;  
95.}  
96./* 
97. * Alloc an object from the cache 
98. */ 
99.void *Cache::allocObj()  
100.{  
101.    void *obj = NULL;  
102.    SLAB *slab;  
103.    if (firstNotFull == &slabList)  
104.        slab = newSlab();  
105.    else {  
106.        slab = LIST_ENTRY(firstNotFull, SLAB, item);  
107.        if (!slab->inuse)  
108.            numFreeSlabs--;  
109.    }  
110.    if (slab) {  
111.        slab->inuse++;  
112.        obj = slab->free + 1;  
113.        slab->free = slab->free->next;  
114.        if (!slab->free)  
115.            firstNotFull = slab->item.next;  
116.    }  
117.    return obj;  
118.}  
119./* 
120. * Free an object in the cache 
121. */ 
122.void Cache::freeObj(void *p)  
123.{  
124.#ifdef _DEBUG  
125.    memset(p, 0xdd, objSize - sizeof(OBJ));  
126.#endif  
127.    OBJ *obj = (OBJ *) p - 1;  
128.    SLAB *slab = obj->slab;  
129.    obj->next = slab->free;  
130.    slab->free = obj;  
131.    ListHead *pos;  
132.    if (slab->inuse-- == numObjs) {  
133.        ListHead *t = firstNotFull;  
134.        pos = &slab->item;  
135.        firstNotFull = pos;  
136.        if (pos->next != t) {  
137.            pos->remove();  
138.            t->add(pos);  
139.        }  
140.    } else if (!slab->inuse) {  
141.        int n = ++numFreeSlabs - MAX_FREE_SLABS;  
142.        if (n > 0)  
143.            reclaim(n);  
144.        ListHead *t = firstNotFull->prev;  
145.        pos = &slab->item;  
146.        pos->remove();  
147.        slabList.add(pos);  
148.        if (firstNotFull == &slab->item)  
149.            firstNotFull = t->next;  
150.    }  
151.} 
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/
#include "slab.h"
#include <stdlib.h>
#include <memory.h>
#define MAX_FREE_SLABS  8
Cache *Cache::cacheList = NULL;
int Cache::reclaimAll()
{
 int ret = 0;
 for (Cache *p = cacheList; p; p = p->nextCache)
  ret += p->reclaim();
 return ret;
}
Cache::Cache(int size, int n)
{
 objSize = size + sizeof(OBJ);
 numObjs = n;
 numFreeSlabs = 0;
 firstNotFull = &slabList;
 slabSize = sizeof(SLAB) + objSize * n;
 // Add it to the cache chain
 nextCache = cacheList;
 cacheList = this;
}
Cache::~Cache()
{
 while (!slabList.isEmpty()) {
  ListHead *pos = slabList.removeHead();
  SLAB *slab = LIST_ENTRY(pos, SLAB, item);
  free(slab);
 }
}
/*
 * Reclaim empty slabs in this cache
 */
int Cache::reclaim(int n)
{
 SLAB *slab;
 ListHead *pos, *t = firstNotFull;
 int i = 0;
 while (i < n && (pos = slabList.prev) != &slabList) {
  slab = LIST_ENTRY(pos, SLAB, item);
  if (slab->inuse)
   break;
  i++;
  if (firstNotFull == pos)
   firstNotFull = pos->prev;
  pos->remove();
  free(slab);
 }
 if (firstNotFull != t && firstNotFull != &slabList) {
  slab = LIST_ENTRY(firstNotFull, SLAB, item);
  if (slab->inuse == numObjs)
   firstNotFull = &slabList;
 }
 numFreeSlabs += i;
 return i;
}
/*
 * Alloc a new slab
 */
SLAB *Cache::newSlab()
{
 SLAB *slab = (SLAB *) malloc(slabSize);
 if (!slab) {
  if (reclaimAll() > 0) {
   slab = (SLAB *) malloc(slabSize);
   if (!slab)
    return NULL;
  }
 }
 slab->inuse = 0;
 OBJ *obj = (OBJ *) (slab + 1);
 slab->free = obj;
 for (int i = 0; i < numObjs - 1; ++i) {
  OBJ *next = (OBJ *) ((char *) obj + objSize);
  obj->next = next;
  obj->slab = slab;
  obj = next;
 }
 obj->next = NULL;
 obj->slab = slab;
 slabList.add(&slab->item);
 firstNotFull = &slab->item;
 return slab;
}
/*
 * Alloc an object from the cache
 */
void *Cache::allocObj()
{
 void *obj = NULL;
 SLAB *slab;
 if (firstNotFull == &slabList)
  slab = newSlab();
 else {
  slab = LIST_ENTRY(firstNotFull, SLAB, item);
  if (!slab->inuse)
   numFreeSlabs--;
 }
 if (slab) {
  slab->inuse++;
  obj = slab->free + 1;
  slab->free = slab->free->next;
  if (!slab->free)
   firstNotFull = slab->item.next;
 }
 return obj;
}
/*
 * Free an object in the cache
 */
void Cache::freeObj(void *p)
{
#ifdef _DEBUG
 memset(p, 0xdd, objSize - sizeof(OBJ));
#endif
 OBJ *obj = (OBJ *) p - 1;
 SLAB *slab = obj->slab;
 obj->next = slab->free;
 slab->free = obj;
 ListHead *pos;
 if (slab->inuse-- == numObjs) {
  ListHead *t = firstNotFull;
  pos = &slab->item;
  firstNotFull = pos;
  if (pos->next != t) {
   pos->remove();
   t->add(pos);
  }
 } else if (!slab->inuse) {
  int n = ++numFreeSlabs - MAX_FREE_SLABS;
  if (n > 0)
   reclaim(n);
  ListHead *t = firstNotFull->prev;
  pos = &slab->item;
  pos->remove();
  slabList.add(pos);
  if (firstNotFull == &slab->item)
   firstNotFull = t->next;
 }
}

内存池是SLAB结构打头的一个大块内存,里面有多个对象内存快,这些内存快个数在下面的#define IMPLEMENT_SLAB(type, num) 宏中的num来指定个数,每个对象空间前面有个OBJ的结构头部。

SLAB后面是连续的OBJ内存快,SLAB结构里的free指向第一个可使用的对象内存快。在回收内存块时这个free指针会指向回收的这块内存,而这块内存会指向free指向的内存块,形成一个可用内存快链表。而内存快又是以next的形式链接在一起。这种实现形式和SGI的STL的内存池的实现非常相似,具体可以参考侯捷的《内存春秋》里说的,里面说得非常详细易懂!

cache类是一个以list_head来链接的双向链表,其链接的是SLAB结构的内存块。

#define DECLARE_SLAB(type) 宏用在类中声明一个静态变量static Cache type##_cache;并且里面重新定义了new和delete,以便从内存池中分配和销毁。

#define IMPLEMENT_SLAB(type, num) 宏用来类的定义出定义这个静态变量,type用于制定对象大小,num用于指定分配多少个快

下面是类DBRequest中使用了这个内存池:

dbmanager.h

view plaincopy to clipboardprint?
01./*************************************************************************** 
02. *                                                                         * 
03. *   This program is free software; you can redistribute it and/or modify  * 
04. *   it under the terms of the GNU General Public License as published by  * 
05. *   the Free Software Foundation; either version 2 of the License, or     * 
06. *   (at your option) any later version.                                   * 
07. *                                                                         * 
08. *   copyright            : (C) 2002 by Zhang Yong                         * 
09. *   email                : z-yong163@163.com                              * 
10. ***************************************************************************/ 
11.#ifndef _DB_MANAGER_H  
12.#define _DB_MANAGER_H  
13.#include <mysql.h>  
14.#include "myicq.h"  
15.#include "list.h"  
16.#include "slab.h"  
17.#define WRITE_STR(req, str)     req->writeString(str, sizeof(str) - 1)  
18.#define MAX_SQL     4096  
19.extern MYSQL *mysqlWrite;  
20.char *conv10(uint32 num, char *bufEnd);  
21.class RefObject;  
22.class DBRequest;  
23.typedef void (*DB_CALLBACK)(DBRequest *req);  
24.enum {  
25.    DBF_UPDATE = 0x01,  
26.    DBF_INSERT = 0x02,  
27.};  
28.class DBRequest {  
29.friend class DBManager;  
30.public:  
31.    DBRequest(uint8 flags, DB_CALLBACK cb = NULL, RefObject *obj = NULL, uint32 d = 0);  
32.    void writeString(const char *text, int n) {  
33.        if (cursor - sql + n <= MAX_SQL) {  
34.            memcpy(cursor, text, n);  
35.            cursor += n;  
36.        }  
37.    }  
38.    DBRequest &operator <<(ICQ_STR &str) {  
39.        if (cursor - sql + (str.len << 1) < MAX_SQL - 2) {  
40.            *cursor++ = '/'';  
41.            cursor += mysql_real_escape_string(mysqlWrite, cursor, str.text, str.len);  
42.            *cursor++ = '/'';  
43.        }  
44.        return *this;  
45.    }  
46.    DBRequest &operator <<(char c) {  
47.        if (cursor - sql <= (int) (MAX_SQL - sizeof(c)))  
48.            *cursor++ = c;  
49.        return *this;  
50.    }  
51.    DBRequest &operator <<(uint8 num) {  
52.        *this << (uint32) num;  
53.        return *this;  
54.    }  
55.    DBRequest &operator <<(uint16 num) {  
56.        *this <<(uint32) num;  
57.        return *this;  
58.    }  
59.    DBRequest &operator <<(uint32 num) {  
60.        char buf[16];  
61.        char *p = conv10(num, buf + sizeof(buf));  
62.        writeString(p, buf + sizeof(buf) - p);  
63.        return *this;  
64.    }  
65.    ListHead listItem;  
66.    DB_CALLBACK callback;  
67.    RefObject *refObj;  
68.    uint32 data;  
69.    union {  
70.        MYSQL_RES *res;  
71.        int ret;  
72.    };  
73.    uint32 lastInsertID;  
74.private:  
75.    int sqlLen() {  
76.        return cursor - sql;  
77.    }  
78.    uint8 flags;  
79.    char sql[MAX_SQL];  
80.    char *cursor;  
81.    DECLARE_SLAB(DBRequest)  
82.};  
83.class DBManager {  
84.public:  
85.    DBManager();  
86.    ~DBManager();  
87.    bool create(DB_INFO &dbSlave);  
88.    void processQuery();  
89.    static bool init(DB_INFO &dbMaster);  
90.    static void destroy();  
91.    static void query(DBRequest *req);  
92.    static void processUpdate();  
93.    static void dispatch();  
94.private:  
95.    MYSQL *mysqlRead;  
96.};  
97.#endif 
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright            : (C) 2002 by Zhang Yong                         *
 *   email                : z-yong163@163.com                              *
 ***************************************************************************/
#ifndef _DB_MANAGER_H
#define _DB_MANAGER_H
#include <mysql.h>
#include "myicq.h"
#include "list.h"
#include "slab.h"
#define WRITE_STR(req, str)  req->writeString(str, sizeof(str) - 1)
#define MAX_SQL  4096
extern MYSQL *mysqlWrite;
char *conv10(uint32 num, char *bufEnd);
class RefObject;
class DBRequest;
typedef void (*DB_CALLBACK)(DBRequest *req);
enum {
 DBF_UPDATE = 0x01,
 DBF_INSERT = 0x02,
};
class DBRequest {
friend class DBManager;
public:
 DBRequest(uint8 flags, DB_CALLBACK cb = NULL, RefObject *obj = NULL, uint32 d = 0);
 void writeString(const char *text, int n) {
  if (cursor - sql + n <= MAX_SQL) {
   memcpy(cursor, text, n);
   cursor += n;
  }
 }
 DBRequest &operator <<(ICQ_STR &str) {
  if (cursor - sql + (str.len << 1) < MAX_SQL - 2) {
   *cursor++ = '/'';
   cursor += mysql_real_escape_string(mysqlWrite, cursor, str.text, str.len);
   *cursor++ = '/'';
  }
  return *this;
 }
 DBRequest &operator <<(char c) {
  if (cursor - sql <= (int) (MAX_SQL - sizeof(c)))
   *cursor++ = c;
  return *this;
 }
 DBRequest &operator <<(uint8 num) {
  *this << (uint32) num;
  return *this;
 }
 DBRequest &operator <<(uint16 num) {
  *this <<(uint32) num;
  return *this;
 }
 DBRequest &operator <<(uint32 num) {
  char buf[16];
  char *p = conv10(num, buf + sizeof(buf));
  writeString(p, buf + sizeof(buf) - p);
  return *this;
 }
 ListHead listItem;
 DB_CALLBACK callback;
 RefObject *refObj;
 uint32 data;
 union {
  MYSQL_RES *res;
  int ret;
 };
 uint32 lastInsertID;
private:
 int sqlLen() {
  return cursor - sql;
 }
 uint8 flags;
 char sql[MAX_SQL];
 char *cursor;
 DECLARE_SLAB(DBRequest)
};
class DBManager {
public:
 DBManager();
 ~DBManager();
 bool create(DB_INFO &dbSlave);
 void processQuery();
 static bool init(DB_INFO &dbMaster);
 static void destroy();
 static void query(DBRequest *req);
 static void processUpdate();
 static void dispatch();
private:
 MYSQL *mysqlRead;
};
#endif

可以看到在类的最后使用了DECLARE_SLAB(DBRequest)来声明。

并且在dbmanager.cpp中调用IMPLEMENT_SLAB(DBRequest, 16)来实现,可以看到每次分配是16个对象。

如果使用满了,会在获取下一个空余对象空间时,自动在cache里在分配一个slab内存快,然后以list_head的双向链表形式链接起来。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fjb2080/archive/2011/06/15/6546858.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyICQ 0.8 alpha1测试版 ==================================================== --------------- 1. MyICQ是什么? --------------- MyICQ是一套公开源代码的即时通讯软件,包括服务器端和客户端,可以用于互联网或局域网中。可以运行在Windows或Linux(KDE/Qt)操作系统上,这是Windows版。目前客户端程序的界面完全模仿腾讯的QQ(如果Tencent告我的话,我会马上改的:-)。 总之,如果你崇尚自由,对QQ的越来越多的广告骚扰感到深恶痛绝的话,MyICQ绝对是你很好的选择。 -------- 2. 版本 -------- 这是MyICQ 0.8版本的alpha1 测试版,基本上还没有经过什么严格测试。 -------- 3. 版权 -------- 完全遵循GPL协议2.0或以后协议版本。 --------------- 4. 基本功能特点 --------------- 1) 收发(离线)消息(如果客户端之间能直接通讯,则通过UDP协议发送,否则通过服务器中转) 2) 添加/删除好友(可以设置身份验证) 3) 服务器端存储好友列表 4) 在客户端存储好友资料和聊天记录 5) 客户端与服务器端用DES的密钥加密方式通讯 6) 支持代理服务器(SOCKS5/HTTP) 7) 向在线的一组好友发送消息 8) 系统管理员(MyICQ号 < 1000)可以发送系统广播消息 9) 皮肤系统 10)完全基于插件,使扩展更容易。目前提供的插件有: a. 收发文件 b. 二人世界(可以实时语音聊天) c. 闹钟提醒 ------------------ 5. 分发包里有什么? ------------------ 分发包里有三个目录: myicq/ 客户端程序 myicqd/ 服务器端程序 myicqhttp/ HTTP的转换程序。MyICQ支持HTTP代理,但需要在MyICQ的服务器端运行myicqhttp程序 -------- 6. 安装 -------- 客户端程序不写Windows注册表,无需安装。双击MyICQ.exe运行。 服务器端由于内部采用MySQL数据库,所以安装稍微麻烦一些: 1) 到http://www.mysql.com下载MySQL 2) 打开一个DOS命令窗口,在MySQL中建立一个数据库,并添加一个用户: C:\mysql\bin> mysql -uroot -p ******** (输入root密码,如果还没有设置,直接输入回车即可) mysql> GRANT ALL ON myicq.* TO myicq@localhost IDENTIFIED BY 'myicq'; mysql> CREATE DATABASE myicq; mysql> quit 3) 创建表格: C:\mysql\bin> mysql -umyicq -Dmyicq -p < [myicqd目录]\myicq.sql password: myicq 注意: [myicqd目录]代表myicqd所在的目录 4) 运行myicqd: 双击myicqd.exe即可运行。如果没有错误,应该显示"MyICQ server is now started". 接下来就可以从客户端注册新用户了。 5) 你可能想要添加一个系统用户,以发送系统广播消息: C:\mysql\bin> mysql -umyicq -Dmyicq -p password: myicq mysql> INSERT INTO basic_tbl (uin, passwd) VALUES(100, password('yourpassword')); mysql> INSERT INTO ext_tbl (uin) VALUES(100); 注意: yourpassword代表系统用户的密码 然后选择客户端程序的注册向导,取回100这个号码。完成后,你会发现在主菜单中多了"广播消息"一项。此后,你可以选择个人设定来设定你的个人信息(比如,不允许任何人加我为好友) ------------- 7. 编译源代码 ------------- 如果你是一个程序员,那么一定要编译MyICQ的源代码:-) 1) 到http://www.mysql.com下载MySQL 2) 由于MyICQ在存储好友资料和聊天记录时,使用Berkeley DB库,所以先到 http://www.s
大家期待已久的MyICQ 1.0终于发布了! 现在刚刚发布alpha1测试版本,还处于测试阶段,希望大家能够多多支持 MyICQ是一套完全公开源代码的即时通讯软件,包括服务器端和客户端,可以用于互联网或局域网中。可以运行在Windows或Linux(KDE/Qt)操作系统上,这是Windows的客户端。MyICQ完全支持服务器之间的松散连接,这意味着任何人都可以在Internet上架设自己的服务器。群组功能使您能够享受到聊天室和网络游戏所带来的快乐。 MyICQ 1.0新增加了两个非常非常重要的功能: 1) 服务器互联 采用"MyICQ号码@服务器地址"的统一编码方式,这样可以保证每台MyICQ服务器分配的号码不会重复,类似于现在的email系统。各个服务器在启动的时候谁也不必知道谁的存在,但是如果有人按照MyICQ号码添加其它服务器的好友的话,以后这台服务器就会出现在服务器列表中,所有的用户就可以随机查找这台服务器上的用户了。 2) 群组支持 包括聊天室和游戏平台。聊天室可以允许最多8个人一起针对某个话题聊天;游戏平台就像联众的游戏大厅一样,上面跑着各种各样的游戏(插件)。现在只有"五子棋",不过我们会不断的开发新游戏的。而且,相信随着MyICQ的流行,会有越来越多的人为MyICQ开发各种各样的游戏 大家可以到 http://cosoft.org.cn/projects/myicq 下载最新的MyICQ-1.0a1测试版本。如果大家觉得MyICQ很有前途,请推荐自己身边的好友来用MyICQ;如果觉得不好,或者有什么想法和意见,也请一定要通知我。 另外,胡正在很短的时间里编写了一个gaim的myicq-0.9插件,而且做的很不错。现在大家可以通过Linux 来访问MyICQ服务器了。不过目前还不支持MyICQ 1.0的一些新特性,胡正还在不断地完善它。gaim-myicq的最新版本可以也在http://cosoft.org.cn/projects/myicq下找到。 基本功能特点 --------------- 收发(离线)消息(如果客户端之间能直接通讯,则通过TCP协议发送,否则通过服务器中转) 添加/删除好友(可以设置身份验证) 服务器端存储好友列表 在客户端存储好友资料和聊天记录 客户端与服务器端用DES的密钥加密方式通讯 支持代理服务器(SOCKS5/HTTP) 向一组在线好友发送消息 表情符号和选择字体 自动识别URL 系统管理员(MyICQ# = 10000)可以发送系统广播消息 皮肤系统 消息管理(可导入/导出聊天记录) 完全基于插件,使扩展更容易。目前提供的插件有: a. 收发文件 b. 二人世界(可以实时语音聊天) c. 闹钟提醒 支持服务器松散连接,采用uin@domain的形式 群组功能,包括聊天室和游戏大厅 ----------------------- 作者: 张勇(freeman) [email protected]
MyICQ 0.8 alpha1测试版 ==================================================== --------------- 1. MyICQ是什么? --------------- MyICQ是一套公开源代码的即时通讯软件,包括服务器端和客户端,可以用于互联网或局域网中。可以运行在Windows或Linux(KDE/Qt)操作系统上,这是Windows版。目前客户端程序的界面完全模仿腾讯的QQ(如果Tencent告我的话,我会马上改的:-)。 总之,如果你崇尚自由,对QQ的越来越多的广告骚扰感到深恶痛绝的话,MyICQ绝对是你很好的选择。 -------- 2. 版本 -------- 这是MyICQ 0.8版本的alpha1 测试版,基本上还没有经过什么严格测试。 -------- 3. 版权 -------- 完全遵循GPL协议2.0或以后协议版本。 --------------- 4. 基本功能特点 --------------- 1) 收发(离线)消息(如果客户端之间能直接通讯,则通过UDP协议发送,否则通过服务器中转) 2) 添加/删除好友(可以设置身份验证) 3) 服务器端存储好友列表 4) 在客户端存储好友资料和聊天记录 5) 客户端与服务器端用DES的密钥加密方式通讯 6) 支持代理服务器(SOCKS5/HTTP) 7) 向在线的一组好友发送消息 8) 系统管理员(MyICQ号 < 1000)可以发送系统广播消息 9) 皮肤系统 10)完全基于插件,使扩展更容易。目前提供的插件有: a. 收发文件 b. 二人世界(可以实时语音聊天) c. 闹钟提醒 ------------------ 5. 分发包里有什么? ------------------ 分发包里有三个目录: myicq/ 客户端程序 myicqd/ 服务器端程序 myicqhttp/ HTTP的转换程序。MyICQ支持HTTP代理,但需要在MyICQ的服务器端运行myicqhttp程序 -------- 6. 安装 -------- 客户端程序不写Windows注册表,无需安装。双击MyICQ.exe运行。 服务器端由于内部采用MySQL数据库,所以安装稍微麻烦一些: 1) 到http://www.mysql.com下载MySQL 2) 打开一个DOS命令窗口,在MySQL中建立一个数据库,并添加一个用户: C:\mysql\bin> mysql -uroot -p ******** (输入root密码,如果还没有设置,直接输入回车即可) mysql> GRANT ALL ON myicq.* TO myicq@localhost IDENTIFIED BY 'myicq'; mysql> CREATE DATABASE myicq; mysql> quit 3) 创建表格: C:\mysql\bin> mysql -umyicq -Dmyicq -p < [myicqd目录]\myicq.sql password: myicq 注意: [myicqd目录]代表myicqd所在的目录 4) 运行myicqd: 双击myicqd.exe即可运行。如果没有错误,应该显示"MyICQ server is now started". 接下来就可以从客户端注册新用户了。 5) 你可能想要添加一个系统用户,以发送系统广播消息: C:\mysql\bin> mysql -umyicq -Dmyicq -p password: myicq mysql> INSERT INTO basic_tbl (uin, passwd) VALUES(100, password('yourpassword')); mysql> INSERT INTO ext_tbl (uin) VALUES(100); 注意: yourpassword代表系统用户的密码 然后选择客户端程序的注册向导,取回100这个号码。完成后,你会发现在主菜单中多了"广播消息"一项。此后,你可以选择个人设定来设定你的个人信息(比如,不允许任何人加我为好友) ------------- 7. 编译源代码 ------------- 如果你是一个程序员,那么一定要编译MyICQ的源代码:-) 1) 到http://www.mysql.com下载MySQL 2) 由于MyICQ在存储好友资料和聊天记录时,使用Berkeley DB库,所以先到 http://www.sleepycat.com下载 3) 编译Berkeley DB 4) 在VC的Tools->Options->Directories中设置好MySQL和BerkeleyDB的include和library路径 5) 在VC中打开myicq-win32/src/win32/myicq.dsw项目文件 6) 编译 --------- 8. TODO --------- 1) POP3邮件自动监测(插件) 2) 文件共享(插件) 3) 一些小游戏(插件,如俄罗斯方块) 4) 发送好友/URL消息 5) 更完善的皮肤系统 6) 服务器端改为Windows服务程序 7) 服务器端的性能和稳定性 ----------- 9. 共同开发 ----------- MyICQ是我利用上学和上班的空闲时间编写的,发展到现在已经是一个比较大的工程了,以我一个人的力量继续编写下去将非常困难。希望广大的程序员高手能够参与到这个项目中来,为自由软件贡献一份力量。 我在sourceforge.net上申请了CVS服务空间,项目名是myicq-free。有意加入者请与我联系。 ----------- 10. 联系方式 ----------- 如果你在使用MyICQ的过程中,遇到了什么BUG,或是有什么新的想法和建议,或是喜欢这个程序,我将非常高兴收到你的来信。 Email: [email protected] 张勇 Linux用户请不要着急,等在Windows下测试稳定后,马上就会出Linux版的! 天才的人是流星,注定要燃烧自己以照亮他们的世纪 ----- 拿破仑波拿巴 一辆法拉利小车只是物质享受,做人最重要的是真诚 ----- John Carmack 什么叫专业,这就... ----- 张勇:-)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值