如何加快ORACLE本地OCI的调用速度[3]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 coyichen 的 blog

6.1 interposition of the open() function call

whenever a file is opened, the control is transferred to the interposed open() from cache_oraus.so. the interposed open() checks to see if the file being opened is the oraus.msb (see step 3 in the following code example). if so, the file is opened, and memory mapped (step 5.1). the descriptor returned by open() is also cached. for all other opens, the control is transferred to the original libc.so (step 7).

int open(const char *path, int oflag, mode_t mode) {
 static int(*fptr)() = 0;
 static char* msb_path;
step 1 
if (fptr == 0) {   
         fptr = (int (*)())dlsym(rtld_next, "open");
  if (fptr == null) {
   fprintf(stderr, "dlopen: %s \n", dlerror());
   return 0;
  }
step 1.1
  msb_path = (char*)getenv("oraus_msb_file");
 }
step 2
 if  (!msb_path) {
  msb_path = "/oracle/app/oracle/product/8.1.7/rdbms/mesg/oraus.msb";
 }
step 3
 if (strcmp(path, msb_path) == 0) {
step 4 
 if (k_bm_fd == -1) {
   k_bm_fd = ((*fptr)(path, oflag, mode));
   if (k_bm_fd <= 0) {
    perror(path);
    exit(1);
   }
step 5 
   fstat(k_bm_fd, &k_bm_stat_buf);
step 5.1
   k_bm_buf = (char*)mmap((caddr_t) 0, 
    k_bm_stat_buf.st_size, (prot_read),
       map_shared, k_bm_fd, 0);
   assert(k_bm_buf != map_failed);
   return k_bm_fd;
  } else {
step 6
   return k_bm_fd;
  } 
 }
step 7
 return ((*fptr)(path, oflag, mode));
}
steps description
1 use dlysym() to get a pointer to the original libc.so open() call, so that we can chain to it.
1.1 we use an environment variable, oraus_msb_file, to find the location of the oraus.msb file.
2 if this variable is not set, we use a default path.
3 we make sure the open call is related to the oraus_msb_file. for all other open calls, we chain to the original open() call.
4 we make sure this is the first time we are going through this code path as we want to map the file into memory only once. we open the file and cache the returned descriptor in k_bm_fd.
5 we get some information about the file itself, such as size.
5.1 the most important step: we map the file into memory.
6 we have already opened the file, and we return the cache descriptor.
7 for all other opens, the interpose gives control back to the original libc.so open() call.

table 1: open() call

6.2 interposition of the fcntl() function call

a fcntl() call is made to change the file control parameters. the first time fcntl() is executed to change oraus.msb control parameters, the control is first transferred to the fcntl() in libc.so. the return value is cached, as well as returned back to the oracle client (step 2). the next time fcntl() is executed, if the file descriptor matches the oraus.msb file descriptor, the cached return value is returned (step 3). the control is not transferred to fcntl() in libc.so.

int fcntl(int fildes, int cmd, int arg) {
 static int  ret;
 static int(*fptr)() = 0;
 char* path;
step 1
 if (fptr == 0) {
         fptr = (int (*)())dlsym(rtld_next, "fcntl");
  if (fptr == null) {
   fprintf(stderr, "dlopen: %s \n", dlerror());
   return 0;
  }
 }
step 2
 if (k_fcntl_bm_fd == -1) {
  if (fildes == k_bm_fd) {
   ret = ((*fptr)(fildes, cmd, arg));
   k_fcntl_bm_fd = k_bm_fd;
   return ret;;
  }
step 3 
} else if (k_fcntl_bm_fd == fildes) {
  return ret;
 } 
step 4
 return ((*fptr)(fildes, cmd, arg));
}
steps description
1 use dlysym() to get a pointer to the original libc.so fcntl() call, so that we can chain to it.
2 we make sure this is the first time we are going through this code path as we want to execute fcntl() only once. we also make a copy of the open descriptor in k_fcntl_bm_fd.
3 if the fildes is equal to k_fcntl_bm_fd, then we just return the cached return value.
4 for all other opens, the interpose gives control back to the original libc.so fcntl() call.

table 2: fcntl() call

back to top

6.3 interposition of the lseek(), read(), and close() function calls

for the lseek() call, if the file descriptor matches the cached oraus.msb file descriptor, the file offset is stored instead of calling the lseek() in libc.so (step l2). on a read() call, if the file descriptor matches the cached oraus.msb file descriptor, the file offset stored from the lseek() is used to index into the memory mapped oraus.msb data. a memcpy() is then executed (step r2). so an i/o call is now transformed to a simple memcpy() call. a close() on the cached file descriptor is ignored so that the cached file descriptor can be reused.

off_t lseek(int fildes, off_t offset, int whence) {
 static off_t (*fptr)() = 0;
step l1
 if (fptr == 0) {
        fptr = (int (*)())dlsym(rtld_next, "lseek");
  if (fptr == null) {
   fprintf(stderr, "dlopen: %s \n", dlerror());
   return 0;
  }
 }
step l2
 if (fildes == k_bm_fd) {
  k_bm_offset = offset;
  return offset;
 }
step l3
 return ((*fptr)(fildes, offset, whence));
}
steps description
l1 use dlysym() to get a pointer to the original libc.so lseek() call, so that we can chain to it.
l2 if the fildes is equal to k_bm_fd, then we keep track of the k_bm_offset so that we access this memory location.
l3 for all other opens, the interpose gives control back to the original libc.so lseek() call.

table 3: lseek() call

ssize_t read(int fildes, void *buf, size_t nbyte) {
   static ssize_t  (*fptr)() = 0;
step r1
   if (fptr == 0) {
    fptr = (ssize_t (*)())dlsym(rtld_next, "read");
    if (fptr == null) {
      fprintf(stderr, "dlopen: %s\n", dlerror());
      return (0);
    }
 }
step r2
 if (fildes == k_bm_fd) {
  memcpy(buf, k_bm_buf+k_bm_offset, nbyte);
  return  nbyte;
 }
step r3
 return ((*fptr)(fildes, buf, nbyte));
}
steps description
r1 use dlysym() to get a pointer to the original libc.so read() call, so that we can chain to it.
r2 if the fildes is equal to k_bm_fd, then we use the stored k_bm_offset to access the right memory location, and do a memcpy().
r3 for all other opens, the interpose gives control back to the original libc.so read() call.

本文关键:如何加快ORACLE本地OCI的调用速度
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top