1. introduction
if you work with oracle clients that make use of oci (oracle call interface), you may have noticed that the oci driver in 8.1.7.x makes thousands of calls to translate messages from the oraus.msb file. this can degrade application performance by 5 percent or more (quite severely in some cases). this problem has been documented by oracle under bug id 2142623.
the problem can be overcome by caching the oraus.msb file in memory, and translating the file access and system calls to user calls and memory operations. the caching solution is dynamic, and code changes are not needed. the solution can improve the performance of the oracle client application. recently, this solution resulted in bringing down the application runtime from 15 minutes to a few seconds at a major customer – about 100x times performance improvement.
the performance benefits can be seen in applications like sqlplus and oracle clients (c and c++) making use of the oci driver. java technology-based applications using jdbc (native driver) should also see similar benefits.
2. identifying the problem
an oracle client application can be trussed on the solaris operating system (os) to see the calls being made to this file -- "truss" is a system utility available on the solaris platform, and it can be used to trace system calls made by an application. a running oracle client application can be trussed as follows:
truss -p [oracle client pid]
the truss command will show all the system calls being made by the application. the ones of interest are the open(), fcntl(), lseek(), read(), and close() calls. these calls are made by the oci driver repeatedly to translate messages. here is a truss snippet showing the problem calls:
open("/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb", o_rdonly) = 9
fcntl(9, f_setfd, 0x00000001) = 0
lseek(9, 0, seek_set) = 0
read(9, "1513 "011303\t\t\0\0\0\0".., 256) = 256
lseek(9, 512, seek_set) = 512
read(9, "1c88 y r ~ m\0\0\0\0\0\0".., 512) = 512
lseek(9, 1024, seek_set) = 1024
read(9, "\018\0 $\0 7\0 @\0 j\0 v".., 512) = 512
lseek(9, 39936, seek_set) = 39936
read(9, "\0\t0519\0\0\0 >051a\0\0".., 512) = 512
close(9) = 0
these system calls can be expensive. the number of times these system calls are executed depends on the client application and the duration of the application run.
3. the workaround: cache oraus.msb in memory
the workaround is to cache the contents of the oraus.msb in memory and not make these system calls. this can be done dynamically by using the ld_preload technique available on the solaris oe. (for further information, see the references section.) ld_preload is an environment variable on solaris that allows shared libraries to be preloaded before an application begins execution. to make use of this technique, we need to build a shared library that will interpose on the open(), fcntl(), lseek(), read(), and close() calls.
4. building cache_oraus.so
the shared library can be built with the forte c compiler (now part of the sun one compiler collection) using the following switches:
32-bit:
cc -g -o cache_oraus.so -fast cache_oraus.c -l dl
64-bit:
cc -g -o cache_oraus.so -fast -xarch=v9a cache_oraus.c -l dl
5. how to use cache_oraus.so
the following environment variables need to be set to use the caching mechanism:
export ld_preload=./cache_oraus.so export oraus_msb_file=/ora/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb
this can be set in a shell script used to start the client application.
6. how the caching works
the caching works by interposing the open(), fcntl(), lseek(), read(), and close() calls. the first time the application executes one of these calls, the control is first transferred to the interposed function code.