# -*- coding: utf-8 -*- # # Copyright (C) 2005 Edgewall Software # Copyright (C) 2006 K.S.Sreeram # Copyright (C) 2007-2010 Lele Gaifax # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at http://trac.edgewall.com/license.html. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://projects.edgewall.com/trac/. # # Author: K.S.Sreeram import re from trac import __version__ as tracVersion # these values are used in the 'node_type' field in the # 'darcs_nodes' table. NODE_FILE_TYPE = 'F' NODE_DIR_TYPE = 'D' # these values are used in the 'change' field in the # 'darcs_node_changes' table CHANGE_ADDED = 'A' CHANGE_REMOVED = 'R' CHANGE_MOVED = 'M' CHANGE_EDITED = 'E' CHANGE_MOVED_EDITED = 'ME' IS_TRAC_0_10_X = not not re.match(r'^0\.10', tracVersion) IS_TRAC_0_11_X = not not re.match(r'^0\.11', tracVersion) IS_TRAC_0_12_OR_BETTER = not not re.match(r'^0\.1[2-9]', tracVersion) def query_nodes_for_revision(repo_id, rev=None): ''' Returns a query which represents the nodes available as of revision 'rev'. If 'rev' is None, then the latest revision is used. Returns a set of 'node_id,rev,path,parent_id' values. ''' if rev is None: revfilter = "dn.remove_rev IS NULL" else: revfilter = ("dnc2.rev <= %d" " AND ((dn.remove_rev IS NULL) " " OR (dn.remove_rev > %d))" % (rev,rev)) q = """SELECT dnc.node_id, dnc.rev, dnc.path, dnc.parent_id FROM darcs_node_changes AS dnc WHERE dnc.repo_id = %s AND dnc.rev = (SELECT max(dnc2.rev) FROM darcs_node_changes AS dnc2, darcs_nodes AS dn WHERE dnc2.repo_id = dnc.repo_id AND dnc2.node_id = dnc.node_id AND dn.repo_id = dnc2.repo_id AND dn.node_id = dnc2.node_id AND %s)""" % (repo_id, revfilter) return q def get_node_type(db, repo_id, node_id): c = db.cursor() c.execute('SELECT node_type FROM darcs_nodes ' 'WHERE repo_id = %s AND node_id = %s', (repo_id, node_id)) return c.fetchone()[0] def get_prev_path_rev(db, repo_id, node_id, rev): c = db.cursor() c.execute('SELECT path,rev FROM darcs_node_changes ' 'WHERE repo_id = %s AND node_id = %s AND rev < %s ' 'ORDER BY rev DESC LIMIT 1', (repo_id, node_id, rev)) path,rev = c.fetchone() return path,rev def get_repository_id(db, path): if IS_TRAC_0_10_X or IS_TRAC_0_11_X: return '' c = db.cursor() c.execute('SELECT r1.id ' 'FROM repository r1, repository r2 ' 'WHERE r1.id = r2.id ' ' AND r1.name = %s AND r1.value = %s ' ' AND r2.name = %s AND r2.value = %s ' 'LIMIT 1', ('dir', path, 'type', 'darcs')) row = c.fetchone() if row is not None: return row[0] return '' if __debug__: class TimedCursor(object): "Wrapper around a database cursor that keeps track of execution timings." # Map a given statement to its stats, four values respectively # number of executions, fastest run, slowest run, total time. _timings = {} def __init__(self, cursor): self.cursor = cursor def execute(self, stmt, *args): from time import time t0 = time() self.cursor.execute(stmt, *args) t1 = time() usec = (t1-t0) * 1e6 old = self._timings.setdefault(stmt, [0, None, 0, 0]) old[0] += 1 if old[1] is None or old[1] > usec: old[1] = usec if old[2] < usec: old[2] = usec old[3] += usec def fetchone(self): return self.cursor.fetchone() def fetchall(self): return self.cursor.fetchall() def __iter__(self): return iter(self.cursor) @classmethod def report(klass, log): def trepr(usec): if usec < 1000: return "%.*g microsecs" % (3, usec) else: msec = usec / 1000 if msec < 1000: return "%.*g millisecs" % (3, msec) else: sec = msec / 1000 return "%.*g seconds" % (3, sec) all = list(klass._timings.items()) if all: all.sort(key=lambda item: item[1][3]/item[1][0]) log.debug("Executed %d different statements, ordered by average execution time:", len(all)) for stmt, stats in all: nr, mint, maxt, tott = stats if nr>1: avg = tott / nr log.debug("%s: %d executions in %s, fastest run %s, slowest %s, average %s", stmt, nr, trepr(tott), trepr(mint), trepr(maxt), trepr(avg)) else: log.debug("%s: executed once in %s", stmt, trepr(tott)) klass._timings.clear() class TimedDB(object): "Simple wrapper around a connection uses TimedCursors and print a final report." def __init__(self, db, log): self.db = db self.log = log def __del__(self): TimedCursor.report(self.log) def commit(self): return self.db.commit() def rollback(self): return self.db.rollback() def cursor(self): return TimedCursor(self.db.cursor()) else: def TimedDB(db, log): return db