2013-04-21
Oracle Database のサーバー・プロセスが通信する際にどのようなソケットオプションを使っているか調べる
環境
[root@localhost ~]# cat /etc/issue Enterprise Linux Enterprise Linux Server release 5.5 (Carthage) Kernel \r on an \m [root@localhost ~]# uname -a Linux localhost.localdomain 2.6.18-194.17.1.0.1.el5 #1 SMP Wed Sep 29 15:40:03 EDT 2010 i686 i686 i386 GNU/Linux
- Oracle Database
SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production PL/SQL Release 11.2.0.2.0 - Production CORE 11.2.0.2.0 Production TNS for Linux: Version 11.2.0.2.0 - Production NLSRTL Version 11.2.0.2.0 - Production
[oracle@localhost OPatch]$ ./opatch lsinventory ... Installed Top-level Products (1): Oracle Database 11g 11.2.0.2.0 There are 1 products installed in this Oracle Home. There are no Interim patches installed in this Oracle Home.
strace でシステムコールをトレースする
- リスナープロセスの PID を調べる。
[root@localhost ~]# ps -ef|grep [t]ns oracle 3249 1 0 19:35 ? 00:00:00 /home/oracle/app/oracle/product/11.2.0/dbhome_2/bin/tnslsnr LISTENER -inherit
[root@localhost ~]# strace -tf -p 3249 -o strace.log
[root@localhost ~]# grep -i setsockopt strace.log 3250 20:12:35 setsockopt(14, SOL_SOCKET, SO_LINGER, {onoff=1, linger=900}, 8) = 0 3249 20:12:36 setsockopt(14, SOL_TCP, TCP_NODELAY, [1], 4) = 0 3601 20:12:36 setsockopt(14, SOL_TCP, TCP_NODELAY, [1], 4) = 0 3601 20:12:37 setsockopt(14, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 3601 20:12:37 setsockopt(14, SOL_SOCKET, SO_SNDTIMEO, "\0\0\0\0\0\0\0\0", 8) = 0 3601 20:12:37 setsockopt(14, SOL_SOCKET, SO_RCVTIMEO, "\0\0\0\0\0\0\0\0", 8) = 0 3601 20:12:37 setsockopt(14, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 3250 20:12:40 setsockopt(14, SOL_SOCKET, SO_LINGER, {onoff=1, linger=900}, 8) = 0 3249 20:12:40 setsockopt(14, SOL_TCP, TCP_NODELAY, [1], 4) = 0 3603 20:12:40 setsockopt(14, SOL_TCP, TCP_NODELAY, [1], 4) = 0 3603 20:12:40 setsockopt(14, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 3603 20:12:41 setsockopt(14, SOL_SOCKET, SO_SNDTIMEO, "\0\0\0\0\0\0\0\0", 8) = 0 3603 20:12:41 setsockopt(14, SOL_SOCKET, SO_RCVTIMEO, "\0\0\0\0\0\0\0\0", 8) = 0 3603 20:12:41 setsockopt(14, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0
Oracle Net トレース・ファイルから確認する
- Oracle Database の sqlnet.ora にトレース・レベルを設定する
[oracle@localhost ~]$ cat /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/sqlnet.ora TRACE_LEVEL_SERVER=16
- テストケース実行後、トレース・ファイルを確認する。
[oracle@localhost trace]$ grep testc * orcl_ora_3564.trc:2013-04-20 20:09:41.321368 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3566.trc:2013-04-20 20:09:42.272207 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3579.trc:2013-04-20 20:10:59.363429 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3581.trc:2013-04-20 20:11:04.073404 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3590.trc:2013-04-20 20:11:35.457958 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3601.trc:2013-04-20 20:12:37.614055 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc| orcl_ora_3603.trc:2013-04-20 20:12:41.459677 : nsbasic_brc:2F 2A 20 74 65 73 74 63 |/*.testc|
- トレース・ファイルの中身を確認する。
[oracle@localhost trace]$ grep -i tcp orcl_ora_3601.trc 2013-04-20 20:12:36.959360 : nsinh_hoff:ADR="(ADDRESS=(PROTOCOL=tcp)(DEV=14)(HOST=192.168.56.101)(PORT=1521))" 2013-04-20 20:12:36.959715 : nsc2addr:(ADDRESS=(PROTOCOL=tcp)(DEV=14)(HOST=192.168.56.101)(PORT=1521)) 2013-04-20 20:12:36.966778 : nttcon:NT layer TCP/IP connection has been established. 2013-04-20 20:12:36.966984 : nttcon:set TCP_NODELAY on 14 2013-04-20 20:12:37.002025 : nsprecv:3D 74 63 70 29 28 48 4F |=tcp)(HO| 2013-04-20 20:12:37.100779 : nsgetclientaddress:Client address: "(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.1)(PORT=1849))" [oracle@localhost trace]$ grep -i tcp orcl_ora_3603.trc 2013-04-20 20:12:40.797698 : nsinh_hoff:ADR="(ADDRESS=(PROTOCOL=tcp)(DEV=14)(HOST=192.168.56.101)(PORT=1521))" 2013-04-20 20:12:40.798505 : nsc2addr:(ADDRESS=(PROTOCOL=tcp)(DEV=14)(HOST=192.168.56.101)(PORT=1521)) 2013-04-20 20:12:40.806009 : nttcon:NT layer TCP/IP connection has been established. 2013-04-20 20:12:40.806195 : nttcon:set TCP_NODELAY on 14 2013-04-20 20:12:40.841755 : nsprecv:3D 74 63 70 29 28 48 4F |=tcp)(HO| 2013-04-20 20:12:40.941021 : nsgetclientaddress:Client address: "(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.1)(PORT=1851))"
テスト手順
- Oracle Database の sqlnet.ora にトレース・レベル(16)を設定する。
- strace でリスナープロセスと fork されるプロセスのシステムコールをトレースする。
- テストプログラムを実行する。
exec_testcase1.bat exec_testcase2.bat
テストに使ったファイル
- set_env.bat
set JAVA_HOME=C:\Program Files\Java\jdk1.5.0_22 set PATH=%JAVA_HOME%\bin;%PATH%
- build_testcase1.bat
call set_env.bat %~d0 cd %~p0 set CLASSPATH=.;ojdbc5.jar javac TestCase1.java pause
- build_testcase2.bat
call set_env.bat %~d0 cd %~p0 set CLASSPATH=.;ojdbc5.jar javac TestCase2.java pause
- exec_testcase1.bat
call set_env.bat %~d0 cd %~p0 set CLASSPATH=.;ojdbc5.jar java TestCase1 pause
- exec_testcase2.bat
call set_env.bat %~d0 cd %~p0 set CLASSPATH=.;ojdbc5.jar java TestCase2 pause
- TestCase1.java
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; public class TestCase1 { public static void main(String args[]) { Connection conn = null; Statement stmt = null; ResultSet resultSet = null; try { Class.forName ("oracle.jdbc.driver.OracleDriver"); conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.56.101:1521:orcl","system","manager"); stmt = conn.createStatement(); resultSet = stmt.executeQuery("select /* testcase1 */ sys_context('USERENV','INSTANCE_NAME'), sys_context('USERENV','SERVER_HOST') from dual"); for(;resultSet.next();) { System.out.println(resultSet.getString(1)); System.out.println(resultSet.getString(2)); } try { if (resultSet != null) { resultSet.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e){ e.printStackTrace(); } } catch (SQLException e) { System.out.println("Error code: " + e.getErrorCode()); System.out.println("SQL state: " + e.getSQLState()); e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (resultSet != null) { resultSet.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (conn != null) { conn.close(); } } catch (SQLException e){ e.printStackTrace(); } } } }
- TestCase2.java
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; public class TestCase2 { public static void main(String args[]) { Connection conn = null; Statement stmt = null; ResultSet resultSet = null; try { Class.forName ("oracle.jdbc.driver.OracleDriver"); java.util.Properties info = new java.util.Properties(); info.setProperty("user", "system"); info.setProperty("password", "manager"); info.setProperty("TCP.NODELAY", "YES"); conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.56.101:1521:ORCL",info); stmt = conn.createStatement(); resultSet = stmt.executeQuery("select /* testcase2 */ sys_context('USERENV','INSTANCE_NAME'), sys_context('USERENV','SERVER_HOST') from dual"); for(;resultSet.next();) { System.out.println(resultSet.getString(1)); System.out.println(resultSet.getString(2)); } try { if (resultSet != null) { resultSet.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e){ e.printStackTrace(); } } catch (SQLException e) { System.out.println("Error code: " + e.getErrorCode()); System.out.println("SQL state: " + e.getSQLState()); e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (resultSet != null) { resultSet.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e){ e.printStackTrace(); } try { if (conn != null) { conn.close(); } } catch (SQLException e){ e.printStackTrace(); } } } }
おまけ(ltrace でライブラリコールのトレースを取得する)
[root@localhost ~]# ltrace -tf -p 13079 -o ltrace.log
[root@localhost ~]# grep -C 2 -i setsockopt ltrace.log 13090 21:04:07 __ctype_b_loc() = 0x147ed0 13090 21:04:07 free(0x11b6d080) = <void> 13090 21:04:07 setsockopt(14, 6, 1, 0xbfaec328, 4) = 0 13090 21:04:07 malloc(4096) = 0x11b6d080 13090 21:04:07 vsnprintf("set TCP_NODELAY on 14\n", 4096, "set TCP_NODELAY on %d\n", 0xbfaec264) = 22 -- 13090 21:04:08 write(8, "m}nttctl*0TgSY"1;\n", 18) = 18 13090 21:04:08 free(0x11b750d0) = <void> 13090 21:04:08 setsockopt(14, 1, 9, 0xbfaebcbc, 4) = 0 13090 21:04:08 malloc(4096) = 0x11b750d0 13090 21:04:08 vsnprintf("normal exit\n", 4096, "normal exit\n", 0xbfaebf80) = 12 -- 13090 21:04:13 write(8, "W}0TgmT"1;\n", 11) = 11 13090 21:04:13 free(0x11b76110) = <void> 13090 21:04:13 setsockopt(14, 1, 21, 0xbfaf522c, 8) = 0 13090 21:04:13 malloc(4096) = 0x11b76110 13090 21:04:13 vsnprintf("entry\n", 4096, "entry\n", 0xbfaf52a0) = 6 -- 13090 21:04:13 write(8, "}0TgdP"1;\n", 10) = 10 13090 21:04:13 free(0x11b76110) = <void> 13090 21:04:13 setsockopt(14, 1, 20, 0xbfaf522c, 8) = 0 13090 21:04:13 malloc(4096) = 0x11b76110 13090 21:04:13 vsnprintf("entry\n", 4096, "entry\n", 0xbfaf5224) = 6 -- 13090 21:04:13 write(8, "!nttdisc*0ThdS"1;\n", 18) = 18 13090 21:04:13 free(0x11b76110) = <void> 13090 21:04:13 setsockopt(14, 1, 9, 0xbfaf520c, 4) = 0 13090 21:04:13 close(14) = 0 13090 21:04:13 malloc(4096) = 0x11b76110 -- 13097 21:04:19 __ctype_b_loc() = 0x633690 13097 21:04:19 free(0x1241a080) = <void> 13097 21:04:19 setsockopt(14, 6, 1, 0xbf990628, 4) = 0 13097 21:04:19 malloc(4096) = 0x1241a080 13097 21:04:19 vsnprintf("set TCP_NODELAY on 14\n", 4096, "set TCP_NODELAY on %d\n", 0xbf990564) = 22 -- 13097 21:04:20 write(8, "m}nttctl*0TgEW"1;\n", 18) = 18 13097 21:04:20 free(0x124220d0) = <void> 13097 21:04:20 setsockopt(14, 1, 9, 0xbf98ffbc, 4) = 0 13097 21:04:20 malloc(4096) = 0x124220d0 13097 21:04:20 vsnprintf("normal exit\n", 4096, "normal exit\n", 0xbf990280) = 12 -- 13097 21:04:25 write(8, "W}0Tg4U"8;\n", 11) = 11 13097 21:04:25 free(0x12423110) = <void> 13097 21:04:25 setsockopt(14, 1, 21, 0xbf99952c, 8) = 0 13097 21:04:25 malloc(4096) = 0x12423110 13097 21:04:25 vsnprintf("entry\n", 4096, "entry\n", 0xbf9995a0) = 6 -- 13097 21:04:25 write(8, "}0TgUT"8;\n", 10) = 10 13097 21:04:25 free(0x12423110) = <void> 13097 21:04:25 setsockopt(14, 1, 20, 0xbf99952c, 8) = 0 13097 21:04:25 malloc(4096) = 0x12423110 13097 21:04:25 vsnprintf("entry\n", 4096, "entry\n", 0xbf999524) = 6 -- 13097 21:04:25 write(8, "!nttdisc*0ThAR"1;\n", 18) = 18 13097 21:04:25 free(0x12423110) = <void> 13097 21:04:25 setsockopt(14, 1, 9, 0xbf99950c, 4) = 0 13097 21:04:25 close(14) = 0 13097 21:04:25 malloc(4096) = 0
参考
2013-03-23
Thunderbirdでimapでサーバサイドで振り分けルールを設定している場合にフォルダを選択しないと受信されない
Thunderbird 10.0.4 でメールサーバ (beehive) が imap でサーバサイドで振り分けルールを設定している場合に、フォルダを選択しないとメールが受信されないのが不便だったのでちょっと調べてみた。mail.server.default.check_all_folders_for_new を true に設定するとよい。
設定方法
- [ツール]-[オプション]-[詳細]-[一般]-[高度な設定]-[設定エディタ]を選択する。
- フィルタに「mail.server.default.check_all_folders_for_new」と入力する。
- ダブルクリックして"false"を"true"に変更する。
参考情報
以下のの情報が参考になった。
「受信」アイコンをクリックしても変わらず。フォルダをクリックしないと新規メールは現れないようです。
どのフォルダ(ラベル)にメールが来るかはわかりませんから、これでは本当に不便です。
(中略)
設定名"mail.check_all_imap_folders_for_new"を見つけて
ダブルクリックすれば"false"と"true"が切り替えられます。(初期値"false")
Thunderbird 上で imap で同期したアカウントの読み込みが遅い | E-MailのQ&A【OKWave】
2012-12-08
パイプライン表関数
テーブル・ファンクションは、行のコレクション(ネストした表またはVARRAY)を戻すユーザー定義のPL/SQLファンクションです。SELECT文のTABLE句の内部でテーブル・ファンクションを起動することで、データベース表のようにこのコレクションから要素を選択できます。次に例を示します。
SELECT * FROM TABLE(table_function_name(parameter_list))(中略)
テーブル・ファンクションの実行をパラレル化でき、戻された行を中間的なステージングなしで次のプロセスに直接送ることができます。テーブル・ファンクションから戻されたコレクションに含まれる行を、パイプライン化することもできます。つまり、テーブル・ファンクションの入力の処理がすべて完了した後にバッチで戻すかわりに、生成されるたびに反復的に戻すことができます。
(中略)
スタンドアロン・ファンクションでは、CREATE FUNCTION文にPIPELINEDオプションを指定します(構文は、「CREATE FUNCTION文」を参照してください)。パッケージ・ファンクションでは、ファンクション宣言とファンクション定義の両方にPIPELINEDオプションを指定します(構文は、「ファンクションの宣言および定義」を参照してください)。
PL/SQLの最適化とチューニング
非パイプライン・テーブル・ファンクションの場合、問合せで1つの結果行が戻されるには、その前にテーブル・ファンクションから戻されるコレクション全体が構成され、サーバーに戻される必要があります。パイプライン化により、行が生成されるたびに反復的に戻すことができます。また、これにより、オブジェクト・キャッシュではコレクション全体をマテリアライズする必要がないため、テーブル・ファンクションに必要なメモリーも減少します。
(中略)
テーブル・ファンクションでのみ使用し、このファンクションがパイプラインであることを指定します。パイプライン・テーブル・ファンクションは、行を処理した直後に起動元に行を戻し、行の処理を継続します。起動元に(制御を戻さずに)行を戻すために、このファンクションでは「PIPE ROW文」を使用します。
ファンクションの宣言および定義
ライン生産方式などパイプライン的なものは様々なところに存在する。自動車の組み立てを考えてみよう。流れ作業の一工程として、エンジンのシャーシへの設置、フードの設置、車輪の設置があり、この順番で実施されるとする。ラインの各工程には、1台の組み立て中の自動車だけがある。エンジンを設置し終えた自動車は、次にフードの設置工程に移され、エンジン設置用の機械設備は次の自動車に取り掛かることができる。最初の自動車はさらに車輪設置工程に進み、2台目の自動車はフード設置工程に進み、3台目の自動車がエンジン設置工程に進んでくる。エンジン設置に20分かかり、フード設置に5分、車輪設置に10分かかるとすると、一度に1台ずつ組み立てると3台組み立てるのに105分かかる。しかし、ライン生産方式では75分で3台の組み立てが完了する。その後も20分間隔で自動車が組み立てられていく。
パイプライン処理 - Wikipedia
まとめ*1
- 表関数は表をSELECTしたときのように複数行を返す関数。
- 結果が全部揃うまで待つのではなくできた行から順次帰す表関数がパイプライン表関数。
- 仕組みは自動車組立工場のライン生産方式と同じ。
- 1人の職人が一から自動車を組立ていた時代もあるが、自動車組立工場では100台全てのシャーシにエンジンを設置し終えてからタイヤを取り付けるのではなく、できたものが次の工程に流して各工程の組立を並列で行っているため、同じ時間でたくさんの自動車を作ることができる。
- パイプライン表関数のメリットとして全部結果ができてから返すのではなく、できた行から順次返すのでデータを溜めておくメモリが少なくてすむといった点がある。
関連
*1:正確さよりわかりやすさ重視
2012-11-23
LINUXカーネルHACKS
図書館で借りてきた本。買いたい本だが、たしか会社にあったので必要な時は会社で借りよう。
返却する前に crash コマンドで気になったところをメモしておく。
P.401
crash コマンドはカーネルイメージの解析が可能なデバッグツールです。gdb コマンドをベースに設計されており、カーネル内部の各種情報を参照するために多くのコマンドを駆使して、対話的に作業を進めることができます。
P.406
btコマンド
...
-f オプションはフレーム内のスタックデータをすべて表示します。このオプションは関数への引数を確認するときに便利です。-l オプションはファイル名と行数を表示します。
P.409
kemem コマンド
カーネルのメモリ使用量に関する情報を表示します。-s オプションはスラブキャッシュの情報を表示します。/proc/slabinfo と同等の情報になります。
...
-i オプションは、メモリ全体の利用状況を表示します。
...
-p オプションでメモリマップを表示します。
P.413
runq コマンドだけ試してみた。
crash> runq CPU 0 RUNQUEUE: c170e780 CURRENT: PID: 13000 TASK: e8c48aa0 COMMAND: "crash" ACTIVE PRIO_ARRAY: c170ec3c [115] PID: 13000 TASK: e8c48aa0 COMMAND: "crash" PID: 12932 TASK: f7384000 COMMAND: "sshd" [117] PID: 13113 TASK: cfccf000 COMMAND: "less" [125] PID: 13108 TASK: e8c48550 COMMAND: "perl" PID: 13107 TASK: cfccf550 COMMAND: "perl" EXPIRED PRIO_ARRAY: c170e7c4 [no tasks queued]
2012-11-06
特定の拡張子のファイルの合計サイズを調べる
man で調べてみると、
$ man du ... -c, --total produce a grand total
-c というオプションがあるらしいので試してみると、
$ du -c *.txt 224 1.txt 20 2.txt 244 total
でた。
xargs で標準入力がない場合は何もしない
F本さんに
オハヨウゴザイマス
コマンド結果 | xargsで、
コマンド結果がない場合、xargsにつながないようにするのって
どうするんでしたっけ?
と聞かれたので調べてみた。
-r 標準入力に空白しか含まれていない場合は、指定したコマンドを実行しない。 通常では、入力が全くない場合でも、コマンドが一回は実行されるのだ。 このオプションは GNU の拡張である。
Man page of XARGS
-r オプションでできるみたいなので試してみた。
$ echo|xargs echo foo foo $ echo|xargs -r echo foo
できますた。
追記:
GNU xargs使うときは -0r デフォですね。OSXのだと -r ないけど。。。
Twitter / yoshikaw: GNU xargs使うときは -0r ...
r は知りませんですた。すんまそん。

