Merge lp:~wgrant/launchpad/9.1-serializable-is-special into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Stuart Bishop
Approved revision: no longer in the source branch.
Merged at revision: 15064
Proposed branch: lp:~wgrant/launchpad/9.1-serializable-is-special
Merge into: lp:launchpad
Prerequisite: lp:~wgrant/launchpad/psycopg2-2.4.4
Diff against target: 146 lines (+17/-9)
8 files modified
lib/lp/registry/doc/convert-person-to-team.txt (+1/-1)
lib/lp/services/config/schema-lazr.conf (+1/-1)
lib/lp/services/config/tests/test_database_config.py (+2/-2)
lib/lp/services/database/multitablecopy.py (+1/-1)
lib/lp/services/database/sqlbase.py (+2/-0)
lib/lp/services/database/tests/script_isolation.py (+1/-1)
lib/lp/services/database/tests/test_isolation_changes.py (+6/-2)
lib/lp/services/webapp/adapter.py (+3/-1)
To merge this branch: bzr merge lp:~wgrant/launchpad/9.1-serializable-is-special
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+100913@code.launchpad.net

Commit message

Switch appservers from SERIALIZABLE to REPEATABLE READ isolation. No change in behaviour under PostgreSQL 8.4, but much lighter on 9.1.

Description of the change

Appservers currently ask psycopg2 for SERIALIZABLE isolation. In PostgreSQL 9.1 this uses SSI, which is far more expensive than 8.4's implementation. 9.1's REPEATABLE READ is equivalent to 8.4's SERIALIZABLE, and in 8.4 REPEATABLE READ is just an alias for SERIALIZABLE, so we should use REPEATABLE READ instead.

This branch adds support for REPEATABLE READ, and changes SERIALIZABLE defaults to REPEATABLE READ.

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

This looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/registry/doc/convert-person-to-team.txt'
--- lib/lp/registry/doc/convert-person-to-team.txt 2011-12-30 06:14:56 +0000
+++ lib/lp/registry/doc/convert-person-to-team.txt 2012-04-05 06:30:43 +0000
@@ -25,7 +25,7 @@
25 025 0
2626
27 # The script already committed its transaction but this test runs27 # The script already committed its transaction but this test runs
28 # the LaunchpadFunctionalLayer which, in turn, uses the SERIALIZABLE28 # the LaunchpadFunctionalLayer which, in turn, uses the REPEATABLE READ
29 # isolation level, so we need to forcibly begin another transaction here.29 # isolation level, so we need to forcibly begin another transaction here.
30 >>> import transaction; transaction.abort()30 >>> import transaction; transaction.abort()
3131
3232
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2012-03-27 02:20:56 +0000
+++ lib/lp/services/config/schema-lazr.conf 2012-04-05 06:30:43 +0000
@@ -542,7 +542,7 @@
542# will not be used.542# will not be used.
543max_usable_lag: 120543max_usable_lag: 120
544544
545isolation_level: serializable545isolation_level: repeatable_read
546546
547# SQL statement timeout in milliseconds. If a statement547# SQL statement timeout in milliseconds. If a statement
548# takes longer than this to execute, then it will be aborted.548# takes longer than this to execute, then it will be aborted.
549549
=== modified file 'lib/lp/services/config/tests/test_database_config.py'
--- lib/lp/services/config/tests/test_database_config.py 2012-01-01 02:58:52 +0000
+++ lib/lp/services/config/tests/test_database_config.py 2012-04-05 06:30:43 +0000
@@ -21,7 +21,7 @@
21 # dbuser and isolation_level can be overridden at runtime.21 # dbuser and isolation_level can be overridden at runtime.
22 dbc = DatabaseConfig()22 dbc = DatabaseConfig()
23 self.assertEqual('launchpad_main', dbc.dbuser)23 self.assertEqual('launchpad_main', dbc.dbuser)
24 self.assertEqual('serializable', dbc.isolation_level)24 self.assertEqual('repeatable_read', dbc.isolation_level)
2525
26 # dbuser and isolation_level overrides both work.26 # dbuser and isolation_level overrides both work.
27 dbc.override(dbuser='not_launchpad', isolation_level='autocommit')27 dbc.override(dbuser='not_launchpad', isolation_level='autocommit')
@@ -36,7 +36,7 @@
36 # Overriding with None removes the override.36 # Overriding with None removes the override.
37 dbc.override(dbuser=None, isolation_level=None)37 dbc.override(dbuser=None, isolation_level=None)
38 self.assertEqual('launchpad_main', dbc.dbuser)38 self.assertEqual('launchpad_main', dbc.dbuser)
39 self.assertEqual('serializable', dbc.isolation_level)39 self.assertEqual('repeatable_read', dbc.isolation_level)
4040
41 def test_reset(self):41 def test_reset(self):
42 # reset() removes any overrides.42 # reset() removes any overrides.
4343
=== modified file 'lib/lp/services/database/multitablecopy.py'
--- lib/lp/services/database/multitablecopy.py 2011-12-30 06:47:17 +0000
+++ lib/lp/services/database/multitablecopy.py 2012-04-05 06:30:43 +0000
@@ -158,7 +158,7 @@
158158
159 This stage will lock the rows that are being inserted in the source159 This stage will lock the rows that are being inserted in the source
160 tables, if the database is so inclined (e.g. when using postgres with160 tables, if the database is so inclined (e.g. when using postgres with
161 SERIALIZABLE isolation level). For that reason, the pouring is done in161 REPEATABLE READ isolation level). For that reason, the pouring is done in
162 smaller, controlled batches. If you give the object a database162 smaller, controlled batches. If you give the object a database
163 transaction to work with, that transaction will be committed and restarted163 transaction to work with, that transaction will be committed and restarted
164 between batches.164 between batches.
165165
=== modified file 'lib/lp/services/database/sqlbase.py'
--- lib/lp/services/database/sqlbase.py 2012-03-27 13:38:55 +0000
+++ lib/lp/services/database/sqlbase.py 2012-04-05 06:30:43 +0000
@@ -14,6 +14,7 @@
14 'ISOLATION_LEVEL_AUTOCOMMIT',14 'ISOLATION_LEVEL_AUTOCOMMIT',
15 'ISOLATION_LEVEL_DEFAULT',15 'ISOLATION_LEVEL_DEFAULT',
16 'ISOLATION_LEVEL_READ_COMMITTED',16 'ISOLATION_LEVEL_READ_COMMITTED',
17 'ISOLATION_LEVEL_REPEATABLE_READ',
17 'ISOLATION_LEVEL_SERIALIZABLE',18 'ISOLATION_LEVEL_SERIALIZABLE',
18 'quote',19 'quote',
19 'quote_like',20 'quote_like',
@@ -33,6 +34,7 @@
33from psycopg2.extensions import (34from psycopg2.extensions import (
34 ISOLATION_LEVEL_AUTOCOMMIT,35 ISOLATION_LEVEL_AUTOCOMMIT,
35 ISOLATION_LEVEL_READ_COMMITTED,36 ISOLATION_LEVEL_READ_COMMITTED,
37 ISOLATION_LEVEL_REPEATABLE_READ,
36 ISOLATION_LEVEL_SERIALIZABLE,38 ISOLATION_LEVEL_SERIALIZABLE,
37 )39 )
38import pytz40import pytz
3941
=== modified file 'lib/lp/services/database/tests/script_isolation.py'
--- lib/lp/services/database/tests/script_isolation.py 2011-12-30 06:20:00 +0000
+++ lib/lp/services/database/tests/script_isolation.py 2012-04-05 06:30:43 +0000
@@ -44,6 +44,6 @@
44disconnect_stores()44disconnect_stores()
45check()45check()
4646
47dbconfig.override(isolation_level='serializable')47dbconfig.override(isolation_level='repeatable_read')
48disconnect_stores()48disconnect_stores()
49check()49check()
5050
=== modified file 'lib/lp/services/database/tests/test_isolation_changes.py'
--- lib/lp/services/database/tests/test_isolation_changes.py 2011-12-30 06:20:00 +0000
+++ lib/lp/services/database/tests/test_isolation_changes.py 2012-04-05 06:30:43 +0000
@@ -74,6 +74,10 @@
74 set_isolation_level('read_committed')74 set_isolation_level('read_committed')
75 self.failUnlessEqual(self.getCurrentIsolation(), 'read committed')75 self.failUnlessEqual(self.getCurrentIsolation(), 'read committed')
7676
77 def test_repeatableRead(self):
78 set_isolation_level('repeatable_read')
79 self.failUnlessEqual(self.getCurrentIsolation(), 'repeatable read')
80
77 def test_serializable(self):81 def test_serializable(self):
78 set_isolation_level('serializable')82 set_isolation_level('serializable')
79 self.failUnlessEqual(self.getCurrentIsolation(), 'serializable')83 self.failUnlessEqual(self.getCurrentIsolation(), 'serializable')
@@ -113,8 +117,8 @@
113 self.failUnlessEqual(script_output, dedent("""\117 self.failUnlessEqual(script_output, dedent("""\
114 read committed118 read committed
115 read committed119 read committed
116 serializable120 repeatable read
117 serializable121 repeatable read
118 """))122 """))
119123
120 def test_connect(self):124 def test_connect(self):
121125
=== modified file 'lib/lp/services/webapp/adapter.py'
--- lib/lp/services/webapp/adapter.py 2012-03-06 23:39:08 +0000
+++ lib/lp/services/webapp/adapter.py 2012-04-05 06:30:43 +0000
@@ -25,6 +25,7 @@
25from psycopg2.extensions import (25from psycopg2.extensions import (
26 ISOLATION_LEVEL_AUTOCOMMIT,26 ISOLATION_LEVEL_AUTOCOMMIT,
27 ISOLATION_LEVEL_READ_COMMITTED,27 ISOLATION_LEVEL_READ_COMMITTED,
28 ISOLATION_LEVEL_REPEATABLE_READ,
28 ISOLATION_LEVEL_SERIALIZABLE,29 ISOLATION_LEVEL_SERIALIZABLE,
29 QueryCanceledError,30 QueryCanceledError,
30 )31 )
@@ -467,6 +468,7 @@
467isolation_level_map = {468isolation_level_map = {
468 'autocommit': ISOLATION_LEVEL_AUTOCOMMIT,469 'autocommit': ISOLATION_LEVEL_AUTOCOMMIT,
469 'read_committed': ISOLATION_LEVEL_READ_COMMITTED,470 'read_committed': ISOLATION_LEVEL_READ_COMMITTED,
471 'repeatable_read': ISOLATION_LEVEL_REPEATABLE_READ,
470 'serializable': ISOLATION_LEVEL_SERIALIZABLE,472 'serializable': ISOLATION_LEVEL_SERIALIZABLE,
471 }473 }
472474
@@ -543,7 +545,7 @@
543 flags = _get_dirty_commit_flags()545 flags = _get_dirty_commit_flags()
544546
545 if dbconfig.isolation_level is None:547 if dbconfig.isolation_level is None:
546 self._isolation = ISOLATION_LEVEL_SERIALIZABLE548 self._isolation = ISOLATION_LEVEL_REPEATABLE_READ
547 else:549 else:
548 self._isolation = isolation_level_map[dbconfig.isolation_level]550 self._isolation = isolation_level_map[dbconfig.isolation_level]
549551