Locations of visitors to this page

Wednesday, May 27, 2009

co-process in shell Shell中的协进程

co-process in shell
Shell中的协进程

今日阅读第147期Log Buffer, 有重大发现
其中一篇文章"How to reuse connection in shell"提到了协同进程(coprocess)的概念, 介绍了使用协进程重用数据库连接的方法


1.文章中的例子

脚本1, 用嵌入文档(here document)重定向的方式, 向sqlplus发送命令序列, 运行2次, 取得2个表的行数.
countlines() {
  c=$(sqlplus -s /nolog <<EOF | grep -v Connected
connect sarpt/sarpt
set feed off head off
select count(*) from $1;
EOF
)
  echo there are $c lines in $1
}

countlines CHANNEL
countlines CHANNEL_STATE
运行结果
$ time ksh script1
there are 70 lines in CHANNEL
there are 116 lines in CHANNEL_STATE

real    0m0.083s
user    0m0.017s
sys     0m0.024s

脚本2, 起一个sqlplus作为协同进程, 然后向协同进程发送命令/接受返回的结果
sqlplus -s /nolog |&

print -p "connect sarpt/sarpt"

read -p line
if [ $line != Connected. ]
then
  exit 1
fi

print -p "set feed off head off"

countlines() {
  print -p "select count(*) from $1;"
  read -p line
  read -p c
  echo "there is $c lines in $1"
}

countlines CHANNEL
countlines CHANNEL_STATE

print -p disconnect
运行结果
$ time ksh script2
there is 70 lines in CHANNEL
there is 116 lines in CHANNEL_STATE

real    0m0.042s
user    0m0.001s
sys     0m0.002s
因为只起了一次sqlplus,重用了数据库连接,比第一种方式快了很多


2. 协进程

其实就是在命令后加上"|&", 后台的启动一个进程, 并自动创建一个双向的管道通信. 用"print -p"向协进程发送命令, 用"read -p"从协进程获取返回信息. 可以在Shell脚本里实现以交互的方式同另一个进程(协进程)的协同工作. 而前面script1中的嵌入文档(here document)方法只能一次性的向某进程发送全部命令, 不能在运行时根据返回结果, 动态的决定下步操作命令.
ksh协进程的使用,见Coprocesses and Background jobs

协进程是在ksh93(Korn Shell)提出的功能, 在bash(Bourne-Again Shell)中用不了. bash4.0才支持协进程, 调用方法跟ksh也有所不同, 请见bash manual 3.2.5 CoprocessesThe coproc keyword


3. 用命名管道(named pipe)实现协进程
脚本3, 显式的创建2个命名管道, 一个用于输入, 另一个用于输出
mkfifo p_in
mkfifo p_out
(trap "rm -f p_in p_out" 0; sqlplus -s /nolog <p_in >p_out; ) &
exec 4>p_in 5<p_out

echo "connect sarpt/sarpt" >&4
read line <&5

echo "set feed off head off" >&4

countlines() {
  echo "select count(*) from $1;" >&4
  read line <&5
  read c <&5
  echo "there is $c lines in $1"
}

countlines CHANNEL
countlines CHANNEL_STATE

echo disconnect >&4

exec 4>&- 5<&-
运行结果
$ time ksh script3
there is 70 lines in CHANNEL
there is 116 lines in CHANNEL_STATE

real    0m0.045s
user    0m0.002s
sys     0m0.002s
实现了类似ksh协进程的功能, 这可用于bash中
$ time bash script3
there is 70 lines in CHANNEL
there is 116 lines in CHANNEL_STATE

real    0m0.048s
user    0m0.002s
sys     0m0.005s
文章Discovering Web Access Latencies Using Bash Co-Processing有一个更完善的例子





-fin-

Tuesday, May 26, 2009

A simple example of deploying Tomcat failover cluster 部署Tomcat故障转移集群

A simple example of deploying Tomcat failover cluster

有关Red Hat Cluster Suite的基本概念和操作请见:
Cluster Suite Overview
Cluster Administration

下面介绍部署Tomcat故障转移集群(failover cluster)的简单例子

环境:
2台Dell 1850

节点1:Perf-LG-6.s3lab.mot.com 192.168.16.16
节点2:Perf-LG-7.s3lab.mot.com 192.168.16.17

打算部署一个2节点的集群, 浮动IP用192.168.16.31


1. 安装集群软件
yum -y groupinstall "Clustering"
[root@Perf-LG-6.s3lab.mot.com ~]# yum -y groupinstall "Clustering"
Loading "fastestmirror" plugin
Loading mirror speeds from cached hostfile
 * EPEL-base: 192.168.11.16
 * base: 192.168.11.16
 * update: 192.168.11.16
base                      100% |=========================| 1.1 kB    00:00
update                    100% |=========================|  951 B    00:00
primary.xml.gz            100% |=========================| 434 kB    00:00
update    : ################################################## 959/959
Setting up Group Process
Loading mirror speeds from cached hostfile
 * EPEL-base: 192.168.11.16
 * base: 192.168.11.16
 * update: 192.168.11.16
Resolving Dependencies
--> Running transaction check
---> Package piranha.x86_64 0:0.8.4-9.3.el5 set to be updated
---> Package modcluster.x86_64 0:0.12.0-7.el5.centos set to be updated
--> Processing Dependency: libcman.so.2()(64bit) for package: modcluster
---> Package system-config-cluster.noarch 0:1.0.52-1.1 set to be updated
---> Package cluster-cim.x86_64 0:0.12.0-7.el5.centos set to be updated
--> Processing Dependency: tog-pegasus for package: cluster-cim
---> Package luci.x86_64 0:0.12.0-7.el5.centos.3 set to be updated
--> Processing Dependency: python-imaging for package: luci
---> Package rgmanager.x86_64 0:2.0.38-2.el5_2.1 set to be updated
---> Package ricci.x86_64 0:0.12.0-7.el5.centos.3 set to be updated
---> Package ipvsadm.x86_64 0:1.24-8.1 set to be updated
---> Package cluster-snmp.x86_64 0:0.12.0-7.el5.centos set to be updated
--> Processing Dependency: net-snmp for package: cluster-snmp
--> Running transaction check
---> Package cman.x86_64 0:2.0.84-2.el5_2.3 set to be updated
--> Processing Dependency: libSaCkpt.so.2(OPENAIS_CKPT_B.01.01)(64bit) for package: cman
--> Processing Dependency: perl(XML::LibXML) for package: cman
--> Processing Dependency: openais for package: cman
--> Processing Dependency: libSaCkpt.so.2()(64bit) for package: cman
--> Processing Dependency: libcpg.so.2()(64bit) for package: cman
--> Processing Dependency: libcpg.so.2(OPENAIS_CPG_1.0)(64bit) for package: cman
--> Processing Dependency: perl(Net::Telnet) for package: cman
---> Package net-snmp.x86_64 1:5.3.1-24.el5_2.2 set to be updated
--> Processing Dependency: libsensors.so.3()(64bit) for package: net-snmp
---> Package tog-pegasus.x86_64 2:2.7.0-2.el5_2.1 set to be updated
---> Package python-imaging.x86_64 0:1.1.5-5.el5 set to be updated
--> Processing Dependency: tkinter for package: python-imaging
--> Processing Dependency: libtk8.4.so()(64bit) for package: python-imaging
--> Running transaction check
---> Package lm_sensors.x86_64 0:2.10.0-3.1 set to be updated
---> Package perl-XML-LibXML.x86_64 0:1.58-5 set to be updated
--> Processing Dependency: perl-XML-NamespaceSupport for package: perl-XML-LibXML
--> Processing Dependency: perl-XML-LibXML-Common for package: perl-XML-LibXML
--> Processing Dependency: perl(XML::SAX::Exception) for package: perl-XML-LibXML
--> Processing Dependency: perl(XML::LibXML::Common) for package: perl-XML-LibXML
--> Processing Dependency: perl-XML-SAX for package: perl-XML-LibXML
--> Processing Dependency: perl(XML::SAX::DocumentLocator) for package: perl-XML-LibXML
--> Processing Dependency: perl(XML::SAX::Base) for package: perl-XML-LibXML
--> Processing Dependency: perl(XML::NamespaceSupport) for package: perl-XML-LibXML
---> Package openais.x86_64 0:0.80.3-15.el5 set to be updated
---> Package tkinter.x86_64 0:2.4.3-21.el5 set to be updated
--> Processing Dependency: libTix8.4.so()(64bit) for package: tkinter
---> Package perl-Net-Telnet.noarch 0:3.03-7.el5 set to be updated
---> Package tk.x86_64 0:8.4.13-5.el5_1.1 set to be updated
--> Running transaction check
---> Package perl-XML-NamespaceSupport.noarch 0:1.09-1.2.1 set to be updated
---> Package perl-XML-LibXML-Common.x86_64 0:0.13-8.2.2 set to be updated
---> Package perl-XML-SAX.noarch 0:0.14-5 set to be updated
---> Package tix.x86_64 1:8.4.0-11.fc6 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

=============================================================================
 Package                 Arch       Version          Repository        Size
=============================================================================
Installing:
 cluster-cim             x86_64     0.12.0-7.el5.centos  base              142 k
 cluster-snmp            x86_64     0.12.0-7.el5.centos  base              139 k
 luci                    x86_64     0.12.0-7.el5.centos.3  base               27 M
 piranha                 x86_64     0.8.4-9.3.el5    base              714 k
 rgmanager               x86_64     2.0.38-2.el5_2.1  update            294 k
 ricci                   x86_64     0.12.0-7.el5.centos.3  base              1.1 M
 system-config-cluster   noarch     1.0.52-1.1       base              290 k
Installing for dependencies:
 cman                    x86_64     2.0.84-2.el5_2.3  update            649 k
 ipvsadm                 x86_64     1.24-8.1         base               31 k
 lm_sensors              x86_64     2.10.0-3.1       base              504 k
 modcluster              x86_64     0.12.0-7.el5.centos  base              331 k
 net-snmp                x86_64     1:5.3.1-24.el5_2.2  update            702 k
 openais                 x86_64     0.80.3-15.el5    base              374 k
 perl-Net-Telnet         noarch     3.03-7.el5       EPEL-base          56 k
 perl-XML-LibXML         x86_64     1.58-5           base              230 k
 perl-XML-LibXML-Common  x86_64     0.13-8.2.2       base               16 k
 perl-XML-NamespaceSupport  noarch     1.09-1.2.1       base               15 k
 perl-XML-SAX            noarch     0.14-5           base               75 k
 python-imaging          x86_64     1.1.5-5.el5      base              408 k
 tix                     x86_64     1:8.4.0-11.fc6   base              333 k
 tk                      x86_64     8.4.13-5.el5_1.1  base              901 k
 tkinter                 x86_64     2.4.3-21.el5     base              281 k
 tog-pegasus             x86_64     2:2.7.0-2.el5_2.1  update            6.8 M

Transaction Summary
=============================================================================
Install     23 Package(s)
Update       0 Package(s)
Remove       0 Package(s)

Total download size: 41 M
Downloading Packages:
(1/23): ricci-0.12.0-7.el 100% |=========================| 1.1 MB    00:00
(2/23): cman-2.0.84-2.el5 100% |=========================| 649 kB    00:00
(3/23): lm_sensors-2.10.0 100% |=========================| 504 kB    00:00
(4/23): tix-8.4.0-11.fc6. 100% |=========================| 333 kB    00:00
(5/23): piranha-0.8.4-9.3 100% |=========================| 714 kB    00:00
(6/23): python-imaging-1. 100% |=========================| 408 kB    00:00
(7/23): cluster-cim-0.12. 100% |=========================| 142 kB    00:00
(8/23): perl-XML-SAX-0.14 100% |=========================|  75 kB    00:00
(9/23): tkinter-2.4.3-21. 100% |=========================| 281 kB    00:00
(10/23): net-snmp-5.3.1-2 100% |=========================| 702 kB    00:00
(11/23): tk-8.4.13-5.el5_ 100% |=========================| 901 kB    00:00
(12/23): modcluster-0.12. 100% |=========================| 331 kB    00:00
(13/23): system-config-cl 100% |=========================| 290 kB    00:00
(14/23): perl-XML-LibXML- 100% |=========================| 230 kB    00:00
(15/23): rgmanager-2.0.38 100% |=========================| 294 kB    00:00
(16/23): luci-0.12.0-7.el 100% |=========================|  27 MB    00:02
(17/23): cluster-snmp-0.1 100% |=========================| 139 kB    00:00
(18/23): perl-XML-LibXML- 100% |=========================|  16 kB    00:00
(19/23): perl-XML-Namespa 100% |=========================|  15 kB    00:00
(20/23): perl-Net-Telnet- 100% |=========================|  56 kB    00:00
(21/23): tog-pegasus-2.7. 100% |=========================| 6.8 MB    00:00
(22/23): ipvsadm-1.24-8.1 100% |=========================|  31 kB    00:00
(23/23): openais-0.80.3-1 100% |=========================| 374 kB    00:00
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing: tk                           ####################### [ 1/23]
  Installing: tix                          ####################### [ 2/23]
  Installing: tkinter                      ####################### [ 3/23]
  Installing: python-imaging               ####################### [ 4/23]
  Installing: lm_sensors                   ####################### [ 5/23]
  Installing: net-snmp                     ####################### [ 6/23]
  Installing: tog-pegasus                  ####################### [ 7/23]
  Installing: perl-XML-LibXML-Common       ####################### [ 8/23]
  Installing: ipvsadm                      ####################### [ 9/23]
  Installing: openais                      ####################### [10/23]
  Installing: perl-XML-NamespaceSupport    ####################### [11/23]
  Installing: perl-XML-SAX                 ####################### [12/23]
  Installing: perl-XML-LibXML              ####################### [13/23]
