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
1=== modified file 'lib/lp/registry/doc/convert-person-to-team.txt'
2--- lib/lp/registry/doc/convert-person-to-team.txt 2011-12-30 06:14:56 +0000
3+++ lib/lp/registry/doc/convert-person-to-team.txt 2012-04-05 06:30:43 +0000
4@@ -25,7 +25,7 @@
5 0
6
7 # The script already committed its transaction but this test runs
8- # the LaunchpadFunctionalLayer which, in turn, uses the SERIALIZABLE
9+ # the LaunchpadFunctionalLayer which, in turn, uses the REPEATABLE READ
10 # isolation level, so we need to forcibly begin another transaction here.
11 >>> import transaction; transaction.abort()
12
13
14=== modified file 'lib/lp/services/config/schema-lazr.conf'
15--- lib/lp/services/config/schema-lazr.conf 2012-03-27 02:20:56 +0000
16+++ lib/lp/services/config/schema-lazr.conf 2012-04-05 06:30:43 +0000
17@@ -542,7 +542,7 @@
18 # will not be used.
19 max_usable_lag: 120
20
21-isolation_level: serializable
22+isolation_level: repeatable_read
23
24 # SQL statement timeout in milliseconds. If a statement
25 # takes longer than this to execute, then it will be aborted.
26
27=== modified file 'lib/lp/services/config/tests/test_database_config.py'
28--- lib/lp/services/config/tests/test_database_config.py 2012-01-01 02:58:52 +0000
29+++ lib/lp/services/config/tests/test_database_config.py 2012-04-05 06:30:43 +0000
30@@ -21,7 +21,7 @@
31 # dbuser and isolation_level can be overridden at runtime.
32 dbc = DatabaseConfig()
33 self.assertEqual('launchpad_main', dbc.dbuser)
34- self.assertEqual('serializable', dbc.isolation_level)
35+ self.assertEqual('repeatable_read', dbc.isolation_level)
36
37 # dbuser and isolation_level overrides both work.
38 dbc.override(dbuser='not_launchpad', isolation_level='autocommit')
39@@ -36,7 +36,7 @@
40 # Overriding with None removes the override.
41 dbc.override(dbuser=None, isolation_level=None)
42 self.assertEqual('launchpad_main', dbc.dbuser)
43- self.assertEqual('serializable', dbc.isolation_level)
44+ self.assertEqual('repeatable_read', dbc.isolation_level)
45
46 def test_reset(self):
47 # reset() removes any overrides.
48
49=== modified file 'lib/lp/services/database/multitablecopy.py'
50--- lib/lp/services/database/multitablecopy.py 2011-12-30 06:47:17 +0000
51+++ lib/lp/services/database/multitablecopy.py 2012-04-05 06:30:43 +0000
52@@ -158,7 +158,7 @@
53
54 This stage will lock the rows that are being inserted in the source
55 tables, if the database is so inclined (e.g. when using postgres with
56- SERIALIZABLE isolation level). For that reason, the pouring is done in
57+ REPEATABLE READ isolation level). For that reason, the pouring is done in
58 smaller, controlled batches. If you give the object a database
59 transaction to work with, that transaction will be committed and restarted
60 between batches.
61
62=== modified file 'lib/lp/services/database/sqlbase.py'
63--- lib/lp/services/database/sqlbase.py 2012-03-27 13:38:55 +0000
64+++ lib/lp/services/database/sqlbase.py 2012-04-05 06:30:43 +0000
65@@ -14,6 +14,7 @@
66 'ISOLATION_LEVEL_AUTOCOMMIT',
67 'ISOLATION_LEVEL_DEFAULT',
68 'ISOLATION_LEVEL_READ_COMMITTED',
69+ 'ISOLATION_LEVEL_REPEATABLE_READ',
70 'ISOLATION_LEVEL_SERIALIZABLE',
71 'quote',
72 'quote_like',
73@@ -33,6 +34,7 @@
74 from psycopg2.extensions import (
75 ISOLATION_LEVEL_AUTOCOMMIT,
76 ISOLATION_LEVEL_READ_COMMITTED,
77+ ISOLATION_LEVEL_REPEATABLE_READ,
78 ISOLATION_LEVEL_SERIALIZABLE,
79 )
80 import pytz
81
82=== modified file 'lib/lp/services/database/tests/script_isolation.py'
83--- lib/lp/services/database/tests/script_isolation.py 2011-12-30 06:20:00 +0000
84+++ lib/lp/services/database/tests/script_isolation.py 2012-04-05 06:30:43 +0000
85@@ -44,6 +44,6 @@
86 disconnect_stores()
87 check()
88
89-dbconfig.override(isolation_level='serializable')
90+dbconfig.override(isolation_level='repeatable_read')
91 disconnect_stores()
92 check()
93
94=== modified file 'lib/lp/services/database/tests/test_isolation_changes.py'
95--- lib/lp/services/database/tests/test_isolation_changes.py 2011-12-30 06:20:00 +0000
96+++ lib/lp/services/database/tests/test_isolation_changes.py 2012-04-05 06:30:43 +0000
97@@ -74,6 +74,10 @@
98 set_isolation_level('read_committed')
99 self.failUnlessEqual(self.getCurrentIsolation(), 'read committed')
100
101+ def test_repeatableRead(self):
102+ set_isolation_level('repeatable_read')
103+ self.failUnlessEqual(self.getCurrentIsolation(), 'repeatable read')
104+
105 def test_serializable(self):
106 set_isolation_level('serializable')
107 self.failUnlessEqual(self.getCurrentIsolation(), 'serializable')
108@@ -113,8 +117,8 @@
109 self.failUnlessEqual(script_output, dedent("""\
110 read committed
111 read committed
112- serializable
113- serializable
114+ repeatable read
115+ repeatable read
116 """))
117
118 def test_connect(self):
119
120=== modified file 'lib/lp/services/webapp/adapter.py'
121--- lib/lp/services/webapp/adapter.py 2012-03-06 23:39:08 +0000
122+++ lib/lp/services/webapp/adapter.py 2012-04-05 06:30:43 +0000
123@@ -25,6 +25,7 @@
124 from psycopg2.extensions import (
125 ISOLATION_LEVEL_AUTOCOMMIT,
126 ISOLATION_LEVEL_READ_COMMITTED,
127+ ISOLATION_LEVEL_REPEATABLE_READ,
128 ISOLATION_LEVEL_SERIALIZABLE,
129 QueryCanceledError,
130 )
131@@ -467,6 +468,7 @@
132 isolation_level_map = {
133 'autocommit': ISOLATION_LEVEL_AUTOCOMMIT,
134 'read_committed': ISOLATION_LEVEL_READ_COMMITTED,
135+ 'repeatable_read': ISOLATION_LEVEL_REPEATABLE_READ,
136 'serializable': ISOLATION_LEVEL_SERIALIZABLE,
137 }
138
139@@ -543,7 +545,7 @@
140 flags = _get_dirty_commit_flags()
141
142 if dbconfig.isolation_level is None:
143- self._isolation = ISOLATION_LEVEL_SERIALIZABLE
144+ self._isolation = ISOLATION_LEVEL_REPEATABLE_READ
145 else:
146 self._isolation = isolation_level_map[dbconfig.isolation_level]
147