句柄数据库(HDB)
关于HDB的所有代码在hdb.h中。
corosync 的所有操作都是以句柄为单位操作的。
HDB 既用于 corosync IPC通讯的 server 端管理句柄,又用于 corosync IPC 通讯的 client 端管理句柄。
handle的主要结构:
1 struct hdb_handle {
2 int state;
3 void *instance;
4 int check;
5 int ref_count;
6 };
hdb_handle state的类型:
1 enum HDB_HANDLE_STATE {
2 HDB_HANDLE_STATE_EMPTY,
3 HDB_HANDLE_STATE_PENDINGREMOVAL,
4 HDB_HANDLE_STATE_ACTIVE
5 };
句柄的结构实际上就是指向服务的指针,带着引用计数和状态。
在corosync中,会把hdb_handle作为数组存储,这时就需要一个统一管理数组的结构。例如链表代码,都是由链表节点结构和链表头结构组成一样。
hdb_handle_database 结构:
1 struct hdb_handle_database {
2 unsigned int handle_count;
3 struct hdb_handle *handles;
4 unsigned int iterator;
5 void (*destructor) (void *);
6 pthread_mutex_t lock;
7 unsigned int first_run;
8 };
对HDB的使用只有三个基本操作:
1 hdb_handle_create
2
3 hdb_handle_get
4
5 hdb_handle_put
1. hdb_handle_create 句柄的创建:
函数头结构:
1 static inline int hdb_handle_create (
2 struct hdb_handle_database *handle_database,
3 int instance_size,
4 hdb_handle_t *handle_id_out)
首先,hdb_handle_create会遍历所有已经存在的句柄,看是否会有空闲的句柄存在,如果有可以用来复用。这样可以节省malloc为新句柄分配空间的时间。
这也说明了如果句柄不用,可以被置为HDB_HANDLE_STATE_EMPTY,而不应该被释放掉。
1 for (handle = 0; handle < handle_database->handle_count; handle++) {
2 if (handle_database->handles[handle].state == HDB_HANDLE_STATE_EMPTY) {
3 found = 1;
4 break;
5 }
6 }
如果没有找到合适的空闲句柄,则增加句柄数组的空间,并创建新的句柄。
1 if (found == 0) {
2 handle_database->handle_count += 1;
3 new_handles = (struct hdb_handle *)realloc (handle_database->handles,
4 sizeof (struct hdb_handle) * handle_database->handle_count);
5 if (new_handles == NULL) {
6 hdb_database_unlock (&handle_database->lock);
7 errno = ENOMEM;
8 return (-1);
9 }
10 handle_database->handles = new_handles;
11 }
12
13instance = (void *)malloc (instance_size);
14
15 memset (instance, 0, instance_size);
16
17 handle_database->handles[handle].state = HDB_HANDLE_STATE_ACTIVE;
18
19 handle_database->handles[handle].instance = instance;
20
21 handle_database->handles[handle].ref_count = 1;
22
23 handle_database->handles[handle].check = check;
24
25 *handle_id_out = (((unsigned long long)(check)) << 32) | handle;
2.hdb_handle_get
函数原型:
1 static inline int hdb_handle_get (
2 struct hdb_handle_database *handle_database,
3 hdb_handle_t handle_in,
4 void **instance)
入参是由hdb_handle_create生成的句柄值handle_in。
得到的实例句柄将会传给instance,由调用者使用。并且此实例的句柄引用计数将增加。
1 *instance = handle_database->handles[handle].instance;
2
3 handle_database->handles[handle].ref_count += 1;
3.hdb_handle_put
函数原型:
1 static inline int hdb_handle_put (
2 struct hdb_handle_database *handle_database,
3 hdb_handle_t handle_in)
入参依然是由hdb_handle_create生成的句柄值handle_in。
hdb_handle_put将会对handle_in所得到的句柄引用减1,当句柄引用为0的时候,通过回调
handle_database->destuctor函数对实例句柄进行回收。
1 handle_database->handles[handle].ref_count -= 1;
2 assert (handle_database->handles[handle].ref_count >= 0);
3
4 if (handle_database->handles[handle].ref_count == 0) {
5 if (handle_database->destructor) {
6 handle_database->destructor (handle_database->handles[handle].instance);
7 }
8 free (handle_database->handles[handle].instance);
9 memset (&handle_database->handles[handle], 0, sizeof (struct hdb_handle));
10 }
个人总结:
这个hdb实际上可以看成是对象的句柄池。hdb对corosync的服务生成对象的实例,通过句柄结构进行统一管理,这样不但通过引用的方式复用了相同服务的句柄,而且把对象实例的产生,回收和使用抽象成相同的代码行为。
如果需要写服务器的对象池,连接池,线程池的代码,都可以改造hdb代码为自己所用。