Hello all,
We are facing a problem when using history_meta.py recipe.
It seems like two concurrent transactions read the same (id,version) tuple
at "#1" and then each one tries to insert a new row into the pbases_history
table with the same pk (id, version) combination (see #2)
By removing #2, the issue goes away but of course, there is no history kept
anywhere.
####### CODE SNIPPET WHERE THE ISSUE IS TRIGGERED
history_meta.py:
attr['version'] = obj.version # 1
hist = history_cls()
for key, value in attr.items():
setattr(hist, key, value)
session.add(hist) # 2
obj.version += 1
####### STACK TRACE:
140, in collection_post
p2model.DBSession.flush()
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py",
line 150, in do
return getattr(self.registry(), name)(*args, **kwargs)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
line 1919, in flush
self._flush(objects)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
line 2037, in _flush
transaction.rollback(_capture_exception=True)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py",
line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
line 2001, in _flush
flush_context.execute()
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py",
line 367, in execute
n.execute_aggregate(self, set_)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py",
line 459, in execute_aggregate
self.execute(uow)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py",
line 526, in execute
uow
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py",
line 65, in save_obj
mapper, table, insert)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py",
line 570, in _emit_insert_statements
execute(statement, multiparams)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py",
line 729, in execute
return meth(self, multiparams, params)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/sql/elements.py",
line 321, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py",
line 826, in _execute_clauseelement
compiled_sql, distilled_params
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py",
line 958, in _execute_context
context)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py",
line 1160, in _handle_dbapi_exception
exc_info
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py",
line 199, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py",
line 951, in _execute_context
context)
File
"/home/plannotate/.virtualenvs/P2v0.0.1/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py",
line 436, in do_execute
cursor.execute(statement, parameters)
IntegrityError: (IntegrityError) duplicate key value violates unique
constraint "pbases_history_pkey"
DETAIL: Key (id, version)=(125, 21) already exists.
####### MODEL
The simplified version of our model looks like this:
class PBase(Versioned, Base):
__tablename__ = 'pbases'
id = Column(Integer, primary_key=True)
uuid = Column(String(50), unique=True)
classname = Column(String(50))
__mapper_args__ = {
'polymorphic_identity' : 'PBase',
'polymorphic_on' : classname
}
class PDocument(PBase):
__tablename__ = 'pdocuments'
id = Column(Integer, ForeignKey('p2bases.id'), primary_key=True)
name = Column(String)
__mapper_args__ = {
'polymorphic_identity' : 'P2Document',
}
class PNote(PBase):
__tablename__ = 'pnotes'
id = Column(Integer, ForeignKey('p2bases.id'), primary_key=True)
comment = Column(String)
position = Column(Integer)
document_id = Column(Integer, ForeignKey('p2documents.id'))
document_version = Column(Integer, default=0)
document = relationship("PDocument", primaryjoin="PDocument.id ==
PNode.document_id",
backref=backref('pages', order_by=
"PNode.position", collection_class=ordering_list('position')))
__mapper_args__ = {
'polymorphic_identity' : 'PNote',
}
@event.listens_for(PNode.document_id, 'set', active_history=True)
def _on_note_set_document_id(note, new_doc_id, old_old_id, initiator):
doc = None
if new_doc_id:
doc = DBSession.query(PDocument).filter(PDocument.id ==
new_doc_id).one()
elif old_doc_id:
page = DBSession.query(PDocument).filter(PDocument.id ==
old_doc_id).one()
if doc:
note.document_version = doc.version
####### SYSTEM CONFIG
PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu
4.8.2-19ubuntu1) 4.8.2, 64-bit
argparse (1.2.1)
beautifulsoup4 (4.3.2)
Chameleon (2.16)
colander (1.0b1)
cornice (0.17)
coverage (3.7.1)
Mako (1.0.0)
MarkupSafe (0.23)
nose (1.3.4)
p2server (0.0)
PasteDeploy (1.5.2)
pip (1.5.6)
psycopg2 (2.5.4)
Pygments (1.6)
pyramid (1.5.1)
pyramid-chameleon (0.3)
pyramid-debugtoolbar (2.2)
pyramid-mako (1.0.2)
pyramid-tm (0.7)
repoze.lru (0.6)
requests (2.4.3)
setuptools (3.6)
simplejson (3.6.4)
six (1.8.0)
SQLAlchemy (0.9.7)
transaction (1.4.3)
translationstring (1.1)
venusian (1.0)
waitress (0.8.9)
WebOb (1.4)
WebTest (2.0.16)
wsgiref (0.1.2)
zope.deprecation (4.1.1)
zope.interface (4.1.1)
zope.sqlalchemy (0.7.5)
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.