Am 14.09.2009 11:35, Данило Шеган schrieb:
> = Bug #408717 =
>
> Note: this is a cherrypick candidate so is kept as simple as possible.
> It's critical for Launchpad Translations (poimport is blocked on this).
Thanks for taking this on so quickly and finding a solution. If Stuart
thinks it's a great idea, who am I to argue? ;-)
review approve
Just two comments below.
> === modified file 'lib/canonical/config/schema-lazr.conf'
> --- lib/canonical/config/schema-lazr.conf 2009-09-08 15:16:33 +0000
> +++ lib/canonical/config/schema-lazr.conf 2009-09-14 09:12:58 +0000
> @@ -1429,6 +1429,10 @@
> storm_cache: generational
> storm_cache_size: 500
>
> +# Statement timeout (in seconds), limited to super-fast-imports query.
> +# Set to 'timeout' to make it timeout every time (for tests).
> +statement_timeout: 300
> +
> [processmail]
> # The database user which will be used by this process.
> # datatype: string
>
> === modified file 'lib/lp/translations/utilities/tests/test_superfastimports.py'
> --- lib/lp/translations/utilities/tests/test_superfastimports.py 2009-07-17 02:25:09 +0000
> +++ lib/lp/translations/utilities/tests/test_superfastimports.py 2009-09-14 09:12:58 +0000
> @@ -5,8 +5,9 @@
>
> import unittest
>
> +from canonical.config import config
> from canonical.testing import ZopelessDatabaseLayer
> -from lp.testing import TestCaseWithFactory, verifyObject
Thanks for cleaning this.
> +from lp.testing import TestCaseWithFactory
> from lp.translations.utilities.translation_import import (
> ExistingPOFileInDatabase)
> from lp.translations.utilities.translation_common_format import (
> @@ -67,6 +68,27 @@
> self.assertFalse(cached_file.isAlreadyImportedTheSame(message_data))
> self.assertFalse(cached_file.isAlreadyTranslatedTheSame(message_data))
>
> + def test_query_timeout(self):
> + # Test that super-fast-imports doesn't cache anything when it hits
> + # a timeout.
> +
> + # Override the config option to force a timeout error.
> + new_config = ("""
> + [poimport]
> + statement_timeout: timeout
> + """)
> + config.push('super_fast_timeout', new_config)
> +
> + # Add a message that would otherwise be cached (see other tests).
> + current_message = self.factory.makeTranslationMessage(
> + pofile=self.pofile, is_imported=False)
> + message_data = self.getTranslationMessageData(current_message)
> + cached_file = ExistingPOFileInDatabase(self.pofile)
> + self.assertFalse(cached_file.isAlreadyTranslatedTheSame(message_data))
> +
> + # Restore the old configuration.
> + config.pop('super_fast_timeout')
> +
>
> def test_suite():
> return unittest.TestLoader().loadTestsFromName(__name__)
>
> === modified file 'lib/lp/translations/utilities/translation_import.py'
> --- lib/lp/translations/utilities/translation_import.py 2009-08-05 13:11:00 +0000
> +++ lib/lp/translations/utilities/translation_import.py 2009-09-14 09:12:58 +0000
> @@ -18,8 +18,13 @@
>
> from operator import attrgetter
>
> +import transaction
> +
> +from canonical.config import config
> from canonical.database.sqlbase import cursor, quote
>
> +from storm.exceptions import TimeoutError
> +
> from canonical.cachedproperty import cachedproperty
> from lp.registry.interfaces.person import (
> IPersonSet,
> @@ -119,7 +124,6 @@
> # Pre-fill self.messages and self.imported with data.
> self._fetchDBRows()
>
> -
> def _fetchDBRows(self):
> msgstr_joins = [
> "LEFT OUTER JOIN POTranslation pt%d "
> @@ -168,8 +172,32 @@
> TranslationTemplateItem.sequence,
> TranslationMessage.potemplate NULLS LAST
> ''' % substitutions
> +
> cur = cursor()
> - cur.execute(sql)
> + try:
> + # XXX 2009-09-14 DaniloSegan (bug #408718):
> + # this statement causes postgres to eat the diskspace
> + # from time to time. Let's wrap it up in a timeout.
> + timeout = config.poimport.statement_timeout
> +
> + # We have to commit what we've got so far or we'll lose
> + # it when we hit TimeoutError.
> + transaction.commit()
> +
> + if timeout == 'timeout':
> + # This is used in tests.
> + query = "SELECT pg_sleep(2)"
> + timeout = '1s'
> + else:
> + timeout = 1000 * int(timeout)
> + query = sql
> + cur.execute("SET statement_timeout to %s" % quote(timeout))
> + cur.execute(query)
> + except TimeoutError:
> + # Restart the transaction and return empty SelectResults.
> + transaction.abort()
> + transaction.begin()
> + cur.execute("SELECT 1 WHERE 1=0")
As you mentioned on IRC, you should reset the statement_timeout back to
what it was (if that is not done by abort() ?). Please extend the test
to check that, too.
Also, could you consider using EmptyResultSet instead of such useless
queries, please? ;)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Am 14.09.2009 11:35, Данило Шеган schrieb:
> = Bug #408717 =
>
> Note: this is a cherrypick candidate so is kept as simple as possible.
> It's critical for Launchpad Translations (poimport is blocked on this).
Thanks for taking this on so quickly and finding a solution. If Stuart
thinks it's a great idea, who am I to argue? ;-)
review approve
Just two comments below.
> === modified file 'lib/canonical/ config/ schema- lazr.conf' config/ schema- lazr.conf 2009-09-08 15:16:33 +0000 config/ schema- lazr.conf 2009-09-14 09:12:58 +0000 translations/ utilities/ tests/test_ superfastimport s.py' translations/ utilities/ tests/test_ superfastimport s.py 2009-07-17 02:25:09 +0000 translations/ utilities/ tests/test_ superfastimport s.py 2009-09-14 09:12:58 +0000 eLayer tory, verifyObject
> --- lib/canonical/
> +++ lib/canonical/
> @@ -1429,6 +1429,10 @@
> storm_cache: generational
> storm_cache_size: 500
>
> +# Statement timeout (in seconds), limited to super-fast-imports query.
> +# Set to 'timeout' to make it timeout every time (for tests).
> +statement_timeout: 300
> +
> [processmail]
> # The database user which will be used by this process.
> # datatype: string
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -5,8 +5,9 @@
>
> import unittest
>
> +from canonical.config import config
> from canonical.testing import ZopelessDatabas
> -from lp.testing import TestCaseWithFac
Thanks for cleaning this.
> +from lp.testing import TestCaseWithFactory .utilities. translation_ import import ( nDatabase) .utilities. translation_ common_ format import ( e(cached_ file.isAlreadyI mportedTheSame( message_ data)) e(cached_ file.isAlreadyT ranslatedTheSam e(message_ data)) timeout( self): push('super_ fast_timeout' , new_config) makeTranslation Message( tionMessageData (current_ message) nDatabase( self.pofile) e(cached_ file.isAlreadyT ranslatedTheSam e(message_ data)) pop('super_ fast_timeout' ) TestLoader( ).loadTestsFrom Name(__ name__) translations/ utilities/ translation_ import. py' translations/ utilities/ translation_ import. py 2009-08-05 13:11:00 +0000 translations/ utilities/ translation_ import. py 2009-09-14 09:12:58 +0000 database. sqlbase import cursor, quote cachedproperty import cachedproperty interfaces. person import ( lateItem. sequence, age.potemplate NULLS LAST poimport. statement_ timeout commit( )
> from lp.translations
> ExistingPOFileI
> from lp.translations
> @@ -67,6 +68,27 @@
> self.assertFals
> self.assertFals
>
> + def test_query_
> + # Test that super-fast-imports doesn't cache anything when it hits
> + # a timeout.
> +
> + # Override the config option to force a timeout error.
> + new_config = ("""
> + [poimport]
> + statement_timeout: timeout
> + """)
> + config.
> +
> + # Add a message that would otherwise be cached (see other tests).
> + current_message = self.factory.
> + pofile=self.pofile, is_imported=False)
> + message_data = self.getTransla
> + cached_file = ExistingPOFileI
> + self.assertFals
> +
> + # Restore the old configuration.
> + config.
> +
>
> def test_suite():
> return unittest.
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -18,8 +18,13 @@
>
> from operator import attrgetter
>
> +import transaction
> +
> +from canonical.config import config
> from canonical.
>
> +from storm.exceptions import TimeoutError
> +
> from canonical.
> from lp.registry.
> IPersonSet,
> @@ -119,7 +124,6 @@
> # Pre-fill self.messages and self.imported with data.
> self._fetchDBRows()
>
> -
> def _fetchDBRows(self):
> msgstr_joins = [
> "LEFT OUTER JOIN POTranslation pt%d "
> @@ -168,8 +172,32 @@
> TranslationTemp
> TranslationMess
> ''' % substitutions
> +
> cur = cursor()
> - cur.execute(sql)
> + try:
> + # XXX 2009-09-14 DaniloSegan (bug #408718):
> + # this statement causes postgres to eat the diskspace
> + # from time to time. Let's wrap it up in a timeout.
> + timeout = config.
> +
> + # We have to commit what we've got so far or we'll lose
> + # it when we hit TimeoutError.
> + transaction.
> +
> + if timeout == 'timeout':
> + # This is used in tests.
> + query = "SELECT pg_sleep(2)"
> + timeout = '1s'
> + else:
> + timeout = 1000 * int(timeout)
> + query = sql
> + cur.execute("SET statement_timeout to %s" % quote(timeout))
> + cur.execute(query)
> + except TimeoutError:
> + # Restart the transaction and return empty SelectResults.
> + transaction.abort()
> + transaction.begin()
> + cur.execute("SELECT 1 WHERE 1=0")
As you mentioned on IRC, you should reset the statement_timeout back to
what it was (if that is not done by abort() ?). Please extend the test
to check that, too.
Also, could you consider using EmptyResultSet instead of such useless
queries, please? ;)
> rows = cur.fetchall() tants.MAX_ PLURAL_ FORMS == 6, (
>
> assert TranslationCons
>
Thanks!
Henning
-----BEGIN PGP SIGNATURE----- enigmail. mozdev. org
uGY8ACgkQBT3oW1 L17ijQYQCg4/ O+WFfckuMG/ Y3ug+/jLpEP r0bS3bfuxQWd2tC se
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkq
t6UAniuipfgdRR2
=i+ew
-----END PGP SIGNATURE-----