Merge "Print number of rows archived per table in db archive_deleted_rows"
This commit is contained in:
commit
a1de711ff2
@ -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]``
|
||||
|
||||
|
@ -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 '
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
####################
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user