一般来说,我们写个客户端程序大概的样子是这样的:

 /* 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的更多相关文章

  1. glusterfs 4.0.1 rpc 分析笔记1

    Jimmy的文档:Glusterfs的rpc模块分析 第一节.rpc服务器端实现原理及代码分析 第二节.rpc客户端实现原理及代码分析 第三节.rpc通信过程分析 经过阅读源码对比之前提及的文档,我个 ...

  2. glusterfs 4.0.1 rpc 分析笔记2 (socket.so 模块)

    socket.c在4000行位置定义了一组结构函数,我们可以从这里开始找到入口,如果是客户端则需要调用connect, 如果是服务端则需要调用listen, struct rpc_transport_ ...

  3. glusterfs4.0.1 mempool 分析笔记

    关于3.2.5版本分析,详见<GlusterFS之内存池(mem-pool)实现原理及代码详解> 此4.0.1版本内存池与版本3中的描述变化有点大,总的原理还是类似LINUX中的SLAB算 ...

  4. 分析现有 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 ...

  5. 从零开始搭建.NET Core 2.0 API(学习笔记一)

    从零开始搭建.NET Core 2.0 API(学习笔记一) 一. VS 2017 新建一个项目 选择ASP.NET Core Web应用程序,再选择Web API,选择ASP.NET Core 2. ...

  6. Windows录音API学习笔记(转)

    源:Windows录音API学习笔记 Windows录音API学习笔记 结构体和函数信息  结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { W ...

  7. Windows录音API学习笔记

    Windows录音API学习笔记 结构体和函数信息  结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD      wMid; 用于波形 ...

  8. Windows录音API学习笔记--转

    Windows录音API学习笔记 结构体和函数信息  结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { WORD      wMid; 用于波形 ...

  9. TCP协议和socket API 学习笔记

    本文转载至 http://blog.chinaunix.net/uid-16979052-id-3350958.html 分类:  原文地址:TCP协议和socket API 学习笔记 作者:gilb ...

随机推荐

  1. php析构方法

    析构方法说明: 1. 析构方法会自动调用 2. 析构方法主要用于销毁资源(比如释放数据库的链接,图片资源...销毁某个对象..); 析构函数会在到对象的所有的引用都被删除或者当对象被显示销毁时执行. ...

  2. nodejs 全局变量

    1.全局对象 所有模块都可以调用 1)global:表示Node所在的全局环境,类似于浏览器中的window对象. 2)process:指向Node内置的process模块,允许开发者与当前进程互动. ...

  3. Linux--初次体验

    关于Linux已经听闻很久的大名了,但是一直没有机会来使用,这次趁着放假的机会,来体验一把Linux吧. 之前使用visuabox和Ubuntu16,但是虚拟机总是不能连接互联网,在虚拟机上面无法上网 ...

  4. 英语词汇(2)fall down,fall off和fall over

    一.fall down,fall off和fall over都表示"摔倒.跌倒"的意思,但它们各自的含义不同. 1.fall over 落在...之上, 脸朝下跌倒 fall ov ...

  5. C# 解析json数据出现---锘縖

    解析json数据的时候出现 - 锘縖,不知道是不是乱码,反正我是不认识这俩字.后来发现是json的 '[' 字符转换的 网上搜了一下,说的是字符集不匹配,把字符集改为GB2312. 一.贴下处理jso ...

  6. EasyUI datagrid动态生成列

    任务描述:根据用户选择时间段,生成列数据,如图

  7. Python之编码

    一.Python2与Python3的区别 1.从宏观上考虑,Python2重复代码太多,错误率高,不够规范.Python崇尚的是语言简洁.优美.清晰.Python3更加规范,重复代码少: 2.Pyth ...

  8. Python之面向对象四

    面向对象进阶 一.关于面向对象的两个内置函数 isinstance   判断类与对象的关系    isinstance(obj,cls)检查obj是否是类 cls 的对象,返回值是bool值 issu ...

  9. Android fragment切换后onresume时报 Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim'

    动态加载fragment以后,调用了remove方法移除Fragment,在返回来的时候报 Attempt to write to field 'int android.support.v4.app. ...

  10. javascript数组去重的3种方法

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! javascript数组去重 <!DOCTYPE html> <html> < ...