Merge lp:~stub/launchpad/bugsummary into lp:launchpad/db-devel

Proposed by Stuart Bishop
Status: Merged
Approved by: Stuart Bishop
Approved revision: 10694
Merged at revision: 10832
Proposed branch: lp:~stub/launchpad/bugsummary
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~stub/launchpad/db-cleanups
Diff against target: 176 lines (+160/-1)
2 files modified
database/schema/patch-2208-76-4.sql (+159/-0)
database/schema/security.cfg (+1/-1)
To merge this branch: bzr merge lp:~stub/launchpad/bugsummary
Reviewer Review Type Date Requested Status
Stuart Bishop (community) db Approve
Review via email: mp+69632@code.launchpad.net

Commit message

[r=stub][bug=810104] Speed up BugSummaryJournal rollup

Description of the change

= Summary =

Rolling up the BugSummaryJournal entries into the BugSummary table is slow.

== Proposed fix ==

Rewrite the logic in constructs that PG optimizes better in this case.

Move removal of 'count 0' rows to once per rollup, rather than once per decrement.

== Pre-implementation notes ==

== Implementation details ==

The old code is in patch-2208-75-0.sql

== Tests ==

== Demo and Q/A ==

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  database/schema/patch-2208-76-4.sql

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) :
review: Approve (db)
lp:~stub/launchpad/bugsummary updated
10695. By Stuart Bishop

Add a batchsize for future garbo job

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'database/schema/patch-2208-76-4.sql'
2--- database/schema/patch-2208-76-4.sql 1970-01-01 00:00:00 +0000
3+++ database/schema/patch-2208-76-4.sql 2011-07-28 13:00:58 +0000
4@@ -0,0 +1,159 @@
5+-- Copyright 2011 Canonical Ltd. This software is licensed under the
6+-- GNU Affero General Public License version 3 (see the file LICENSE).
7+
8+SET client_min_messages=ERROR;
9+
10+DROP FUNCTION bugsummary_rollup_journal();
11+
12+CREATE OR REPLACE FUNCTION bugsummary_rollup_journal(batchsize integer=NULL)
13+RETURNS VOID
14+LANGUAGE plpgsql VOLATILE
15+CALLED ON NULL INPUT
16+SECURITY DEFINER SET search_path TO public AS
17+$$
18+DECLARE
19+ d bugsummary%ROWTYPE;
20+ max_id integer;
21+BEGIN
22+ -- Lock so we don't content with other invokations of this
23+ -- function. We can happily lock the BugSummary table for writes
24+ -- as this function is the only thing that updates that table.
25+ -- BugSummaryJournal remains unlocked so nothing should be blocked.
26+ LOCK TABLE BugSummary IN ROW EXCLUSIVE MODE;
27+
28+ IF batchsize IS NULL THEN
29+ SELECT MAX(id) INTO max_id FROM BugSummaryJournal;
30+ ELSE
31+ SELECT MAX(id) INTO max_id FROM (
32+ SELECT id FROM BugSummaryJournal ORDER BY id LIMIT batchsize
33+ ) AS Whatever;
34+ END IF;
35+
36+ FOR d IN
37+ SELECT
38+ NULL as id,
39+ SUM(count),
40+ product,
41+ productseries,
42+ distribution,
43+ distroseries,
44+ sourcepackagename,
45+ viewed_by,
46+ tag,
47+ status,
48+ milestone,
49+ importance,
50+ has_patch,
51+ fixed_upstream
52+ FROM BugSummaryJournal
53+ WHERE id <= max_id
54+ GROUP BY
55+ product, productseries, distribution, distroseries,
56+ sourcepackagename, viewed_by, tag, status, milestone,
57+ importance, has_patch, fixed_upstream
58+ HAVING sum(count) <> 0
59+ LOOP
60+ IF d.count < 0 THEN
61+ PERFORM bug_summary_dec(d);
62+ ELSIF d.count > 0 THEN
63+ PERFORM bug_summary_inc(d);
64+ END IF;
65+ END LOOP;
66+
67+ -- Clean out any counts we reduced to 0.
68+ DELETE FROM BugSummary WHERE count=0;
69+ -- Clean out the journal entries we have handled.
70+ DELETE FROM BugSummaryJournal WHERE id <= max_id;
71+END;
72+$$;
73+
74+COMMENT ON FUNCTION bugsummary_rollup_journal(integer) IS
75+'Collate and migrate rows from BugSummaryJournal to BugSummary';
76+
77+
78+CREATE OR REPLACE FUNCTION bug_summary_dec(bugsummary) RETURNS VOID
79+LANGUAGE SQL AS
80+$$
81+ -- We own the row reference, so in the absence of bugs this cannot
82+ -- fail - just decrement the row.
83+ UPDATE BugSummary SET count = count + $1.count
84+ WHERE
85+ ((product IS NULL AND $1.product IS NULL)
86+ OR product = $1.product)
87+ AND ((productseries IS NULL AND $1.productseries IS NULL)
88+ OR productseries = $1.productseries)
89+ AND ((distribution IS NULL AND $1.distribution IS NULL)
90+ OR distribution = $1.distribution)
91+ AND ((distroseries IS NULL AND $1.distroseries IS NULL)
92+ OR distroseries = $1.distroseries)
93+ AND ((sourcepackagename IS NULL AND $1.sourcepackagename IS NULL)
94+ OR sourcepackagename = $1.sourcepackagename)
95+ AND ((viewed_by IS NULL AND $1.viewed_by IS NULL)
96+ OR viewed_by = $1.viewed_by)
97+ AND ((tag IS NULL AND $1.tag IS NULL)
98+ OR tag = $1.tag)
99+ AND status = $1.status
100+ AND ((milestone IS NULL AND $1.milestone IS NULL)
101+ OR milestone = $1.milestone)
102+ AND importance = $1.importance
103+ AND has_patch = $1.has_patch
104+ AND fixed_upstream = $1.fixed_upstream;
105+$$;
106+
107+CREATE OR REPLACE FUNCTION bug_summary_inc(d bugsummary) RETURNS VOID
108+LANGUAGE plpgsql AS
109+$$
110+BEGIN
111+ -- Shameless adaption from postgresql manual
112+ LOOP
113+ -- first try to update the row
114+ UPDATE BugSummary SET count = count + d.count
115+ WHERE
116+ ((product IS NULL AND $1.product IS NULL)
117+ OR product = $1.product)
118+ AND ((productseries IS NULL AND $1.productseries IS NULL)
119+ OR productseries = $1.productseries)
120+ AND ((distribution IS NULL AND $1.distribution IS NULL)
121+ OR distribution = $1.distribution)
122+ AND ((distroseries IS NULL AND $1.distroseries IS NULL)
123+ OR distroseries = $1.distroseries)
124+ AND ((sourcepackagename IS NULL AND $1.sourcepackagename IS NULL)
125+ OR sourcepackagename = $1.sourcepackagename)
126+ AND ((viewed_by IS NULL AND $1.viewed_by IS NULL)
127+ OR viewed_by = $1.viewed_by)
128+ AND ((tag IS NULL AND $1.tag IS NULL)
129+ OR tag = $1.tag)
130+ AND status = $1.status
131+ AND ((milestone IS NULL AND $1.milestone IS NULL)
132+ OR milestone = $1.milestone)
133+ AND importance = $1.importance
134+ AND has_patch = $1.has_patch
135+ AND fixed_upstream = $1.fixed_upstream;
136+ IF found THEN
137+ RETURN;
138+ END IF;
139+ -- not there, so try to insert the key
140+ -- if someone else inserts the same key concurrently,
141+ -- we could get a unique-key failure
142+ BEGIN
143+ INSERT INTO BugSummary(
144+ count, product, productseries, distribution,
145+ distroseries, sourcepackagename, viewed_by, tag,
146+ status, milestone,
147+ importance, has_patch, fixed_upstream)
148+ VALUES (
149+ d.count, d.product, d.productseries, d.distribution,
150+ d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
151+ d.status, d.milestone,
152+ d.importance, d.has_patch, d.fixed_upstream);
153+ RETURN;
154+ EXCEPTION WHEN unique_violation THEN
155+ -- do nothing, and loop to try the UPDATE again
156+ END;
157+ END LOOP;
158+END;
159+$$;
160+
161+
162+
163+INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 76, 4);
164
165=== modified file 'database/schema/security.cfg'
166--- database/schema/security.cfg 2011-07-25 08:48:47 +0000
167+++ database/schema/security.cfg 2011-07-28 13:00:58 +0000
168@@ -143,7 +143,7 @@
169 public.bugnotificationrecipientarchive = SELECT, UPDATE
170 public.bugsummary = SELECT
171 public.bugsummaryjournal = SELECT
172-public.bugsummary_rollup_journal() = EXECUTE
173+public.bugsummary_rollup_journal(integer) = EXECUTE
174 public.bugtag = SELECT, INSERT, DELETE
175 public.bugtrackercomponent = SELECT, INSERT, UPDATE
176 public.bugtrackercomponentgroup = SELECT, INSERT, UPDATE

Subscribers

People subscribed via source and target branches

to status/vote changes: