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




назад далее