外篇  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選項。
    
2024, LCREAD.COM 手機連城