Merge lp:~jtv/launchpad/bug-719267 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 12425
Proposed branch: lp:~jtv/launchpad/bug-719267
Merge into: lp:launchpad
Diff against target: 65 lines (+25/-2)
3 files modified
lib/lp/translations/model/pofile.py (+12/-0)
lib/lp/translations/model/potemplate.py (+1/-2)
lib/lp/translations/tests/test_pofile.py (+12/-0)
To merge this branch: bzr merge lp:~jtv/launchpad/bug-719267
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+50651@code.launchpad.net

Commit message

[r=lifeless][bug=719267] Fix timeouts on approval of new translations templates.

Description of the change

= Summary =

Timeouts were blocking translations import queue reviews, at least the creation of new templates. The time went into recalculating the statistics of each POFile that is created to match ones in sharing templates. Some large queries are involved.

== Proposed fix ==

A new template is created empty, so there's no need to query the database — all the counts that get constructed directly from the queries are zero.

I considered adding a parameter for "don't bother calculating the statistics," since the problem happens in a known scenario where the statistics don't need calculating. But in the end I just created some shortcuts: if the template is empty, the queries are skipped and zero counts are returned. This doesn't affect any APIs and may even benefit additional invocations.

== Pre-implementation notes ==

Robert looked into optimizing statistics calculation for multiple languages at once. The results are promising, though in this case there's no need to go to the trouble.

== Implementation details ==

The call that led to the unnecessary queries had an unnecessary line break. There is no other reason why I changed it.

== Tests ==

The statistics as calculated by the changed methods are extensively tested by:
{{{
./bin/test -vvc lp.translations.tests.test_pofile
}}}

I'm adding one for the zero case, just in case it's not properly covered: test_updateStatistics_counts_zero_for_empty_template.

== Demo and Q/A ==

Approve the oldest translation template uploads awaiting review. The requests should not time out.

Run cronscripts/rosetta-pofile-stats.py. This will take hours. Afterwards, POFile translation statistics will still be valid (and not all zeroed out as would happen if the change kicked in inappropriately).

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/translations/model/pofile.py
  lib/lp/translations/model/potemplate.py

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/model/pofile.py'
2--- lib/lp/translations/model/pofile.py 2011-01-26 23:33:20 +0000
3+++ lib/lp/translations/model/pofile.py 2011-02-21 20:08:53 +0000
4@@ -825,6 +825,12 @@
5
6 def _countTranslations(self):
7 """Count `currentcount`, `updatescount`, and `rosettacount`."""
8+ if self.potemplate.messageCount() == 0:
9+ # Shortcut: if the template is empty, as it is when it is
10+ # first created, we know the answers without querying the
11+ # database.
12+ return 0, 0, 0
13+
14 side_traits = getUtility(ITranslationSideTraitsSet).getForTemplate(
15 self.potemplate)
16 has_other_msgstrs = "COALESCE(%s) IS NOT NULL" % ", ".join([
17@@ -889,6 +895,12 @@
18
19 def _countNewSuggestions(self):
20 """Count messages with new suggestions."""
21+ if self.potemplate.messageCount() == 0:
22+ # Shortcut: if the template is empty, as it is when it is
23+ # first created, we know the answers without querying the
24+ # database.
25+ return 0
26+
27 flag_name = getUtility(ITranslationSideTraitsSet).getForTemplate(
28 self.potemplate).flag_name
29 suggestion_nonempty = "COALESCE(%s) IS NOT NULL" % ', '.join([
30
31=== modified file 'lib/lp/translations/model/potemplate.py'
32--- lib/lp/translations/model/potemplate.py 2011-02-14 17:14:17 +0000
33+++ lib/lp/translations/model/potemplate.py 2011-02-21 20:08:53 +0000
34@@ -1155,8 +1155,7 @@
35 if shared_template is template:
36 continue
37 for pofile in shared_template.pofiles:
38- template.newPOFile(
39- pofile.language.code, False)
40+ template.newPOFile(pofile.language.code, create_sharing=False)
41 # Do not continue, else it would trigger an existingpo assertion.
42 return
43
44
45=== modified file 'lib/lp/translations/tests/test_pofile.py'
46--- lib/lp/translations/tests/test_pofile.py 2011-02-17 22:06:02 +0000
47+++ lib/lp/translations/tests/test_pofile.py 2011-02-21 20:08:53 +0000
48@@ -760,6 +760,18 @@
49 # A `POFile` starts out with consistent statistics.
50 self.assertTrue(self.factory.makePOFile().testStatistics())
51
52+ def test_updateStatistics_counts_zero_for_empty_template(self):
53+ # Statistics for an empty template are all calculated as zero.
54+ pofile = self.factory.makePOFile()
55+ pofile.updateStatistics()
56+ self.assertEquals(0, self.devel_pofile.messageCount())
57+ self.assertEquals(0, self.devel_pofile.translatedCount())
58+ self.assertEquals(0, self.devel_pofile.untranslatedCount())
59+ self.assertEquals(0, self.devel_pofile.currentCount())
60+ self.assertEquals(0, self.devel_pofile.rosettaCount())
61+ self.assertEquals(0, self.devel_pofile.updatesCount())
62+ self.assertEquals(0, self.devel_pofile.unreviewedCount())
63+
64 def test_updateStatistics(self):
65 # Test that updating statistics keeps working.
66