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.0);

     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》

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM