Mercurial > p > roundup > code
comparison roundup/backends/back_postgresql.py @ 5118:57452bc6d989
issue2550853 - better error handling and cleanup on some postgres
tests by Stuart McGraw.
My postgres tests passed both before and after I applied his patch,
but the code change seems rational.
issue2086536 - back_postgresql: fixing pg_command and prefering
psycopg2. Patch done by Philipp Gortan (mephinet). His patch
also improves handling of retryable errors. Applied and
edited by John Rouillard. Edits included removing support for
psycopg1. See:
https://sourceforge.net/p/roundup/mailman/message/32855027/
for rational for dropping it
Again all 137 postgres tests pass.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sat, 02 Jul 2016 21:15:23 -0400 |
| parents | e74c3611b138 |
| children | 198b6e810c67 |
comparison
equal
deleted
inserted
replaced
| 5117:14abd0a67207 | 5118:57452bc6d989 |
|---|---|
| 10 import os, shutil, time | 10 import os, shutil, time |
| 11 ISOLATION_LEVEL_READ_UNCOMMITTED = None | 11 ISOLATION_LEVEL_READ_UNCOMMITTED = None |
| 12 ISOLATION_LEVEL_READ_COMMITTED = None | 12 ISOLATION_LEVEL_READ_COMMITTED = None |
| 13 ISOLATION_LEVEL_REPEATABLE_READ = None | 13 ISOLATION_LEVEL_REPEATABLE_READ = None |
| 14 ISOLATION_LEVEL_SERIALIZABLE = None | 14 ISOLATION_LEVEL_SERIALIZABLE = None |
| 15 try: | 15 |
| 16 import psycopg | 16 from psycopg2 import psycopg1 as psycopg |
| 17 from psycopg import QuotedString | 17 from psycopg2.extensions import QuotedString |
| 18 from psycopg import ProgrammingError | 18 from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED |
| 19 TransactionRollbackError = ProgrammingError | 19 from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED |
| 20 try: | 20 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ |
| 21 from psycopg.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED | 21 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE |
| 22 from psycopg.extensions import ISOLATION_LEVEL_READ_COMMITTED | 22 from psycopg2.psycopg1 import ProgrammingError |
| 23 from psycopg.extensions import ISOLATION_LEVEL_REPEATABLE_READ | 23 from psycopg2.extensions import TransactionRollbackError |
| 24 from psycopg.extensions import ISOLATION_LEVEL_SERIALIZABLE | 24 |
| 25 except ImportError: | |
| 26 pass | |
| 27 except: | |
| 28 from psycopg2 import psycopg1 as psycopg | |
| 29 from psycopg2.extensions import QuotedString | |
| 30 from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED | |
| 31 from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED | |
| 32 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ | |
| 33 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE | |
| 34 from psycopg2.psycopg1 import ProgrammingError | |
| 35 from psycopg2.extensions import TransactionRollbackError | |
| 36 import logging | 25 import logging |
| 37 | 26 |
| 38 from roundup import hyperdb, date | 27 from roundup import hyperdb, date |
| 39 from roundup.backends import rdbms_common | 28 from roundup.backends import rdbms_common |
| 40 from roundup.backends import sessions_rdbms | 29 from roundup.backends import sessions_rdbms |
| 106 | 95 |
| 107 If there is a concurrent update, retry the command. | 96 If there is a concurrent update, retry the command. |
| 108 ''' | 97 ''' |
| 109 try: | 98 try: |
| 110 cursor.execute(command) | 99 cursor.execute(command) |
| 111 except psycopg.ProgrammingError, err: | 100 except psycopg.DatabaseError, err: |
| 112 response = str(err).split('\n')[0] | 101 response = str(err).split('\n')[0] |
| 113 if response.find('FATAL') != -1: | 102 if "FATAL" not in response : |
| 114 raise RuntimeError(response) | 103 msgs = ( |
| 115 else: | |
| 116 msgs = [ | |
| 117 'is being accessed by other users', | 104 'is being accessed by other users', |
| 118 'could not serialize access due to concurrent update', | 105 'could not serialize access due to concurrent update', |
| 119 ] | 106 ) |
| 120 can_retry = 0 | 107 for msg in msgs : |
| 121 for msg in msgs: | 108 if msg in response : |
| 122 if response.find(msg) == -1: | 109 time.sleep(0.1) |
| 123 can_retry = 1 | 110 return 0 |
| 124 if can_retry: | 111 raise RuntimeError (response) |
| 125 time.sleep(1) | |
| 126 return 0 | |
| 127 raise RuntimeError(response) | |
| 128 return 1 | 112 return 1 |
| 129 | 113 |
| 130 def db_exists(config): | 114 def db_exists(config): |
| 131 """Check if database already exists""" | 115 """Check if database already exists""" |
| 132 db = connection_dict(config, 'database') | 116 db = connection_dict(config, 'database') |
| 192 | 176 |
| 193 self.conn, self.cursor = self.sql_open_connection() | 177 self.conn, self.cursor = self.sql_open_connection() |
| 194 | 178 |
| 195 try: | 179 try: |
| 196 self.load_dbschema() | 180 self.load_dbschema() |
| 197 except psycopg.ProgrammingError, message: | 181 except ProgrammingError, message: |
| 198 if str(message).find('schema') == -1: | 182 if str(message).find('schema') == -1: |
| 199 raise | 183 raise |
| 200 self.rollback() | 184 self.rollback() |
| 201 self.init_dbschema() | 185 self.init_dbschema() |
| 202 self.sql("CREATE TABLE schema (schema TEXT)") | 186 self.sql("CREATE TABLE schema (schema TEXT)") |
| 265 ''' | 249 ''' |
| 266 logging.getLogger('roundup.hyperdb').info('commit') | 250 logging.getLogger('roundup.hyperdb').info('commit') |
| 267 | 251 |
| 268 try: | 252 try: |
| 269 self.conn.commit() | 253 self.conn.commit() |
| 270 except psycopg.ProgrammingError, message: | 254 except ProgrammingError, message: |
| 271 # we've been instructed that this commit is allowed to fail | 255 # we've been instructed that this commit is allowed to fail |
| 272 if fail_ok and str(message).endswith('could not serialize ' | 256 if fail_ok and str(message).endswith('could not serialize ' |
| 273 'access due to concurrent update'): | 257 'access due to concurrent update'): |
| 274 logging.getLogger('roundup.hyperdb').info( | 258 logging.getLogger('roundup.hyperdb').info( |
| 275 'commit FAILED, but fail_ok') | 259 'commit FAILED, but fail_ok') |
