首先我们用sqlplus 连上数据库, 查看一下这个连接的 session
select * from v$session where username='APPS' and program like 'sqlplus%';
查看当前 APPS 用户用 sqlplus 连接数据库的session 信息; 可以看到 SID = 38, SERIAL# = 28631,
然后查出这个session 的进程:
select p.* from v$process p,v$session s where p.addr = s.paddr and s.sid = 38;
看到 PID = 28, SPID = 5010. SERIAL# = 233.
这时我们设置 10046 trace 事件
alter session set tracefile_identifier='123456';
alter session set events '10046 trace name context forever, level 12';
重新查 v$process 表, 发现 TRACEID = 123456, 并且 TRACEFILE = "DIR.../VID_ora_5010_123456.trc", 这就设置了SQL trace, 这一次连接的所有数据库操作都会被记录到这个文件中, 文件名以进程 id 和一个标识符组成, 如果标识符为空, 就只有进程号.
现在我们来看 Form 的数据库连接进程号, 打开 Form 之后点 help -> about Oracle Applications, 里面可以查到 Database Server PID : 5762 (连接方式 frmweb@erik-lnx.oracle.com (TNS V1-V3), 这可以关联v$process 和 v$session 表查到), 于是在 Form 界面上所有数据库操作都会被记录到进程号 5762 的 trace 文件当中.
现在问题来了, Form 上提交的 concurrent request 进行的数据库操作会被记录到哪里的 trace 文件中呢?
在 Form 服务和 concurrent manager 服务都打开的情况下, 查看后台进程 ps -aef, 可以看到 oracle 用户下面有一些进程, 大概可以分下类:
1. oracleVID (LOCAL=NO) 这类表示数据库连接, 例如上面的 sqlplus 和 Form 连接, 都是这种, 他们的 PPID = 1, 说明都是由主进程启动的;
2. ora_w000_VID 这种属于数据库自己的进程, 可以不管
3. 我们要关注的是这些
oracle 7451 1 0 Jan25 pts/1 00:00:00 sh
oracle 7456 7451 0 Jan25 pts/1 00:00:25 FNDLIBR
oracle 7686 1 0 Jan25 ? 00:00:03 FNDSM
oracle 7744 7686 0 Jan25 ? 00:00:00 RCVOLTM14
oracle 7749 7686 0 Jan25 ? 00:00:00 FFTM
oracle 7750 7686 0 Jan25 ? 00:00:01 INCTM
oracle 7751 7686 0 Jan25 ? 00:00:00 CYQLIB
这里有好几个进程的 PPID = 7686, 然后看下 PID = 7686 的进程叫 FNDSM, 这个就是 concurrent manager 进程了. 由这个进程启动了其他好多进程, 例如 RCVOLTM (RCV 模块的 online manager), FFTM INCTM... 等等.
这时如果我们去提交一个 RTP 请求,再查看后台进程, 发现多了一个进程叫 RVCTP
oracle 6161 7885 0 18:43 ? 00:00:00 RVCTP
进程 id PID = 6161, PPID = 7885, PID = 7885 的一个进程是 FNDLIBR, 是由 PID = 7686 FNDSM 产生的, 所以总结一下, 就是 FNDSM 产生了FNDLIBR, 然后再产生了RVCTP, 当我们提交请求, 其实就是调用了下面的函数
fnd_request.submit_request('PO','RVCTP',NULL,NULL,FALSE,'IMMEDIATE',p_group_id,...)
于是就创建了RVCTP 这个进程. 但是RVCTP 进程并没有真正去做数据库操作, 而是会生成另一个进程, 进程号比RVCTP 的 PID 增加 2 (6163), 去做实际的数据处理, 因此数据库的访问会被记录在 VID_ora_6163_123456.trc 里面. 查看 VID_ora_6163_123456.trc 就可以看到下面一句话, SQL trace 文件已经告诉你这是由哪个进程产生的 trace 文件.
*** MODULE NAME:(RVCTP@erik-lnx.oracle.com (TNS V1-V3)) 2015-01-26 19:54:06.518
RVCTP 进程在处理完之后自动消失.
RCVOLTM 和 RVCTP 不一样, 这是 on-line transaction manager, 负责处理 online 的请求. 比如我们用 online 模式接收一个PO (实际上是调用 fnd_transaction.synchronous(l_timeout,l_outcome,l_msg,'PO','RCVTPO','ONLINE',p_group_id,...)), 可以看到下面的进程:
oracle 7760 7686 0 Jan25 ? 00:00:00 RCVOLTM14
oracle 7762 1 0 Jan25 ? 00:00:03 oracleVID (LOCAL=NO)
于是产生的trace 文件是 VID_ora_7762_123456.trc, 这也是因为 RCVOLTM 进程并不真正去做数据处理的工作, 而是生成一个子进程处理. 打开这个trace 文件看一下: MODULE NAME:(e:PO:cp:RCVOLTM14), 确实是由 RCVOLTM14 产生的;
这基本上是一个 manager - worker 的结构, 不管是 Form 里面提交请求, 产生一个 RVCTP 进程, 还是online 模式下运行早已存在的RCVOLTM14 进程, 都会由此产生一个新的子进程, 子进程的 PID = 父进程的 PID + 2. 至于为什么 +2 而不是 +1, 这就要问写代码的人了. 在 Immediate 和 Batch 模式下, 产生的是 RVCTP 进程, 这个进程在调用fnd_request.submit_request() 后产生, 运行结束后进程消失. online 模式下, 会在原本就存在的进程RCVOLTM14 里运行, 结束后进程不会消失, 依然存在.
RVCTP 和 RCVOLTM 这两个进程实际上是两个可执行程序, 我们到 $PO_TOP 下看,
[oracle@erik-lnx bin]$ ls $PO_TOP/bin
libpo.a POCDMC POCFH POCIRM POCISO POCRMC POXCON POXRAF POXRSR RCVOLTM RVCTP
就可以看到最后两个文件, 就是上面我们说的产生上面那两个进程的程序.
strings RVCTP |grep '$Header'
可以看到里面有很多文件, 例如 rvtii.lpc rvtuq.lpc 等等, 这些都是源代码文件, 因为 RVCTP 的源代码是用 C 写的, 所以要把这些文件编译完连接起来才能变成可执行文件 RVCTP/RCVOLTM. 例如 rvtii.lpc 编译完产生的 rvtii.o 文件在 $PO_TOP/lib 目录下, 再用adrelink.sh 命令把所有的 .o 文件连接成可执行文件.
所以说, concurrent manager 是有层级关系的, 一个进程由另一个进程产生, 有的进程运行完就消失, 有的会一直存在. 所有上面提到的这些进程都有一个父进程, 就是FNDSM (standard manager), 由它产生其他的 concurrent manager, 而FNDSM (PID=7686) 这个进程和 Form 进程(PID = 5762)是处于相同地位的, 也就是说, Form 和 FNDSM 是相同地位的两个进程, 有时候我们启动了 Form 服务, 但是没有启动 concurrent manager 服务, 那么提交请求的时候就会报 "no manager" 的警告.
最后说一下怎样启动 FNDSM 进程. 在 $ADMIN_SCRIPTS_HOME 目录下有一些很好用的脚本, adcmctl.sh 用于管理 concurrent manager 的启动与停止, adcmctl.sh stop/start apps/apps 可以用来停止/开始 concurrent manager 服务.
[oracle@erik-lnx scripts]$ adcmctl.sh stop apps/apps
You are running adcmctl.sh version 120.17.12010000.5
Shutting down concurrent managers for VID ...
[oracle@erik-lnx scripts]$ ps -aef |grep 'FNDLIBR'
oracle 8576 6181 0 20:27 pts/1 00:00:00 grep FNDLIBR
[oracle@erik-lnx scripts]$ ps -aef |grep 'FNDSM'
oracle 8578 6181 0 20:27 pts/1 00:00:00 grep FNDSM
发现 FNDSM 进程已经消失了. 这时提交任何请求都会报 "no manager" 的警告. 重新启动之后提交的请求就会继续被处理了.
最后的最后, 说下由不同进程产生的SQL trace 的特点, 打开 .trc 文件, 在文件开头查找 MODULE, 就可以看到产生 trace 的进程是哪个了. 例如:
*** MODULE NAME:(SQL*Plus)
*** MODULE NAME:(e:PO:cp:RCVOLTM14)
*** MODULE NAME:(RVCTP@erik-lnx.oracle.com (TNS V1-V3))
*** MODULE NAME:(frmweb@erik-lnx.oracle.com (TNS V1-V3)) --Form 进程
*** MODULE NAME:(fnd.framework.service.lookups.server.LookUpAM:R) --OAF 进程