Merge lp:~therve/storm/postgres-repeatable-read into lp:storm

Proposed by Thomas Herve
Status: Merged
Merged at revision: 442
Proposed branch: lp:~therve/storm/postgres-repeatable-read
Merge into: lp:storm
Diff against target: 79 lines (+25/-7)
3 files modified
NEWS (+5/-0)
storm/databases/postgres.py (+7/-3)
tests/databases/postgres.py (+13/-4)
To merge this branch: bzr merge lp:~therve/storm/postgres-repeatable-read
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Jamu Kakar (community) Approve
Review via email: mp+99967@code.launchpad.net

Description of the change

The branch adds support for the 2 others serialization level in the URI, and it switches to repeatable read by default for Postgres 9. See http://wiki.postgresql.org/wiki/Serializable#PostgreSQL_Implementation for the reason why it makes sense. To have this support, psycopg2 2.4 needs to be used. Older versions will fallback to serializable.

The tests is fairly ugly, but I didn't any better idea...

To post a comment you must log in.
Revision history for this message
Jamu Kakar (jkakar) wrote :

This looks good to me, +1! One thought is that you could have some
surprised if you manually specify 'isolation=repeatable-read' in your
connection string and then subsequently connect to a version of
PostgreSQL you don't expect. I'm not really sure what we can do about
that though, so probably just need to be clear in our documentation
about what each isolation level means for different versions of
PostgreSQL.

review: Approve
Revision history for this message
Stuart Bishop (stub) wrote :

This can be simpler by always using repeatable read, no matter the PostgreSQL version. As the SQL standards defined the 4 levels, when an application requests an isolation the database needs to provide *at least* that much protection. PostgreSQL <9.0 supports setting the isolation level to 'repeatable read' and does the right thing by internally using an actual isolation protection of 'serializable'. It even reports the isolation level as 'repeatable read'. http://www.postgresql.org/docs/8.4/static/transaction-iso.html for details.

psycopg2 < 2.4 does seem to be broken in that it decided to bump up the isolation level itself, rather than leave it to PostgreSQL to make the decision. I'd suggest dropping support for < 2.4, except that Launchpad is still on 2.2 and keeping support makes my life easier :-)

443. By Thomas Herve

Remove the dynamic setting, and use REPEATABLE READ everywhere

Revision history for this message
Thomas Herve (therve) wrote :

Thanks for the insights, I made the changes accordingly. If you use psycogp2 < 2.4 it keeps the same behavior everywhere. Starting 2.4 it uses REPEATABLE READ everywhere, which is equivalent with serializable on Postgres < 9, but different starting with 9.

444. By Thomas Herve

Add NEWS statement

Revision history for this message
Stuart Bishop (stub) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2012-03-27 10:45:17 +0000
3+++ NEWS 2012-03-30 08:45:23 +0000
4@@ -33,6 +33,11 @@
5 - Add a new Distinct expression for pre-pending the 'DISTINCT' token to
6 SQL expressions that support it (like columns).
7
8+- Switch to REPEATABLE READ as isolation level for Postgres. If you use
9+ psycopg2 < 2.4, it doesn't change anything. For psycopg2 2.4 and newer, it
10+ will keep the same behavior on Postgres < 9 as it's equivalent to
11+ SERIALIZABLE, but it will be less strict on Postgres >= 9.
12+
13 Bug fixes
14 ---------
15
16
17=== modified file 'storm/databases/postgres.py'
18--- storm/databases/postgres.py 2012-03-10 15:16:18 +0000
19+++ storm/databases/postgres.py 2012-03-30 08:45:23 +0000
20@@ -345,12 +345,16 @@
21 "'psycopg2' >= %s not found. Found %s."
22 % (REQUIRED_PSYCOPG2_VERSION, PSYCOPG2_VERSION))
23 self._dsn = make_dsn(uri)
24- isolation = uri.options.get("isolation", "serializable")
25+ isolation = uri.options.get("isolation", "repeatable-read")
26 isolation_mapping = {
27 "autocommit": psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT,
28 "serializable": psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
29- "read-committed": psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED,
30- }
31+ "read-committed":
32+ psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED,
33+ "repeatable-read":
34+ psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ,
35+ "read-uncommitted":
36+ psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED}
37 try:
38 self._isolation = isolation_mapping[isolation]
39 except KeyError:
40
41=== modified file 'tests/databases/postgres.py'
42--- tests/databases/postgres.py 2012-03-08 14:01:31 +0000
43+++ tests/databases/postgres.py 2012-03-30 08:45:23 +0000
44@@ -553,8 +553,17 @@
45 connection.rollback()
46
47 def test_default_isolation(self):
48+ """
49+ The default isolation level is REPEATABLE READ, but it's only supported
50+ by psycopg2 2.4 and newer. Before, SERIALIZABLE is used instead.
51+ """
52 result = self.connection.execute("SHOW TRANSACTION ISOLATION LEVEL")
53- self.assertEquals(result.get_one()[0], u"serializable")
54+ import psycopg2
55+ psycopg2_version = psycopg2.__version__.split(None, 1)[0]
56+ if psycopg2_version < "2.4":
57+ self.assertEquals(result.get_one()[0], u"serializable")
58+ else:
59+ self.assertEquals(result.get_one()[0], u"repeatable read")
60
61 def test_unknown_serialization(self):
62 self.assertRaises(ValueError, create_database,
63@@ -696,13 +705,13 @@
64 "SELECT current_database()")
65
66 if has_psycopg:
67- import psycopg2._psycopg
68- psycopg2_version = psycopg2._psycopg.__version__.split(None, 1)[0]
69+ import psycopg2
70+ psycopg2_version = psycopg2.__version__.split(None, 1)[0]
71 if psycopg2_version in ("2.4", "2.4.1", "2.4.2"):
72 test_pgbouncer_stopped.skip = (
73 "Fails with pyscopg2 %s; see https://bugs.launchpad"
74 ".net/storm/+bug/900702.") % psycopg2_version
75-
76+
77
78 if has_fixtures:
79 # Upgrade to full test case class with fixtures.

Subscribers

People subscribed via source and target branches

to status/vote changes: