分析一 corosync服务的load
1 什么是corosync服务
corosync只是一个高可用的网络通讯的框架,所以的功能均是以服务的方式存在于框架之中。
为了可以实现服务的动态装入和可裁剪的架构灵活性,corosync把自身的网络通讯功能部分也做成了服务。
2 corosync服务load的层次
corosync的架构:
1 +----------------------------------------+ 2 | IPC Manager | 3 +----------------------------------------+ 4 | Service Manager | 5 +----------------------------------------+ 6 | Synchronization Engine | 7 +----------------------------------------+ 8 | The Totem Stack | 9 +----------------------------------------+ 10 | Timers | 11 +----------------------------------------+ 12 | Logging System | 13 +----------------------------------------+ 14 | Object Database | 15 +----------------------------------------+ 16 | Live Component Replacement | 17 +----------------------------------------+ 18 | Handle Database Manager | 19 +----------------------------------------+
上面是corosync引擎内部的层次框架,从Object Database开始向上的所有层都被corosync以服务的形式实现。
只有Handle Database Manager 和 Live Component Replacement这两层的代码是以直接调用的方式实现的。
Handle Database Manager只是corosync用来保存服务句柄的一个Map
真正的实现服务的装载的就是Live Component Replacement层
3 corosync服务的装载如果服务是从Object Database开始,那么最先装载的肯定就是Objdb服务了。从corosync的main代码中可以找到:
1 /* 2 * Load the object database interface 3 */ 4 res = lcr_ifact_reference ( 5 &objdb_handle, 6 "objdb", 7 0, 8 &objdb_p, 9 0); 10 if (res == -1) { 11 log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't open configuration object database component.\n"); 12 corosync_exit_error (AIS_DONE_OBJDB); 13 }
从上面的代码中可以看出 lcr_ifact_reference 就是装入函数。下面看这个函数
1 int lcr_ifact_reference ( 2 hdb_handle_t *iface_handle, 3 const char *iface_name, 4 int version, 5 void **iface, 6 void *context) 7 { 8 9 /* 10 * Determine if the component is already loaded 11 */ 12 instance = lcr_comp_find (iface_name, version, &iface_number); 13 if (instance) { 14 goto found; 15 } 16 17 if (lcr_initialized == 0) { 18 lcr_initialized = 1; 19 defaults_path_build (); 20 ld_library_path_build (); 21 ldso_path_build ("/etc", "ld.so.conf"); 22 } 23 24 // TODO error checking in this code is weak 25 /* 26 * Search through all lcrso files for desired interface 27 */ 28 for (i = 0; i < path_list_entries; i++) { 29 res = interface_find_and_load ( 30 path_list[i], 31 iface_name, 32 version, 33 &instance, 34 &iface_number); 35 36 if (res == 0) { 37 goto found; 38 } 39 }
从上面的代码看,lcr_comp_find将通过iface_name去装入objdb服务。
但是由于corosync刚启动还没有任何服务,所以第12行将找不到任务服务而不能执行goto found,只能继续执行。
第一次调用lcr_ifact_reference,第17行lcr_initialized这个参数将为0,进入这个分支 lcr_initialized变量被置为1,并执行defaults_path_build,ld_library_path_build,ldso_path_build这个三个函数找到服务.so文件的正确位置。
第一个default_path_build中的LCRSODIR宏告诉我们,所有服务的.so文件将在"/usr/libexec/lcrso"这个路径被加载,而这个函数也只是把.so文件的路径放到path_list的数组中。
真正的服务的装载工作是由第29行的interface_find_and_load函数去负责,这个函数将会把每个服务的.so的文件装入其中。 跟进这个函数,我们将看到下面的代码
1 for (libs_to_scan = 0; libs_to_scan < scandir_entries; libs_to_scan++) { 2 /* 3 * Load objects, scan them, unload them if they are not a match 4 */ 5 snprintf (dl_name, sizeof(dl_name), "%s/%s", 6 path, scandir_list[libs_to_scan]->d_name); 7 /* 8 * Don't reload already loaded libraries 9 */ 10 if (lcr_lib_loaded (dl_name)) { 11 continue; 12 } 13 dl_handle = dlopen (dl_name, RTLD_NOW); 14 if (dl_handle == NULL) { 15 fprintf(stderr, "%s: open failed: %s\n", 16 dl_name, dlerror()); 17 continue; 18 } 19 instance = lcr_comp_find (iface_name, version, iface_number); 20 if (instance) { 21 instance->dl_handle = dl_handle; 22 strcpy (instance->library_name, dl_name); 23 goto found; 24 }
上面的代码的第13行,将会通过dlopen打开服务的.so文件。
注意在第21行的时候,服务组件的实例将会和服务的.so建立联系。
然后我们就可以通过服务组件的实例去使用服务的功能了。
4. 最后总结
我对corosync架构的理解:如果把服务都减去的话,corosync的架构就是一个对象实例管理器,一个大map。