could not find ParserDetails.ini in /usr/lib/perl5/vendor_perl/5.8.8/XML/SAX
  Installing: perl-Net-Telnet              ####################### [14/23]
  Installing: piranha                      ####################### [15/23]
  Installing: luci                         ####################### [16/23]
  Installing: cman                         ####################### [17/23]
  Installing: modcluster                   ####################### [18/23]
  Installing: cluster-snmp                 ####################### [19/23]
  Installing: rgmanager                    ####################### [20/23]
  Installing: system-config-cluster        ####################### [21/23]
  Installing: cluster-cim                  ####################### [22/23]
  Installing: ricci                        ####################### [23/23]

Installed: cluster-cim.x86_64 0:0.12.0-7.el5.centos cluster-snmp.x86_64 0:0.12.0-7.el5.centos luci.x86_64 0:0.12.0-7.el5.centos.3 piranha.x86_64 0:0.8.4-9.3.el5 rgmanager.x86_64 0:2.0.38-2.el5_2.1 ricci.x86_64 0:0.12.0-7.el5.centos.3 system-config-cluster.noarch 0:1.0.52-1.1
Dependency Installed: cman.x86_64 0:2.0.84-2.el5_2.3 ipvsadm.x86_64 0:1.24-8.1 lm_sensors.x86_64 0:2.10.0-3.1 modcluster.x86_64 0:0.12.0-7.el5.centos net-snmp.x86_64 1:5.3.1-24.el5_2.2 openais.x86_64 0:0.80.3-15.el5 perl-Net-Telnet.noarch 0:3.03-7.el5 perl-XML-LibXML.x86_64 0:1.58-5 perl-XML-LibXML-Common.x86_64 0:0.13-8.2.2 perl-XML-NamespaceSupport.noarch 0:1.09-1.2.1 perl-XML-SAX.noarch 0:0.14-5 python-imaging.x86_64 0:1.1.5-5.el5 tix.x86_64 1:8.4.0-11.fc6 tk.x86_64 0:8.4.13-5.el5_1.1 tkinter.x86_64 0:2.4.3-21.el5 tog-pegasus.x86_64 2:2.7.0-2.el5_2.1
Complete!
[root@Perf-LG-6.s3lab.mot.com ~]#



2. 安装Tomcat 6
useradd tomcat
tar -C /home/tomcat -zxf /u01/software/blur/apache-tomcat-6.0.18.blur.tar.gz
chown -R tomcat:tomcat /home/tomcat/apache-tomcat-6.0.18.blur
mkdir -p /usr/java
tar -C /usr/java -xf /u01/software/blur/jdk1.6.0_11.tar
cat >/etc/profile.d/java.sh <<'EOF'
#
# Automatically generated file, check puppet master to make changes
#
export JAVA_HOME=/usr/java/jdk1.6.0_11
export PATH=$JAVA_HOME/bin:$PATH
export CATALINA_OPTS="-Xms512m -Xmx512m -XX:MaxPermSize=256M"
# perhaps pass the tc version as a param
export CATALINA_PID=/home/tomcat/apache-tomcat-6.0.18.blur/bin/tomcat.pid
export LD_LIBRARY_PATH=/usr/local/apr/lib
EOF
chmod +x /etc/profile.d/java.sh


3. 将Tomcat服务的监听地址指定为浮动IP地址
vi /home/tomcat/apache-tomcat-6.0.18.blur/conf/server.xml
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" address="192.168.16.31" />


4. 为Tomcat增加一种资源类型
cat >/usr/share/cluster/tomcat6.sh <<'EOFEOFEOF'
#!/bin/sh
#
# Startup script for Tomcat Servlet Engine
#
# (Automatically generated file, check puppet master to make changes)
#
# chkconfig: 345 86 14
# description: Tomcat Servlet Engine
# processname: tomcat
# pidfile: /home/tomcat/apache-tomcat-6.0.16/bin/tomcat.pid
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin

#. $(dirname $0)/ocf-shellfuncs
#. $(dirname $0)/utils/config-utils.sh
#. $(dirname $0)/utils/messages.sh
#. $(dirname $0)/utils/ra-skelet.sh

. /etc/init.d/functions


# User under which tomcat will run
TOMCAT_USER=tomcat
TOMCAT_HOMELOC=/home/tomcat/apache-tomcat-6.0.18.blur

RETVAL=0
prog=tomcat6.0.18.blur

# start, debug, stop, and status functions
meta_data() {
cat <<'EOF'
<?xml version="1.0"?>
<resource-agent version="rgmanager 2.0" name="tomcat6">
    <version>1.0</version>

    <longdesc lang="en">
        This defines an instance of Tomcat 6 server
    </longdesc>
    <shortdesc lang="en">
        Defines a Tomcat 6 server
    </shortdesc>

    <parameters>
        <parameter name="name" primary="1">
            <longdesc lang="en">
                Specifies a service name for logging and other purposes
            </longdesc>
            <shortdesc lang="en">
                Name
            </shortdesc>
            <content type="string"/>
        </parameter>
        <parameter name="service_name" inherit="service%name">
            <longdesc lang="en">
                Inherit the service name.  We need to know
                the service name in order to determine file
                systems and IPs for this service.
            </longdesc>
            <shortdesc lang="en">
                Inherit the service name.
            </shortdesc>
            <content type="string"/>
        </parameter>
    </parameters>

    <actions>
        <action name="start" timeout="60"/>
        <action name="stop" timeout="60"/>

        <!-- Checks to see if it''s mounted in the right place -->
        <action name="status" interval="10" timeout="10"/>
        <action name="monitor" interval="10" timeout="10"/>

        <!--
        <action name="status" depth="*" timeout="120" interval="5m"/>
        <action name="monitor" depth="*" timeout="120" interval="5m"/>
        -->

        <action name="meta-data" timeout="10"/>
        <action name="verify-all" timeout="10"/>

    </actions>

    <special tag="rgmanager">
    </special>
</resource-agent>
EOF
}

verify_all()
{
        return 0
}

start() {
    # Start Tomcat in normal mode
    SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
    if [ $SHUTDOWN_PORT -ne 0 ]; then
        echo -n "Tomcat already started"
        echo_success
        echo
    else
        echo "Starting tomcat..."
        chown -R $TOMCAT_USER:$TOMCAT_USER $TOMCAT_HOMELOC/*
        su -l $TOMCAT_USER -c "$TOMCAT_HOMELOC/bin/startup.sh"
        SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
        while [ $SHUTDOWN_PORT -eq 0 ]; do
            sleep 1
        #    echo -n "."
            SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
        done
        RETVAL=$?
        echo
        echo -n "Tomcat started in normal mode"
        echo_success
        echo
        [ $RETVAL=0 ] && touch /var/lock/subsys/tomcat6
    fi
}

debug() {
    # Start Tomcat in debug mode
    SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
    if [ $SHUTDOWN_PORT -ne 0 ]; then
        echo -n "Tomcat already started"
        echo_success
        echo
    else
        echo "Starting tomcat in debug mode..."
        chown -R $TOMCAT_USER:$TOMCAT_USER $TOMCAT_HOMELOC/*
        su -l $TOMCAT_USER -c "$TOMCAT_HOMELOC/bin/catalina.sh jpda start"
        SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
        while [ $SHUTDOWN_PORT -eq 0 ]; do
            sleep 1
        #    echo -n "."
            SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
        done
        RETVAL=$?
        echo
        echo -n "Tomcat started in debug mode"
        echo_success
        echo
        [ $RETVAL=0 ] && touch /var/lock/subsys/tomcat6
    fi
}

stop() {
    SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
    if [ $SHUTDOWN_PORT -eq 0 ]; then
        echo -n "Tomcat already stopped"
        echo_success
        echo
    else
        echo "Stopping tomcat..."
        su -l $TOMCAT_USER -c "$TOMCAT_HOMELOC/bin/shutdown.sh -force"
        RETVAL=$?
        sleep 5
        echo_success
        echo -n "Tomcat stopped"
        # tomcat smackdown
        #kill -9 `ps -ef |grep tomcat | grep -v grep | awk '{print $2}'` 2> /dev/null
        echo
        [ $RETVAL=0 ] && rm -f /var/lock/subsys/tomcat6 $TOMCAT_HOMELOC/bin/tomcat.pid
    fi
}

status() {
    SHUTDOWN_PORT=`netstat -vatn|grep LISTEN|grep 8005|wc -l`
    if [ $SHUTDOWN_PORT -eq 0 ]; then
        echo -n "Tomcat stopped"
        echo_success
        echo
        return $OCF_ERR_GENERIC
    else
        MODE="normal"
        JPDA_PORT=`netstat -vatn|grep LISTEN|grep 8000|wc -l`
        if [ $JPDA_PORT -ne 0 ]; then
            MODE="debug"
        fi
        echo "Tomcat running in $MODE mode"
    fi
}

case "$1" in
  start)
        verify_all && start
        exit $?
        ;;
  debug)
        debug
        ;;
  stop)
        verify_all && stop
        exit $?
        ;;
  restart)
        verify_all
        stop
        start
        exit $?
        ;;
  redebug)
        stop
        debug
        ;;
  status|monitor)
        verify_all
        status
        RETVAL=$?
        ;;
  meta-data)
        meta_data
        exit 0
        ;;
  verify-all)
        verify_all
        exit $?
        ;;
  *)
        echo "Usage: $0 {start|debug|stop|restart|redebug|status|meta-data}"
        exit $OCF_ERR_GENERIC
esac

exit $RETVAL

EOFEOFEOF

chmod +x /usr/share/cluster/tomcat6.sh


5. 配置集群

cat >/etc/cluster/cluster.conf<<EOF
<?xml version="1.0" ?>
<cluster alias="new_cluster" config_version="17" name="new_cluster">
        <fence_daemon post_fail_delay="0" post_join_delay="3"/>
        <clusternodes>
                <clusternode name="192.168.16.16" nodeid="1" votes="1">
                        <fence>
                                <method name="1">
                                        <device name="testFence" nodename="192.168.16.16"/>
                                </method>
                        </fence>
                </clusternode>
                <clusternode name="192.168.16.17" nodeid="2" votes="1">
                        <fence>
                                <method name="1">
                                        <device name="testFence" nodename="192.168.16.17"/>
                                </method>
                        </fence>
                </clusternode>
        </clusternodes>
        <cman expected_votes="1" two_node="1"/>
        <fencedevices>
                <fencedevice agent="fence_manual" name="testFence"/>
        </fencedevices>
        <rm>
                <failoverdomains>
                        <failoverdomain name="testFailoverDom" ordered="0" restricted="0">
                                <failoverdomainnode name="192.168.16.16" priority="1"/>
                                <failoverdomainnode name="192.168.16.17" priority="1"/>
                        </failoverdomain>
                </failoverdomains>
                <resources>
                        <ip address="192.168.16.31" monitor_link="1"/>
                        <tomcat6 name="tc6test"/>
                </resources>
                <service autostart="1" domain="testFailoverDom" name="tc6svc" recovery="relocate">
                        <ip ref="192.168.16.31">
                                <tomcat6 ref="tc6test"/>
                        </ip>
                </service>
        </rm>
</cluster>
EOF


6. 启动集群服务
service rgmanager stop
service cman stop
service cman start
service rgmanager start
[root@Perf-LG-6.s3lab.mot.com ~]# service rgmanager stop
Cluster Service Manager is stopped.
[root@Perf-LG-6.s3lab.mot.com ~]# service cman stop
Stopping cluster:
   Stopping fencing... done
   Stopping cman... done
   Stopping ccsd... done
   Unmounting configfs... done
                                                           [  OK  ]
[root@Perf-LG-6.s3lab.mot.com ~]# service cman start
Starting cluster:
   Loading modules... done
   Mounting configfs... done
   Starting ccsd... done
   Starting cman... done
   Starting daemons... done
   Starting fencing... done
                                                           [  OK  ]
[root@Perf-LG-6.s3lab.mot.com ~]# service rgmanager start
Starting Cluster Service Manager:                          [  OK  ]

root     30617    35  0 03:03 ?        00:00:00 [gfs2_scand]
root     30619    35  0 03:03 ?        00:00:00 [glock_workqueue]
root     30620    35  0 03:03 ?        00:00:00 [glock_workqueue]
root     30637     1  0 03:03 ?        00:00:00 /sbin/ccsd
root     30643     1  0 03:03 ?        00:00:00 aisexec
root     30653     1  0 03:03 ?        00:00:00 /sbin/groupd
root     30661     1  0 03:03 ?        00:00:00 /sbin/fenced
root     30667     1  0 03:03 ?        00:00:00 /sbin/dlm_controld
root     30673     1  0 03:03 ?        00:00:00 /sbin/gfs_controld
root     30703     1  0 03:04 ?        00:00:00 clurgmgrd
root     30704 30703  0 03:04 ?        00:00:00 clurgmgrd
root     30705    35  0 03:04 ?        00:00:00 [dlm_astd]
root     30706    35  0 03:04 ?        00:00:00 [dlm_scand]
root     30707    35  0 03:04 ?        00:00:00 [dlm_recv]
root     30708    35  0 03:04 ?        00:00:00 [dlm_send]
root     30709    35  0 03:04 ?        00:00:00 [dlm_recoverd]
root     31125 28541  0 03:04 pts/7    00:00:00 ps -ef

停止cman服务如果停不掉, 可用
cman_tool leave force
cman_tool leave force remove
然后再停

服务rgmanager起来之后,tomcat6被自动启动
[root@Perf-LG-6.s3lab.mot.com ~]# ps -ef|grep java
tomcat    4542     1 97 04:50 ?        00:00:06 /usr/java/jdk1.6.0_11/bin/java -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=/home/tomcat/apache-tomcat-6.0.18.blur/conf/logging.properties -Xms512m -Xmx512m -XX:MaxPermSize=256M -Djava.endorsed.dirs=/home/tomcat/apache-tomcat-6.0.18.blur/endorsed -classpath :/home/tomcat/apache-tomcat-6.0.18.blur/bin/bootstrap.jar -Dcatalina.base=/home/tomcat/apache-tomcat-6.0.18.blur -Dcatalina.home=/home/tomcat/apache-tomcat-6.0.18.blur -Djava.io.tmpdir=/home/tomcat/apache-tomcat-6.0.18.blur/temp org.apache.catalina.startup.Bootstrap start
root      4679 28541  0 04:50 pts/7    00:00:00 grep java


7. 测试
如果在节点1上杀掉tomcat进程, 大约过10秒钟后, 在节点2上重启



-fin-

Monday, May 25, 2009

Mail for Exchange for Nokia S60 诺基亚手机接收Exchange邮件

Mail for Exchange for Nokia S60

使用Nokia的Mail for Exchange可以您你的手机上与您公司的微软Exchange服务器进行邮件, 日历, 任务和联系人的信息同步
下载地址是Mail for Exchange

2009年4月发布了版本2.9.158
支持的操作系统是: S60第3版和第5版
支持的手机类型是:
E50/E51/E60/E61/E61i/E62/E63/E65/E66/E70/E71/E71X/E90
N73/N76/N77/N78/N79/N81/N81 8GB/N82/N85/N95/N95 8GB/N96/N97
5320 XpressMusic/5630 XpressMusic/5730 XpressMusic/5800 XpressMusic
6120 Classic/6124/6210 Navigator/6220 Classic/6650/6720 Classic
支持的服务器端版本是:
*Microsoft Exchange Server 2003 SP2
*Microsoft Exchange Server 2007 SP1
#Microsoft Exchange Server 2003 SP1
#Microsoft Exchange Server 2007 (no service pack)
#Microsoft Small Business Server
(*Certified/#Supported)

更多信息,请到Mail for Exchange查看发布说明.



安装后"我的程序"增加2个图标,"Company Directory"和"Mail For Exchange"
mail for exchange - icons

进入"Mail For Exchange", 界面如下
mail for exchange - main

选择"Option", 打开菜单
mail for exchange - main menu

选择"Edit profile"编辑
mail for exchange - edit profile
按实际情况进行配置

"Connection"选项卡
mail for exchange - edit profile - connection
mail for exchange - edit profile - connection2
Exchange server: Exchange服务器地址
Secure connection: HTTP或HTTPS连接
Access point: 访问Internet的接入点
Sync while roaming: 当漫游时是否同步
Use default port: 是否用默认端口

"Credentials"选项卡
mail for exchange - edit profile - credentials
Username: 用户名
Password: 密码
Domain: 域名

"Sync schedule"选项卡
mail for exchange - edit profile - sync schedule
Peak sync schedule: 高峰期同步时间表
Off-peak sync schedule: 非高峰期同步时间表
Peak start time: 高峰期开始时间
Peak end time: 高峰期结束时间
peak days: 高峰期日期
In case of conflict: 当发生冲突时, 服务器优先还是手机优先

"Calendar"选项卡
mail for exchange - edit profile - calendar

"Tasks"选项卡
mail for exchange - edit profile - tasks

"Contacts"选项卡
mail for exchange - edit profile - contacts


"Email"选项卡
mail for exchange - edit profile - email
mail for exchange - edit profile - email2
Synchronize mail: 是否同步邮件
Email address: 邮件地址
Show new mail popup: 新邮件到来弹出提示
Use signature: 是否使用签名
Signature: 用户签名的内容
When sending mail: 何时发送邮件
Sync messages back: 同步多长时间内的邮件

设置完成后, 选"Save"保存, 然后就可以用了, 收发邮件(同步)都是定时自动进行的

再到信息"Messaging"查看, 增加了一个选项卡
mail for exchange - messaging
如果有新邮件, 会在这里显示出来

还可以编写新邮件
mail for exchange - messaging - create


更多信息请, 请参考Mail for Exchange上的用户手册.



外部链接:
Mail for Exchange
Mail For Exchange(中)



-fin-

Wednesday, May 20, 2009

1z0-043 lesson 8 Monitoring and Managing Memory

1z0-043 lesson 8

完成!!!

是否显示我的答案
是否显示书上的答案和我的注释


1.
1、You observe that a database performance has degraded over a period of time. While investigating the reason, you find that the size of the database buffer cache is not large enough to cache all the needed data blocks. Which advisory component would you refer to, in order to determine that required size of the database buffer cache?
A. Memory Advisor
B. Segment Advisor
C. SQL Tuning Advisor
D. SQL Access Advisor
E. Automatic Database Diagnostic Monitor (ADDM)
E

是不是没有Memory Advisor这个东西
A

教材8-13
就叫Memory Advisor


2.
4、 You have set some of the initialization parameters as:
DB_BLOCK_SIZE = 8KB
SGA_MAX_SIZE = 2GB
SGA_TARGET = 0
SHARED_POOL_SIZE = 120MB
DB_CACHE_SIZE = 896MB
STREAM_POOL_SIZE = 0
LARGE_POOL_SIZE = 110 MB
Which two statements are correct? (Choose two.)
A. You cannot set a value for the DB_8K_CACHE_SIZE parameter.
B. If you increase the size of the large pool to 120 MB, then the memory allocated to the shared poll will be reduced to 110 MB.
C. If the value for SGA_TARGET is changed to 1 GB and SHARED_POOL_SIZE is set to 120 MB, then memory cannot be taken from the shared pool, even if the shared pool has free space available.
D. If an application attempts to allocate more than 120 MB from the shared pool and freespace is available in the buffer pool, then the free space from the buffer pool is allocatedto the shared pool.
AC
AC

A 教材8-7


3.
28. You enabled Automatic Shared Memory Management. The initialization parameters are set as shown below:
SGA_TARGET= 10GB
SGA_MAX_SIZE = 14GB
STREAMS_POOL_SIZE = 1GB
SHARED_POOL_SIZE = 3GB
Which two statements are correct in this scenario? (Choose two.)
A. A maximum of 3 GB can be allocated to shared pool.
B. The value for SGA_TARGET can be increased up to a maximum of 14 GB.
C. A total of 14 GB memory will be allocated to the automatically tuned memory components.
D. Increasing the value for SGA_TARGET will automatically increase the memory allocated for STREAMS_POOL_SIZE.
E. Increasing the value for SGA_TARGET to 12 GB will automatically increase the memory allocated to autotuned parameters.
F. Reducing the value for SGA_TARGET to 9 GB will automatically decrease the memory allocated to shared pool from 3 GB to 2 GB.
BE
BE


4.
44. Your database is running on the automatic Program Global Area (PGA) memory management and Shared Memory Management mode. You want to increase the memory available for the SQL work areas. What would you do?
A. modify the HASH_AREA_SIZE initialization parameter
B. modify the PGA_AGGREGATE_TARGET initialization parameter
C. modify the WORK_AREASIZE_POLICY initialization parameter
D. increase the value of the SGA_TARGET initialization parameter
E. increase the value of the SGA_MAX_SIZE initialization parameter
F. increase the value of the SORT_AREA_SIZE initialization parameter
B
B


5.
117. You are working in a dedicated server environment. Your database is running in the automatic Program Global Area (PGA) memory management mode. Which two statements are correct in this scenario? (Choose two)
A. The WORK_AREASIZE_POLICY initialization parameter cannot be set to AUTO.
B. The Oracle database automatically controls the amount of PGA memory allotted to SQL work areas.
C. Setting the value of the SGA_TARGET initialization parameter to 0 will disable the automatic PGA memory management.
D. The SORT_AREA_SIZE parameter is ignored by all the sessions running in the automatic PGA memory management mode.
BD
BD

教材8-29


6.
140. You have configured Automatic Shared Memory Management. Which four memory structures would be automatically tuned? (Choose four)
A. log buffer
B. Java pool
C. Large pool
D. Fixed SGA
E. Shared pool
F. Streams pool
G. Keep buffer cache
H. Database buffer cache
BCEFH
这题不对

BCEH

教材8-15
应该有5个是对的


7.
151. You noticed that large memory allocations for the Oracle backup and restore operations are causing a performance overhead on the shared pool. Which memory structure would you configure to avoid this performance overhead?
A. recycle buffer cache
B. large pool
C. streams pool
D. keep buffer cache
E. redo log buffer
B
不知道
B

不懂为什么选B


8.
161. The database has the data block size set to 8 KB. You need to import a tablespace with a 4 KB block size into the database. Which additional memory parameter(s) should be configured to perform a transportable tablespace import?
A. DB_4K_CACHE_SIZE only
B. DB_8K_CACHE_SIZE only
C. DB_BLOCK_SIZE and DB_4K_CACHE_SIZE
D. DB_BLOCK_SIZE and DB_8K_CACHE_SIZE
E. SGA_TARGET and DB_4K_CACHE_SIZE
F. DB_CACHE_SIZE only
A
什么意思, 选C?
A
对了


9.
164. You configured the large pool for Oracle backup and restore operations. As a result, which component would require less memory?
A. streams pool
B. shared pool
C. log buffer
D. keep buffer cache
E. recycle buffer cache
B
不懂
B

这题也不对, 应该是AB


10.
172. You enabled Automatic Shared Memory Management. The initialization parameters are set as shown below:
SGA_TARGET = 10GB
SGA_MAX_SIZE = 14GB
STREAMS_POOL_SIZE = 1GB
SHARED_POOL_SIZE = 3GB
Which two statements are correct in this scenario? (Choose two.)
A. A total of 14 GB memory will be allocated to the automatically tuned memory components.
B. Reducing the value for SGA_TARGET to 9 GB will automatically decrease the memory allocated to shared pool from 3 GB to 2 GB.
C. The value for SGA_TARGET can be increased up to a maximum of 14 GB.
D. A maximum of 3 GB can be allocated to shared pool.
E. Increasing the value for SGA_TARGET to 12 GB will automatically increase the memory allocated to autotuned parameters.
F. Increasing the value for SGA_TARGET will automatically increase the memory allocated for STREAMS_POOL_SIZE.
CE
跟第3题差不多
CE


=====

没了




-fin-

Thursday, May 14, 2009

A discussion about tablespace allocation specification

A discussion about tablespace allocation specification

Round 1:

from wen xie
to ddd
date Thu, May 14, 2009 at 21:43
subject Re: 答复: 给看看有啥问题(表空间分配规范)
mailed-by googlemail.com

hide details 21:43 (10 minutes ago)


Reply

Follow up message


2009/5/14 ddd

1,数据文件命名贵发没法给你,正在写,发给你的也是今天下午写的

一般, 数据文件的前缀同表空间名, 同一个表空间的第一个编号01, 第二个编号02, 依此类推

还有什么更好的建议吗

2,临时表是指临时创建的表,

如何控制用户建表使用哪个表空间呢? 好像只能细分用户权限, 不同用户有不同权限, 可是你又不愿意建那么多的用户


3,请给出让表空间自动扩展的理由,如果是裸设备怎么自动扩展

你自己说的就是数据文件

如果是数据文件则可以. 在可控的空间范围内, 文件大小自动扩展, 兼顾空间使用率和可扩展性

如果是裸设备, 本来就扩展不了, 何必专门提出
另外, 没用过裸设备, 不知道如何扩展/收缩大小, 总觉得没文件方便


4,业务表达的近1000个,不可能将业务表部署在一个表空间上,这些修改较少的,主要是相对一些每天都大量修改的表,大量修改肯定会形成碎片,单独部署到表空间能确保其他少修改的表数据能规整些,如果全表扫描,也能降低访问次数

碎片定义1: 指表空间中存在的一些小的不连续的空闲空间, 由于太小, 无法被使用

使用盘区(extent)本地管理,自动分配大小, 即可解决此问题


碎片定义2: 指因为表空间中数据对象占用的空间不是一次性分配的,盘区是随着数据量增长,自动扩展分配的, 肯定要分配多个盘区, 所以造成了同一个数据对象的盘区的分布是不连续的

数据对象分配本来就是一个一个盘区分配的, 不可能是连续的, 除非表空间里只有一个数据对象, 或数据对象只分配了一个大的盘区
第一种情况(盘区是连续的): 也没有意义, 比如说全表扫描读取, 也是一个一个盘区读的(其实是多数据块读multiblock read), 效果跟不连续的是一样的, 所以连续的盘区并不能带来读写上的优势
第二种情况(单一的盘区, 或者较少数量的盘区): 8i以前的字典管理下, 较少的盘区可能会带来性能上的少许提高, 8i之后是本地管理, 再加上自动分配大小, 这不再是问题了.


碎片定义3: 数据块中有未被使用/不能使用的空间, 数据行是不连续的,存在于多个数据块内.
不写了.

这TMD都跟表空间命名规范/使用规范, 频繁不频繁,没一点儿关系.

估计你主要指的是第二种, 是不成立的


- Hide quoted text -

5,业务表所属表空间确实不适合使用数字编号,按业务或功能确实比较合适,




发件人: wen xie [mailto:xiewenxiewen at googlemail.com]
发送时间: 2009年5月14日 17:35
收件人: ddd
主题: Re: 给看看有啥问题(表空间分配规范)



1. 没有制定数据文件的命名规范, 也就是说没有考虑表空间对应的数据文件的规范


2. 临时表指的是什么, 临时创建的表, 还是oracle的临时表?
这个好像无法限制用户在哪个表空间创建

3. 表空间(其实应该是数据文件)应该设置为自动扩展, 但要设置一个最大大小, 以免疯狂扩展

4."数据量及增删较少,不会形成大量碎块,部署到单独表空间,能有效提高查询性能"
这就是你第4条"频繁更新的表和其它表部署在不同表空间上"的理由
但是理由不充分. 是什么?

表空间应使用自动分配管理, 基本上就可避免碎块

5. 以数字编号命名表空间不是个好的方法, 一个表空间多个数据文件的情况下数据文件才应该带上编号,
表空间按业务,功能区分即可, 分区表空间可按分区字段命名, 比如日期

2009/5/14 ddd
一、实施背景及目的

目前基本上所有系统,都只有一个表空间,系统对应用户下的所有表、索引及其他都全部建立在同一个表空间下,存在较大的安全及性能问题,随着业务的开展,数据量的急剧增加,数据的管理及共享方式也将受到影响,为了更好的提高数据库性能,有必要对表空间划分建立规范,新系统建立依照规范执行
二、实施基本原则

本规范实施中必须遵循的主要原则有:

1, 备份表和生产表必须分开在不同表空间上

2, 临时表单独建立在独立的表空间上

3, 基表和业务表分离在不同表空间上

4, 频繁更新的表和其它表部署在不同表空间上

5, 日志表单独部署表空间

6, 超大表采用分区表方式,部署在不同表空间上

7, 索引和表对应,基表对应基表索引表空间,频繁更新表的索引单独部署表空间

8, 表空间数据文件不能自动扩展(asm除外)
三、数据库表空间划分

按照表空间的功能进行划分建立

1, 基表所属表空间

命名规则:系统简称_+BASE

用途:用于保存所有基础表,由于基础表数据量及增删较少,不会形成大量碎块,部署到单独表空间,能有效提高查询性能

2, 业务表所属表空间

命名规则:系统简称_+DATA+编号(01,02….)

用途:用于保存部分业务表,业务表数据的增长情况

3, 频繁更新表所属表空间

命名规范:系统简称_+DATA+

用途:由于频繁更新,导致表空间碎片增加,通过将表独立部署到单独表空间,能提高其他表数据的规整性,有效提高性能

4, 日志表所属表空间

命名规则:系统简称_+LOG+编号(01,02….)

用途:用于保存业务系统各个日志表数据,日志表单独部署,可以

5, 超大表分区表空间

命名规则:系统简称_+PART+编号(01,02….)

用途:用于保存业务系统各个超大表分区数据

6, 索引表空间和数据所属表空间一一对应

命名规则:系统简称_+IDX_+PART+编号(01,02….)

用途:用于保存各个表表空间中表的索引数据,索引空间和表空间一一对应,确保早迁



Continued

from wen xie
to ddd
date Fri, May 15, 2009 at 12:24
subject Re: 答复: Re:
mailed-by googlemail.com

hide details 12:24 (18 hours ago)


Reply

Follow up message


http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/instance_tune.htm
10.3.4 db file sequential read

This event signifies that the user process is reading a buffer into the SGA buffer cache and is waiting for a physical I/O call to return. A sequential read is a single-block read.

Single block I/Os are usually the result of using indexes. Rarely, full table scan calls could get truncated to a single block call due to extent boundaries, or buffers already present in the buffer cache. These waits would also show up as 'db file sequential read'.


等我有时间再做个实验证实一下!
- Hide quoted text -


2009/5/15 ddd

我得学习学习了,需要确认一下你说的到底有没有问题,没有骗人吧?如果extent只有128k,那么db_file_multiblock_read_count设置再大也没有用?在哪记载?



临时表特指数据库中创建的用于清单报表打印、业务中间处理、关联系统数据同步、上传和下载中间处理的,不需长期保存,且表或数据清除后不影响业务的表。





发件人: wen xie [mailto:xiewenxiewen at googlemail.com]
发送时间: 2009年5月15日 10:08
收件人: ddd
主题: Re:



多数据块读不能跨盘区, 即最多读取的数量等于: db_file_multiblock_read_count和extent两者取一个最大值

2009/5/15 ddd

这个应该有影响因素吧?

如果我将db_file_multiblock_read_count设为64,一次读取64块,将近1m的数据,表的extent大小为65k,那么如果这16个extent都是一个表数据,全表扫描是否16个extent一次性读取;

而当这16个extent包含多个表数据并且互相交叉,是否要多次访问才能将某个表数据都取出:







碎片定义1: 指表空间中存在的一些小的不连续的空闲空间, 由于太小, 无法被使用

使用盘区(extent)本地管理,自动分配大小, 即可解决此问题


碎片定义2: 指因为表空间中数据对象占用的空间不是一次性分配的,盘区是随着数据量增长,自动扩展分配的, 肯定要分配多个盘区, 所以造成了同一个数据对象的盘区的分布是不连续的

数据对象分配本来就是一个一个盘区分配的, 不可能是连续的, 除非表空间里只有一个数据对象, 或数据对象只分配了一个大的盘区
第一种情况(盘区是连续的): 也没有意义, 比如说全表扫描读取, 也是一个一个盘区读的(其实是多数据块读multiblock read), 效果跟不连续的是一样的, 所以连续的盘区并不能带来读写上的优势
第二种情况(单一的盘区, 或者较少数量的盘区): 8i以前的字典管理下, 较少的盘区可能会带来性能上的少许提高, 8i之后是本地管理, 再加上自动分配大小, 这不再是问题了.


碎片定义3: 数据块中有未被使用/不能使用的空间, 数据行是不连续的,存在于多个数据块内.
不写了.

这TMD都跟表空间命名规范/使用规范, 频繁不频繁,没一点儿关系.

估计你主要指的是第二种, 是不成立的



Round 2:

from wen xie
to ddd
date Fri, May 15, 2009 at 22:57
subject Re: 答复: 答复: 答复: 你觉得频繁更新表的表空间不需要建立?
mailed-by googlemail.com

hide details 22:57 (7 hours ago)


Reply

Follow up message


2009/5/15 ddd

呵呵,

1,运维用户确实只应该只对备份表空间有配额

2,DBLINK 可能其他人维护,如果没有一个配额,若想临时备份数据,备份到哪?

你的DBLINK用户是做什么的?

- Hide quoted text -

3,对于管理用户,我现在真的没想好,一直使用system或sys对数据库做管理,就他妈我一个人,建多个用户干什么用,



发件人: wen xie [mailto:xiewenxiewen@googlemail.com]
发送时间: 2009年5月15日 17:04
收件人: ddd
主题: Re: 答复: 答复: 你觉得频繁更新表的表空间不需要建立?



那么运维用户应该只对备份表空间有配额, 其它表空间无配额. 你写的是所有表空间用户的配额都一样, 是不对的

数据库连接用户就是建立数据库连接和视图和授权的, 这些都不占用用户表空间,不需要配额
你后面说的我没看懂, 什么同义词备份, 原表无法操作?

管理用户如果是system, 你竟然限制它使用1G? 而且system具有dba角色, 拥有unlimited tablespace系统权限, 你没限制住.


2009/5/15 ddd

运维用户肯定需要的,修改数据前需要对表备份,dblink用户一般情况是不需要用,一般通过建同义词使用,但现在有时可能真有对同义词数据进行保存操作,原表无法操作,那么只好对同义词查询的数据进行备份

管理用户实际不需要太大的空间,我个人理解管理用户应该就是system,不单独建用户



发件人: wen xie [mailto:xiewenxiewen at googlemail.com]

发送时间: 2009年5月15日 13:12
收件人: ddd
主题: Re: 答复: 你觉得频繁更新表的表空间不需要建立?



运维用户需要建表吗? dblink用户肯定是不用的. 管理用户为什么只有1G?

2009/5/15 ddd

2,我的目的就是控制不让某个用户大量建表并插入数据,如果配额等于0,当真有需要空间,那不歇菜了?



发件人: wen xie [mailto:xiewenxiewen at googlemail.com]
发送时间: 2009年5月15日 12:36
收件人: ddd
主题: Re: 你觉得频繁更新表的表空间不需要建立?




1.单独放到另一个磁盘上, 可能更有用处

2. 配额管理只对表的所有者有效. 比如有表scott.depts, 你给scott用户限额是无限, 给运维用户a限额为1m, 用户a有对scott.depts的操作权限, 那么用户a对表scott.depts的空间使用也是无限的, 只有它自己建的表才不能超过1m.
因此你的目的完全没有达到, 还不如对其它用户不授予任何空间配额, 即配额等于0

3.先写这么多

2009/5/15 ddd
一、实施背景及目的

目前基本上所有系统,都只有一个表空间,系统对应用户下的所有表、索引及其他都全部建立在同一个表空间下,存在较大的安全及性能问题,随着业务的开展,数据量的急剧增加,数据的管理及共享方式也将受到影响,为了更好的提高数据库性能,有必要对表空间划分建立规范,新系统建立依照规范执行
二、实施基本原则

本规范实施中必须遵循的主要原则有:

1, 备份表和生产表必须分开在不同表空间上

2, 基表和业务表分离在不同表空间上

3, 业务表根据功能划分部署到不同表空间上

4, 频繁更新的表和其它表部署在不同表空间上

5, 日志表单独部署表空间

6, 超大表采用分区表方式,部署在不同表空间上

7, 索引和表对应,基表对应基表索引表空间,频繁更新表的索引单独部署表空间

8, 表空间数据文件不能自动扩展(asm除外)
三、数据库表空间划分

按照表空间的功能进行划分建立

1, 基表所属表空间

命名规则:系统简称_+BASE

用途:用于保存所有基础表,由于基础表数据量及增删较少,不会形成大量碎块,部署到单独表空间,能有效提高查询性能

2, 业务表所属表空间

命名规则:系统简称_+功能

用途:用于保存部分业务表,根据业务功能划分表空间,同一功能业务表部署到同一表空间中

3, 频繁更新表所属表空间

命名规范:系统简称_+DATA

用途:由于频繁更新,导致表空间碎片增加,通过将表独立部署到单独表空间,能提高其他表数据的规整性,有效提高性能

4, 日志表所属表空间

命名规则:系统简称_+LOG

用途:用于保存业务系统各个日志表数据

5, 备份表所属表空间

命名规则:系统简称_+BAK

用途:用于保存数据修改是需要对表备份形成的备份表及临时表



6, 超大表分区表空间

命名规则:系统简称_+PART+分区字段,如系统简称+PART+时间

用途:用于保存业务系统各个超大表分区数据

7, 索引表空间和数据所属表空间一一对应

命名规则:对因数据表空间名称 + IDX

用途:用于保存各个表空间中表的索引数据,索引空间和表空间一一对应


四、各表空间分配原则及规范

1,基础表空间对中间件用户的配额为无限制,对运维修改用户、DBLINK及管理用户配额为1G

2,业务表空间对中间件用户的配额为无限制,对运维修改用户、DBLINK及管理用户配额为1G

3,备份表空间对运维修改用户的配额为无限制,对中间件用户、DBLINK及管理用户配额为1G

4,日志表空间对中间件用户的配额为无限制,对运维修改用户、DBLINK及管理用户配额为1G

5,索引表空间对中间件用户的配额为无限制,对运维修改用户、DBLINK及管理用户配额为1G

6,分区表空间对中间件用户的配额为无限制,对运维修改用户、DBLINK及管理用户配额为1G


五、各表空间数据文件建立原则及规范

1,操作系统为32位,采用文件系统方式建立表空间的,每个数据文件大小不超过2G

2,操作系统为32位,采用裸设备作为数据文件建立表空间的,每个裸设备一般设置为5G,最大不超过10G

3,操作系统为64位,采用文件系统方式建立表空间的,每个数据文件大小为5G

4,操作系统为64位,采用裸设备作为数据文件建立表空间的,每个裸设备大小一般设置为10G,最大不超过20G
六、各表空间数据文件命名规范

1,采用文件系统方式建立表空间的,数据文件命名采用:

数据文件命名:表空间名 +编号 (01,02 。。。)+..dbf

2,采用裸设备作为数据文件建立表空间的,需要采用链接将裸设备指定到相应目录,具体目录参照数据库软件安装规范,裸设备命名采用:

数据文件命名:表空间名 +编号 (01,02 。。。)







-fin-

Inter-Session Communication DBMS_PIPE 会话间通信 DBMS_PIPE

Inter-Session Communication DBMS_PIPE
会话间通信 DBMS_PIPE


DBMS_PIPE在Oracle7引入, 也是会话间通信的一种, 常用于与外部服务通信,调试PL/SQL程序,或安全审计


1.
DBMS_PIPE与DBMS_ALERT的比较:
1)DBMS_ALERT是单向的. DBMS_PIPE是双向的.
2)DBMS_ALERT是基于事务的, 提交后发出警报. DBMS_PIPE不是基于事务的.
3)DBMS_ALERT一条警报可以有多个接收者, 可以是广播模式的. DBMS_PIPE的一条消息只能被最后等待一个用户接收到.
4)DBMS_ALERT是由DBMS_PIPE和DBMS_LOCK实现的
5)DBMS_ALERT只能发送一条VARCHAR2型字符串, 最多1800个字符. DBMS_PIPE可以发送多条信息,多种数据类型
6)都只能在同一个实例内会话间通信
7)发送的消息不是持久的, 数据库实例关闭, 消息就被清除
8)都是异步的

另参考
Can I do mutlithreaded programming in PLSQL:
dbms_alert is used to send a signal to ALL interested parties. It is transactional (the
signal is not sent until you commit). It "loses" signals -- if I signal the same event 5
times and commit -- only one event might get broadcast. It is like a unix signal in this
way. Dbms_alert is asyncronous -- the sender never gets anything back from the reciever.

dbms_pipe is used to send a message to a SINGLE interested party (although >1 person can
be reading the pipe, only ONE person will get the message). The message is sent
immediately, regardless of your transactions state. It is like a unix pipe. Dbms_pipe
can be syncronous -- i can send a message and get a message back.


2.
参考Oracle文档DBMS_PIPE:

The DBMS_PIPE package lets two or more sessions in the same instance communicate. Oracle pipes are similar in concept to the pipes used in UNIX, but Oracle pipes are not implemented using the operating system pipe mechanisms.
DBMS_PIPE包让处于同一实例中的两个或多个会话进行通信. Oracle管道和UNIX中使用的管道的概念类似, 但不是用操作系统的管道机制实现的.

Pipe functionality has several potential applications:
管道功能有几种可能的应用:

External service interface: You can communicate with user-written services that are external to the RDBMS. This can be done effectively in a shared server process, so that several instances of the service are executing simultaneously. Additionally, the services are available asynchronously. The requestor of the service does not need to block a waiting reply. The requestor can check (with or without time out) at a later time. The service can be written in any of the 3GL languages that Oracle supports.
外部服务接口:能够与RDBMS之外的用户编写的服务进行通信.(略)

Independent transactions: The pipe can communicate to a separate session which can perform an operation in an independent transaction (such as logging an attempted security violation detected by a trigger).
独立的事务:管道能够与在一个独立事务(比如记录由触发器发现的违反安全的尝试)s中运行操作的单独的会话通信

Alerters (non-transactional): You can post another process without requiring the waiting process to poll. If an "after-row" or "after-statement" trigger were to alert an application, then the application would treat this alert as an indication that the data probably changed. The application would then read the data to get the current value. Because this is an "after" trigger, the application would want to do a "SELECT FOR UPDATE" to make sure it read the correct data.
警报(非事务性的):你能够通知另一个进程,无需那个等待的进程去轮询.(略)

Debugging: Triggers and stored procedures can send debugging information to a pipe. Another session can keep reading out of the pipe and display it on the screen or write it to a file.
调试:触发器和存储过程向管道发送调试信息. 另一个会话从管道读取并显示到屏幕或写入文件.

Concentrator: This is useful for multiplexing large numbers of users over a fewer number of network connections, or improving performance by concentrating several user-transactions into one DBMS transaction.
集中器:用于多路复用网络连接数较少的大量用户, 或者将多个用户事务集中到一个DBMS事务中用以改善性能.(这个比较有意思,但到底是什么意思呢?)

-----
Public Pipes
公有管道

You may create a public pipe either implicitly or explicitly. For implicit public pipes, the pipe is automatically created when it is referenced for the first time, and it disappears when it no longer contains data. Because the pipe descriptor is stored in the SGA, there is some space usage overhead until the empty pipe is aged out of the cache.
可以隐式或显式的创建公有管道.隐式公有管道在第一次被引用时自动创建,当不再存在数据时消失.(略)

You create an explicit public pipe by calling the CREATE_PIPE function with the private flag set to FALSE. You must deallocate explicitly-created pipes by calling the REMOVE_PIPE function.
调用CREATE_PIPE加上private标记等于FALSE创建显式公有管道.必须调用REMOVE_PIPE删除显式创建的管道.

The domain of a public pipe is the schema in which it was created, either explicitly or implicitly.
公有管道的域(是啥?)是被创建的用户, 不论显式的或隐式的

-----
Writing and Reading Pipes
读写管道

Each public pipe works asynchronously. Any number of schema users can write to a public pipe, as long as they have EXECUTE permission on the DBMS_PIPE package, and they know the name of the public pipe. However, once buffered information is read by one user, it is emptied from the buffer, and is not available for other readers of the same pipe.
公有管道是异步工作的. 可以有任意数量的用户写一个公有管道, 只要它们拥有DBMS_PIPE的执行权限, 和知道公有管道名. 但是, 缓冲的信息一旦被一个用户读取了, 它就从缓冲区中被清空, 对于其它用户就不可以使用了.

The sending session builds a message using one or more calls to the PACK_MESSAGE procedure. This procedure adds the message to the session's local message buffer. The information in this buffer is sent by calling the SEND_MESSAGE function, designating the pipe name to be used to send the message. When SEND_MESSAGE is called, all messages that have been stacked in the local buffer are sent.
发送会话调用PACK_MESSAGE一次或多次来创建一个信息. 这个过程将消息加到会话本地的信息缓冲区. 调用SEND_MESSAGE函数,指定发送消息的管道名,用以发送缓冲区中的信息. 当SEND_MESSAGE被调用, 堆放在本地缓冲区的所有信息都被发送出去.

A process that wants to receive a message calls the RECEIVE_MESSAGE function, designating the pipe name from which to receive the message. The process then calls the UNPACK_MESSAGE procedure to access each of the items in the message.
想要接受信息的进程调用RECEIVE_MESSAGE函数, 并指定接受信息的管道名. 然后调用UNPACK_MESSAGE过程去访问信息中的每条.

-----
Private Pipes
私有管道

You explicitly create a private pipe by calling the CREATE_PIPE function. Once created, the private pipe persists in shared memory until you explicitly deallocate it by calling the REMOVE_PIPE function. A private pipe is also deallocated when the database instance is shut down.
可以通过调用CREATE_PIPE函数显式的创建一个私有管道. 私有管道一旦被创建, 就持久保存在共享内存中, 直到显式的调用REMOVE_PIPE函数清除它. 当数据库实例关闭时私有管道也被清除.

You cannot create a private pipe if an implicit pipe exists in memory and has the same name as the private pipe you are trying to create. In this case, CREATE_PIPE returns an error.
如果已经有一个隐式的同名管道存在了, 就不能再创建同名的私有管道. 这种情况下, CREATE_PIPE返回一个错误.

Access to a private pipe is restricted to:
访问私有管道有如下限制:
Sessions running under the same userid as the creator of the pipe
在与管道创建者同样的用户的会话下运行.
Stored subprograms executing in the same userid privilege domain as the pipe creator
在与管道创建者同样用户权限域的存储过程下运行
Users connected as SYSDBA
SYSDBA用户

An attempt by any other user to send or receive messages on the pipe, or to remove the pipe, results in an immediate error. Any attempt by another user to create a pipe with the same name also causes an error.

As with public pipes, you must first build your message using calls to PACK_MESSAGE before calling SEND_MESSAGE. Similarly, you must call RECEIVE_MESSAGE to retrieve the message before accessing the items in the message by calling UNPACK_MESSAGE.




另外参考Definitions and Examples of how Oracle Pipes works:

Let's assume we have sessions A, B and C.
假设有会话A,B,C

Case 1
------
Let's say A and B send messages through the pipe and C is waiting on them.
If A sends a message first and then B sends another message, C will receive A's message first and then B's message.
会话A,B通过管道发送信息, 会话C等待信息
如果A首先发送了一条信息, 然后B发送了另一条, C会首先接收到A的信息, 然后是B的.

Case 2
------
Now, Let's put A and B to receive and C to send.
A will wait for message first and B will wait for a message after A did it.
When C sends a message, B is the one who receives it but A will remain waiting.
If C sends another message now A receives the message.
A和B接收, C发送
首先A等待信息, 然后B等待信息.
C发出一条信息, B接收到, A仍然等待.
C再发出一条信息, 这次A接收到

This shows that the queue for waiting a pipe behaves in a "stack" manner. Which ever waits first receives the message last and whichever waits last will receives it first.
这表明等待管道的队列是堆栈的方式. 最先等待的接收到最后的信息, 最后等待的接收到最先的信息.


3.
举例, 也参考前面的连接(Definitions and Examples of how Oracle Pipes works):

创建发送,接收存储过程,和测试表等
/**
 * 发送.
 */
create or replace procedure send_pipe as
  result number;
  my_pipe varchar2(30);
  user user_users%rowtype;
begin
  select * into user from user_users;
  --生成一个管道名, 这个管道将用于传递用户信息等
  my_pipe := dbms_pipe.UNIQUE_SESSION_NAME;
  --将my_pipe管道名发送到'waiter'管道, 'waiter'管道也是隐式创建的
  dbms_pipe.pack_message(my_pipe);
  result := dbms_pipe.send_message('waiter');
  --然后, 将用户信息发送到my_pipe管道中
  -- this message will have 3 parts. A varchar2, a number and a date. 
  dbms_pipe.pack_message(user.USERNAME);
  dbms_pipe.pack_message(user.user_id);
  dbms_pipe.pack_message(user.created);
  result := dbms_pipe.send_message(my_pipe);
end;
/


/**
 * 接收.
 */
create or replace procedure read_pipe as
  result number;
  v varchar2(4000);
  d date;
  n number;
  w raw(32767);
  r rowid;
  his_pipe varchar2(30);
  type_not_handled exception;
begin
  --从'waiter'管道接收信息, 得到对端的my_pipe管道名, 这里叫his_pipe.
  result := dbms_pipe.RECEIVE_MESSAGE('waiter');
  dbms_pipe.unpack_message(his_pipe);
  dbms_output.put_line('Pipe :'||his_pipe);
  --然后, 从his_pipe管道获取并打印接收到的信息
  result := dbms_pipe.RECEIVE_MESSAGE(his_pipe);
  result := dbms_pipe.next_item_type;
  while result <> 0 loop
    dbms_output.put_line('type =>'||to_char(result));
    if result=9 then -- varchar2
      dbms_pipe.unpack_message(v);
      dbms_output.put_line(v);
    elsif result=6 then -- number
      dbms_pipe.unpack_message(n);
      dbms_output.put_line(n);
    elsif result=12 then -- date
      dbms_pipe.unpack_message(d);
      dbms_output.put_line(d);
    elsif result=11 then -- rowid
      dbms_pipe.unpack_message_rowid(r);
      dbms_output.put_line(r);
    elsif result=23 then -- raw
      dbms_pipe.unpack_message_raw(w);
      dbms_output.put_line(w);
    else 
      raise type_not_handled;
    end if;
    result := dbms_pipe.next_item_type;
  end loop;
exception
  when type_not_handled then
    dbms_output.put_line('Type '||to_char(result)||' not handled');
    dbms_pipe.purge(his_pipe);
  when others then
    dbms_output.put_line('error: '||to_char(result));
    dbms_pipe.purge(his_pipe);
end;
/


/**
 * 删除所有的管道.
 */
create or replace procedure remove_all_pipes is
  result number;
begin
  for i in (select * from v$db_pipes) loop
    dbms_output.put('Pipe '||i.name);
    begin
      result := dbms_pipe.remove_pipe(i.name);
      dbms_output.put_line(' removed.');
    exception
      when others then
        dbms_output.put_line(' not removed.');
    end;
  end loop;
end;
/


--建测试表, 其上创建触发器
drop table any_table;
create table any_table(dummy varchar2(30));

create or replace trigger audit_any_table
  after insert on any_table
  for each row
declare
  name varchar2(30);
  result number;
  usid varchar2(30);
begin
  --同样, 先将自己的管道名发送非'waiter'
  usid := dbms_pipe.unique_session_name;
  dbms_pipe.pack_message(usid);
  result := dbms_pipe.send_message('waiter');
  --然后, 将用户信息等发送到自己的管道, 由waiter端接收
  select username into name from user_users;
  dbms_pipe.pack_message(name);
  dbms_pipe.pack_message(:new.dummy);
  result := dbms_pipe.send_message(usid);
end;
/


Case 1
------
Session: A
Explanation: The same user can read from it's own pipe.
Two pipes are created. One is 'waiter' the other has the name of the unique_session_name.

1) A: exec send_pipe
2) A: exec read_pipe
3) A: Select * from v$db_pipes;

同一个会话:
同一个用户能够读取它自己的管道
SQL> exec send_pipe

PL/SQL procedure successfully completed.

SQL> exec read_pipe
Pipe :ORA$PIPE$0659B71A0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

SQL> Select * from v$db_pipes;

   OWNERID NAME                           TYPE     PIPE_SIZE
---------- ------------------------------ ------- ----------
           ORA$PIPE$0659B71A0001          PUBLIC        1686
           WAITER                         PUBLIC        1671


Case 2
------
Sessions: A & B
Explanation: A sends info, B receives it. No new pipes.

1) A: exec send_pipe
2) B: exec read_pipe
3) A: Select * from v$db_pipes;

会话A发送信息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B接收
SQL> exec read_pipe
Pipe :ORA$PIPE$0659B71A0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

查看管道信息
SQL> Select * from v$db_pipes;

   OWNERID NAME                           TYPE     PIPE_SIZE
---------- ------------------------------ ------- ----------
           ORA$PIPE$0659B71A0001          PUBLIC        1686
           WAITER                         PUBLIC        1671


Case 3
------
Sessions: A & B
Explanation: A will hold until a message is received.
A new pipe is created.

1) A: exec read_pipe
2) B: exec send_pipe
3) A: Select * from v$db_pipes;

会话A先等待接收
SQL> exec read_pipe
会话B再发送
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B发送时,隐式创建了一个新的管道
Pipe :ORA$PIPE$06573F5C0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

