Merge lp:~unifield-team/unifield-server/sp115 into lp:unifield-server

Proposed by jftempo
Status: Merged
Merged at revision: 3443
Proposed branch: lp:~unifield-team/unifield-server/sp115
Merge into: lp:unifield-server
Diff against target: 125 lines (+60/-42)
1 file modified
bin/osv/osv.py (+60/-42)
To merge this branch: bzr merge lp:~unifield-team/unifield-server/sp115
Reviewer Review Type Date Requested Status
UniField Dev Team Pending
Review via email: mp+152396@code.launchpad.net
To post a comment you must log in.
3443. By jftempo

SP-115 [FIX] confirm_update: lock on row in relation "ir_sequence"
lp:~unifield-team/unifield-server/sp115

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/osv/osv.py'
--- bin/osv/osv.py 2011-05-25 13:26:12 +0000
+++ bin/osv/osv.py 2013-03-08 13:05:18 +0000
@@ -28,14 +28,19 @@
28import pooler28import pooler
29import copy29import copy
30import logging30import logging
31from psycopg2 import IntegrityError, errorcodes31from psycopg2 import IntegrityError, OperationalError, errorcodes
32from tools.func import wraps32from tools.func import wraps
33from tools.translate import translate33from tools.translate import translate
34import time
35import random
3436
35module_list = []37module_list = []
36module_class_list = {}38module_class_list = {}
37class_pool = {}39class_pool = {}
3840
41PG_CONCURRENCY_ERRORS_TO_RETRY = (errorcodes.LOCK_NOT_AVAILABLE, errorcodes.SERIALIZATION_FAILURE, errorcodes.DEADLOCK_DETECTED)
42MAX_TRIES_ON_CONCURRENCY_FAILURE = 7
43
39class except_osv(Exception):44class except_osv(Exception):
40 def __init__(self, name, value, exc_type='warning'):45 def __init__(self, name, value, exc_type='warning'):
41 self.name = name46 self.name = name
@@ -116,47 +121,60 @@
116 def _(src):121 def _(src):
117 return tr(src, 'code')122 return tr(src, 'code')
118123
119 try:124 tries = 0
120 if not pooler.get_pool(dbname)._ready:125 while True:
121 raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.')126 try:
122 return f(self, dbname, *args, **kwargs)127 if not pooler.get_pool(dbname)._ready:
123 except orm.except_orm, inst:128 raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.')
124 if inst.name == 'AccessError':129 return f(self, dbname, *args, **kwargs)
125 self.logger.debug("AccessError", exc_info=True)130 except OperationalError, e:
126 self.abortResponse(1, inst.name, 'warning', inst.value)131 # Automatically retry the typical transaction serialization errors
127 except except_osv, inst:132 if e.pgcode not in PG_CONCURRENCY_ERRORS_TO_RETRY:
128 self.abortResponse(1, inst.name, inst.exc_type, inst.value)133 raise
129 except IntegrityError, inst:134 if tries >= MAX_TRIES_ON_CONCURRENCY_FAILURE:
130 osv_pool = pooler.get_pool(dbname)135 self.logger.warning("%s, maximum number of tries reached" % e.pgcode)
131 for key in osv_pool._sql_error.keys():136 raise
132 if key in inst[0]:137 wait_time = random.uniform(0.0, 2 ** tries)
133 self.abortResponse(1, _('Constraint Error'), 'warning',138 tries += 1
134 tr(osv_pool._sql_error[key], 'sql_constraint') or inst[0])139 self.logger.info("%s, retrying %d/%d in %.04f sec..." % (e.pgcode, tries, MAX_TRIES_ON_CONCURRENCY_FAILURE, wait_time))
135 if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):140 time.sleep(wait_time)
136 msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set')141 except orm.except_orm, inst:
137 self.logger.debug("IntegrityError", exc_info=True)142 if inst.name == 'AccessError':
138 try:143 self.logger.debug("AccessError", exc_info=True)
139 errortxt = inst.pgerror.replace('«','"').replace('»','"')144 self.abortResponse(1, inst.name, 'warning', inst.value)
140 if '"public".' in errortxt:145 except except_osv, inst:
141 context = errortxt.split('"public".')[1]146 self.abortResponse(1, inst.name, inst.exc_type, inst.value)
142 model_name = table = context.split('"')[1]147 except IntegrityError, inst:
143 else:148 osv_pool = pooler.get_pool(dbname)
144 last_quote_end = errortxt.rfind('"')149 for key in osv_pool._sql_error.keys():
145 last_quote_begin = errortxt.rfind('"', 0, last_quote_end)150 if key in inst[0]:
146 model_name = table = errortxt[last_quote_begin+1:last_quote_end].strip()151 self.abortResponse(1, _('Constraint Error'), 'warning',
147 model = table.replace("_",".")152 tr(osv_pool._sql_error[key], 'sql_constraint') or inst[0])
148 model_obj = osv_pool.get(model)153 if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):
149 if model_obj:154 msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set')
150 model_name = model_obj._description or model_obj._name155 self.logger.debug("IntegrityError", exc_info=True)
151 msg += _('\n\n[object with reference: %s - %s]') % (model_name, model)156 try:
152 except Exception:157 errortxt = inst.pgerror.replace('«','"').replace('»','"')
153 pass158 if '"public".' in errortxt:
154 self.abortResponse(1, _('Integrity Error'), 'warning', msg)159 context = errortxt.split('"public".')[1]
155 else:160 model_name = table = context.split('"')[1]
156 self.abortResponse(1, _('Integrity Error'), 'warning', inst[0])161 else:
157 except Exception:162 last_quote_end = errortxt.rfind('"')
158 self.logger.exception("Uncaught exception")163 last_quote_begin = errortxt.rfind('"', 0, last_quote_end)
159 raise164 model_name = table = errortxt[last_quote_begin+1:last_quote_end].strip()
165 model = table.replace("_",".")
166 model_obj = osv_pool.get(model)
167 if model_obj:
168 model_name = model_obj._description or model_obj._name
169 msg += _('\n\n[object with reference: %s - %s]') % (model_name, model)
170 except Exception:
171 pass
172 self.abortResponse(1, _('Integrity Error'), 'warning', msg)
173 else:
174 self.abortResponse(1, _('Integrity Error'), 'warning', inst[0])
175 except Exception:
176 self.logger.exception("Uncaught exception")
177 raise
160178
161 return wrapper179 return wrapper
162180

Subscribers

People subscribed via source and target branches

to all changes: