2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
1 |
#!/usr/bin/env python
|
3149.1.5
by Stuart Bishop
Staging config |
2 |
# Copyright 2005-2006 Canonical Ltd. All rights reserved.
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
3 |
|
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
4 |
import _pythonpath |
5 |
||
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
6 |
import sys |
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
7 |
from optparse import OptionParser |
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
8 |
|
9 |
from zope.component import getUtility |
|
10 |
||
11 |
from canonical.config import config |
|
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
12 |
from canonical.lp import initZopeless, AUTOCOMMIT_ISOLATION |
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
13 |
from canonical.launchpad.scripts import ( |
14 |
execute_zcml_for_scripts, logger_options, logger |
|
15 |
)
|
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
16 |
from canonical.launchpad.scripts.lockfile import LockFile |
17 |
from canonical.launchpad.interfaces import IPersonSet |
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
18 |
from canonical.database.sqlbase import connect |
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
19 |
|
20 |
_default_lock_file = '/var/lock/launchpad-karma-update.lock' |
|
21 |
||
22 |
||
23 |
def update_karma_cache(): |
|
24 |
"""Update the KarmaCache table for all valid Launchpad users.
|
|
25 |
||
26 |
For each Launchpad user with a preferred email address, calculate his
|
|
27 |
karmavalue for each category of actions we have and update his entry in
|
|
28 |
the KarmaCache table. If a user doesn't have an entry for that category in
|
|
29 |
KarmaCache a new one will be created.
|
|
30 |
"""
|
|
2976.4.4
by Stuart Bishop
Updates from review |
31 |
# We use the autocommit transaction isolation level to minimize
|
32 |
# contention, and also allows us to not bother explicitly calling
|
|
33 |
# COMMIT all the time. This script in no way relies on transactions,
|
|
34 |
# so it is safe.
|
|
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
35 |
ztm = initZopeless( |
36 |
dbuser=config.karmacacheupdater.dbuser, |
|
37 |
implicitBegin=False, isolation=AUTOCOMMIT_ISOLATION |
|
38 |
)
|
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
39 |
con = connect(config.karmacacheupdater.dbuser) |
40 |
con.set_isolation_level(AUTOCOMMIT_ISOLATION) |
|
41 |
cur = con.cursor() |
|
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
42 |
karma_expires_after = '1 year' |
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
43 |
|
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
44 |
# Calculate everyones karma. Karma degrades each day, becoming
|
45 |
# worthless after karma_expires_after. This query produces odd results
|
|
46 |
# when datecreated is in the future, but there is really no point adding
|
|
47 |
# the extra WHEN clause.
|
|
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
48 |
log.info("Calculating everyones karma") |
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
49 |
cur.execute(""" |
50 |
SELECT person, category, ROUND(SUM(
|
|
51 |
CASE WHEN datecreated + %(karma_expires_after)s::interval |
|
52 |
<= CURRENT_TIMESTAMP AT TIME ZONE 'UTC' THEN 0
|
|
53 |
ELSE points * (1 - extract(
|
|
54 |
EPOCH FROM CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - datecreated
|
|
55 |
) / extract(EPOCH FROM %(karma_expires_after)s::interval)) |
|
56 |
END
|
|
57 |
))
|
|
58 |
FROM Karma, KarmaAction
|
|
59 |
WHERE action = KarmaAction.id
|
|
60 |
GROUP BY person, category
|
|
61 |
""", vars()) |
|
62 |
||
63 |
# Suck into RAM to avoid tieing up resources on the DB.
|
|
64 |
results = list(cur.fetchall()) |
|
65 |
||
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
66 |
log.info("Got %d (person, category) scores", len(results)) |
67 |
||
2976.4.1
by Stuart Bishop
Make karma update cronscript a lot less database intensive. |
68 |
# Note that we don't need to commit each iteration because we are running
|
69 |
# in autocommit mode.
|
|
70 |
for person, category, points in results: |
|
71 |
log.debug( |
|
72 |
"Setting person=%(person)d, category=%(category)d, " |
|
73 |
"points=%(points)d", vars() |
|
74 |
)
|
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
75 |
|
76 |
if points <= 0: |
|
77 |
# Don't allow our table to bloat with inactive users
|
|
78 |
cur.execute(""" |
|
79 |
DELETE FROM KarmaCache WHERE
|
|
80 |
person=%(person)s AND category=%(category)s |
|
81 |
""", vars()) |
|
82 |
else: |
|
83 |
# Attempt to UPDATE. If no rows modified, perform an INSERT
|
|
84 |
cur.execute(""" |
|
85 |
UPDATE KarmaCache SET karmavalue=%(points)s |
|
86 |
WHERE person=%(person)s AND category=%(category)s |
|
87 |
""", vars()) |
|
88 |
assert cur.rowcount in (0, 1), \ |
|
89 |
'Bad rowcount %r returned from DML' % (cur.rowcount,) |
|
90 |
if cur.rowcount == 0: |
|
91 |
cur.execute(""" |
|
92 |
INSERT INTO KarmaCache (person, category, karmavalue)
|
|
93 |
VALUES (%(person)s, %(category)s, %(points)s) |
|
94 |
""", vars()) |
|
95 |
||
96 |
# VACUUM KarmaCache since we have just touched every record in it
|
|
97 |
cur.execute("""VACUUM KarmaCache""") |
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
98 |
|
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
99 |
# Update the KarmaTotalCache table
|
100 |
log.info("Rebuilding KarmaTotalCache") |
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
101 |
# Trash old records
|
102 |
cur.execute(""" |
|
103 |
DELETE FROM KarmaTotalCache
|
|
104 |
WHERE person NOT IN (SELECT person FROM KarmaCache)
|
|
105 |
""") |
|
106 |
# Update existing records
|
|
107 |
cur.execute(""" |
|
108 |
UPDATE KarmaTotalCache SET karma_total=sum_karmavalue
|
|
109 |
FROM (
|
|
110 |
SELECT person AS sum_person, SUM(karmavalue) AS sum_karmavalue
|
|
111 |
FROM KarmaCache GROUP BY person
|
|
112 |
) AS sums
|
|
113 |
WHERE KarmaTotalCache.person = sum_person
|
|
114 |
""") |
|
115 |
||
116 |
# VACUUM KarmaTotalCache since we have just touched every row in it.
|
|
117 |
cur.execute("""VACUUM KarmaTotalCache""") |
|
118 |
||
119 |
# Insert new records into the KarmaTotalCache table. If deadlocks
|
|
120 |
# become a problem, first LOCK the corresponding rows in the Person table
|
|
121 |
# so the bulk insert cannot fail. We don't bother at the moment as this
|
|
122 |
# would involve granting UPDATE rights on the Person table to the
|
|
123 |
# karmacacheupdater user.
|
|
124 |
## cur.execute("BEGIN")
|
|
125 |
## cur.execute("""
|
|
126 |
## SELECT * FROM Person
|
|
127 |
## WHERE id NOT IN (SELECT person FROM KarmaTotalCache)
|
|
128 |
## FOR UPDATE
|
|
129 |
## """)
|
|
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
130 |
cur.execute(""" |
131 |
INSERT INTO KarmaTotalCache (person, karma_total)
|
|
132 |
SELECT person, SUM(karmavalue) FROM KarmaCache
|
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
133 |
WHERE person NOT IN (SELECT person FROM KarmaTotalCache)
|
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
134 |
GROUP BY person
|
135 |
""") |
|
3149.1.4
by Stuart Bishop
Make foaf-update-karma-cache friendlier and less likely to trigger deadlocks |
136 |
## cur.execute("COMMIT")
|
137 |
||
2976.4.2
by Stuart Bishop
Drop person.karma, replacing with new KarmaTotalCache table |
138 |
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
139 |
if __name__ == '__main__': |
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
140 |
parser = OptionParser() |
141 |
logger_options(parser) |
|
142 |
(options, arguments) = parser.parse_args() |
|
143 |
if arguments: |
|
144 |
parser.error("Unhandled arguments %s" % repr(arguments)) |
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
145 |
execute_zcml_for_scripts() |
146 |
||
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
147 |
log = logger(options, 'karmacache') |
148 |
log.info("Updating the karma cache of Launchpad users.") |
|
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
149 |
|
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
150 |
lockfile = LockFile(_default_lock_file, logger=log) |
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
151 |
try: |
152 |
lockfile.acquire() |
|
153 |
except OSError: |
|
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
154 |
log.info("lockfile %s already exists, exiting", _default_lock_file) |
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
155 |
sys.exit(1) |
156 |
||
157 |
try: |
|
158 |
update_karma_cache() |
|
159 |
finally: |
|
160 |
lockfile.release() |
|
161 |
||
2125
by Canonical.com Patch Queue Manager
[r=bjornt] Cronscript refactorings |
162 |
log.info("Finished updating the karma cache of Launchpad users.") |
2002
by Canonical.com Patch Queue Manager
Implements the karma framework (according to the KarmaImplementation spec) and hook it into Malone events. r=spiv,stub |
163 |