Merge "Fix for FK constraint violation"
This commit is contained in:
commit
3d52684346
|
@ -1322,6 +1322,35 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
|
||||||
continue
|
continue
|
||||||
if hasattr(model_class, 'deleted'):
|
if hasattr(model_class, 'deleted'):
|
||||||
tables.append(model_class.__tablename__)
|
tables.append(model_class.__tablename__)
|
||||||
|
|
||||||
|
# First force purging of records that are not soft deleted but
|
||||||
|
# are referencing soft deleted tasks/images records (e.g. task_info
|
||||||
|
# records). Then purge all soft deleted records in glance tables in the
|
||||||
|
# right order to avoid FK constraint violation.
|
||||||
|
t = Table("tasks", metadata, autoload=True)
|
||||||
|
ti = Table("task_info", metadata, autoload=True)
|
||||||
|
joined_rec = ti.join(t, t.c.id == ti.c.task_id)
|
||||||
|
deleted_task_info = sql.select([ti.c.task_id],
|
||||||
|
t.c.deleted_at < deleted_age).\
|
||||||
|
select_from(joined_rec).order_by(t.c.deleted_at).limit(max_rows)
|
||||||
|
delete_statement = DeleteFromSelect(ti, deleted_task_info,
|
||||||
|
ti.c.task_id)
|
||||||
|
LOG.info(_LI('Purging deleted rows older than %(age_in_days)d day(s) '
|
||||||
|
'from table %(tbl)s'),
|
||||||
|
{'age_in_days': age_in_days, 'tbl': ti})
|
||||||
|
try:
|
||||||
|
with session.begin():
|
||||||
|
result = session.execute(delete_statement)
|
||||||
|
except (db_exception.DBError, db_exception.DBReferenceError) as ex:
|
||||||
|
LOG.exception(_LE('DBError detected when force purging '
|
||||||
|
'table=%(table)s: %(error)s'),
|
||||||
|
{'table': ti, 'error': six.text_type(ex)})
|
||||||
|
raise
|
||||||
|
|
||||||
|
rows = result.rowcount
|
||||||
|
LOG.info(_LI('Deleted %(rows)d row(s) from table %(tbl)s'),
|
||||||
|
{'rows': rows, 'tbl': ti})
|
||||||
|
|
||||||
# get rid of FK constraints
|
# get rid of FK constraints
|
||||||
for tbl in ('images', 'tasks'):
|
for tbl in ('images', 'tasks'):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1946,6 +1946,7 @@ class DBPurgeTests(test_utils.BaseTestCase):
|
||||||
self.adm_context = context.get_admin_context(show_deleted=True)
|
self.adm_context = context.get_admin_context(show_deleted=True)
|
||||||
self.db_api = db_tests.get_db(self.config)
|
self.db_api = db_tests.get_db(self.config)
|
||||||
db_tests.reset_db(self.db_api)
|
db_tests.reset_db(self.db_api)
|
||||||
|
self.context = context.RequestContext(is_admin=True)
|
||||||
self.image_fixtures, self.task_fixtures = self.build_fixtures()
|
self.image_fixtures, self.task_fixtures = self.build_fixtures()
|
||||||
self.create_tasks(self.task_fixtures)
|
self.create_tasks(self.task_fixtures)
|
||||||
self.create_images(self.image_fixtures)
|
self.create_images(self.image_fixtures)
|
||||||
|
@ -2079,6 +2080,29 @@ class DBPurgeTests(test_utils.BaseTestCase):
|
||||||
images_rows = session.query(images).count()
|
images_rows = session.query(images).count()
|
||||||
self.assertEqual(4, images_rows)
|
self.assertEqual(4, images_rows)
|
||||||
|
|
||||||
|
def test_purge_task_info_with_refs_to_soft_deleted_tasks(self):
|
||||||
|
session = db_api.get_session()
|
||||||
|
engine = db_api.get_engine()
|
||||||
|
|
||||||
|
# check initial task and task_info row number are 3
|
||||||
|
tasks = self.db_api.task_get_all(self.adm_context)
|
||||||
|
self.assertEqual(3, len(tasks))
|
||||||
|
|
||||||
|
task_info = sqlalchemyutils.get_table(engine, 'task_info')
|
||||||
|
task_info_rows = session.query(task_info).count()
|
||||||
|
self.assertEqual(3, task_info_rows)
|
||||||
|
|
||||||
|
# purge soft deleted rows older than yesterday
|
||||||
|
self.db_api.purge_deleted_rows(self.context, 1, 5)
|
||||||
|
|
||||||
|
# check 1 row of task table is purged
|
||||||
|
tasks = self.db_api.task_get_all(self.adm_context)
|
||||||
|
self.assertEqual(2, len(tasks))
|
||||||
|
|
||||||
|
# and no task_info was left behind, 1 row purged
|
||||||
|
task_info_rows = session.query(task_info).count()
|
||||||
|
self.assertEqual(2, task_info_rows)
|
||||||
|
|
||||||
|
|
||||||
class TestVisibility(test_utils.BaseTestCase):
|
class TestVisibility(test_utils.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue