Add indexes to tables

This adds indexes to most tables, and make some changes to keep
consistency

Change-Id: I6cd2a52f927cad98d70d7af3b52951782d6b2e22
This commit is contained in:
Zhenguo Niu 2017-07-13 13:44:26 +08:00
parent ec7d5d0d69
commit 00c8ed1122
7 changed files with 114 additions and 74 deletions

View File

@ -149,7 +149,7 @@ class InvalidUUID(Invalid):
class FlavorAlreadyExists(Conflict):
_msg_fmt = _("Flavor with uuid %(uuid)s already exists.")
_msg_fmt = _("Flavor with name %(name)s already exists.")
class FlavorNotFound(NotFound):

View File

@ -84,12 +84,12 @@ class Connection(object):
# Flavor access
@abc.abstractmethod
def flavor_access_add(self, context, flavor_id, project_id):
def flavor_access_add(self, context, flavor_uuid, project_id):
"""Add flavor access for project."""
@abc.abstractmethod
def flavor_access_get(self, context, flavor_id):
"""Get flavor access by flavor id."""
def flavor_access_get(self, context, flavor_uuid):
"""Get flavor access by flavor uuid."""
@abc.abstractmethod
def flavor_access_remove(self, context, flavor_id, project_id):

View File

@ -32,6 +32,7 @@ def upgrade():
'flavors',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
@ -39,7 +40,7 @@ def upgrade():
sa.Column('resource_traits', sa.Text(), nullable=True),
sa.Column('is_public', sa.Boolean(), nullable=False),
sa.Column('disabled', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('uuid'),
sa.PrimaryKeyConstraint('id'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
@ -48,10 +49,10 @@ def upgrade():
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('flavor_uuid', sa.String(length=36), nullable=True),
sa.Column('flavor_id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['flavor_uuid'],
['flavors.uuid']),
sa.ForeignKeyConstraint(['flavor_id'],
['flavors.id']),
sa.PrimaryKeyConstraint('id'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
@ -81,6 +82,8 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_index('servers_project_id_idx', 'servers', ['project_id'],
unique=False)
op.create_table(
'server_nics',
sa.Column('created_at', sa.DateTime(), nullable=True),
@ -96,6 +99,8 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_index('server_nics_server_uuid_idx', 'server_nics',
['server_uuid'], unique=False)
op.create_table(
'server_faults',
sa.Column('id', sa.Integer(), nullable=False),
@ -110,6 +115,8 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_index('server_faults_server_uuid_idx', 'server_faults',
['server_uuid'], unique=False)
op.create_table(
'quotas',
sa.Column('created_at', sa.DateTime(), nullable=True),
@ -141,6 +148,8 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_index('quota_usage_project_id_idx', 'quota_usages',
['project_id'], unique=False)
op.create_table(
'reservations',
sa.Column('created_at', sa.DateTime(), nullable=True),
@ -162,6 +171,8 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_index('reservations_project_id_idx', 'reservations',
['project_id'], unique=False)
op.create_table(
'key_pairs',
sa.Column('created_at', sa.DateTime(), nullable=True),

View File

@ -117,7 +117,7 @@ class Connection(api.Connection):
session.add(flavor)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.FlavorAlreadyExists(uuid=values['uuid'])
raise exception.FlavorAlreadyExists(name=values['name'])
return flavor
def flavor_get(self, context, flavor_uuid):
@ -163,13 +163,13 @@ class Connection(api.Connection):
def flavor_destroy(self, context, flavor_uuid):
with _session_for_write():
type_id = _type_get_id_from_type(context, flavor_uuid)
flavor_id = _get_id_from_flavor(context, flavor_uuid)
# Clean up all access related to this flavor
project_query = model_query(
context,
models.FlavorProjects).filter_by(
flavor_uuid=type_id)
flavor_id=flavor_id)
project_query.delete()
# Then delete the type record
@ -256,19 +256,21 @@ class Connection(api.Connection):
ref.update(values)
return ref
def flavor_access_get(self, context, flavor_id):
def flavor_access_get(self, context, flavor_uuid):
flavor_id = _get_id_from_flavor(context, flavor_uuid)
return _flavor_access_query(context, flavor_id)
def flavor_access_add(self, context, flavor_id, project_id):
def flavor_access_add(self, context, flavor_uuid, project_id):
flavor_id = _get_id_from_flavor(context, flavor_uuid)
access_ref = models.FlavorProjects()
access_ref.update({"flavor_uuid": flavor_id,
access_ref.update({"flavor_id": flavor_id,
"project_id": project_id})
with _session_for_write() as session:
try:
session.add(access_ref)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.FlavorAccessExists(flavor_id=flavor_id,
raise exception.FlavorAccessExists(flavor_id=flavor_uuid,
project_id=project_id)
return access_ref
@ -687,18 +689,18 @@ class Connection(api.Connection):
user_id=user_id).count()
def _type_get_id_from_type_query(context, type_id):
def _get_id_from_flavor_query(context, type_id):
return model_query(context, models.Flavors). \
filter_by(uuid=type_id)
def _type_get_id_from_type(context, type_id):
result = _type_get_id_from_type_query(context, type_id).first()
def _get_id_from_flavor(context, type_id):
result = _get_id_from_flavor_query(context, type_id).first()
if not result:
raise exception.FlavorNotFound(flavor_id=type_id)
return result.uuid
return result.id
def _flavor_access_query(context, flavor_id):
return model_query(context, models.FlavorProjects). \
filter_by(flavor_uuid=flavor_id)
filter_by(flavor_id=flavor_id)

View File

@ -21,7 +21,8 @@ from oslo_db import options as db_options
from oslo_db.sqlalchemy import models
from oslo_db.sqlalchemy import types as db_types
import six.moves.urllib.parse as urlparse
from sqlalchemy import Boolean, Column, DateTime, Enum, ForeignKey, Text
from sqlalchemy import (Boolean, Column, DateTime, Enum, ForeignKey,
Index, Text)
from sqlalchemy import orm
from sqlalchemy import schema, String, Integer
from sqlalchemy.dialects.mysql import MEDIUMTEXT
@ -68,6 +69,7 @@ class Server(Base):
__tablename__ = 'servers'
__table_args__ = (
Index('servers_project_id_idx', 'project_id'),
schema.UniqueConstraint('uuid', name='uniq_servers0uuid'),
table_args()
)
@ -134,7 +136,11 @@ class ServerNic(Base):
"""Represents the NIC info for servers."""
__tablename__ = 'server_nics'
server_uuid = Column(String(36), nullable=True)
__table_args__ = (
Index('server_nics_server_uuid_idx', 'server_uuid'),
table_args()
)
server_uuid = Column(String(36), ForeignKey('servers.uuid'))
port_id = Column(String(36), primary_key=True)
mac_address = Column(String(32), nullable=False)
network_id = Column(String(36), nullable=True)
@ -147,11 +153,38 @@ class ServerNic(Base):
primaryjoin='Server.uuid == ServerNic.server_uuid')
class ServerFault(Base):
"""Represents fault info for server"""
__tablename__ = "server_faults"
__table_args__ = (
Index('server_faults_server_uuid_idx', 'server_uuid'),
table_args()
)
id = Column(Integer, primary_key=True, nullable=False)
server_uuid = Column(String(36), ForeignKey('servers.uuid'))
code = Column(Integer(), nullable=False)
message = Column(String(255))
detail = Column(MediumText())
server = orm.relationship(
Server,
backref=orm.backref('server_faults', uselist=False),
foreign_keys=server_uuid,
primaryjoin='Server.uuid == ServerFault.server_uuid')
class Flavors(Base):
"""Represents possible types for servers."""
__tablename__ = 'flavors'
uuid = Column(String(36), primary_key=True)
__table_args__ = (
schema.UniqueConstraint("uuid", name="uniq_flavors0uuid"),
schema.UniqueConstraint("name", name="uniq_flavors0name"),
table_args()
)
id = Column(Integer, primary_key=True)
uuid = Column(String(36), nullable=False)
name = Column(String(255), nullable=False)
description = Column(MediumText())
resources = Column(db_types.JsonEncodedDict)
@ -171,37 +204,21 @@ class FlavorProjects(Base):
__tablename__ = 'flavor_projects'
__table_args__ = (
schema.UniqueConstraint(
'flavor_uuid', 'project_id',
name='uniq_flavor_projects0flavor_uuid0project_id'
'flavor_id', 'project_id',
name='uniq_flavor_projects0flavor_id0project_id'
),
table_args()
)
id = Column(Integer, primary_key=True)
flavor_uuid = Column(Integer, nullable=True)
flavor_id = Column(Integer, ForeignKey('flavors.id'),
nullable=True)
project_id = Column(String(36), nullable=True)
servers = orm.relationship(
flavors = orm.relationship(
Flavors,
backref=orm.backref('projects', uselist=False),
foreign_keys=flavor_uuid,
primaryjoin='FlavorProjects.flavor_uuid'
' == Flavors.uuid')
class ServerFault(Base):
"""Represents fault info for server"""
__tablename__ = "server_faults"
id = Column(Integer, primary_key=True, nullable=False)
server_uuid = Column(String(36), ForeignKey('servers.uuid'))
code = Column(Integer(), nullable=False)
message = Column(String(255))
detail = Column(MediumText())
server = orm.relationship(
Server,
backref=orm.backref('server_faults', uselist=False),
foreign_keys=server_uuid,
primaryjoin='Server.uuid == ServerFault.server_uuid')
foreign_keys=flavor_id,
primaryjoin='FlavorProjects.flavor_id'
' == Flavors.id')
class Quota(Base):
@ -227,6 +244,7 @@ class QuotaUsage(Base):
__table_args__ = (
schema.UniqueConstraint('resource_name', 'project_id',
name='uniq_quotas0resource_name'),
Index('quota_usage_project_id_idx', 'project_id'),
table_args()
)
@ -248,6 +266,7 @@ class Reservation(Base):
__tablename__ = 'reservations'
__table_args__ = (
schema.UniqueConstraint('uuid', name='uniq_reservation0uuid'),
Index('reservations_project_id_idx', 'project_id'),
table_args()
)

View File

@ -86,6 +86,7 @@ def create_test_server(context={}, **kw):
def get_test_flavor(**kw):
return {
'id': kw.get('id', 123),
'uuid': kw.get('uuid', uuidutils.generate_uuid()),
'name': kw.get('name', 'test'),
'description': kw.get('description', 'test'),
@ -109,6 +110,9 @@ def create_test_flavor(context={}, **kw):
"""
flavor = get_test_flavor(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del flavor['id']
dbapi = db_api.get_instance()
return dbapi.flavor_create(context, flavor)

View File

@ -24,58 +24,62 @@ class TestFlavorObject(base.DbTestCase):
def setUp(self):
super(TestFlavorObject, self).setUp()
self.ctxt = context.get_admin_context()
self.fake_type = utils.get_test_flavor(context=self.ctxt)
self.fake_type['extra_specs'] = {}
self.fake_flavor = utils.get_test_flavor(context=self.ctxt)
self.fake_flavor['extra_specs'] = {}
def test_get(self):
uuid = self.fake_type['uuid']
uuid = self.fake_flavor['uuid']
with mock.patch.object(self.dbapi, 'flavor_get',
autospec=True) as mock_type_get:
mock_type_get.return_value = self.fake_type
autospec=True) as mock_flavor_get:
with mock.patch.object(self.dbapi, 'flavor_access_get',
autospec=True) as mock_access_get:
mock_flavor_get.return_value = self.fake_flavor
mock_access_get.return_value = []
flavor = objects.Flavor.get(self.context, uuid)
flavor = objects.Flavor.get(self.context, uuid)
mock_type_get.assert_called_once_with(self.context, uuid)
self.assertEqual(self.context, flavor._context)
mock_flavor_get.assert_called_once_with(self.context, uuid)
mock_access_get.assert_called_once_with(self.context, uuid)
self.assertEqual(self.context, flavor._context)
def test_list(self):
with mock.patch.object(self.dbapi, 'flavor_get_all',
autospec=True) as mock_type_get_all:
mock_type_get_all.return_value = [self.fake_type]
autospec=True) as mock_flavor_get_all:
mock_flavor_get_all.return_value = [self.fake_flavor]
types = objects.Flavor.list(self.context)
flavors = objects.Flavor.list(self.context)
mock_type_get_all.assert_called_once_with(self.context)
self.assertIsInstance(types[0], objects.Flavor)
self.assertEqual(self.context, types[0]._context)
mock_flavor_get_all.assert_called_once_with(self.context)
self.assertIsInstance(flavors[0], objects.Flavor)
self.assertEqual(self.context, flavors[0]._context)
def test_create(self):
with mock.patch.object(self.dbapi, 'flavor_create',
autospec=True) as mock_type_create:
mock_type_create.return_value = self.fake_type
flavor = objects.Flavor(self.context, **self.fake_type)
autospec=True) as mock_flavor_create:
mock_flavor_create.return_value = self.fake_flavor
flavor = objects.Flavor(self.context, **self.fake_flavor)
values = flavor.obj_get_changes()
flavor.create(self.context)
mock_type_create.assert_called_once_with(self.context, values)
self.assertEqual(self.fake_type['uuid'], flavor['uuid'])
mock_flavor_create.assert_called_once_with(self.context, values)
self.assertEqual(self.fake_flavor['uuid'], flavor['uuid'])
def test_destroy(self):
uuid = self.fake_type['uuid']
uuid = self.fake_flavor['uuid']
with mock.patch.object(self.dbapi, 'flavor_destroy',
autospec=True) as mock_type_destroy:
mock_type_destroy.return_value = self.fake_type
flavor = objects.Flavor(self.context, **self.fake_type)
autospec=True) as mock_flavor_destroy:
mock_flavor_destroy.return_value = self.fake_flavor
flavor = objects.Flavor(self.context, **self.fake_flavor)
flavor.destroy(self.context)
mock_type_destroy.assert_called_once_with(self.context, uuid)
mock_flavor_destroy.assert_called_once_with(self.context, uuid)
def test_save(self):
uuid = self.fake_type['uuid']
uuid = self.fake_flavor['uuid']
with mock.patch.object(self.dbapi, 'flavor_update',
autospec=True) as mock_flavor_update:
flavor = objects.Flavor(self.context, **self.fake_type)
flavor = objects.Flavor(self.context, **self.fake_flavor)
flavor.name = 'changed_name'
updates = flavor.obj_get_changes()
flavor.save(self.context)
mock_flavor_update.return_value = self.fake_type
mock_flavor_update.return_value = self.fake_flavor
mock_flavor_update.assert_called_once_with(
self.context, uuid, updates)