прямой доступ к SGA / способ 2: C extension + python
План такой:
Пишем простой C extension модуль, который умел бы подсоединиться к куску
shared memory, прочитать байт, два байта, четыре байта и строку указанной
длины.
Впрочем, писать по шагам не будем, а просто приведём готовый код:
/* readSGA.c */ /* http://www.oracledba.ru */ #include "Python.h" #include <sys/types.h> #include <sys/shm.h> #include <string.h> static PyObject *readSGA_attach(PyObject *self, PyObject *arg) { int shmid; long shmaddr; PyArg_ParseTuple(arg,"il",&shmid,&shmaddr); if (shmat(shmid,(void *)shmaddr,SHM_RDONLY) != (void *)-1) { return Py_BuildValue("i",0); } else { return Py_BuildValue("i",-1); } } static PyObject *readSGA_read1(PyObject *self, PyObject *arg) { PyObject *ret; long caddr; char v1; PyArg_ParseTuple(arg,"l",&caddr); v1 = *(char *)caddr; ret = Py_BuildValue("i",v1); return ret; } static PyObject *readSGA_read2(PyObject *self, PyObject *arg) { PyObject *ret; long caddr; short v1; PyArg_ParseTuple(arg,"l",&caddr); v1 = *(short *)caddr; ret = Py_BuildValue("i",v1); return ret; } static PyObject *readSGA_read4(PyObject *self, PyObject *arg) { PyObject *ret; long caddr; int v1; PyArg_ParseTuple(arg,"l",&caddr); v1 = *(int *)caddr; ret = Py_BuildValue("i",v1); return ret; } static PyObject *readSGA_reads(PyObject *self, PyObject *arg) { PyObject *ret; char *dest; int csize; long caddr; PyArg_ParseTuple(arg,"li",&caddr, &csize); dest = (char *)malloc((size_t)csize); memcpy(dest,(void *)caddr,csize); ret = Py_BuildValue("s",dest); free(dest); return ret; } static struct PyMethodDef readSGA_methods[] = { {"attach",readSGA_attach,1}, {"read1",readSGA_read1,1}, {"read2",readSGA_read2,1}, {"read4",readSGA_read4,1}, {"reads",readSGA_reads,1}, {NULL,NULL} }; void initreadSGA() { (void)Py_InitModule("readSGA",readSGA_methods); }
Далее, создаём микро-скрипт setup.py со следующим содержимым:
from distutils.core import setup, Extension setup(name='readSGA', ext_modules=[ Extension('readSGA',sources=['readSGA.c']) ])
Для его успешного выполнения нужно, чтобы был установлен пакет типа 'python-dev'.
Далее, набираем что-то вроде 'python setup.py build' после чего (если всё пройдёт успешно) в недрах появившегося каталога build можно будет найти файл readSGA.so.
Для тех, кто желает приобщиться к прекрасному без всех этих компиляций и установок пакетов мы выкладываем уже откомпилированную версию readSGA.so. Однако, т.к. эта версия собрана на Linux 2.4 с glibc2 и python 2.3.4, то и работать она будет только на чём-то таком похожем.
Теперь мы можем приступать к созданию простенького скрипта:
#!/usr/bin/env python # http://www.oracledba.ru import sys import readSGA shmid = 131074 sgaBase = 0x50000000 ksuseAddr = 0x5B2B1680 rowCount = 170 rowSize = 2408 def readstatus (statusid,ksuseflg): if (statusid & 11 == 1): status = 'ACTIVE' elif (statusid & 11 == 0): if (ksuseflg & 4096 == 0): status = 'INACTIVE' else: status = 'CACHED' elif (statusid & 11 == 2): status = 'SNIPED' elif (statusid & 11 == 3): status = 'SNIPED' else: status = 'KILLED' return status rc = readSGA.attach(shmid,sgaBase) if (rc == -1): sys.exit("can't attach to SGA with id %d" % shmid) print "'select from v$session' made by reading SGA directly:" print " SID SERIAL# USERNAME STATUS" print "---------- ---------- ------------------------------ --------" memaddr = ksuseAddr for i in range(1,rowCount): 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): print "%10d %10d %-30s %-8s" % (sid,serial,username,status) memaddr += rowSize
Если Вы подставите свои значения в начало скрипта, то у Вас получится работающий скрипт для "моментального" просмотра сессий без участия Oracle (но только до следующей перезагрузки Oracle'а :) )