标签 Solaris 下的文章

分享一个Oracle OCI库的BUG

上周测试组反馈在一台HP X86-64主机Solaris 10 for X86环境下部署的应用无法连接Oracle数据库,错误码ORA-12154。而另外一个产品的部署在这台主机上的应用却能正常连接到数据库。本周安排专人对该问题进行查找,在先后排除了用户环境设置、Oracle数据库服务端等问题后,我们最终把目光集中在了Oracle客户端的OCI库上。

定位过程如下:
1、SQLPLUS可以访问数据库;
2、同环境下另一个应用可以访问数据库;
以上证明用户环境和tnsnames.ora配置没有问题;
3、通过抓包未发现客户端有到Oracle服务端的链接和数据传输,所以该问题应该与Oracle Server端一毛钱关系都没有;
4、发现我们产品的应用使用的是32bit库编译的,而另外一个产品的应用使用的是64bit库,但两个产品底层调用都是一样的;
5、基本锁定是该主机上装的Oracle OCI 32bit库有bug;
6、我们的资深系统工程师在Oracle官方找到了该问题的根源;
7、安装新patch后,应用顺利连接到Oracle Server,问题解决。

Oracle官方对该问题的说明摘录如下:
Solaris x86-64: Running 32-bit Applications Connecting to Database Using TNS Naming Adapter Fails With Segmentation Fault (SIGSEGV) or ORA-12154
  Doc ID:  388631.1 Type:  PROBLEM
  Modified Date :  23-OCT-2007 Status:  PUBLISHED

——————————————————————————–
Applies to:
Oracle Server – Enterprise Edition – Version: 10.2.0.2

Symptoms
Running 32-bit applications connecting to Database using TNS Naming Adapter Fails With Segmentation Violation (SIGSEGV)

Segmentation Fault(coredump)

Running 64-bit work as expected.

Other symptoms would be

ORA-12154: TNS:could not resolve the connect identifier specified

Cause
This has been identified to be caused by
Bug 5389730 10.2.0.1 32BIT OCI EXECUTABLES FAILS WITH ORA-12154 ON SOLARIS 10 X86-64(AMD64)

TNS Naming Adapter was not included within the 32-bit Naming Libraries.

Solution
This is fixed Oracle11g Client 11.0.

There exists patches for 10.2.0.2 and 10.2.0.3:

download and installPatch 5389730 with opatch or

To implement the solution manually, please execute the following steps:

Download Patch 5389730
cp $ORACLE_HOME/network/lib/ins_net_client.mk
$ORACLE_HOME/network/lib/ins_net_client.mk.prePatch_5389730
extract ins_net_client.mk into $ORACLE_HOME/network/lib/ins_net_client.mk
cd $ORACLE_HOME/network/lib
make -f ins_net_client.mk nnfgt.o
Which update (check this)
$ORACLE_HOME/lib/libn10.a and $ORACLE_HOME/lib32/libn10.a
make -f ins_net_client.mk client_sharedlib

which update (check this)
#$ORACLE_HOME/lib32/libclntsh.so
#$ORACLE_HOME/lib32/libclntsh.so.10.1
#$ORACLE_HOME/lib/libclntsh.so
#$ORACLE_HOME/lib/libclntsh.so.10.1

Check that executable is loading $ORACLE_HOME/lib32/libclntsh.so.10.1 by ldd ‘executable’

All dynamically linked applications that use libclntsh should work now.
Static linked applications, need to be relinked with the new libraries.

简说GLIBC strncpy实现

比较以下两组代码,你认为哪组运行的更快些呢?
Example1:
        int n   = 100;
        int n4  = n >> 2;
        int i   = 0;

        int a[100];

        for (i = 0; i < n4 ;i += 4) {
                a[i] = i;
                a[i+1] = i+1;
                a[i+2] = i+2;
                a[i+3] = i+3;
        }

Example2:
       for (i = 0;i < 100;i++) {
             a[i] = i;
       }

其实这个问题在"代码大全2nd"中也有讨论,从"代码大全"中的统计结果来看,一般来说Example1更占有优势。我在solaris上做了测试,在未开优化的情况下:两者运行时间分别为2ms和6ms;在打开-O2优化后,两者均为1ms。这种通过减少循环次数的方法在GLIBC中也有体现,比如说strncpy的实现:

下面是strncpy的GLIBC源码:
char *
x_strncpy (s1, s2, n)
        char *s1;
        const char *s2;
        size_t n;
{
        reg_char c;
        char *s = s1;

        –s1;

        if (n >= 4)
        {
                size_t n4 = n >> 2; /* n4 = n / 4, n4表示下面的循环执行的次数*/

                for (;;)
                {
                        c = *s2++;
                        *++s1 = c;
                        if (c == '')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '')
                                break;
                        if (–n4 == 0)
                                goto last_chars;  /* 如果n = 10,s2 = "hello world",则两轮循环后,还有"尾巴"没有copy完,在last_chars处继续处理 */
                }
                n = n – (s1 – s) – 1;  /* 还没有copy完n个字节,s2就到达末尾了,跳到zero_fill处继续为s1补零 */
                if (n == 0)
       return s;
                goto zero_fill;
        }

last_chars:     
        n &= 3;       /* n = n & 3 结果 n <= 3,n即为上面循环过后"尾巴字符"的数量 */
        if (n == 0)
                return s;
        do
        {
                c = *s2++;
                *++s1 = c;
                if (–n == 0)
                        return s;
        } while (c != '');

zero_fill:       
        do
                *++s1 = '';
        while (–n > 0);

        return s;
}

相比于strlen的实现,strncpy的实现更易理解。其字面上的逻辑就是每四个字节(n>>2)作为一组,每组逐个字节进行拷贝赋值,其内在目的则是减少循环次数,以获得性能的提升。要想知道为什么减少循环次数能提升性能的话,那就要深入到汇编层面去了,这里不再详述。另外还要一提的是GLIBC中的strncmp,strncat的实现也遵循着与上面同样的逻辑。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats