外篇 MOSIX集群係統
加入書簽
章節字數:5406
滾屏速度:
保存設置 開始滾屏
集群係統的各組成部分經常要互相通訊,MOSIX提供了一個連接層抽象(linkerlayer),在套接字接口之上使用TCP/UDP協議進行通信。
作為一個集群係統,節點之間要經常合作,不時的散布和收集負載信息,獲取其它節點的情況。另外,我們也已經看到,在MOSIX中,一個遷移進程實際上是由deputy和remote兩部分組成的。Deputy和remote是兩個單獨的進程,分別位於不同的節點,但在邏輯上,它們卻是看出一個獨立的進程的。它們之間經常要通過頻繁的通訊來合作。因此,通信機製是至關重要的。MOSIX提供了一個連接層抽象(linkerlayer),在套接字接口之上封裝了一層,提供了一係列類似BSDSOCKET的接口函數用於在進程間接收和發送MOSIX相關數據的。MOSIX連接是位於內核中的,對用戶態進程是不可見的。
作為一個集群係統,MOSIX中的每個節點都被分配一個唯一的節點號,節點號是一個整型值,從1開始連續分配的。0表示的是當前節點。通過節點號抽象,可以很方便的定位某個節點。但是通過網絡發送和接收數據,都是以IP地址來尋找節點的。因此,MOSIX係統提供了一係列函數用於在節點號和IP地址間的互相轉換和匹配。每個節點在/etc/目錄下都存在著一個配置文件mosix。map,保存著整個集群係統節點的IP地址信息。該文件的每一行都包含3個域,分別為節點範圍的起始號,IP地址或主機名,該範圍中的節點數目。例如某係統的配置文件如下:
1172。26。4。1381
2172。26。4。1392
4MOSIX_41
機器MOSIX_4的IP為172。26。4。22。在這個係統中,節點1的IP為172。26。4。138。節點2,3的IP則分別為172。26。4。139,172。26。4。140。節點4的IP則為172。26。4。22。
數據結構
structmosix_link表示一條MOSIX連接,它維持著該連接的狀態和一些控製信息。定義如下:
structmosix_link{
structsocket*sock;/*套接字控製結構,用於通訊,通過它進行實際的網絡操作*/
intflags;/*狀態標誌*/
intdlen;/*懸掛數據的長度*/
intpeer;/*連接另一端的節點號*/
char*hideptr;/*指向當前隱藏數據的指針*/
char*hidebuf;/*指向隱藏數據緩衝區起始地址的指針*/
inthidelen;/*隱藏數據的長度*/
charhead[COMM_DEF_HEADSIZE];/*存放著消息頭*/
};
structcomm_header{消息格式
unsignedshortolen;//Optiondatalength--
unsignedshorthlen;
inttype;
intdlen;
intregs;
intdfsalen;
};
#defineCOMM_HLEN(sizeof(structcomm_header))
MOSIX中,每個進程的控製塊中都保持著一條MOSIX連接contact(structmosix_link*contact),用於deputy和remote之間的通訊。進程的remote部分可以在節點間多次遷移,但是deputy總能根據它的contact連接來定位remote部分;remote也能根據它的contact連接和deputy部分通訊合作。對於未遷移的進程,contact總是為NULL。
回頁首
MOSIX連接層接口
MOSIX連接層提供了一係列接口用於集群間進程之間互相發送和接收數據。從這些接口的名字上,我們就很容易判斷出它們的功能。
comm_open():為MOSIX通訊打開一條連接
mosix_link*comm_open(intmos,mosix_addr*maddr,unsignedlongtimo)
如果mos0,則連接到第#mos號節點上的遷移守護進程。
如果mos=COMM_TOADDR,則連接maddr-saddr中給定的地址。
如果mos=COMM_ACCEPT,則打開一個SOCKET,並且可以接受連接。
如果mos=COMM_MIGD,則為遷移守護進程設置SOCKET。
如果mos=COMM_INFOD,則為信息守護進程設置SOCKET。
如果mos=COMM_LOOSE,則允許連接多個守護進程。
comm_use():為進程設置新的連接並返回舊的連接
mosix_link*comm_use(structtask_struct*p,mosix_link*mlink)
進程p將使用mlink連接進行通訊。
comm_close():關閉Mosix通訊連接
voidcomm_close(mosix_link*mlink)
調用comm_shutdown(mlink)關閉對連接的寫入,然後通過sock_release(mlink-sock)釋放該連接上的套接字。
comm_accept():在Mosix通訊套接字上接受連接
intcomm_accept(mosix_link*ml,mosix_link**mlp,mosix_addr*ma,unsignedlongt)
接受建立連接請求,mlp指向建立的新連接,連接的另一端的地址保存在ma中。
comm_waitaccept():在Mosix通訊套接字上接受連接
staticint
comm_waitaccept()comm_waitaccept()調用comm_accept接收連接請求並建立一條新的連接,然後comm_use這條新的連接並關閉舊的連接。
comm_send():發送一條消息(head+data)
intcomm_send(inttype,void*head,inthlen,void*data,intdlen,intuspace)
如果要發送的數據來自用戶空間(uspace),且可能會導致遠程page-fault(dirty_all_remote_pages),則先把數據從用戶空間拷入內核,然後檢查地址範圍的有效性(ucache_ok)。
如果type&COMM_MFREGS或則type&COMM_MFIDENT,則分別通過comm_packregs(0,0)和comm_packident(0)進行壓縮,可能產生選項數據。
將數據按照消息格式組裝起來,然後調用套接字操作集上的sendmsg操作將消息發送出去。
comm_sendto():發送一個數據報
intcomm_sendto(intmos,void*data,intlen,mosix_link*mlink,mosix_addr*to)
通過mlink連接,發送len長的數據到to指明的地址,發送的數據在data中。
to指明目的地址,如果為空,則數據是發送給節點mos上的負載信息守護進程(INFO_DAEMON)。
調用套接字操作集上的sendmsg操作將消息發送到指定的地址。
comm_dorecv():從連接中可靠的讀取數據
intcomm_dorecv(structsocket*sock,structmsghdr*msg,intlen)
根據msg,通過調用套接字操作集上的recvmsg操作從網絡連接上讀取數據。它讀的是字節流,並沒有格式的。
comm_recv():接收消息頭
intcomm_recv(void**headp,int*hlen)
如果當前進程的連接處於等待接受連接請求狀態(COMM_WAITACCEPT),則等待直到接受請求。然後通過comm_dorecv()接收消息頭長度(COMM_HLEN)的數據,得到消息頭的實際長度(hlen+olen),然後準備空間存放消息頭數據(comm_mkhead),再通過comm_dorecv()接收實際的消息頭數據,並根據其中的信息,調用不同的解壓處理程序。因為為了減少傳輸的數據量,消息數據發送前都經過了壓縮。
如果有數據COMM_MFDATA,則將數據長度保存在連接的數據長度中(mlink-dlen=header。dlen),這樣,隨後調用comm_copydata和comm_recvdata時,我們將知道應該能夠從網絡中讀取多少數據。
comm_copydata():從消息中拷貝數據
intcomm_copydata(void*data,intlen,intuspace)返回0表示成功。
從消息中拷貝長度為len的數據。讀入的數據保存在data指向的buffer中。Uspace表明data是指向用戶空間還是內核空間。成功時返回0。
如果要data指向用戶空間(uspace),且會導致遠程page-fault(dirty_all_remote_pages),則返回內存不足錯誤。
如果連接中不存在數據,但是隱藏數據緩衝區不為空,則從隱藏數據緩衝區拷貝len長數據到data中。否則則通過comm_dorecv函數從網絡中讀取數據。
comm_recvdata():從連接中將所有數據讀取到已分配緩衝區中/*
intcomm_recvdata(void**data)返回0表示成功。
如果連接中存在隱藏數據(COMM_HIDEDATA),則data指向隱藏數據緩衝區,然後置連接的隱藏數據緩衝區為NULL。
否則,調用comm_malloc分配內存,通過comm_dorecv試圖將連接所有的數據(mlink-dlen)都接收放入到其中。data將指向分配的內存緩衝區。
comm_recvfrom():接收數據報
intcomm_recvfrom(void*data,intlen,mosix_link*mlink,mosix_addr*from,unsignedlongtimo)
讀取長為len的數據放在data中,from返回接收數據報的源地址。timo指明超時值,單位為微秒。返回接收數據的長度(0)或者錯誤。
調用套接字操作集上的recvmsg操作來接收數據,數據報的源地址返回在from中。如果接收到數據,則通過net_to_mos檢查該源地址是否屬於MOSIX節點。
如果不屬於MOSIX節點,則comm_recvfrom()返回錯誤。
comm_free():釋放不再被使用的消息頭或數據。
voidcomm_free(void*head)
如果當前進程的該連接是COMM_INFOLINK,則釋放head,返回。
首先檢查head是否超出連接消息頭範圍。如果head指向消息頭的起始地址,則標記該消息頭不再被使用(~COMM_HEADINUSE)。否則釋放head所指的內存空間。
comm_mkhead():準備指定大小的消息頭空間
void*comm_mkhead(inthlen)
從內核中分配hlen大小的GFP_KERNEL內存空間,mlink-head指向分配的起始地址。
comm_flushdata():清空前一個消息剩餘的數據
voidcomm_flushdata(intdlen)
如果當前連接是隱藏數據(mlink-flags&COMM_HIDEDATA),則從隱藏數據中flush長度為dlen的數據。否則,調用comm_dorecv從連接中讀取長度為dlen的數據。
comm_peek():檢查該連接是否有數據懸掛
intcomm_peek(void)
調用套接字操作集上的poll函數來判斷是否有數據懸掛。
comm_poll():等待直到有通訊事件、中斷或MOSIX事件產生
intcomm_poll(intmask,intinterruptible,unsignedlongtimo)
interruptible指明是否可以被中斷,timeo設置等待超時時間。
comm_wait():等待消息到達或者MOSIX事件產生
intcomm_wait(void)
返回1表示消息到達,返回0則表示先產生了一個事件。
comm_send_urgent():使用緊急數據(OOB)發送事件通知
intcomm_send_urgent(void)
緊急事件通知隻能由代理發送。MOSIX中將OOB數據定為0xdb。它隻發送一個字節的有效數據(0xdb),通過將msghdr的msg_flags標誌位設置MSG_OOB|MSG_NOSIGNAL來表示緊急情況。
comm_test_urgent():檢查是否懸掛了緊急數據(OOB)
intcomm_test_urgent(void)
通過設置MSG_OOB|MSG_PEEK|MSG_DONTWAIT|MSG_NOSIGNAL屬性來調用套接字操作集上的recvmsg操作來接收數據。如果接收到的長度為1且等於0xdb,則表明懸掛了緊急數據。
comm_take_urgent():從流中取出懸掛的OOB數據,以免被轉化為普通數據處理
voidcomm_take_urgent(void)
調用者必須確保流中沒有其它的數據。
首先以MSG_OOB|MSG_DONTWAIT|MSG_NOSIGNAL屬性讀取一字節,判斷是否有OOB數據,然後設置套接字SO_OOBINLINE選項為on,讓帶外數據保留在正常的輸入隊列中。然後調用套接字操作集上的recvmsg操作來讀取這一個字節的帶外數據。最後關閉套接字的SO_OOBINLINE選項。