прямой доступ к SGA / способ 1: C extension + ruby
План такой:
Пишем простой C extension модуль, который умел бы подсоединиться к куску
shared memory, прочитать байт, два байта, четыре байта и строку указанной
длины.
Впрочем, писать по шагам не будем, а просто приведём готовый код:
/* readSGA.c */ /* http://www.oracledba.ru */ #include <sys/types.h> #include <sys/shm.h> #include <string.h> #include "ruby.h" VALUE readSGA_attach(VALUE self, VALUE shmemid, VALUE shmemaddr) { int shmid; long shmaddr; shmid = NUM2INT(shmemid); shmaddr = NUM2LONG(shmemaddr); if (shmat(shmid,(void *)shmaddr,SHM_RDONLY) != (void *)-1) { return INT2NUM(0); } else { return INT2NUM(-1); } } VALUE readSGA_read1(VALUE self, VALUE addr) { VALUE ret; void *caddr = (void *)NUM2INT(addr); char v1; v1 = *(char *)caddr; ret = INT2NUM((int)v1); return ret; } VALUE readSGA_read2(VALUE self, VALUE addr) { VALUE ret; void *caddr = (void *)NUM2INT(addr); short v1; v1 = *(short *)caddr; ret = INT2NUM(v1); return ret; } VALUE readSGA_read4(VALUE self, VALUE addr) { VALUE ret; void *caddr = (void *)NUM2INT(addr); int v1; v1 = *(int *)caddr; ret = INT2NUM(v1); return ret; } VALUE readSGA_reads(VALUE self, VALUE addr, VALUE size) { VALUE ret; void *caddr = (void *)NUM2INT(addr); char *dest; int csize = NUM2INT(size); dest = (char *)malloc((size_t)csize); memcpy(dest,(void *)caddr,csize); ret = rb_str_new2(dest); free(dest); return ret; } static VALUE mreadSGA; void Init_readSGA() { mreadSGA = rb_define_module("ReadSGA"); rb_define_module_function(mreadSGA,"attach",readSGA_attach,2); rb_define_module_function(mreadSGA,"read1",readSGA_read1,1); rb_define_module_function(mreadSGA,"read2",readSGA_read2,1); rb_define_module_function(mreadSGA,"read4",readSGA_read4,1); rb_define_module_function(mreadSGA,"reads",readSGA_reads,2); }
Далее, выполняем микро-скрипт
ruby -e 'require "mkmf"; create_makefile("readSGA")'
Для его успешного выполнения нужно, чтобы был установлен пакет типа 'ruby-dev'.
Далее, набираем 'make' после чего должен создаться файл readSGA.so.
Для тех, кто желает приобщиться к прекрасному без всех этих компиляций и установок пакетов мы выкладываем уже откомпилированную версию readSGA.so. Однако, т.к. эта версия собрана на Linux 2.4 с glibc2 и ruby 1.8.2, то и работать она будет только на чём-то таком похожем.
Теперь мы можем приступать к созданию простенького скрипта:
#!/usr/bin/env ruby # readSGA.rb # http://www.oracledba.ru require 'readSGA' shmid = 131074 sgaBase = 0x50000000 ksuseAddr = 0x5B2B1680 rowCount = 170 rowSize = 2408 def readstatus (statusid,ksuseflg) if (statusid & 11 == 1) status = 'ACTIVE' elsif (statusid & 11 == 0) if (ksuseflg & 4096 == 0) status = 'INACTIVE' else status = 'CACHED' end elsif (statusid & 11 == 2) status = 'SNIPED' elsif (statusid & 11 == 3) status = 'SNIPED' else status = 'KILLED' end return status end if ReadSGA.attach(shmid,sgaBase)==-1 print "can't attach to SGA with id #{shmid}\n" exit end puts "'select from v$session' made by reading SGA directly:" puts " SID SERIAL# USERNAME STATUS" puts "---------- ---------- ------------------------------ --------" memaddr = ksuseAddr (1..rowCount).each do |i| ksspaflg = ReadSGA.read1(memaddr+1) ksuseflg = ReadSGA.read4(memaddr+1388) sid = i serial = ReadSGA.read2(memaddr+1382) username = ReadSGA.reads(memaddr+67,30) statusid = ReadSGA.read1(memaddr+1420) status = readstatus(statusid,ksuseflg) if (ksspaflg & 1 != 0) and (ksuseflg & 1 != 0) printf "%10d %10d %-30s %-8s\n",sid,serial,username,status end memaddr += rowSize end
Если Вы подставите свои значения в начало скрипта, то у Вас получится работающий скрипт для "моментального" просмотра сессий без участия Oracle (но только до следующей перезагрузки Oracle'а :) )