SQL> Select * from v$db_pipes;

   OWNERID NAME                           TYPE     PIPE_SIZE
---------- ------------------------------ ------- ----------
           ORA$PIPE$0659B71A0001          PUBLIC        1686
           WAITER                         PUBLIC        1671
           ORA$PIPE$06573F5C0001          PUBLIC        1686


Case 4
------
Sessions: A & B
Notes: A must have the table any_table and the trigger audit_any_table in its schema.
Explanation: B will hold until a message from the trigger is recieved which is sent when A inserts a new value. Commit or rollback doesn't have any effect, the message was already been received.
No new pipes.

1) B: exec read_pipe
2) A: insert into any_table values('New Value');
3) A: try both commit and rollback.

会话B等待信息
SQL> exec read_pipe
会话A插入数据,触发触发器发送信息
事务B立即收到信息, 不论(不等)会话A事务提交与否
Pipe :ORA$PIPE$0659B71A0001
type =>9
A
type =>9
New Value

PL/SQL procedure successfully completed.

SQL>
会话A回滚
SQL> rollback;

Rollback complete.


Case 5
------
Sessions: A, B & C
Explanation: On step 3, B will receive the message. On Step 4 A receives it.
A new pipe is created.

1) A: exec read_pipe
2) B: exec read_pipe
3) C: exec send_pipe
4) C: exec send_pipe

