句柄数据库(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;
函数原型:
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;
函数原型:
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代码为自己所用。