def parse_hdr(line): "Parse line from header" for key, valtype, name in items_hdr: if line.startswith(key): # Check for GSTAT_VERSION if db.gstat_version is None: if key == 'Checksum': db.gstat_version = GSTAT_25 db.tables = ObjectList(_cls=StatTable, key_expr='item.name') db.indices = ObjectList(_cls=StatIndex, key_expr='item.name') elif key == 'System Change Number': db.gstat_version = GSTAT_30 db.tables = ObjectList(_cls=StatTable3, key_expr='item.name') db.indices = ObjectList(_cls=StatIndex3, key_expr='item.name') # value = line[len(key):].strip() if valtype == 'i': # integer value = int(value) elif valtype == 's': # string pass elif valtype == 'd': # date time value = datetime.datetime.strptime(value, '%b %d, %Y %H:%M:%S') elif valtype == 'l': # list if value == '': value = [] else: value = [x.strip() for x in value.split(',')] value = tuple([ATTRIBUTES.index(x) for x in value]) else: raise ParseError("Unknown value type %s" % valtype) if name is None: name = key.lower().replace(' ', '_') setattr(db, name, value) return raise ParseError('Unknown information (line %i)' % line_no)
def _get_variables(self): if self.__variables is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_25: self._ic.execute("select * from mon$context_variables") self.__variables = ObjectList((ContextVariableInfo(self, row) for row in self._ic.itermap()), ContextVariableInfo, 'item.stat_id') else: self.__variables = ObjectList() self.__variables.freeze() return self.__variables
def _get_callstack(self): if self.__callstack is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$call_stack") self.__callstack = ObjectList((CallStackInfo(self, row) for row in self._ic.itermap()), CallStackInfo, 'item.id') else: self.__callstack = ObjectList() self.__callstack.freeze() return self.__callstack
def _get_statements(self): if self.__statements is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$statements") self.__statements = ObjectList((StatementInfo(self, row) for row in self._ic.itermap()), StatementInfo, 'item.id') else: self.__statements = ObjectList() self.__statements.freeze() return self.__statements
def _get_transactions(self): if self.__transactions is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$transactions") self.__transactions = ObjectList((TransactionInfo(self, row) for row in self._ic.itermap()), TransactionInfo, 'item.id') else: self.__transactions = ObjectList() self.__transactions.freeze() return self.__transactions
def _get_tablestats(self): if self.__tablestats is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_30: self._ic.execute("""SELECT ts.MON$STAT_ID, ts.MON$STAT_GROUP, ts.MON$TABLE_NAME, ts.MON$RECORD_STAT_ID, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, r.MON$RECORD_LOCKS, r.MON$RECORD_WAITS, r.MON$RECORD_CONFLICTS, r.MON$BACKVERSION_READS, r.MON$FRAGMENT_READS, r.MON$RECORD_RPT_READS FROM MON$TABLE_STATS ts join MON$RECORD_STATS r on ts.MON$RECORD_STAT_ID = r.MON$STAT_ID""") self.__tablestats = ObjectList((TableStatsInfo(self, row) for row in self._ic.itermap()), TableStatsInfo, 'item.stat_id') else: self.__tablestats = ObjectList() self.__tablestats.freeze() return self.__tablestats
def _get_iostats(self): if self.__iostats is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_30: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, r.MON$RECORD_LOCKS, r.MON$RECORD_WAITS, r.MON$RECORD_CONFLICTS, r.MON$BACKVERSION_READS, r.MON$FRAGMENT_READS, r.MON$RECORD_RPT_READS, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES, m.MON$MEMORY_ALLOCATED, m.MON$MEMORY_USED, m.MON$MAX_MEMORY_ALLOCATED, m.MON$MAX_MEMORY_USED FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP join MON$MEMORY_USAGE m on r.MON$STAT_ID = m.MON$STAT_ID and r.MON$STAT_GROUP = m.MON$STAT_GROUP""") elif self._con.ods >= fdb.ODS_FB_25: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES, m.MON$MEMORY_ALLOCATED, m.MON$MEMORY_USED, m.MON$MAX_MEMORY_ALLOCATED, m.MON$MAX_MEMORY_USED FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP join MON$MEMORY_USAGE m on r.MON$STAT_ID = m.MON$STAT_ID and r.MON$STAT_GROUP = m.MON$STAT_GROUP""") elif self._con.ods >= fdb.ODS_FB_21: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP""") if self._con.ods >= fdb.ODS_FB_21: self.__iostats = ObjectList((IOStatsInfo(self, row) for row in self._ic.itermap()), IOStatsInfo, 'item.stat_id') else: self.__iostats = ObjectList() self.__iostats.freeze() return self.__iostats
class Monitor(object): """Class for access to Firebird monitoring tables. """ def __init__(self): self._con = None self._ic = None self.__internal = False self.clear() def __del__(self): if not self.closed: self._close() def __get_closed(self): return self._con is None def __fail_if_closed(self): if self.closed: raise fdb.ProgrammingError("Monitor is not binded to connection.") def _close(self): self._ic.close() self._con = None self._ic = None def _set_as_internal(self): """Mark this instance as `internal` (embedded). This blocks calls to :meth:`bind` and :meth:`close`.""" self.__internal = True self._con = weakref.proxy(self._con) #--- protected def _get_database(self): if self.__database is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$database") self.__database = DatabaseInfo(self, self._ic.fetchonemap()) return self.__database def _get_attachments(self): if self.__attachments is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$attachments") self.__attachments = ObjectList((AttachmentInfo(self, row) for row in self._ic.itermap()), AttachmentInfo, 'item.id') else: self.__attachments = ObjectList() self.__attachments.freeze() return self.__attachments def _get_this_attachment(self): return self.get_attachment(self._con.db_info(fdb.isc_info_attachment_id)) def _get_transactions(self): if self.__transactions is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$transactions") self.__transactions = ObjectList((TransactionInfo(self, row) for row in self._ic.itermap()), TransactionInfo, 'item.id') else: self.__transactions = ObjectList() self.__transactions.freeze() return self.__transactions def _get_statements(self): if self.__statements is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$statements") self.__statements = ObjectList((StatementInfo(self, row) for row in self._ic.itermap()), StatementInfo, 'item.id') else: self.__statements = ObjectList() self.__statements.freeze() return self.__statements def _get_callstack(self): if self.__callstack is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_21: self._ic.execute("select * from mon$call_stack") self.__callstack = ObjectList((CallStackInfo(self, row) for row in self._ic.itermap()), CallStackInfo, 'item.id') else: self.__callstack = ObjectList() self.__callstack.freeze() return self.__callstack def _get_iostats(self): if self.__iostats is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_30: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, r.MON$RECORD_LOCKS, r.MON$RECORD_WAITS, r.MON$RECORD_CONFLICTS, r.MON$BACKVERSION_READS, r.MON$FRAGMENT_READS, r.MON$RECORD_RPT_READS, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES, m.MON$MEMORY_ALLOCATED, m.MON$MEMORY_USED, m.MON$MAX_MEMORY_ALLOCATED, m.MON$MAX_MEMORY_USED FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP join MON$MEMORY_USAGE m on r.MON$STAT_ID = m.MON$STAT_ID and r.MON$STAT_GROUP = m.MON$STAT_GROUP""") elif self._con.ods >= fdb.ODS_FB_25: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES, m.MON$MEMORY_ALLOCATED, m.MON$MEMORY_USED, m.MON$MAX_MEMORY_ALLOCATED, m.MON$MAX_MEMORY_USED FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP join MON$MEMORY_USAGE m on r.MON$STAT_ID = m.MON$STAT_ID and r.MON$STAT_GROUP = m.MON$STAT_GROUP""") elif self._con.ods >= fdb.ODS_FB_21: self._ic.execute("""SELECT r.MON$STAT_ID, r.MON$STAT_GROUP, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, io.MON$PAGE_FETCHES, io.MON$PAGE_MARKS, io.MON$PAGE_READS, io.MON$PAGE_WRITES FROM MON$RECORD_STATS r join MON$IO_STATS io on r.MON$STAT_ID = io.MON$STAT_ID and r.MON$STAT_GROUP = io.MON$STAT_GROUP""") if self._con.ods >= fdb.ODS_FB_21: self.__iostats = ObjectList((IOStatsInfo(self, row) for row in self._ic.itermap()), IOStatsInfo, 'item.stat_id') else: self.__iostats = ObjectList() self.__iostats.freeze() return self.__iostats def _get_variables(self): if self.__variables is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_25: self._ic.execute("select * from mon$context_variables") self.__variables = ObjectList((ContextVariableInfo(self, row) for row in self._ic.itermap()), ContextVariableInfo, 'item.stat_id') else: self.__variables = ObjectList() self.__variables.freeze() return self.__variables def _get_tablestats(self): if self.__tablestats is None: self.__fail_if_closed() if self._con.ods >= fdb.ODS_FB_30: self._ic.execute("""SELECT ts.MON$STAT_ID, ts.MON$STAT_GROUP, ts.MON$TABLE_NAME, ts.MON$RECORD_STAT_ID, r.MON$RECORD_SEQ_READS, r.MON$RECORD_IDX_READS, r.MON$RECORD_INSERTS, r.MON$RECORD_UPDATES, r.MON$RECORD_DELETES, r.MON$RECORD_BACKOUTS, r.MON$RECORD_PURGES, r.MON$RECORD_EXPUNGES, r.MON$RECORD_LOCKS, r.MON$RECORD_WAITS, r.MON$RECORD_CONFLICTS, r.MON$BACKVERSION_READS, r.MON$FRAGMENT_READS, r.MON$RECORD_RPT_READS FROM MON$TABLE_STATS ts join MON$RECORD_STATS r on ts.MON$RECORD_STAT_ID = r.MON$STAT_ID""") self.__tablestats = ObjectList((TableStatsInfo(self, row) for row in self._ic.itermap()), TableStatsInfo, 'item.stat_id') else: self.__tablestats = ObjectList() self.__tablestats.freeze() return self.__tablestats #--- Properties #: True if link to :class:`~fdb.Connection` is closed. closed = property(__get_closed) db = LateBindingProperty(_get_database, doc=":class:`DatabaseInfo` object for attached database.") attachments = LateBindingProperty(_get_attachments, doc=":class:`~fdb.utils.ObjectList` of all attachments.\nItems are :class:`AttachmentInfo` objects.") this_attachment = LateBindingProperty(_get_this_attachment, doc=":class:`AttachmentInfo` object for current connection.") transactions = LateBindingProperty(_get_transactions, doc=":class:`~fdb.utils.ObjectList` of all transactions.\nItems are :class:`TransactionInfo` objects.") statements = LateBindingProperty(_get_statements, doc=":class:`~fdb.utils.ObjectList` of all statements.\nItems are :class:`StatementInfo` objects.") callstack = LateBindingProperty(_get_callstack, doc=":class:`~fdb.utils.ObjectList` with complete call stack.\nItems are :class:`CallStackInfo` objects.") iostats = LateBindingProperty(_get_iostats, doc=":class:`~fdb.utils.ObjectList` of all I/O statistics.\nItems are :class:`IOStatsInfo` objects.") variables = LateBindingProperty(_get_variables, doc=":class:`~fdb.utils.ObjectList` of all context variables.\nItems are :class:`ContextVariableInfo` objects.") # FB 3.0 tablestats = LateBindingProperty(_get_tablestats, doc=":class:`~fdb.utils.ObjectList` of all table record I/O statistics.\nItems are :class:`TableStatsInfo` objects.") #--- Public def bind(self, connection): """Bind this instance to specified :class:`~fdb.Connection`. :param connection: :class:`~fdb.Connection` instance. :raises fdb.ProgrammingError: If Monitor object was set as internal (via :meth:`_set_as_internal`) or database has ODS lower than 11.1. """ if self.__internal: raise fdb.ProgrammingError("Call to 'bind' not allowed for embedded Monitor.") if self._con: self.close() if connection.ods < fdb.ODS_FB_21: raise fdb.ProgrammingError("Monitoring tables are available only " \ "for databases with ODS 11.1 and higher.") self._con = connection self._ic = self._con.trans(fdb.ISOLATION_LEVEL_READ_COMMITED_RO).cursor() self.clear() def close(self): """Sever link to :class:`~fdb.Connection`. :raises fdb.ProgrammingError: If Monitor object was set as internal (via :meth:`_set_as_internal`). """ if self.__internal: raise fdb.ProgrammingError("Call to 'close' not allowed for embedded Monitor.") self._close() self.clear() def clear(self): """Drop all cached information objects. Force reload of fresh monitoring information on next reference.""" self.__database = None self.__attachments = None self.__transactions = None self.__statements = None self.__callstack = None self.__iostats = None self.__variables = None self.__tablestats = None if not self.closed: self._ic.transaction.commit() def refresh(self): "Reloads fresh monitoring information." self.__fail_if_closed() self._ic.transaction.commit() self.clear() self._get_database() def get_attachment(self, id): """Get :class:`AttachmentInfo` by ID. :param int id: Attachment ID. :returns: :class:`AttachmentInfo` with specified ID or `None`. """ for attachment in self.attachments: if attachment.id == id: return attachment else: return None def get_transaction(self, id): """Get :class:`TransactionInfo` by ID. :param int id: Transaction ID. :returns: :class:`TransactionInfo` with specified ID or `None`. """ for transaction in self.transactions: if transaction.id == id: return transaction else: return None def get_statement(self, id): """Get :class:`StatementInfo` by ID. :param int id: Statement ID. :returns: :class:`StatementInfo` with specified ID or `None`. """ for statement in self.statements: if statement.id == id: return statement else: return None def get_call(self, id): """Get :class:`CallStackInfo` by ID. :param int id: Callstack ID. :returns: :class:`CallStackInfo` with specified ID or `None`. """ for call in self.callstack: if call.id == id: return call else: return None