会话A等待消息
SQL> exec read_pipe
会话B等待消息
SQL> exec read_pipe
会话C发送消息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B是后启的,先收到消息
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

会话C再次发送消息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

这次会话A收到消息
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.


Case 6
------
Sessions: A, B & C
Explanation: On step 3, B will receive the message. On Step 5 B again receives it.
On step 6 A receives it.

1) A: exec read_pipe
2) B: exec read_pipe
3) C: exec send_pipe
4) B: exec read_pipe
5) C: exec send_pipe
6) C: exec send_pipe

会话A等待消息
SQL> exec read_pipe
会话B等待消息
SQL> exec read_pipe
会话C发送消息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B是后启的,先收到消息
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

会话B再次等待消息
SQL> exec read_pipe
会话C再次发送消息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B还是后启的,又收到了消息
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

会话A仍然在等待消息, 按ctrl-c退出
BEGIN read_pipe; END;

*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01013: user requested cancel of current operation
ORA-06508: PL/SQL: could not find program unit being called: "SYS.DBMS_SYS_ERROR"
ORA-06512: at "SYS.DBMS_PIPE", line 167
ORA-06512: at "SYS.DBMS_PIPE", line 192
ORA-06512: at "A.READ_PIPE", line 46
ORA-06556: the pipe is empty, cannot fulfill the unpack_message request
ORA-06512: at line 1




Case 7
------
Sessions: A, B & C
Explanation: On Step 3, A receives C's message. On Step 4 A received B's Message.

1) C,B: exec dbms_output.put_line(dbms_pipe.unique_session_name)
2) C: exec send_pipe
3) B: exec send_pipe
4) A: exec read_pipe
5) A: exec read_pipe

会话C显示自己的管道名
SQL> exec dbms_output.put_line(dbms_pipe.unique_session_name)
ORA$PIPE$066337EB0001

PL/SQL procedure successfully completed.

会话B显示自己的管道名
SQL> exec dbms_output.put_line(dbms_pipe.unique_session_name)
ORA$PIPE$06573F5C0001

PL/SQL procedure successfully completed.

会话C发送信息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B发送信息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话A接收信息, 收到C发送的信息(先发的信息)
SQL> exec read_pipe
error: 3
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

会话A再次接收信息, 收到了B发送的信息(后发的信息)
SQL> exec read_pipe
Pipe :ORA$PIPE$06573F5C0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.


Case 8
------
Sessions: A,B,C & D
Explanation: On Step 4, B receives D' message. On step 5, A receives C's message.
A new pipe is created.

1) C,D: exec dbms_output.put_line(dbms_pipe.unique_session_name)
2) D: exec send_pipe
3) C: exec send_pipe
4) B: exec read_pipe
5) A: exec read_pipe

会话C显示自己的管道名
SQL> exec dbms_output.put_line(dbms_pipe.unique_session_name)
ORA$PIPE$066337EB0001

PL/SQL procedure successfully completed.

会话D显示自己的管道名
SQL> exec dbms_output.put_line(dbms_pipe.unique_session_name)
ORA$PIPE$06612A790001

PL/SQL procedure successfully completed.

会话D发送信息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话C发送信息
SQL> exec send_pipe

PL/SQL procedure successfully completed.

会话B接收信息, 收到会话D发送的信息
SQL> exec read_pipe
Pipe :ORA$PIPE$06612A790001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.

会话A接收信息, 收到会话C发送的信息
SQL> exec read_pipe
Pipe :ORA$PIPE$066337EB0001
type =>9
A
type =>6
48
type =>12
2008-07-11 09:43:05

PL/SQL procedure successfully completed.


Case 9
------
Session: Any
Explanation: Cleaning up.

1) exec remove_all_pipes
2) select * from v$db_pipes;

查看管道,删除管道
SQL> select * from v$db_pipes;

   OWNERID NAME                           TYPE     PIPE_SIZE
---------- ------------------------------ ------- ----------
           ORA$PIPE$0659B71A0001          PUBLIC        1686
           WAITER                         PUBLIC        1671
           ORA$PIPE$06573F5C0001          PUBLIC        1686
           ORA$PIPE$06612A790001          PUBLIC        1686
           ORA$PIPE$066337EB0001          PUBLIC        1686

SQL> exec remove_all_pipes
Pipe ORA$PIPE$0659B71A0001 removed.
Pipe WAITER removed.
Pipe ORA$PIPE$06573F5C0001 removed.
Pipe ORA$PIPE$06612A790001 removed.
Pipe ORA$PIPE$066337EB0001 removed.

PL/SQL procedure successfully completed.

SQL> select * from v$db_pipes;

no rows selected



4.
源码:
package dbms_pipe is

