PostgreSQLサーバーにクライアントが接続した時のシステムコールを眺める
PostgreSQLサーバー(いわゆるpostmaster process)は常にクライアントからのコネクションを受け付けている。 クライアントからの接続が確立したら、バックエンドプロセスを立ち上げて自身は接続待ちに戻る。
ここで、psqlで接続した時のPostgreSQLサーバー(pid:4110)が発行するシステムコールを見てみる。
今回は、psql -h localhost postgres
で同一マシン上から接続してみる。
なお、同一マシン上でpsql postgres
とhオプションなしで接続するとUnix domain socketが利用されてtcp接続は行われない。
vagrant@localhost postgresql]$ strace -ytp 4110 strace: Process 4110 attached 17:47:58 select(6, [3<socket:[34941]> 4<socket:[34942]> 5<socket:[34943]>], NULL, NULL, {49, 937628}) = 1 (in [3], left {46, 591689}) 17:48:01 rt_sigprocmask(SIG_SETMASK, ~[ILL TRAP ABRT BUS FPE SEGV CONT SYS RTMIN RT_1], NULL, 8) = 0 17:48:01 accept(3<socket:[34941]>, {sa_family=AF_INET6, sin6_port=htons(54486), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 9<socket:[35571]> 17:48:01 getsockname(9<socket:[35571]>, {sa_family=AF_INET6, sin6_port=htons(5432), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0 17:48:01 setsockopt(9<socket:[35571]>, SOL_TCP, TCP_NODELAY, [1], 4) = 0 17:48:01 setsockopt(9<socket:[35571]>, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 17:48:01 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fdafd8a2a10) = 4200 17:48:01 close(9<socket:[35571]>) = 0 17:48:01 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 17:48:01 select(6, [3<socket:[34941]> 4<socket:[34942]> 5<socket:[34943]>], NULL, NULL, {60, 0}^Cstrace: Process 4110 detached <detached ...>
- サーバーは起動時に作成していたソケットを用いてselect(2)でクライアントからの接続を待つ。接続が来たのでファイルディスクリプタfd=3のソケットをリターン
- 接続を受け付けたらシグナルをブロック
- select()で返されたfd=3のソケットを用いて接続を完了させる。この時新しいソケット(fd=9)で接続が完了する。接続の待ち受けに利用していたfd=3のソケットは待ち受けように再びそのまま利用される
- 自分のアドレスを取得している。成功したので0を返している
- tcpのオプションをソケットに設定
- tcpのオプションをソケットに設定
- バックエンドプロセスをforkするためのシステムコール
- コネクションを確立したソケットはこのプロセスではもう不要なので閉じる
- シグナルをブロックする
- 1に戻って待機
下記のnetstatnの表記を見ると、7のclone(2)で作成したバックエンドプロセス(pid=4200)が接続を確立していることが分かる
[vagrant@localhost postgresql]$ netstat -natp|grep postgres (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 4110/postgres tcp6 0 0 ::1:5432 :::* LISTEN 4110/postgres tcp6 0 0 ::1:5432 ::1:54486 ESTABLISHED 4200/postgres: vagr
その他のメモ
- fdの番号はプロセスごとに割り当てられる。
ls -l /proc/$pid/fd/
でソケットに利用されているfdが分かる - この記事は、参考文献で書いてあることの一部をシステムコールを通して言い換えたものである 参考文献:PUG しくみ分科会 勉強会 PostgreSQLソースコード解析 ~ postmaster ~