您好,登錄后才能下訂單哦!
本篇內容介紹了“GlusterFS Translator API怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
在深入translator api前,我們必須理解關于此api所在上下文的兩個概念。
一個是文件系統api,主要通過分配表xlator_fops,來展露大多數文件系統功能。xlator_fops,就是組合linux vfs的file_operations, inode_operations, and super_operations三類操作在一個數組。要理解xlator如何工作,必須理解這些調用做什么,相互關系是什么,比如open/lookup/close,read/write,opendir/readdir,truncate,symlink等。
一個是xlator api的基礎:是異步的并是基于回調的。意思是處理某個請求的代碼必須分為兩部分,一部分是在進入下一個xlator前的處理,一部分是待下一個xlator處理完成請求后。用另一種方式解說,就是你的分配函數(xlator_fops的前半部分)調用下一個xlator的分配函數,然后直接返回,并不阻塞。你的回調函數(后半部分)也許當你調用下一個xlator的分配函數時就很快被調用,或者后面某個時間從某個完全不同的線程中被調用(常常是網絡傳輸的poll線程)。在兩種情況下,回調都不能僅僅是從棧中取得上下文。Glusterfs確實提供了多種方式來在分配函數和回調函數間保持和傳遞上下文,但是不能僅僅依靠棧,需要我們編碼處理一些事情。
一個xlator的主要的分配表常常是fops(xlator動態庫加載代碼利用dlsym查找操作op名)。fops包含指向所有正常文件系統的操作的指針。僅僅需要填充在本xlator我們感興趣的操作。任何其他的操作在運行時基于默認值來填充,并確定個回調函數,并直接把此請求發到下一個xlator。
默認函數和回調函數除了提供默認功能,也有其他目的。當我們需要添加某個新函數時到一個xlator時,我們可以拷貝和修改那些相同操作的默認函數等。這保證了正確的參數列表和合理的默認行為。每個xlator也許有另外的分配表,比如cbk表,此表用來管理inode和文件描述子的生命周期(看inode和file descriptor context部分)
STACK_WIND and STACK_UNWIND是基于回調機制來實現的。這兩個函數不作用于gdb里類似的調用棧,而是一個獨立維護的棧,每個棧幀表示對xlators的調用。當某個fop從內核傳遞過來要調用時,這個調用就作為一個request請求,從FUSE xlator 經過DHT/AFR等到client xlator 直到server xlator 最后到posix xlator。 我們可以在用戶空間fop入口點做任何需要的處理(這里應該就是fuse xlator),然后使用STACK_WIND沿著volume 文件設置的xlator 路徑,傳遞此請求。
define STACK_WIND(frame, rfn, obj, fn, params …)
STACK_WIND (frame, default_setxattr_cbk, FIRST_CHILD(this), FIRST_CHILD(this)→fops→setxattr, loc, dict, flags, xdata);
此函數的參數解釋如下:
frame:表示此請求的棧幀 stack frame。
rfn:當下一個xlator或者其他xlator完成了此請求(包括前半部分和后半部分)后,要調用的回調函數。
obj:要傳遞到的那個xlator對象,也即下一個xlator,不是調用STACK_WIND的本xlator。多個子的情況如何處理?
fn:要調用的具體的xlator的操作,來自下一個xlator的fops分配表。
params …任何其他的入口點相關的參數(比如針對此fop的inodes, file descriptors, offsets, data buffers等)如前敘,rfn回調函數也許在STACK_WIND的調用內部被調用,也或者后來在另一個環境中被調用。不調用下一個xlator就完成請求比如從cache中讀數據,或者當本xlator層完成對req的處理,要從本層的回調中把請求傳回上一個xlator時,我們使用STACK_UNWIND。實際上,我們最好使用 STACK_UNWIND_STRICT。這個函數允許我們確定請求的種類,比如是open還是close等。
#define STACK_UNWIND_STRICT(op, frame, params …)
STACK_UNWIND_STRICT (symlink, frame, op_ret, op_errno, inode, buf, preparent, postparent, xdata);
參數解釋
參數op:操作類型,是open/還是其他。用來檢查額外參數是否匹配此fop。
params …:此請求的一些額外的參數
另外,在op和params直接,還有兩個參數op_ret和op_errno.雖然沒有在宏定義中出現。但在調用時還是要有的。
op_ret:fop的到目前的狀態(讀的字節數或者寫的字節數,常常0表示fop成功,-1表示失敗)
op_errno:標準錯誤碼,在fop失敗的情況下
具體fop相關的參數有其他特殊的參數,我們可以在params …中實現。但是我們也經常需要這兩個參數
frame:當前請求的stack frame。
this:表示此xlator實例的xlator對象
回調函數跟分配函數類似,除了在這兩個參數間有一個額外的參數cookie。是一個未定義數據類型的指針,由相應的STACK_WIND存儲。默認情況下,這是一個由STACK_WIND生成的stack frame的指針,但是STACK_WIND_COOKIE可以允許我們確定一個不同的值。在這種情況下,這個處于rfn和obj直接的額外參數,可以從分配函數到其回調函數傳遞某些上下文。注意這個指針不能指向棧上的任何內容,因為當回調函數調用時,stack可能已經不存在了。
另一個需要注意的:STACK_UNWIND也許會導致整個調用棧退出,此時,最后的那個STACK_UNWIND調用將會釋放所有的frames。因此,永遠不要期望在調用STACK_UNWIND后,當前的frame內容還是完好的。
每個xlator 棧幀有一個local 指針,是用來保存xlator相關的上下文。這是最基本的機制,用來在分配函數和回調間保存上下文。因此我們應該習慣如下代碼模式
/* in dispatch function */
local = (my_locals_t *)GF_CALLOC(1,sizeof(*local),...);
if (!local) {
/* STACK_UNWIND with ENOMEM eror */
}
/* fill in my_locals_t fields */
frame->local = local;
/* in callback */
local = frame->local;
要記住:每個幀frame的非NULL的local域當要毀棧時要用GF_FREE來釋放,不用做其他的清理工作。如果local結構里包含指針或對其他對象的引用,需要我們自己進行這些資源的清理。在毀棧前,內存或者其他資源先清理是個好的習慣,為此就不能依靠GF_FREE來自動清理。最安全的方式是定義我們自己的xlator相關的destructor,在調用STACK_UNWIND前手動調用。
大多數分配函數和回調以文件描述子或節點inode為參數。file descriptor (fd_t) or an inode (inode_t)。常常,xlator需要保存一些這些對象的一些關于此xlator的一些上下文,以此,在一個請求的完整生命周期內信息可以保持。例如,DHT xlator需要保存目錄的layout map和某些inode的已知的位置。有一套函數來存儲操作此類上下文。在每個函數中,第二個參數是此value相關的xlator對象的指針。value是64位無符號×××。
inode_ctx_put (inode, xlator, value) /* NB: put, not set */把value放到inode里?
inode_ctx_get (inode, xlator, &value)從inode中獲取值到value。
inode_ctx_del (inode, xlator, &value)
fd_ctx_set (fd, xlator, value) /* NB: set, not put */
fd_ctx_get (fd, xlator, &value)
fd_ctx_del (fd, xlator, &value)
_del函數實際是破壞性get,先返回然后刪除值。inode函數有兩個value的形式,比如inode_ctx_put2,操作兩個值。使用xlator指針作為key/index并不僅僅是為了好看。當要刪除inode_t or fd_t時, 刪除代碼要瀏覽上下文槽(估計就是遍歷所有xlator)。對于每個使用inode_t or fd_t的xlator的上下文槽,查看xlator的cbk表,調用其forget 或者release。如果上下文是個指針,需要手動釋放資源。傳遞到分配函數和回調的inode_t or fd_t pointer參數,僅僅是個 borrowed reference。如果需要保證以后對象還在,需要調用inode_ref or fd_ref,來達到permanent reference。當不再需要引用時可以 inode_unref or fd_unref。
另一個常見的參數類型dict _t,是一種通用詞典或者hash-map的數據結構,用來以字符串key/索引的方式保存任意值。例如,值可以是可變大小的有無符號的×××,字符串,二進制blob。字符串,二進制blob也許可以用GLusterfs函數free,也可以用glibc free。或者不用free。保存引用計數的值的dict_t* 和the *data_t 對象,在引用數為0的情況下釋放資源。和inode和文件描述子一樣,如果想在以后使用接受到dict_t的對象,需要使用add _ref and _unref來管理其生命周期。詞典不僅僅用于分配函數和回調函數。也用于傳遞options到模塊,比如xlator的init函數所用的options。事實上,目前的xlator的init函數主體大部分是來解釋包含在詞典里的options。要給xlator添加一個option,也需要向xlator的options 數組里添加一項。每個option可以是個boolean/整型/字符串/路徑/xlator 名字/其他類型。如果是個字符串,可以確定一個正確的值的列表。解析后的options,加上其他xlator級別的信息,將存儲在xlator_t structure結構(在大多數上下中用this表示)的private的成員變量中。
在一個xlator里的代碼,經常需要枚舉其子xlator。要不找到一個滿足要求的子xlator的或者操作所有的子xlator。例如,對于DHT xlator,需要從所有的子xlator收集 hash-layout 映射,以確定文件應該放到哪個子xlator;對于 AFR xlator,需要從子xlator中提取同一文件將要執行的操作個數以便確定replication復制狀態。代碼范例如下: xlator_list_t *trav; xlator_t *xl;
for (trav = this->children; trav; trav = trav->next) { xl = trav->xlator; do_something(xl); }
如果目的是扇出一個請求到所有的子xlator,則需要一些努力。在一個分配函數里最常用的方式是如下 local→call_count = priv→num_children;
for (trav = this->children; trav; trav = trav->next) { xl = trav->xlator; STACK_WIND(frame,my_callback,xl,xl->fops->whatever,...); } 然后在回調函數中執行 LOCK(&frame->lock); call_cnt = --local->call_count; UNLOCK(&frame->lock);
/* Do whatever you do for every call */
if (!call_cnt) { /* Do last-call processing. */ STACK_UNWIND(frame,op_ret,op_errno,...); }
return 0; 在某些情況下,可以使用STACK_WIND_COOKIE,這樣可以在回調中知道具體哪個調用返回了。可以查看AFR。
所有的xlator 函數使用類似SEDA和AT&T的STREAMS的異步調用規范。需要的調用幀和調用棧數據結構功能上幾乎與Windows NT里的I/O requst packets 和irp 棧相同。許多xlator函數類似與fuse對應的函數,但是修改了或者添加了其他參數。
在xlator api里這是最基本的數據結構,call_frame_t and call_stack_txlators環境可以看作是個線程庫,每個請求有自己一個輕量級線程。這個線程有自己的棧,但是這些調用棧比c棧更加結構化,同時常常偏離棧的嚴格的FIFO語義。每個調用幀表示一個函數調用,函數調用也許是嵌套的。但是這些函數在c里實際上兩個調用--初始部分執行并在進行任何嵌套調用前返回。收尾部分在嵌套的調用完成后執行。
call_frame_t的成員如下:
root:指向內嵌在call_stack_t里的假幀,不像其他單獨分配的frame。在stack里對所有的frame都相同。
parent指向調用此frame的那個frame。用c說就是調用函數 calling 函數。
next /prev指向下一個/前一個要完成的frame。注意不是要調用的那個幀,
local 私有數據,針對此幀調用的私有數據。是xlagor函數的本地變量,保存在此,可以在分配函數和回調間保持。
this 指向xlator的私有全局狀態。
ret 指向調用者(上層xlator)的回調函數,當本xlator的req完成后執行。
ref_count and complete 調度器用來跟蹤那個frame是active,哪個完成了,哪個需要恢復執行。
lock and cookie:
正常情況下,新frame push到棧后,next就跟parent就相同了。但是,一個frame(幀)可以分支。例如,stripe_writev請求的幀,在每個子xlator返回前生成一個新幀。假設有3個子xlator,即3個子卷。next就只與第一個新幀相同。
根據線程庫模型,call_stack_t對應的就是線程控制塊。
有用的成員變量有:
uid 和gid表示調用幀來自誰,用來鑒權和認證。
pid表示發起此請求的進程pid。
trans 指向請求相關的transport 結構。在服務器端用來實現基于節點的存取控制,或者用來沿著失敗的連接跟蹤請求。在client用作啥用?
frames:假幀,指向請求的第一個真正的frame。
op /type?
call_pool_t?
STACK_WIND and STACK_UNWIND等價與函數的調用和返回。在本xlator的請求的執行,分配表先執行,wind后就停止只ing了。當函數rfn回調函數執行時,此操作就開始恢復執行了。rfn也許被調用多次。(多個子卷)。
todo
call stack
call stub
Version 1.0
Last updated 2014-04-30 12:28:09 CST
“GlusterFS Translator API怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。