nova中的访问数据库的接口都在E:\nova\nova\db\api.py,但是该模块只是一个代理,只剩的实现是IMPL
IMPL的赋值如下:
_BACKEND_MAPPING = {'sqlalchemy': 'nova.db.sqlalchemy.api'}
IMPL = concurrency.TpoolDbapiWrapper(CONF, backend_mapping=_BACKEND_MAPPING)
可见nova是使用python的sqlalchemy
但是在nova中所有的服务是不能直接调用这个接口的,需要通过nova-conductor中转一次.
这里以E:\nova\nova\compute\manager.py 中的stop_instance为例,在这个函数中,操作数据库的代码如下:
instance.power_state = self._get_power_state(context, instance)
instance.vm_state = vm_states.STOPPED
instance.task_state = None
instance.save(expected_task_state=expected_task_state)
从这段code看更新isntance的power_state/vm_state/task_state 后调用 E:\nova\nova\objects\instance.py的save方法保存到数据库
@base.remotable
def save(self, expected_vm_state=None,
expected_task_state=None, admin_state_reset=False):
"""Save updates to this instance
Column-wise updates will be made based on the result of
self.what_changed(). If expected_task_state is provided,
it will be checked against the in-database copy of the
instance before updates are made.
:param:context: Security context
:param:expected_task_state: Optional tuple of valid task states
for the instance to be in
:param:expected_vm_state: Optional tuple of valid vm states
for the instance to be in
:param admin_state_reset: True if admin API is forcing setting
of task_state/vm_state
"""
db.instance_extra_update_by_uuid(context, self.uuid,
self._extra_values_to_save)
看看这里的base.remotable的实现
首先是from nova.objects import base。
在E:\nova\nova\objects\base.py 中可以发现
remotable_classmethod = ovoo_base.remotable_classmethod
remotable = ovoo_base.remotable
原来remotable 是在ovoo_base.remotable 中实现的
def remotable(fn):
"""Decorator for remotable object methods."""
@six.wraps(fn)
def wrapper(self, *args, **kwargs):
ctxt = self._context
if ctxt is None:
raise exception.OrphanedObjectError(method=fn.__name__,
objtype=self.obj_name())
if self.indirection_api:
updates, result = self.indirection_api.object_action(
ctxt, self, fn.__name__, args, kwargs)
for key, value in six.iteritems(updates):
if key in self.fields:
field = self.fields[key]
# NOTE(ndipanov): Since VersionedObjectSerializer will have
# deserialized any object fields into objects already,
# we do not try to deserialize them again here.
if isinstance(value, VersionedObject):
setattr(self, key, value)
else:
setattr(self, key,
field.from_primitive(self, key, value))
self.obj_reset_changes()
self._changed_fields = set(updates.get('obj_what_changed', []))
return result
else:
return fn(self, *args, **kwargs)
wrapper.remotable = True
wrapper.original_fn = fn
return wrappe
由于我们目前在compute 这个进程中,因此self.indirection_api不为null,则调用object_action
object_action是一个rpc调用,其定义在E:\nova\nova\conductor\rpcapi.py
def object_action(self, context, objinst, objmethod, args, kwargs):
cctxt = self.client.prepare()
return cctxt.call(context, 'object_action', objinst=objinst,
objmethod=objmethod, args=args, kwargs=kwargs)
根据rpc调用原理实现在E:\nova\nova\conductor\manager.py 中
def object_action(self, context, objinst, objmethod, args, kwargs):
"""Perform an action on an object."""
oldobj = objinst.obj_clone()
result = self._object_dispatch(objinst, objmethod, args, kwargs)
return updates, result
首先调用obj_clone 来备份原来的对象,然后调用_object_dispatch。
这个方法通用定义在E:\nova\nova\conductor\manager.py 中
def _object_dispatch(self, target, method, args, kwargs):
"""Dispatch a call to an object method.
This ensures that object methods get called and any exception
that is raised gets wrapped in an ExpectedException for forwarding
back to the caller (without spamming the conductor logs).
"""
try:
# NOTE(danms): Keep the getattr inside the try block since
# a missing method is really a client problem
return getattr(target, method)(*args, **kwargs)
except Exception:
raise messaging.ExpectedException()
根据反射机制,调用方法名,这里的方法就是save,但是目前已经在conductor这个进程中,因此此时
base.remotable 中的self.indirection_api为null
这样回到 E:\nova\nova\objects\instance.py的save方法保存到数据库
@base.remotable
def save(self, expected_vm_state=None,
expected_task_state=None, admin_state_reset=False):
"""Save updates to this instance
Column-wise updates will be made based on the result of
self.what_changed(). If expected_task_state is provided,
it will be checked against the in-database copy of the
instance before updates are made.
:param:context: Security context
:param:expected_task_state: Optional tuple of valid task states
for the instance to be in
:param:expected_vm_state: Optional tuple of valid vm states
for the instance to be in
:param admin_state_reset: True if admin API is forcing setting
of task_state/vm_state
"""
db.instance_extra_update_by_uuid(context, self.uuid,
self._extra_values_to_save)
这里的db赋值为from nova import db。这样就
nova中的访问数据库的接口都在E:\nova\nova\db\api.py,但是该模块只是一个代理,只剩的实现是IMPL
IMPL的赋值如下:
_BACKEND_MAPPING = {'sqlalchemy': 'nova.db.sqlalchemy.api'}
IMPL = concurrency.TpoolDbapiWrapper(CONF, backend_mapping=_BACKEND_MAPPING)
可见nova是使用python的sqlalchemy
但是在nova中所有的服务是不能直接调用这个接口的,需要通过nova-conductor中转一次.
nova中的service 访问数据库的过程
最新推荐文章于 2022-12-29 15:09:10 发布