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 ...>
  1. サーバーは起動時に作成していたソケットを用いてselect(2)でクライアントからの接続を待つ。接続が来たのでファイルディスクリプタfd=3のソケットをリターン
  2. 接続を受け付けたらシグナルをブロック
  3. select()で返されたfd=3のソケットを用いて接続を完了させる。この時新しいソケット(fd=9)で接続が完了する。接続の待ち受けに利用していたfd=3のソケットは待ち受けように再びそのまま利用される
  4. 自分のアドレスを取得している。成功したので0を返している
  5. tcpのオプションをソケットに設定
  6. tcpのオプションをソケットに設定
  7. バックエンドプロセスをforkするためのシステムコール
  8. コネクションを確立したソケットはこのプロセスではもう不要なので閉じる
  9. シグナルをブロックする
  10. 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

その他のメモ