Merge lp:~sinzui/launchpad/missing-potmsgset into lp:launchpad

Proposed by Curtis Hovey on 2012-11-15
Status: Merged
Approved by: j.c.sackett on 2012-11-15
Approved revision: no longer in the source branch.
Merged at revision: 16276
Proposed branch: lp:~sinzui/launchpad/missing-potmsgset
Merge into: lp:launchpad
Diff against target: 39 lines (+7/-2)
1 file modified
lib/lp/translations/utilities/translation_import.py (+7/-2)
To merge this branch: bzr merge lp:~sinzui/launchpad/missing-potmsgset
Reviewer Review Type Date Requested Status
j.c.sackett (community) 2012-11-15 Approve on 2012-11-15
Review via email: mp+134483@code.launchpad.net

Commit Message

Ensure POTMsgSets are in the db during poimport.

Description of the Change

The rosetta-poimport script is violating referential integrity:

2011-10-20 23:16:23 ERROR insert or update on table "translationmessage"
    violates foreign key constraint "translationmessage__potmsgset__fk"
    DETAIL: Key (potmsgset)=(11731721) is not present in table "potmsgset".
    -- Slovenian (sl) translation of kaddressbook in
       Ubuntu Oneiric package "kdepim" (id 5905106)

Full traceback: http://paste.ubuntu.com/715011/

A query some 12 hours after this particular failure shows that the
highest used id in potmsgset is 11787759. So the problematic id is quite
a new one.

--------------------------------------------------------------------

RULES

    Pre-implementation: jtv, wgrant, wallyworld
    * We do not know for certain why the POTMsgSet is not yet in the DB.
    * We have confirmed that the UnusedPOTMsgSetPruner is interacting
      with poimport, but getOrCreatePOTMsgSet() ensures one will
      exist (in code) when it is needed.
      * Both processes are iterating over a collection and committing at
        each loop. They do change the DB as both run.
      * We Updated UnusedPOTMsgSetPruner to not delete PotMsgSets during
        the loop if it suddenly became used.
    * In 13 lines of code and a few milliseconds pass between the point
      where getOrCreatePOTMsgSet is called and the call to
      POTMsgSet.getCurrentTranslation() causes a flush() to ensure the
      impending query will work. But the oops shows that the POTMsgSet
      did not arrive in time. Within those 13 lines of code, a
      TranslationMessage is created, approved, then set as the
      current translation. The OOPS is actually about the
      act of creating the TranslationMessage, but we do not see this
      DB error until we execute more lines of code working with it and
      its POTMsgSet and the ORM decides to flush.
    * There are rules to flush the top-level objects (POFile and
      POTemplate) after they are created. There are also rules to
      alter the flush order of messages to ensure the act of reassignment
      does not cause a unique key violation. But the intermediate
      POTMsgSet is not explicitly flushed.
    * Else where in Lp the POTMsgSet is explicitly flushed when it is
      created or modified. In fact the same list of modified POTMsgSet
      attrs get flushed by the testing factory as is changed by poimport.
    * There are two places to call flush() to ensure the POTMsgSet is in
      the DB. 1, immediately after the change to the attrs as is done
      else where, or 2, in storeTranslationsInDatabase()
      * The call to storeTranslationsInDatabase() is exactly where the
        call to flush would be added, so the intent of the method is
        to get all the data into the DB -- Add a call to flush() in
        storeTranslationsInDatabase() one we are certain there wont be
        an early exit.

QA

    * None. We do not know how to create the issue. This code just ensures
      the case cannot happen.

LoC

    * I have a 3000 line credit this week.

LINT

    lib/lp/translations/utilities/translation_import.py

TEST

    ./bin/test -vv lp.translations.utilities.tests.test_file_importer

IMPLEMENTATION

Added a call to flush() the ORM when it is certain the data needs to go
to the DB. Cleanup lint.
    lib/lp/translations/utilities/translation_import.py

To post a comment you must log in.
j.c.sackett (jcsackett) wrote :

Thank you.

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/utilities/translation_import.py'
2--- lib/lp/translations/utilities/translation_import.py 2012-06-29 08:40:05 +0000
3+++ lib/lp/translations/utilities/translation_import.py 2012-11-15 15:18:30 +0000
4@@ -25,6 +25,7 @@
5 )
6 from lp.registry.interfaces.sourcepackage import ISourcePackageFactory
7 from lp.services.config import config
8+from lp.services.database.lpstorm import IStore
9 from lp.services.database.sqlbase import (
10 cursor,
11 quote,
12@@ -373,7 +374,7 @@
13 """
14
15 def __init__(self, translation_import_queue_entry,
16- importer, logger = None):
17+ importer, logger=None):
18 """Base constructor to set up common attributes and parse the imported
19 file into a member variable (self.translation_file).
20
21@@ -536,6 +537,10 @@
22 potmsgset.singular_text, message_data.translations,
23 self.pofile.language.pluralforms)
24
25+ # Flush the store now because flush order rules can cause messages
26+ # to be flushed before the potmsgset arrives in the database.
27+ IStore(potmsgset).flush()
28+
29 if potmsgset.is_translation_credit:
30 # Translation credits cannot be added as suggestions.
31 return self._storeCredits(potmsgset, sanitized_translations)
32@@ -680,7 +685,7 @@
33 message._translations = None
34
35 if len(message.flags) > 0:
36- flags_comment = u", "+u", ".join(message.flags)
37+ flags_comment = u", " + u", ".join(message.flags)
38 else:
39 flags_comment = u""
40