-- DE-HEAD     <- tell SED where to cut when generating fixed package

  ------------
  --  OVERVIEW
  --
  --  This package provides a DBMS "pipe" service which allows messages
  --  to be sent between sessions.
  --
  --  The metaphor is similar to UNIX pipes:  you can do
  --    dbms_pipe.send_message(<pipename>)
  --    dbms_pipe.receive_message(<pipename>)
  --  which will cause a message to be sent or received.  You do
  --    dbms_pipe.pack_message(<varchar2>|<number>|<date>)
  --  to pack an item into a static buffer (which will then be sent with
  --  the "send_message" call), and
  --    dbms_pipe.unpack_message(<varchar2>|<number>|<date>)
  --  to get an item out of the static buffer (which is filled by the
  --  "receive_message" call).
  --  Pipes can be private to a user-id - which only allows session connected
  --  under the same user-id or stored procedure owned by the user-id to read
  --  write to the pipe.  Pipes could be public - and all database users with
  --  execute privilege on dbms_pipe and knowledge of the pipe can read or
  --  write to the pipe.
  --
  --  Pipes operate independently of transactions.  They also operate
  --  asynchronously.  There can be multiple readers and writers of the
  --  same pipe.
  --
  --  Pipes only operate between sessions in the same instance.
  --
  --  Pipes can be explicitly created using
  --    dbms_pipe.create_pipe(<pipename>)
  --  and removed using
  --    dbms_pipe.remove_pipe(<pipename>)
  --  A pipe created using the explicit create command should be removed
  --  using the remove function.  A pipe can also be created implicitly.
  --  Pipes automatically come into existence the first time they are
  --  referenced.  They effectively disappear when they contain no more
  --  data (some overhead remains in the SGA until it gets aged out).
  --  Pipes take up space in the SGA (see "maxpipesize" parameter to
  --  "send_message").


  --------
  --  USES
  --
  --  The pipe functionality has several potential applications:
  --
  --    o External service interface.  You can provide the ability to
  --      communicate with (user-written) services that are external to the
  --      RDBMS.  This can be done in a (effectively) multi-threaded manner
  --      so that several instances of the service can be executing
  --      simultaneously. Additionally, the services are available
  --      asynchronously - the requestor of the service need not block
  --      awaiting a reply.  The requestor can check (with or without
  --      timeout) at a later time.  The service can be written in any
  --      of the 3GL languages that ORACLE supports, not just C.  See
  --      example below.
  --    o Independent transactions.  The pipe can be used to communicate
  --      to a separate session which can perform an operation in an
  --      independent transaction (such as logging an attempted security
  --      violation detected by a trigger).
  --    o Alerters (non-transactional).  You can post another process
  --      without requiring the waiting process to poll.  If an "after-row"
  --      or "after-statement" trigger were to alert an application, then
  --      the application would treat this alert as an indication that
  --      the data probably changed.  The application would then go read
  --      the data to get the current value.  Since this is an "after"
  --      trigger, the application would want to do a "select for update"
  --      to make sure it read the correct data.
  --    o Debugging.  Triggers and/or stored procedures can send debugging
  --      information to a pipe.  Another session can keep reading out
  --      of the pipe and displaying it on the screen or writing it
  --      out to a file.
  --    o Concentrator. Useful for multiplexing large numbers of users
  --      over a fewer number of network connections, or improving
  --      performance by concentrating several user-transactions into
  --      one dbms-transaction.


  ------------
  --  SECURITY
  --
  --  Security can be achieved by use of 'grant execute' on the dbms_pipe
  --  package, by creating a pipe using the 'private' parameter in the create
  --  function and by writing cover packages that only expose particular
  --  features or pipenames to particular users or roles.


  ------------
  --  EXAMPLES
  --
  --  External service interface
  ------------------------------
  --
  --  Put the user-written 3GL code into an OCI or Precompiler program.
  --  The program connects to the database and executes PL/SQL code to read
  --  its request from the pipe, computes the result, and then executes
  --  PL/SQL code to send the result on a pipe back to the requestor.
  --  Below is an example of a stock service request.
  --
  --  The recommended sequence for the arguments to pass on the pipe
  --  for all service requests is
  --
  --      protocol_version      varchar2        - '1', 10 bytes or less
  --      returnpipe            varchar2        - 30 bytes or less
  --      service               varchar2        - 30 bytes or less
  --      arg1                  varchar2/number/date
  --         ...
  --      argn                  varchar2/number/date
  --
  --  The recommended format for returning the result is
  --
  --      success               varchar2        - 'SUCCESS' if OK,
  --                                              otherwise error message
  --      arg1                  varchar2/number/date
  --         ...
  --      argn                  varchar2/number/date
  --
  --
  --  The "stock price request server" would do, using OCI or PRO* (in
  --  pseudo-code):
  --
  --    <loop forever>
  --      begin dbms_stock_server.get_request(:stocksymbol); end;
  --      <figure out price based on stocksymbol (probably from some radio
  --            signal), set error if can't find such a stock>
  --      begin dbms_stock_server.return_price(:error, :price); end;
  --
  --  A client would do:
  --
  --    begin :price := stock_request('YOURCOMPANY'); end;
  --
  --  The stored procedure, dbms_stock_server, which is called by the
  --  "stock price request server" above is:
  --
  --    create or replace package dbms_stock_server is
  --      procedure get_request(symbol out varchar2);
  --      procedure return_price(errormsg in varchar2, price in varchar2);
  --    end;
  --
  --    create  or replace package body dbms_stock_server is
  --      returnpipe    varchar2(30);
  --
  --      procedure returnerror(reason varchar2) is
  --        s integer;
  --      begin
  --        dbms_pipe.pack_message(reason);
  --        s := dbms_pipe.send_message(returnpipe);
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:' || to_char(s) ||
  --            ' sending on pipe');
  --        end if;
  --      end;
  --
  --      procedure get_request(symbol out varchar2) is
  --        protocol_version varchar2(10);
  --        s                  integer;
  --        service            varchar2(30);
  --      begin
  --        s := dbms_pipe.receive_message('stock_service');
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:' || to_char(s) ||
  --            'reading pipe');
  --        end if;
  --        dbms_pipe.unpack_message(protocol_version);
  --        if protocol_version <> '1' then
  --          raise_application_error(-20000, 'Bad protocol: ' ||
  --            protocol_version);
  --        end if;
  --        dbms_pipe.unpack_message(returnpipe);
  --        dbms_pipe.unpack_message(service);
  --        if service != 'getprice' then
  --          returnerror('Service ' || service || ' not supported');
  --        end if;
  --        dbms_pipe.unpack_message(symbol);
  --      end;
  --
  --      procedure return_price(errormsg in varchar2, price in varchar2) is
  --        s integer;
  --      begin
  --        if errormsg is null then
  --          dbms_pipe.pack_message('SUCCESS');
  --          dbms_pipe.pack_message(price);
  --        else
  --          dbms_pipe.pack_message(errormsg);
  --        end if;
  --        s := dbms_pipe.send_message(returnpipe);
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:'||to_char(s)||
  --            ' sending on pipe');
  --        end if;
  --      end;
  --    end;
  --
  --
  --  The procedure called by the client is:
  --
  --    create or replace function stock_request (symbol varchar2)
  --        return varchar2 is
  --      s        integer;
  --      price    varchar2(20);
  --      errormsg varchar2(512);
  --    begin
  --      dbms_pipe.pack_message('1');  -- protocol version
  --      dbms_pipe.pack_message(dbms_pipe.unique_session_name); -- return pipe
  --      dbms_pipe.pack_message('getprice');
  --      dbms_pipe.pack_message(symbol);
  --      s := dbms_pipe.send_message('stock_service');
  --      if s <> 0 then
  --        raise_application_error(-20000, 'Error:'||to_char(s)||
  --          ' sending on pipe');
  --      end if;
  --      s := dbms_pipe.receive_message(dbms_pipe.unique_session_name);
  --      if s <> 0 then
  --        raise_application_error(-20000, 'Error:'||to_char(s)||
  --          ' receiving on pipe');
  --      end if;
  --      dbms_pipe.unpack_message(errormsg);
  --      if errormsg <> 'SUCCESS' then
  --        raise_application_error(-20000, errormsg);
  --      end if;
  --      dbms_pipe.unpack_message(price);
  --      return price;
  --    end;
  --
  --  You would typically only grant execute on 'dbms_stock_service' to
  --  the stock service application server, and would only grant execute
  --  on 'stock_request' to those users allowed to use the service.


  ---------------------
  --  SPECIAL CONSTANTS
  --
  maxwait   constant integer := 86400000; /* 1000 days */
  --  The maximum time to wait attempting to send or receive a message


  ----------------------------
  --  PROCEDURES AND FUNCTIONS
  --
  procedure pack_message(item in varchar2 character set any_cs);
  pragma restrict_references(pack_message,WNDS,RNDS);
  procedure pack_message(item in number);
  pragma restrict_references(pack_message,WNDS,RNDS);
  procedure pack_message(item in date);
  pragma restrict_references(pack_message,WNDS,RNDS);
  procedure pack_message_raw(item in raw);
  pragma restrict_references(pack_message_raw,WNDS,RNDS);
  procedure pack_message_rowid(item in rowid);
  pragma restrict_references(pack_message_rowid,WNDS,RNDS);
  --  Pack an item into the message buffer
  --  Input parameters:
  --    item
  --      Item to pack into the local message buffer.
  --  Exceptions:
  --    ORA-06558 generated if message buffer overflows (currently 4096
  --    bytes).  Each item in the buffer takes one byte for the type,
  --    two bytes for the length, plus the actual data.  There is also one
  --    byte needed to terminate the message.
  --
  procedure unpack_message(item out varchar2 character set any_cs);
  pragma restrict_references(unpack_message,WNDS,RNDS);
  procedure unpack_message(item out number);
  pragma restrict_references(unpack_message,WNDS,RNDS);
  procedure unpack_message(item out date);
  pragma restrict_references(unpack_message,WNDS,RNDS);
  procedure unpack_message_raw(item out raw);
  pragma restrict_references(unpack_message_raw,WNDS,RNDS);
  procedure unpack_message_rowid(item out rowid);
  pragma restrict_references(unpack_message_rowid,WNDS,RNDS);
  --  Unpack an item from the local message buffer
  --  Output parameters:
  --    item
  --      The argument to receive the next unpacked item from the local
  --      message buffer.
  --  Exceptions:
  --    ORA-06556 or 06559 are generated if the buffer contains
  --    no more items, or if the item is not of the same type as that
  --    requested (see 'next_item_type' below).
  --
  function next_item_type return integer;
  pragma restrict_references(next_item_type,WNDS,RNDS);
  --  Get the type of the next item in the local message buffer
  --  Return value:
  --    Type of next item in buffer:
  --        0    no more items
  --        9    varchar2
  --        6    number
  --       11    rowid
  --       12    date
  --       23    raw
  --
  function create_pipe(pipename in varchar2,
                  maxpipesize in integer default 8192,
                  private in boolean default TRUE)
    return integer;
  pragma restrict_references(create_pipe,WNDS,RNDS);
  --  Create an empty pipe with the given name.
  --  Input parameters:
  --    pipename
  --      Name of pipe to be created.  WARNING: Do not use pipe names
  --      beginning with 'ORA$'.  These are reserved for use by procedures
  --      provided by Oracle Corporation.  Pipename should not be longer than
  --      128 bytes, and is case_insensitive.  At this time, the name cannot
  --      contain NLS characters.
  --    maxpipesize
  --      Maximum allowed size for the pipe.  The total size of all the
  --      messages on the pipe cannot exceed this amount.  The maxpipesize
  --      for a pipe becomes part of the pipe and persists for the lifetime
  --      of the pipe.  Callers of send_message with larger values will
  --      cause the maxpipesize to be increased.  Callers with a smaller
  --      value will just use the larger value.  The specification of
  --      maxpipesize here allows us to avoid its use in future send_message
  --      calls.
  --    private
  --      Boolean indicating whether the pipe will be private - and for the
  --      use of the creating user-id, or public.  A private pipe can be used
  --      directly through calls to this package by sessions connected to the
  --      database as the same user as the one that created the pipe.  It can
  --      also be used via stored procedures owned by the user that created
  --      the pipe.  The procedure may be executed by anyone with execute
  --      privilege on it.  A public pipe can be accessed by anyone who has
  --      knowledge of it and execute privilege on dbms_pipe.
  --  Return values:
  --    0 - Success.  This is returned even if the pipe had been created in
  --        mode that permits its use by the user executing the create call.
  --        If a pipe already existed, it is not emptied.
  --  Exceptions:
  --    Null pipe name.
  --    Permission error.  Pipe with the same name already exists and
  --      you are not allowed to use it.
  --
  function remove_pipe(pipename in varchar2)
    return integer;
  pragma restrict_references(remove_pipe,WNDS,RNDS);
  --  Remove the named pipe.
  --  Input Parameters:
  --    pipename
  --      Name of pipe to remove.
  --  Return value:
  --    0 - Success. Calling remove on a pipe that does not exist returns 0.
  --  Exceptions:
  --    Null pipe name.
  --    Permission error.  Insufficient privilege to remove pipe.  The
  --      pipe was created and is owned by someone else.
  --
  function send_message(pipename in varchar2,
                        timeout in integer default maxwait,
                        maxpipesize in integer default 8192)
    return integer;
  pragma restrict_references(send_message,WNDS,RNDS);
  --  Send a message on the named pipe.  The message is contained in the
  --    local message buffer which was filled with calls to 'pack_message'.
  --    A pipe could have been created explicitly using 'create_pipe', or
  --    it will be created implicitly.
  --  Input parameters:
  --    pipename
  --      Name of pipe to place the message on.  The message is copied
  --      from the local buffer which can be filled by the "pack_message"
  --      routine.  WARNING:  Do not use pipe names beginning with 'ORA$'.
  --      These names are reserved for use by procedures provided by
  --      Oracle Corporation.  Pipename should not be longer than 128 bytes,
  --      and is case_insensitive.  At this time, the name cannot
  --      contain NLS characters.
  --    timeout
  --      Time to wait while attempting to place a message on a pipe, in
  --      seconds (see return codes below).
  --    maxpipesize
  --      Maximum allowed size for the pipe.  The total size of all the
  --      messages on the pipe cannot exceed this amount.  If this message
  --      would exceed this amount the call will block.  The maxpipesize
  --      for a pipe becomes part of the pipe and persists for the lifetime
  --      of the pipe.  Callers of send_message with larger values will
  --      cause the maxpipesize to be increased.  Callers with a smaller
  --      value will just use the larger value.  The specification of
  --      maxpipesize here allows us to avoid the use of a "open_pipe" call.
  --  Return value:
  --    0 - Success
  --    1 - Timed out (either because can't get lock on pipe or pipe stays
  --        too full)
  --    3 - Interrupted
  --  Exceptions:
  --    Null pipe name.
  --    Permission error.  Insufficient privilege to write to the pipe.
  --      The pipe is private and owned by someone else.
  function receive_message(pipename in varchar2,
                           timeout in integer default maxwait)
    return integer;
  pragma restrict_references(receive_message,WNDS,RNDS);
  --  Receive a message from the named pipe.  Copy the message into the
  --    local message buffer.  Use 'unpack_message' to access the
  --    individual items in the message.  The pipe can be created explicitly
  --    using the 'create_pipe' function or it will be created implicitly.
  --  Input parameters:
  --    pipename
  --      Name of pipe from which to retrieve a message.  The message is
  --      copied into a local buffer which can be accessed by the
  --      "unpack_message" routine.  WARNING:  Do not use pipe names
  --      beginning with 'ORA$'.  These names are reserved for use by
  --      procedures provided by Oracle Corporation. Pipename should not be
  --      longer than 128 bytes, and is case-insensitive.  At this time,
  --      the name cannot contain NLS characters.
  --    timeout
  --      Time to wait for a message.  A timeout of 0 allows you to read
  --      without blocking.
  --  Return value:
  --    0 - Success
  --    1 - Timed out
  --    2 - Record in pipe too big for buffer (should not happen).
  --    3 - Interrupted
  --  Exceptions:
  --    Null pipe name.
  --    Permission error.  Insufficient privilege to remove the record
  --      from the pipe.  The pipe is owned by someone else.
  procedure reset_buffer;
  pragma restrict_references(reset_buffer,WNDS,RNDS);
  --  Reset pack and unpack positioning indicators to 0.  Generally this
  --    routine is not needed.
  --
  procedure purge(pipename in varchar2);
  pragma restrict_references(purge,WNDS,RNDS);
  --  Empty out the named pipe.  An empty pipe is a candidate for LRU
  --    removal from the SGA, therefore 'purge' can be used to free all
  --    memory associated with a pipe.
  --  Input Parameters:
  --    pipename
  --      Name of pipe from which to remove all messages.  The local
  --      buffer may be overwritten with messages as they are discarded.
  --      Pipename should not be longer than 128 bytes, and is
  --      case-insensitive.
  --  Exceptions:
  --    Permission error if pipe belongs to another user.
  --
  function unique_session_name return varchar2;
  pragma restrict_references(unique_session_name,WNDS,RNDS,WNPS);
  --  Get a name that is unique among all sessions currently connected
  --    to this database.  Multiple calls to this routine from the same
  --    session will always return the same value.
  --  Return value:
  --    A unique name.  The returned name can be up to 30 bytes.
  --

  pragma TIMESTAMP('2000-06-09:14:30:00');

end;

-- CUT_HERE    <- tell sed where to chop off the rest


可以看到,调用的其实都是C的接口
PACKAGE BODY dbms_pipe IS
  PACKBUF   CHAR(4096) := 'a';
  UNPACKBUF CHAR(4096) := 'a';
  PACKPOS   BINARY_INTEGER := 0;
  UNPACKPOS BINARY_INTEGER := 2000000000;


PROCEDURE SENDPIPE(PIPENAME IN VARCHAR2, POS IN BINARY_INTEGER,
  BUFFER IN OUT NOCOPY CHAR, MAXPIPESIZE IN BINARY_INTEGER,
  TIMEOUT IN BINARY_INTEGER, RETVAL OUT BINARY_INTEGER);
PRAGMA INTERFACE (C, SENDPIPE);


PROCEDURE RECEIVEPIPE(PIPENAME IN VARCHAR2, BUFFER IN OUT NOCOPY CHAR,
  TIMEOUT IN BINARY_INTEGER, RETVAL OUT BINARY_INTEGER);
PRAGMA INTERFACE (C, RECEIVEPIPE);


PROCEDURE COPYINTOBUF(A IN VARCHAR2 CHARACTER SET ANY_CS,
  POS IN OUT NOCOPY BINARY_INTEGER, BUF IN OUT NOCOPY CHAR);
PRAGMA INTERFACE (C, COPYINTOBUF);


PROCEDURE COPYINTOBUF(A IN NUMBER, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN OUT NOCOPY CHAR);
PRAGMA INTERFACE (C, COPYINTOBUF);


PROCEDURE COPYINTOBUF(A IN DATE, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN OUT NOCOPY CHAR);
PRAGMA INTERFACE (C, COPYINTOBUF);


PROCEDURE COPYFROMBUF(A OUT VARCHAR2 CHARACTER SET ANY_CS,
  POS IN OUT NOCOPY BINARY_INTEGER, BUF IN CHAR);
PRAGMA INTERFACE (C, COPYFROMBUF);


PROCEDURE COPYFROMBUF(A OUT NUMBER, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN CHAR);
PRAGMA INTERFACE (C, COPYFROMBUF);


PROCEDURE COPYFROMBUF(A OUT DATE, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN CHAR);
PRAGMA INTERFACE (C, COPYFROMBUF);


FUNCTION GETTYPEFROMBUF(POS IN BINARY_INTEGER, BUF IN CHAR)
  RETURN BINARY_INTEGER;
PRAGMA INTERFACE (C, GETTYPEFROMBUF);


PROCEDURE COPYINTOBUFBINARY(A IN RAW, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN OUT NOCOPY CHAR);
PRAGMA INTERFACE (C, COPYINTOBUFBINARY);


PROCEDURE COPYINTOBUFROWID(A IN ROWID, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN OUT NOCOPY CHAR);
PRAGMA INTERFACE (C, COPYINTOBUFROWID);


PROCEDURE COPYFROMBUFBINARY(A OUT RAW , POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN CHAR);
PRAGMA INTERFACE (C, COPYFROMBUFBINARY);


PROCEDURE COPYFROMBUFROWID(A OUT ROWID, POS IN OUT NOCOPY BINARY_INTEGER,
  BUF IN CHAR);
PRAGMA INTERFACE (C, COPYFROMBUFROWID);


PROCEDURE CREATEPIPE(PIPENAME IN VARCHAR2, MAXPIPESIZE IN BINARY_INTEGER,
  PRIVATE IN BOOLEAN, RETVAL OUT BINARY_INTEGER);
PRAGMA INTERFACE (C, CREATEPIPE);


PROCEDURE REMOVEPIPE(PIPENAME IN VARCHAR2, RETVAL OUT BINARY_INTEGER);
PRAGMA INTERFACE (C, REMOVEPIPE);


FUNCTION UNIQUE_SESSION_ID RETURN VARCHAR2;
PRAGMA INTERFACE (C, UNIQUE_SESSION_ID);


PROCEDURE PACK_MESSAGE(ITEM IN VARCHAR2 CHARACTER SET ANY_CS) IS
BEGIN COPYINTOBUF(ITEM, PACKPOS, PACKBUF); END;


PROCEDURE PACK_MESSAGE_RAW(ITEM IN RAW) IS
BEGIN COPYINTOBUFBINARY(ITEM, PACKPOS, PACKBUF); END;


PROCEDURE PACK_MESSAGE_ROWID(ITEM IN ROWID) IS
BEGIN COPYINTOBUFROWID(ITEM, PACKPOS, PACKBUF); END;


PROCEDURE PACK_MESSAGE(ITEM IN NUMBER) IS
BEGIN COPYINTOBUF(ITEM, PACKPOS, PACKBUF); END;


PROCEDURE PACK_MESSAGE(ITEM IN DATE) IS
BEGIN COPYINTOBUF(ITEM, PACKPOS, PACKBUF); END;


PROCEDURE UNPACK_MESSAGE(ITEM OUT VARCHAR2 CHARACTER SET ANY_CS) IS
BEGIN COPYFROMBUF(ITEM, UNPACKPOS, UNPACKBUF); END;


PROCEDURE UNPACK_MESSAGE_RAW(ITEM OUT RAW) IS
BEGIN COPYFROMBUFBINARY(ITEM, UNPACKPOS, UNPACKBUF); END;


PROCEDURE UNPACK_MESSAGE_ROWID(ITEM OUT ROWID) IS
BEGIN COPYFROMBUFROWID(ITEM, UNPACKPOS, UNPACKBUF); END;


PROCEDURE UNPACK_MESSAGE(ITEM OUT NUMBER) IS
BEGIN COPYFROMBUF(ITEM, UNPACKPOS, UNPACKBUF); END;


PROCEDURE UNPACK_MESSAGE(ITEM OUT DATE) IS
BEGIN COPYFROMBUF(ITEM, UNPACKPOS, UNPACKBUF); END;


FUNCTION NEXT_ITEM_TYPE RETURN INTEGER IS
  INTERNAL_TYPE BINARY_INTEGER;
BEGIN
  INTERNAL_TYPE :=  GETTYPEFROMBUF(UNPACKPOS, UNPACKBUF);
  IF INTERNAL_TYPE = 1 THEN
    RETURN 9;
  ELSIF INTERNAL_TYPE = 2 THEN
    RETURN 6;
  ELSE
    RETURN INTERNAL_TYPE;
  END IF;
END;


FUNCTION CREATE_PIPE(PIPENAME IN VARCHAR2,
  MAXPIPESIZE IN INTEGER DEFAULT 8192,
  PRIVATE IN BOOLEAN DEFAULT TRUE)
RETURN INTEGER IS
  RETVAL BINARY_INTEGER;
  MPS    BINARY_INTEGER := MAXPIPESIZE;
  PVT    BOOLEAN := PRIVATE;
BEGIN
  IF PIPENAME IS NULL THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23321, 'Pipename may not be null');
  END IF;
  CREATEPIPE(PIPENAME, MPS, PVT, RETVAL);
  IF RETVAL = 4 THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23322,
      'Insufficient privilege to access pipe');
  END IF;
  RETURN RETVAL;
END;


FUNCTION REMOVE_PIPE(PIPENAME IN VARCHAR2)
RETURN INTEGER IS
  RETVAL BINARY_INTEGER;
BEGIN
  IF PIPENAME IS NULL THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23321, 'Pipename may not be null');
  END IF;
  REMOVEPIPE(PIPENAME, RETVAL);
  IF RETVAL = 4 THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23322,
      'Insufficient privilege to access pipe');
  END IF;
  RETURN RETVAL;
END;


FUNCTION SEND_MESSAGE(PIPENAME IN VARCHAR2,
  TIMEOUT IN INTEGER DEFAULT MAXWAIT,
  MAXPIPESIZE IN INTEGER DEFAULT 8192)
RETURN INTEGER IS
  RETVAL BINARY_INTEGER;
  MPS    BINARY_INTEGER := MAXPIPESIZE;
  TMO    BINARY_INTEGER := TIMEOUT;
BEGIN
  IF PIPENAME IS NULL THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23321, 'Pipename may not be null');
  END IF;
  SENDPIPE(PIPENAME, PACKPOS, PACKBUF, MPS, TMO, RETVAL);
  IF RETVAL = 0 THEN
    PACKPOS := 0;
  END IF;
  IF RETVAL = 4 THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23322,
      'Insufficient privilege to access pipe');
  END IF;
RETURN RETVAL;
END;


FUNCTION RECEIVE_MESSAGE(PIPENAME IN VARCHAR2,
  TIMEOUT IN INTEGER DEFAULT MAXWAIT)
RETURN INTEGER IS
  RETVAL BINARY_INTEGER;
  TMO    BINARY_INTEGER := TIMEOUT;
BEGIN
  IF PIPENAME IS NULL THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23321, 'Pipename may not be null');
  END IF;
  RECEIVEPIPE(PIPENAME, UNPACKBUF, TMO, RETVAL);
  IF RETVAL = 0 THEN
    UNPACKPOS := 0;
  ELSE
    UNPACKPOS := 2000000000;
  END IF;
  IF RETVAL = 4 THEN
    DBMS_SYS_ERROR.RAISE_SYSTEM_ERROR(-23322,
      'Insufficient privilege to access pipe');
  END IF;
RETURN RETVAL;
END;


PROCEDURE RESET_BUFFER IS
BEGIN
  UNPACKPOS := 0;
  PACKPOS := 0;
END;


PROCEDURE PURGE(PIPENAME IN VARCHAR2) IS
  RETVAL BINARY_INTEGER;
BEGIN
  LOOP
    RETVAL := RECEIVE_MESSAGE(PIPENAME, 0);
    IF RETVAL <> 0 THEN
      EXIT;
    END IF;
  END LOOP;
END;


FUNCTION UNIQUE_SESSION_NAME RETURN VARCHAR2 IS
BEGIN
  RETURN ('ORA$PIPE$' || UNIQUE_SESSION_ID);
END;


END;



外部链接:




PACKAGE DBMS_PIPE Specification

When Do DBMS_PIPE Connections Get Closed
管道处于非活动状态或没有消息达到一段时间, 会被从共享池中自动清除, 这时再操作管道就会报错, 通常是ORA-20011
即使是显式创建的管道, 也可能会被自动清除
唯一解决办法是删除并重建

Dynamic SQL and System Commands Using DBMS_PIPE
使用管道调用SQL语句或外部命令

COMMONLY ASKED QUESTIONS ABOUT DBMS_PIPE PACKAGE
使用DBMS_PIPE比用轮询更有效, 但需测试
管道中的数据不是持久性的, 随着数据库实例关闭而丢失

Example of DBMS_PIPE() with Pro*C on Unix
Pro*C程序使用DBMS_PIPE管道

PLSQL: Example use of DBMS_PIPE for Debugging
使用DBMS_PIPE管道取代DBMS_OUTPUT来调试程序

How To Use the PIPE Option with RMAN
使用管道向RMAN发送命令和接收返回信息

What is the difference between PIPE and QUEUE for profile Concurrent:TM Transport Type ?

DBMS_PIPE: Communicating Between Sessions





-fin-
Website Analytics

Followers