並行システム システム情報工学研究科コンピュータサイエンス専攻、電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.cs.tsukuba.ac.jp/~yas/sie/csys-2009/2010-01-08
あるいは、次のページから手繰っていくこともできます。
http://www.cs.tsukuba.ac.jp/~yas/sie/
http://www.cs.tsukuba.ac.jp/~yas/
(<−>文化的には、TCP/IP上のテキストベースのプロトコルとは対照。)
RPCでは、別のアドレス空間の間でデータがやり取りされるので、基本的に 「ポインタ」を受け渡しすることはできない。しかし、SunRPC では、ポイン タの先を再帰的に「コピー」する機能がある。
スタブ(stub) は、プロセス間通信を普通の手続き呼出しと全く同じ形式で行なうことができ るようにするためのプログラム。 もともとは木の切株の意味。
スタブの分類
例2:3種類(回数)
図? rpcgenによるRPCプログラム開発で利用するファイル
name.x
name_client.c
name_server.c
% rpcgen name.x
次の4つのファイルが生成される。
name.h
name_clnt.c
name_xdr.c
name_svc.c
ハッシュ表
typedef string key_t<256>; struct keyvalue_t { key_t key; int value ; }; typedef key_t keyarray_t<>; program HASHTABLE_PROG { version HASHTABLE_VERSION { int PUT(keyvalue_t) = 11 ; int GETVALUE(key_t) = 12 ; keyarray_t GETKEYS(void) = 13 ; } = 1 ; } = 0x20051001 ;遠隔手続き呼出しでは、送受信できるデータは基本的には値だけであり、 ポインタを送ることはできない。
SunRPC では、ポインタの先の1要素だけコピーして送る機能がある。SunRPC では、ポインタによる単純なリストや木構造を送ることができる。
双方向リストなど、内部にループを含むものは SunRPC では送ることができな い。また、ポインタで実現された有向非循環グラフを送ると木構造に展開され てしまう。
インタフェース定義から、次のようなファイルが生成される。
/* * Please do not edit this file. * It was generated using rpcgen. */ #include "hashtable.h" #ifndef _KERNEL #include <stdio.h> #include <stdlib.h> /* getenv, exit */ #endif /* !_KERNEL */ /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; int * put_1(argp, clnt) keyvalue_t *argp; CLIENT *clnt; { static int clnt_res; memset((char *)&clnt_res, 0, sizeof (clnt_res)); if (clnt_call(clnt, PUT, (xdrproc_t) xdr_keyvalue_t, (caddr_t) argp, (xdrproc_t) xdr_int, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); }
ローカルの手続き呼出しでは、リンク時に固定される。
クライアントとサーバは1対1ではない。
binding のための命令
/etc/rpc
というファイルに含まれている。
TCP/IPまたはUDP/IPでデータを送るにはポート番号が必要になる。 サーバが動作しているホストには、 portmapper とよばれる特殊な RPC のサーバが動作している。 サーバは起動時に自分の<プログラム番号, バージョン, プロトコル, ポート番号>をPortmapper に登録する (pmap_set())。
クライアントは、実際にサーバに接続する前に、Portmapper に<プ ログラム番号, バージョン, プロトコル>を送り、 TCP/IPまたはUDP/IPのポート番号を得る(pmap_getport())。最終的には, この ポート番号を使ってメッセージを送る。
Portmapper 自身のポート番号は、111 に固定されている。
図? SunRPC での binding (portmapper)
図? RPCで起こりうる障害
例: 銀行預金転送。
対策:
RPCのセマンティクス
親(クライアント)がいない計算を孤児という。
対応方法
孤児が、ロックを持っていたら、孤児を消しただけでは話を終わらない。
Linux, /usr/include/rpc/clnt.h /* * Rpc calls return an enum clnt_stat. This should be looked at more, * since each implementation is required to live with this (implementation * independent) list of errors. */ enum clnt_stat { RPC_SUCCESS=0, /* call succeeded */ /* * local errors */ RPC_CANTENCODEARGS=1, /* can't encode arguments */ RPC_CANTDECODERES=2, /* can't decode results */ RPC_CANTSEND=3, /* failure in sending call */ RPC_CANTRECV=4, /* failure in receiving result */ RPC_TIMEDOUT=5, /* call timed out */ /* * remote errors */ RPC_VERSMISMATCH=6, /* rpc versions not compatible */ RPC_AUTHERROR=7, /* authentication error */ RPC_PROGUNAVAIL=8, /* program not available */ RPC_PROGVERSMISMATCH=9, /* program version mismatched */ RPC_PROCUNAVAIL=10, /* procedure unavailable */ RPC_CANTDECODEARGS=11, /* decode arguments error */ RPC_SYSTEMERROR=12, /* generic "other problem" */ RPC_NOBROADCAST = 21, /* Broadcasting not supported */ /* * callrpc & clnt_create errors */ RPC_UNKNOWNHOST=13, /* unknown host name */ RPC_UNKNOWNPROTO=17, /* unknown protocol */ RPC_UNKNOWNADDR = 19, /* Remote address unknown */ /* * rpcbind errors */ RPC_RPCBFAILURE=14, /* portmapper failed in its call */ #define RPC_PMAPFAILURE RPC_RPCBFAILURE RPC_PROGNOTREGISTERED=15, /* remote program is not registered */ RPC_N2AXLATEFAILURE = 22, /* Name to addr translation failed */ /* * unspecified error */ RPC_FAILED=16, RPC_INTR=18, RPC_TLIERROR=20, RPC_UDERROR=23, /* * asynchronous errors */ RPC_INPROGRESS = 24, RPC_STALERACHANDLE = 25 };
例:
無状態サーバ(stateless server) とは、サーバ内部に状態を保持しないようなサーバ。
状態の例
RPCで冪等な操作や無状態サーバを実現すると、クラッシュに強いシステムを 作れる。クライアントは、サーバから応答がない場合、何度要求を再送信して もよい。
例:NFS Version 2
サーバは、ファイルに対する書き込み要求を受け付けると、ディスクへ の書き込みを完了してから応答を返す。 応答が返ってきた要求は、 ディスクへの書き込みが完了したことが保証されている。 この段階でサーバがクラッシュしたとしても、なにも失われない。
しかし、、、重たい。NFS Version 3 では、状態付きのサーバになった。
NFS ( Network File System ) は, Sun Microsystems 社が 開発したネットワーク・ファイル・システムの名前(固有名詞, 商標)。
その他のネットワーク・ファイル・システム(用のプロトコル)
NFSを使うと, ネットワークを通じて別のコンピュータ上のファイルシステム
の一部分を, ローカルディスク上にあるファイルシステムと同じように, 自分
のファイルシステムの木に
マウント(mount)
できる。
図? NFSによるファイルの共有
相互に参照し合える。
表? NFSで使われているRPCの手続き
手続き名 | 意味 | 関連するコマンド、 システムコール |
---|---|---|
null() | 何もしない | rpcinfo -u hostname nfs コマンド |
getattr() | 属性の読み出し | ls -l コマンド, stat システムコール , open システムコール |
setattr() | 属性の設定 | chmod , chown コマンド |
lookup() | ファイルの検索 | open システムコール |
readlink() | シンボリックリンクの読み出し | ls -l コマンド, readlink システムコール |
read() | ファイルの読み出し | read システムコール |
write() | ファイルの書き込み | write システムコール |
create() | ファイルの作成 | creat システムコール, open システムコール |
remove() | ハードリンクの削除 | rm コマンド, unlink システムコール |
rename() | ファイル名前の変更 | mv コマンド, rename システムコール |
link() | ハードリンクの作成 | ln コマンド, link システムコール |
symlink() | シンボリックリンクの作成 | ln -s コマンド, symlink システムコール |
mkdir() | ディレクトリの作成 | mkdir コマンド |
rmdir() | ディレクトリの削除 | rmdir コマンド |
readdir() | ディレクトリの読み出し | ls コマンド |
statfs() | ファイルシステムの利用状況 | df コマンド, statfs システムコール |
commit()* | ディスクへの書き込み | fsync システムコール |
access()* | アクセス権のチェック | access システムコール |
open()** | ファイルを開く。 | |
close()** | ファイルを閉じる。 | |
lock()** | ファイルのロック。 | |
renew()** | ファイルのロックの更新。 | |
compound()** | 複合手続き。複数の手続きをまとめて実行する。 |
* は、NFS Version 3 で追加された手続き。
** は、NFS v4 で追加された手続き ☆。
NFS でファイルやディレクトリを区別するための識別子。32バイト。
const NFS_FHSIZE = 32; ... /* * File access handle */ struct nfs_fh { opaque data[NFS_FHSIZE]; };
一番最初のNFSファイル・ハンドルをどうやって入手するか。
手続き名 | 意味 | 関連するコマンド、 システムコール |
---|---|---|
null() | 何もしない | rpcinfo -u hostname mount コマンド |
mnt() | NFSファイルハンドルを返す | mount コマンド |
dump() | マウント一覧表 | showmount hostname コマンド |
umnt() | アンマウント | umount コマンド |
umntall() | 全アンマウント | umount -h hostname コマンド |
export() | アクセス可能なディレクトリのリストを返す |
2.2.5. Look Up File Name diropres NFSPROC_LOOKUP(diropargs) = 4; If the reply "status" is NFS_OK, then the reply "file" and reply "attributes" are the file handle and attributes for the file "name" in the directory given by "dir" in the argument. 2.3.10. diropargs struct diropargs { fhandle dir; filename name; }; The "diropargs" structure is used in directory operations. The "fhandle" "dir" is the directory in which to find the file "name". A directory operation is one in which the directory is affected. 2.3.11. diropres union diropres switch (stat status) { case NFS_OK: struct { fhandle file; fattr attributes; } diropok; default: void; }; The results of a directory operation are returned in a "diropres" structure. If the call succeeded, a new file handle "file" and the "attributes" associated with that file are returned along with the "status".
2.2.7. Read From File struct readargs { fhandle file; unsigned offset; unsigned count; unsigned totalcount; }; union readres switch (stat status) { case NFS_OK: fattr attributes; nfsdata data; default: void; }; readres NFSPROC_READ(readargs) = 6; Returns up to "count" bytes of "data" from the file given by "file", starting at "offset" bytes from the beginning of the file. The first byte of the file is at offset zero. The file attributes after the read takes place are returned in "attributes". Notes: The argument "totalcount" is unused, and is removed in the next protocol revision.
2.2.9. Write to File struct writeargs { fhandle file; unsigned beginoffset; unsigned offset; unsigned totalcount; nfsdata data; }; attrstat NFSPROC_WRITE(writeargs) = 8; Writes "data" beginning "offset" bytes from the beginning of "file". The first byte of the file is at offset zero. If the reply "status" is NFS_OK, then the reply "attributes" contains the attributes of the file after the write has completed. The write operation is atomic. Data from this "WRITE" will not be mixed with data from another client's "WRITE". Notes: The arguments "beginoffset" and "totalcount" are ignored and are removed in the next protocol revision.
RPC のようにコネクションが作られない通信サービスを使う時に冪等や無状態 といった性質を実現する時に必要になる技術。
例:NFSでのディレクトリの読み込み手続き nfsproc_readdir() で、1回の RPC で全部のデータを返せないことが起きる。 ディレクトリのどの位置まで読み込んだかを 示す中間状態を クッキー(cookie) という形でクライアントに返す。
クライアントは、次の RPC の呼び出しで、 前回受けとった応答の中のクッキーを、サーバへの要求に含めて送す。
const NFS_COOKIESIZE = 4; typedef opaque nfscookie[NFS_COOKIESIZE];
2.2.17. Read From Directory struct readdirargs { fhandle dir; nfscookie cookie; unsigned count; }; struct entry { unsigned fileid; filename name; nfscookie cookie; entry *nextentry; }; union readdirres switch (stat status) { case NFS_OK: struct { entry *entries; bool eof; } readdirok; default: void; }; readdirres NFSPROC_READDIR (readdirargs) = 16; Returns a variable number of directory entries, with a total size of up to "count" bytes, from the directory given by "dir". If the returned value of "status" is NFS_OK, then it is followed by a variable number of "entry"s. Each "entry" contains a "fileid" which consists of a unique number to identify the file within a filesystem, the "name" of the file, and a "cookie" which is an opaque pointer to the next entry in the directory. The cookie is used in the next READDIR call to get more entries starting at a given point in the directory. The special cookie zero (all bits zero) can be used to get the entries starting at the beginning of the directory. The "fileid" field should be the same number as the "fileid" in the the attributes of the file. (See section "2.3.5. fattr" under "Basic Data Types".) The "eof" flag has a value of TRUE if there are no more entries in the directory.
nfsproc_readdir() で、1回目と2回目の RPC の間にディレクトリの内容が 更新された場合、どのような結果になるのか不明。
NFS非同期入出力デーモン
(
nfsiod (local NFS asynchronous I/O Daemon)
または
biod (asynchronous Block I/O Daemon)
)
は、NFSのクライアントホスト上で動き、NFSの非同期的な入出力を行う。
クライアント側の lockd
図? NFSにおけるlockd と statd の役割
commit()
という手続きが追加。
それまでに行われた書き込みをディスクに行うように指示できる。
(NFS v2 では、write で必ずディスクに書き込む。)