source: tracdarcs/tracdarcs/dbutil.py @ 168

Revision 168, 5.8 KB checked in by lele@…, 3 years ago (diff)

Update copyright year

Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2005 Edgewall Software
4# Copyright (C) 2006 K.S.Sreeram <sreeram@tachyontech.net>
5# Copyright (C) 2007-2010 Lele Gaifax <lele@metapensiero.it>
6#
7# This software is licensed as described in the file COPYING, which
8# you should have received as part of this distribution. The terms
9# are also available at http://trac.edgewall.com/license.html.
10#
11# This software consists of voluntary contributions made by many
12# individuals. For the exact contribution history, see the revision
13# history and logs, available at http://projects.edgewall.com/trac/.
14#
15# Author: K.S.Sreeram <sreeram@tachyontech.net>
16
17import re
18from trac import __version__ as tracVersion
19
20# these values are used in the 'node_type' field in the
21# 'darcs_nodes' table.
22NODE_FILE_TYPE = 'F'
23NODE_DIR_TYPE = 'D'
24
25# these values are used in the 'change' field in the
26# 'darcs_node_changes' table
27CHANGE_ADDED = 'A'
28CHANGE_REMOVED = 'R'
29CHANGE_MOVED = 'M'
30CHANGE_EDITED = 'E'
31CHANGE_MOVED_EDITED = 'ME'
32
33IS_TRAC_0_10_X = not not re.match(r'^0\.10', tracVersion)
34IS_TRAC_0_11_X = not not re.match(r'^0\.11', tracVersion)
35IS_TRAC_0_12_OR_BETTER = not not re.match(r'^0\.1[2-9]', tracVersion)
36
37def query_nodes_for_revision(repo_id, rev=None):
38    '''
39    Returns a query which represents the nodes available as of
40    revision 'rev'. If 'rev' is None, then the latest revision is
41    used. Returns a set of 'node_id,rev,path,parent_id' values.
42    '''
43
44    if rev is None:
45        revfilter = "dn.remove_rev IS NULL"
46    else:
47        revfilter = ("dnc2.rev <= %d"
48                     " AND ((dn.remove_rev IS NULL) "
49                     "      OR (dn.remove_rev > %d))" % (rev,rev))
50    q = """SELECT dnc.node_id, dnc.rev, dnc.path, dnc.parent_id
51           FROM darcs_node_changes AS dnc
52           WHERE dnc.repo_id = %s
53             AND dnc.rev = (SELECT max(dnc2.rev)
54                            FROM darcs_node_changes AS dnc2, darcs_nodes AS dn
55                            WHERE dnc2.repo_id = dnc.repo_id
56                              AND dnc2.node_id = dnc.node_id
57                              AND dn.repo_id = dnc2.repo_id
58                              AND dn.node_id = dnc2.node_id
59                              AND %s)""" % (repo_id, revfilter)
60    return q
61
62def get_node_type(db, repo_id, node_id):
63    c = db.cursor()
64    c.execute('SELECT node_type FROM darcs_nodes '
65              'WHERE repo_id = %s AND node_id = %s', (repo_id, node_id))
66    return c.fetchone()[0]
67
68def get_prev_path_rev(db, repo_id, node_id, rev):
69    c = db.cursor()
70    c.execute('SELECT path,rev FROM darcs_node_changes '
71              'WHERE repo_id = %s AND node_id = %s AND rev < %s '
72              'ORDER BY rev DESC LIMIT 1', (repo_id, node_id, rev))
73    path,rev = c.fetchone()
74    return path,rev
75
76def get_repository_id(db, path):
77    if IS_TRAC_0_10_X or IS_TRAC_0_11_X:
78        return ''
79
80    c = db.cursor()
81    c.execute('SELECT r1.id '
82              'FROM repository r1, repository r2 '
83              'WHERE r1.id = r2.id '
84              '  AND r1.name = %s  AND r1.value = %s '
85              '  AND r2.name = %s  AND r2.value = %s '
86              'LIMIT 1', ('dir', path,
87                          'type', 'darcs'))
88    row = c.fetchone()
89    if row is not None:
90        return row[0]
91    return ''
92
93if __debug__:
94    class TimedCursor(object):
95        "Wrapper around a database cursor that keeps track of execution timings."
96
97        # Map a given statement to its stats, four values respectively
98        # number of executions, fastest run, slowest run, total time.
99        _timings = {}
100
101        def __init__(self, cursor):
102            self.cursor = cursor
103
104        def execute(self, stmt, *args):
105            from time import time
106
107            t0 = time()
108            self.cursor.execute(stmt, *args)
109            t1 = time()
110            usec = (t1-t0) * 1e6
111            old = self._timings.setdefault(stmt, [0, None, 0, 0])
112            old[0] += 1
113            if old[1] is None or old[1] > usec:
114                old[1] = usec
115            if old[2] < usec:
116                old[2] = usec
117            old[3] += usec
118
119        def fetchone(self):
120            return self.cursor.fetchone()
121
122        def fetchall(self):
123            return self.cursor.fetchall()
124
125        def __iter__(self):
126            return iter(self.cursor)
127
128        @classmethod
129        def report(klass, log):
130            def trepr(usec):
131                if usec < 1000:
132                    return "%.*g microsecs" % (3, usec)
133                else:
134                    msec = usec / 1000
135                    if msec < 1000:
136                        return "%.*g millisecs" % (3, msec)
137                    else:
138                        sec = msec / 1000
139                        return "%.*g seconds" % (3, sec)
140
141            all = list(klass._timings.items())
142            all.sort(key=lambda item: item[1][3]/item[1][0])
143            log.debug("Executed %d different statements, ordered by average execution time:",
144                      len(all))
145            for stmt, stats in all:
146                nr, mint, maxt, tott = stats
147                if nr>1:
148                    avg = tott / nr
149                    log.debug("%s: %d executions in %s, fastest run %s, slowest %s, average %s",
150                              stmt, nr, trepr(tott), trepr(mint), trepr(maxt), trepr(avg))
151                else:
152                    log.debug("%s: executed once in %s", stmt, trepr(tott))
153
154    class TimedDB(object):
155        "Simple wrapper around a connection uses TimedCursors and print a final report."
156
157        def __init__(self, db, log):
158            self.db = db
159            self.log = log
160
161        def __del__(self):
162            TimedCursor.report(self.log)
163
164        def commit(self):
165            return self.db.commit()
166
167        def rollback(self):
168            return self.db.rollback()
169
170        def cursor(self):
171            return TimedCursor(self.db.cursor())
172else:
173    def TimedDB(db, log):
174        return db
Note: See TracBrowser for help on using the repository browser.