glance-manage can purge all deleted rows

When we want to purge all deleted rows
we use "glance-manage db purge" or
"glance-manage purge_images_table"
then we never know how many deleted rows are still in a table.
So we need to launch the command many times until
the command reports that 0 rows were deleted in every table.
It's inconvenient.
The patch introduced new valid value for "max_rows".
If "max_rows" equals -1 all deleted rows are purged.

Closes-Bug: 1702445
Change-Id: Ia9811d93b1c0b67a1b29a9e8ee3e0fc098c57d4a
This commit is contained in:
Mitya_Eremeev 2022-05-04 15:16:29 +03:00
parent 8271cde1e2
commit 360dc45680
5 changed files with 46 additions and 18 deletions

View File

@ -184,7 +184,8 @@ This command takes two optional parameters:
than *NUM* days. The default is 30 days.
--max_rows NUM Purge a maximum of *NUM* rows from each table.
The default is 100.
The default is 100. All deleted rows are purged if equals
-1
Purging the Images Table
@ -212,7 +213,8 @@ It takes two optional parameters:
than *NUM* days. The default is 180 days.
--max_rows NUM Purge a maximum of *NUM* rows from the **images** table.
The default is 100.
The default is 100. All deleted rows are purged if equals
-1
It is possible for this command to fail with an IntegrityError saying
something like "Cannot delete or update a parent row: a foreign key

View File

@ -339,8 +339,8 @@ class DbCommands(object):
sys.exit(_("Must supply a non-negative value for age."))
if age_in_days >= (int(time.time()) / 86400):
sys.exit(_("Maximal age is count of days since epoch."))
if max_rows < 1:
sys.exit(_("Minimal rows limit is 1."))
if max_rows < -1:
sys.exit(_("Minimal rows limit is -1."))
ctx = context.get_admin_context(show_deleted=True)
try:
if purge_images_only:
@ -357,7 +357,8 @@ class DbCommands(object):
@args('--age_in_days', type=int,
help='Purge deleted rows older than age in days')
@args('--max_rows', type=int,
help='Limit number of records to delete')
help='Limit number of records to delete. All deleted rows will be '
'purged if equals -1.')
def purge(self, age_in_days=30, max_rows=100):
"""Purge deleted rows older than a given age from glance tables."""
self._purge(age_in_days, max_rows)
@ -365,7 +366,8 @@ class DbCommands(object):
@args('--age_in_days', type=int,
help='Purge deleted rows older than age in days')
@args('--max_rows', type=int,
help='Limit number of records to delete')
help='Limit number of records to delete. All deleted rows will be '
'purged if equals -1.')
def purge_images_table(self, age_in_days=180, max_rows=100):
"""Purge deleted rows older than a given age from images table."""
self._purge(age_in_days, max_rows, purge_images_only=True)

View File

@ -1510,9 +1510,12 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
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)
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)
if max_rows != -1:
deleted_task_info = deleted_task_info.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) '
@ -1556,9 +1559,10 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
column = tab.c.id
deleted_at_column = tab.c.deleted_at
query_delete = sql.select(
[column], deleted_at_column < deleted_age).order_by(
deleted_at_column).limit(max_rows)
query_delete = sql.select([column], deleted_at_column < deleted_age).\
order_by(deleted_at_column)
if max_rows != -1:
query_delete = query_delete.limit(max_rows)
delete_statement = DeleteFromSelect(tab, query_delete, column)
@ -1600,9 +1604,11 @@ def purge_deleted_rows_from_images(context, age_in_days, max_rows,
column = tab.c.id
deleted_at_column = tab.c.deleted_at
query_delete = sql.select(
[column], deleted_at_column < deleted_age).order_by(
deleted_at_column).limit(max_rows)
query_delete = sql.\
select([column], deleted_at_column < deleted_age).\
order_by(deleted_at_column)
if max_rows != -1:
query_delete = query_delete.limit(max_rows)
delete_statement = DeleteFromSelect(tab, query_delete, column)

View File

@ -41,9 +41,9 @@ class DBCommandsTestCase(test_utils.BaseTestCase):
self.commands.purge(0, 100)
mock_db_purge.assert_called_once_with(self.context, 0, 100)
def test_purge_command_negative_rows(self):
exit = self.assertRaises(SystemExit, self.commands.purge, 1, -1)
self.assertEqual("Minimal rows limit is 1.", exit.code)
def test_purge_command_rows_less_minus_one(self):
exit = self.assertRaises(SystemExit, self.commands.purge, 1, -2)
self.assertEqual("Minimal rows limit is -1.", exit.code)
def test_purge_invalid_age_in_days(self):
age_in_days = 'abcd'
@ -86,3 +86,17 @@ class DBCommandsTestCase(test_utils.BaseTestCase):
exit = self.assertRaises(SystemExit, self.commands.purge, 10, 100)
self.assertEqual("Purge command failed, check glance-manage logs"
" for more details.", exit.code)
@mock.patch.object(db_api, 'purge_deleted_rows')
@mock.patch.object(context, 'get_admin_context')
def test_purge_command_purge_all(self, mock_context, mock_db_purge):
mock_context.return_value = self.context
self.commands.purge(max_rows=-1)
mock_db_purge.assert_called_once_with(self.context, 30, -1)
@mock.patch.object(db_api, 'purge_deleted_rows_from_images')
@mock.patch.object(context, 'get_admin_context')
def test_purge_images_table_purge_all(self, mock_context, mock_db_purge):
mock_context.return_value = self.context
self.commands.purge_images_table(max_rows=-1)
mock_db_purge.assert_called_once_with(self.context, 180, -1)

View File

@ -0,0 +1,4 @@
---
features:
- |
"glance-manage" purges all deleted rows if "--max_rows" equals -1