2013年3月25日月曜日

tail -fしながらファイルをリネームすると追いかけてくれなくなる理由

tail -Fの存在は知っているんですが、
なんで追いかけてくれないのかが気になって途中まで調べた。


$ ls -l error.log*
-rw-rw---- 1 mysql mysql 5954  3月 25 14:44 2013 error.log

$ tail -f error.log
..

2013-03-25 14:44:50 11326 [Note] /usr/mysql/5.6.10/bin/mysqld: ready for connections.
Version: '5.6.10-log'  socket: '/usr/mysql/5.6.10/data/mysql.sock'  port: 64056  Source distribution

$ mv -i error.log error.log.1

$ ls -l error.log*
-rw-rw---- 1 mysql mysql 5954  3月 25 14:44 2013 error.log.1

$ mysqladmin debug

 ⇒mysqladmin debugで(情報として有益かどうかはともかく)mysqldの標準エラー出力にごにょごにょ吐く。


$ ls -l error.log*
-rw-rw---- 1 mysql mysql 8756  3月 25 14:46 2013 error.log.1

 ⇒ちゃんとリネーム後のファイルに出力される。
  tail -f の方はよく知られている様に出力されない。

$ mysql -e "FLUSH ERROR LOGS"

$ ls -l error.log*
-rw-rw---- 1 mysql mysql    0  3月 25 14:50 2013 error.log
-rw-rw---- 1 mysql mysql 8756  3月 25 14:46 2013 error.log.1

$ mysqladmin debug

$ ls -l error.log*
-rw-rw---- 1 mysql mysql 2803  3月 25 14:50 2013 error.log
-rw-rw---- 1 mysql mysql 8756  3月 25 14:46 2013 error.log.1

 ⇒もちろん新しい方に出力される。


なーんか、tail -f が追いかけない話が有名なので、この動作は直感的じゃないけど、
fdはiノード向いてるわけで、どちらかというとtail -f がフツウじゃない気がする。


# lsof -p `pidof mysqld` | grep error.log
mysqld  11326 mysql    1w   REG              253,0      2803 1186510 /usr/mysql/5.6.10/data/error.log
mysqld  11326 mysql    2w   REG              253,0      2803 1186510 /usr/mysql/5.6.10/data/error.log

# lsof -p `pidof tail` | grep error.log
tail    11455 root    3r   REG  253,0     2803 1186510 /usr/mysql/5.6.10/data/error.log

当然同じiノード(1186519)向いてる。


# mv -i /usr/mysql/5.6.10/data/error.log /usr/mysql/5.6.10/data/error.log.2

# lsof -p `pidof mysqld` | grep error.log
mysqld  11326 mysql    1w   REG              253,0      2803 1186510 /usr/mysql/5.6.10/data/error.log.2
mysqld  11326 mysql    2w   REG              253,0      2803 1186510 /usr/mysql/5.6.10/data/error.log.2

# lsof -p `pidof tail` | grep error.log
tail    11455 root    3r   REG  253,0     2803 1186510 /usr/mysql/5.6.10/data/error.log.2

 ⇒Σ(゚д゚lll) あれtailの方はfd閉じちゃうかと思った。


src/tail.cにもぐってみる。
main関数の先頭近くにsleep_intervalとかいうのを発見。こんなのあるんだ。
そのまま下に行くと、 #if HAVE_INOTIFYの中でtail_forever_inotify関数を、
外でtail_forever関数を呼び出しているのを発見。

この辺の違いな気がするのでHAVE_INOTIFYの内側をめっきり消してコンパイルしようかと思ったけど、
#if HAVE_INOTIFYの中でif (!disable_inotify && ..) となってるので、どこかで何か出来そうな予感も。

で、disable_inotifyを探したらDISABLE_INOTIFY_OPTIONに出会って、
最終的に

static struct option const long_options[] ={..  {"-disable-inotify", no_argument, NULL,   DISABLE_INOTIFY_OPTION}, /* do not document */..}
こんなところに出会った。
ドキュメントに書くなって書いてある。書いてない、じゃなくて書くな、なの。。

$ tail -f ---disable-inotify error.log

 ⇒ハイフン3つ。


$ mv -i error.log error.log.3

$ mysqladmin debug


これでtail -f も途切れず出力された。
あとは、inotify側がファイル名の変更でfdを解放するのを調べればQ.E.D.

…たぶん調べない。


【2013/03/25 16:37】


ありがとうございまーすorz

0 件のコメント :

コメントを投稿