fix create_or_update logic to avoid rollbacks

check if entry exists rather than blindly adding entries to table.
this will avoid unnecessary rollback overhead.

Closes-Bug: #1295504
Change-Id: I923cc35ed4c9155ffa04ac189555cdbcb38bcbcf
This commit is contained in:
Gordon Chung 2014-03-20 22:46:37 -04:00
parent f2019732bc
commit 21237b333c
1 changed files with 19 additions and 36 deletions

View File

@ -272,56 +272,39 @@ class Connection(base.Connection):
def _create_or_update(session, model_class, _id, source=None, **kwargs):
if not _id:
return None
try:
# create a nested session for the case of two call of
# record_metering_data run in parallel to not fail the
# record of this sample
# (except for sqlite, that doesn't support nested
# transaction and doesn't have concurrency problem)
nested = session.connection().dialect.name != 'sqlite'
with session.begin(subtransactions=True):
obj = session.query(model_class).get(str(_id))
if obj is None:
obj = model_class(id=str(_id))
session.add(obj)
# raise dbexc.DBDuplicateEntry manually for sqlite
# to not break the current session
if not nested and session.query(model_class).get(str(_id)):
raise dbexc.DBDuplicateEntry()
with session.begin(nested=nested,
subtransactions=not nested):
obj = model_class(id=str(_id))
session.add(obj)
if source and not filter(lambda x: x.id == source.id,
obj.sources):
obj.sources.append(source)
for k in kwargs:
setattr(obj, k, kwargs[k])
except dbexc.DBDuplicateEntry:
# requery the object from the db if this is an other
# parallel/previous call of record_metering_data that
# have successfully created this object
obj = session.query(model_class).get(str(_id))
# update the object
if source and not filter(lambda x: x.id == source.id, obj.sources):
obj.sources.append(source)
for k in kwargs:
setattr(obj, k, kwargs[k])
obj = Connection._create_or_update(session, model_class,
_id, source, **kwargs)
return obj
@staticmethod
def _create_meter(session, name, type, unit):
try:
nested = session.connection().dialect.name != 'sqlite'
if not nested and session.query(models.Meter)\
with session.begin(subtransactions=True):
obj = session.query(models.Meter)\
.filter(models.Meter.name == name)\
.filter(models.Meter.type == type)\
.filter(models.Meter.unit == unit).count() > 0:
raise dbexc.DBDuplicateEntry()
with session.begin(nested=nested,
subtransactions=not nested):
obj = models.Meter(name=name, type=type, unit=unit)
session.add(obj)
.filter(models.Meter.unit == unit).first()
if obj is None:
obj = models.Meter(name=name, type=type, unit=unit)
session.add(obj)
except dbexc.DBDuplicateEntry:
obj = session.query(models.Meter)\
.filter(models.Meter.name == name)\
.filter(models.Meter.type == type)\
.filter(models.Meter.unit == unit).first()
obj = Connection._create_meter(session, name, type, unit)
return obj