прямой доступ к 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'а :) )
