glusterfs 4.0.1 api 分析笔记1
一般来说,我们写个客户端程序大概的样子是这样的:
/* glfs_example.c */ // gcc -o glfs_example glfs_example.c -L /usr/lib64/ -lgfapi -I /usr/include/glusterfs/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "api/glfs.h"
#include "api/glfs-handles.h"
#include <string.h>
#include <time.h> int
main (int argc, char *argv[])
{
glfs_t *fs2 = NULL;
int ret = 0;
glfs_fd_t *fd = NULL;
glfs_fd_t *fd2 = NULL;
char readbuf[32];
char writebuf[32];
char *filename = "/filename2"; if (argc != 3) {
printf ("Expect following args\n\t%s <volname> <hostname>\n", argv[0]);
return -1;
} /* 初始化gluster环境 */
fs2 = glfs_new (argv[1]);
if (!fs2) {
fprintf (stderr, "glfs_new: returned NULL\n");
return 1;
}
ret = glfs_set_volfile_server (fs2, "tcp", argv[2], 24007);
ret = glfs_set_logging (fs2, "/dev/stderr", 1);
ret = glfs_init (fs2);
fprintf (stderr, "glfs_init: returned %d\n", ret); /* 进行libgfapi函数调用 */
fd = glfs_creat (fs2, filename, O_RDWR, 0644);
fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno)); fd2 = glfs_open (fs2, filename, O_RDWR);
fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno)); sprintf (writebuf, "hi there\n");
ret = glfs_write (fd, writebuf, 32, 0); glfs_lseek (fd2, 0, SEEK_SET);
ret = glfs_read (fd2, readbuf, 32, 0);
printf ("read %d, %s", ret, readbuf); glfs_close (fd);
glfs_close (fd2); /* Gluster环境释放 */
glfs_fini (fs2); return ret;
}
我们这里按照程序执行的思路,一句一句的解读程序的执行过程。
1、 fs2 = glfs_new (argv[1]);
/* glfs_new: 创建一个 'virtual mount' 对象 这应该是调用的一个函数. 在这个新建立的对象(glfs_t类型), 你需要设置一个 volfile path
(glfs_set_volfile)或者一个 volfile server (glfs_set_volfile_server). 这个对象还需要使用 glfs_init()初始化,然后才能调用其他的文件操作. @volname: 卷名. 用来标记服务器端的卷以及获取来的卷文件 (等效于 glusterfsd --volfile-id 命令).
当使用 glfs_set_volfile() 函数时,这个 @volname 就没有作用了。
*/ glfs_t *glfs_new (const char *volname) __THROW GFAPI_PUBLIC(glfs_new, 3.4.);
1.1 这句内部定义如下:在(glfs.c中)pub_glfs_new
mem_pools_init_early (); // 初始化mem_pool对象。
mem_pools_init_late (); fs = glfs_new_fs (volname); // 初始化struct glfs *fs 内部各个锁和链表 670行
ctx = glusterfs_ctx_new (); // 18行,建立一个对象 ctx.c /* first globals init, for gf_mem_acct_enable_set () */
ret = glusterfs_globals_init (ctx); // 定义于globals.c 中,内部调用 glusterfs_this_init ()
// 定义了一个全局对象 xlator_t global_xlator,并初始化 old_THIS = THIS; // 通过线程本地存储来保存当前的 xlator_t *old_THIS, 如果还没有,则建议几个新的指针来存储,并设置为之前的全局的 &global_xlator
ret = glfs_init_global_ctx (); /* then ctx_defaults_init, for xlator_mem_acct_init(THIS) */
//ret = glusterfs_ctx_defaults_init (ctx);
// 前移句内部会调用这句。初始化ctx:建立内部的iobuf_pool,建event_pool, frame_mem_pool 等一系列的内部资源池
// 这个函数非常重要!!!里面涉及其他资源的建立,请参考相关部分的分析。
fs->ctx = ctx;
fs->ctx->process_mode = GF_CLIENT_PROCESS; ret = glfs_set_logging (fs, "/dev/null", 0);
fs->ctx->cmd_args.volfile_id = gf_strdup (volname);
到这里,基本内存资源都已经初始化完毕了,event_pool初始化也表示epoll模型也初始化完毕了。
2、glfs_set_volfile_server (fs2, "tcp", argv[2], 24007);
pub_glfs_set_volfile_server // 441行
初始化协议,
3、glfs_init (fs2); 这里开始内部结构的初始化了。
pub_glfs_init (struct glfs *fs) // 1507行
{
// create_master (fs)创建一个xlator_t;建议线程启动epoll;而glfs_volumes_init则是其中最重要的部分!!!
int ret = glfs_init_common (fs);
if (ret == 0)
{ // 之所以有这句,说明前一句里面是异步的初始化,有连接服务器和初始化动作,所以需要等待完成。
ret = glfs_init_wait (fs);
}
if (ret >= 0)
{ // 既然这里已经切换到根目录了,说明之前的两句作用还是很大的!!!
ret = glfs_chdir (fs, "/");
}
}
所以我们继续分析 glfs_volumes_init 该函数 确定当服务器不在当前主机,则执行了glfs_mgmt_init
相关部分请参考:glusterfs 4.0.1 rpc 分析笔记1
// glfs-mgmt.c中
int glfs_mgmt_init (struct glfs *fs)
{
cmd_args_t *cmd_args = NULL;
struct rpc_clnt *rpc = NULL;
dict_t *options = NULL;
int ret = -1;
int port = GF_DEFAULT_BASE_PORT;
char *host = NULL;
glusterfs_ctx_t *ctx = NULL; ctx = fs->ctx; rpc = rpc_clnt_new (options, THIS, THIS->name, 8);
// 建立一个rcp_clnt类型,这个类型封装了客户端的基本操作,
// 这个函数内部,加载rpc_tranport,并动态加载了socket.so模块, // rcp_clnt对象遇到事件回调此函数,
// 这个函数很重要,当连接成功后,将调用glfs_volfile_fetch 进行初始命令交互
ret = rpc_clnt_register_notify (rpc, mgmt_rpc_notify, THIS); // 注册接收数据时候的回调函数
ret = rpcclnt_cbk_program_register (rpc, &mgmt_cbk_prog, THIS);
ctx->notify = glusterfs_mgmt_notify; // 设置管理器为rcp_clnt对象
ctx->mgmt = rpc; // 然后这个对象工作,内部调用 rpc_transport_connect,其实是调用socket.so的connet() ret = rpc_clnt_start (rpc);
return ret;
}
4、我们注意到最后终于执行了socket 的connect函数,当底层连接成功后,会逐级的回调:
最终会执行 mgmt_rpc_notify 函数,此函数里面连接成功部分有如下两句:
rpc_clnt_set_connected (&((struct rpc_clnt*)ctx->mgmt)->conn); ret = glfs_volfile_fetch (fs); // 这一句相当的关键,因为这一句里面触发了连接成功后第一次提交 “远程调用请求”
glfs_volfile_fetch函数的主要代码为:
int
glfs_volfile_fetch (struct glfs *fs)
{
cmd_args_t *cmd_args = NULL;
gf_getspec_req req = {0, };
int ret = 0;
call_frame_t *frame = NULL;
glusterfs_ctx_t *ctx = NULL;
dict_t *dict = NULL; ctx = fs->ctx; frame = create_frame (THIS, ctx->pool); req.key = cmd_args->volfile_id;
req.flags = 0; dict = dict_new (); // Set the supported min and max op-versions, so glusterd can make a
// decision
ret = dict_set_int32 (dict, "min-op-version", GD_OP_VERSION_MIN); ret = dict_set_int32 (dict, "max-op-version", GD_OP_VERSION_MAX); /* Ask for a list of volfile (glusterd2 only) servers */
if (GF_CLIENT_PROCESS == ctx->process_mode) {
req.flags = req.flags | GF_GETSPEC_FLAG_SERVERS_LIST;
} ret = dict_allocate_and_serialize (dict, &req.xdata.xdata_val,
&req.xdata.xdata_len); ret = mgmt_submit_request (&req, frame, ctx, &clnt_handshake_prog,
GF_HNDSK_GETSPEC, glfs_mgmt_getspec_cbk,
(xdrproc_t)xdr_gf_getspec_req);
out:
if (req.xdata.xdata_val)
GF_FREE(req.xdata.xdata_val);
if (dict)
dict_unref (dict); return ret;
}
4、引用一篇文章:《glusterfs通信之rpc》
glusterfs 4.0.1 api 分析笔记1的更多相关文章
- glusterfs 4.0.1 rpc 分析笔记1
Jimmy的文档:Glusterfs的rpc模块分析 第一节.rpc服务器端实现原理及代码分析 第二节.rpc客户端实现原理及代码分析 第三节.rpc通信过程分析 经过阅读源码对比之前提及的文档,我个 ...
- glusterfs 4.0.1 rpc 分析笔记2 (socket.so 模块)
socket.c在4000行位置定义了一组结构函数,我们可以从这里开始找到入口,如果是客户端则需要调用connect, 如果是服务端则需要调用listen, struct rpc_transport_ ...
- glusterfs4.0.1 mempool 分析笔记
关于3.2.5版本分析,详见<GlusterFS之内存池(mem-pool)实现原理及代码详解> 此4.0.1版本内存池与版本3中的描述变化有点大,总的原理还是类似LINUX中的SLAB算 ...
- 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0(使用 .NET Core 3.0 Desktop API Analyzer )
今年五月的 Build 大会上,微软说 .NET Core 3.0 将带来 WPF / Windows Forms 这些桌面应用的支持.当然,是通过 Windows 兼容包(Windows Compa ...
- 从零开始搭建.NET Core 2.0 API(学习笔记一)
从零开始搭建.NET Core 2.0 API(学习笔记一) 一. VS 2017 新建一个项目 选择ASP.NET Core Web应用程序,再选择Web API,选择ASP.NET Core 2. ...
- Windows录音API学习笔记(转)
源:Windows录音API学习笔记 Windows录音API学习笔记 结构体和函数信息 结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { W ...
- Windows录音API学习笔记
Windows录音API学习笔记 结构体和函数信息 结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD wMid; 用于波形 ...
- Windows录音API学习笔记--转
Windows录音API学习笔记 结构体和函数信息 结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD wMid; 用于波形 ...
- TCP协议和socket API 学习笔记
本文转载至 http://blog.chinaunix.net/uid-16979052-id-3350958.html 分类: 原文地址:TCP协议和socket API 学习笔记 作者:gilb ...
随机推荐
- Linux的安装和使用技巧
LinuxCentOs开始设置一个普通的用户,如果想进入root用户,可以su然后设置密码,然后第二次再次输入su,然后输入相同的密码就可以进去了 有很多命令需要在root下才能执行,但是在创建时却是 ...
- javascript 中的类型
javascript 中的类型 js 是一门弱语言,各式各样的错误多种多样,特别是确定返回值有问题的时候,你会用什么来进行表示错误? 我一般有三个选择: null '' error {} 第一个选择 ...
- proxymysql的安装与应用
具体的资料我们可以查看官方的文档:https://github.com/sysown/proxysql/wiki/ProxySQL-Configuration 推荐下载最新的Proxysql. 下面跟 ...
- C语言学习之弹跳小球
重新回过头来看了一遍C语言,才发现我自己的无知,C语言其实好强大,我之前学的不过是一点C语法和做几个数学题.正好3月份的考试要考C语言,重新学一遍,先是在中国大学mooc上把翁恺老师的C语言刷了一遍, ...
- Docker学习笔记 - Docker Compose 脚本命令
Docker Compose 配置文件包含 version.services.networks 三大部分,最关键的是 services 和 networks 两个部分, version: '2' se ...
- GIT入门笔记(20)- 使用eclipse 基于 git 开发过程梳理
一.创建本地分支 1.下载/更新 本地 主干 如果本地还没有 本地主干,下载:git clone 如果本地已有了 本地主干,更新:git pull 工程右键菜单:team -> pull 2.基 ...
- js中的caller属性和callee属性
应该用"属性"来称呼caller和callee,而不是方法. caller:返回调用当前函数的函数的引用.a调用b,则返回a(a是boss,因为a把b叫过去干活了): callee ...
- python/MySQL练习题(二)
python/MySQL练习题(二) 查询各科成绩前三名的记录:(不考虑成绩并列情况) select score.sid,score.course_id,score.num,T.first_num,T ...
- Hibernate(十五):QBC检索、本地SQL检索和HQL删除
QBC检索 QBC查询就是通过使用Hibernate提供的Query By Criteria API来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口. 1)通过Cr ...
- 从感知机到 SVM,再到深度学习(三)
这篇博文详细分析了前馈神经网络的内容,它对应的函数,优化过程等等. 在上一篇博文中已经完整讲述了 SVM 的思想和原理.讲到了想用一个高度非线性的曲线作为拟合曲线.比如这个曲线可以是: ...