Merge "Print number of rows archived per table in db archive_deleted_rows"

This commit is contained in:
Jenkins 2015-11-12 15:09:29 +00:00 committed by Gerrit Code Review
commit a1de711ff2
6 changed files with 93 additions and 16 deletions

View File

@ -50,9 +50,11 @@ Nova Db
Sync the main database up to the most recent version. This is the standard way to create the db as well.
``nova-manage db archive_deleted_rows [--max_rows <number>]``
``nova-manage db archive_deleted_rows [--max_rows <number>] [--verbose]``
Move deleted rows from production tables to shadow tables.
Move deleted rows from production tables to shadow tables. Specifying
--verbose will print the results of the archive operation for any tables
that were changed.
``nova-manage db null_instance_uuid_scan [--delete]``

View File

@ -915,7 +915,9 @@ class DbCommands(object):
@args('--max_rows', metavar='<number>',
help='Maximum number of deleted rows to archive')
def archive_deleted_rows(self, max_rows):
@args('--verbose', action='store_true', dest='verbose', default=False,
help='Print how many rows were archived per table.')
def archive_deleted_rows(self, max_rows, verbose=False):
"""Move up to max_rows deleted rows from production tables to shadow
tables.
"""
@ -924,7 +926,13 @@ class DbCommands(object):
if max_rows < 0:
print(_("Must supply a positive value for max_rows"))
return(1)
db.archive_deleted_rows(max_rows)
table_to_rows_archived = db.archive_deleted_rows(max_rows)
if verbose:
if table_to_rows_archived:
cliutils.print_dict(table_to_rows_archived, _('Table'),
dict_value=_('Number of Rows Archived'))
else:
print(_('Nothing was archived.'))
@args('--delete', action='store_true', dest='delete',
help='If specified, automatically delete any records found where '

View File

@ -1899,7 +1899,17 @@ def archive_deleted_rows(max_rows=None):
"""Move up to max_rows rows from production tables to corresponding shadow
tables.
:returns: number of rows archived.
:returns: dict that maps table name to number of rows archived from that
table, for example:
::
{
'instances': 5,
'block_device_mapping': 5,
'pci_devices': 2,
}
"""
return IMPL.archive_deleted_rows(max_rows=max_rows)

View File

@ -6033,19 +6033,34 @@ def archive_deleted_rows(max_rows=None):
"""Move up to max_rows rows from production tables to the corresponding
shadow tables.
:returns: Number of rows archived.
:returns: dict that maps table name to number of rows archived from that
table, for example:
::
{
'instances': 5,
'block_device_mapping': 5,
'pci_devices': 2,
}
"""
table_to_rows_archived = {}
tablenames = []
for model_class in six.itervalues(models.__dict__):
if hasattr(model_class, "__tablename__"):
tablenames.append(model_class.__tablename__)
rows_archived = 0
total_rows_archived = 0
for tablename in tablenames:
rows_archived += _archive_deleted_rows_for_table(tablename,
max_rows=max_rows - rows_archived)
if rows_archived >= max_rows:
rows_archived = _archive_deleted_rows_for_table(
tablename, max_rows=max_rows - total_rows_archived)
total_rows_archived += rows_archived
# Only report results for tables that had updates.
if rows_archived:
table_to_rows_archived[tablename] = rows_archived
if total_rows_archived >= max_rows:
break
return rows_archived
return table_to_rows_archived
####################

View File

@ -8081,7 +8081,7 @@ class Ec2TestCase(test.TestCase):
self.ctxt, 100500)
class ArchiveTestCase(test.TestCase):
class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
def setUp(self):
super(ArchiveTestCase, self).setUp()
@ -8166,7 +8166,9 @@ class ArchiveTestCase(test.TestCase):
# Verify we have 0 in shadow
self.assertEqual(len(rows), 0)
# Archive 2 rows
db.archive_deleted_rows(max_rows=2)
results = db.archive_deleted_rows(max_rows=2)
expected = dict(instance_id_mappings=2)
self._assertEqualObjects(expected, results)
rows = self.conn.execute(qiim).fetchall()
# Verify we have 4 left in main
self.assertEqual(len(rows), 4)
@ -8174,7 +8176,9 @@ class ArchiveTestCase(test.TestCase):
# Verify we have 2 in shadow
self.assertEqual(len(rows), 2)
# Archive 2 more rows
db.archive_deleted_rows(max_rows=2)
results = db.archive_deleted_rows(max_rows=2)
expected = dict(instance_id_mappings=2)
self._assertEqualObjects(expected, results)
rows = self.conn.execute(qiim).fetchall()
# Verify we have 2 left in main
self.assertEqual(len(rows), 2)
@ -8182,7 +8186,9 @@ class ArchiveTestCase(test.TestCase):
# Verify we have 4 in shadow
self.assertEqual(len(rows), 4)
# Try to archive more, but there are no deleted rows left.
db.archive_deleted_rows(max_rows=2)
results = db.archive_deleted_rows(max_rows=2)
expected = dict()
self._assertEqualObjects(expected, results)
rows = self.conn.execute(qiim).fetchall()
# Verify we still have 2 left in main
self.assertEqual(len(rows), 2)

View File

@ -375,7 +375,7 @@ class VmCommandsTestCase(test.TestCase):
self.assertIn('fake-host', result)
class DBCommandsTestCase(test.TestCase):
class DBCommandsTestCase(test.NoDBTestCase):
def setUp(self):
super(DBCommandsTestCase, self).setUp()
self.commands = manage.DbCommands()
@ -383,6 +383,42 @@ class DBCommandsTestCase(test.TestCase):
def test_archive_deleted_rows_negative(self):
self.assertEqual(1, self.commands.archive_deleted_rows(-1))
@mock.patch.object(db, 'archive_deleted_rows',
return_value=dict(instances=10, consoles=5))
def _test_archive_deleted_rows(self, mock_db_archive, verbose=False):
self.useFixture(fixtures.MonkeyPatch('sys.stdout', StringIO()))
self.commands.archive_deleted_rows(20, verbose=verbose)
mock_db_archive.assert_called_once_with(20)
output = sys.stdout.getvalue()
if verbose:
expected = '''\
+-----------+-------------------------+
| Table | Number of Rows Archived |
+-----------+-------------------------+
| consoles | 5 |
| instances | 10 |
+-----------+-------------------------+
'''
self.assertEqual(expected, output)
else:
self.assertEqual(0, len(output))
def test_archive_deleted_rows(self):
# Tests that we don't show any table output (not verbose).
self._test_archive_deleted_rows()
def test_archive_deleted_rows_verbose(self):
# Tests that we get table output.
self._test_archive_deleted_rows(verbose=True)
@mock.patch.object(db, 'archive_deleted_rows', return_value={})
def test_archive_deleted_rows_verbose_no_results(self, mock_db_archive):
self.useFixture(fixtures.MonkeyPatch('sys.stdout', StringIO()))
self.commands.archive_deleted_rows(20, verbose=True)
mock_db_archive.assert_called_once_with(20)
output = sys.stdout.getvalue()
self.assertIn('Nothing was archived.', output)
@mock.patch.object(migration, 'db_null_instance_uuid_scan',
return_value={'foo': 0})
def test_null_instance_uuid_scan_no_records_found(self, mock_scan):