感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn
前面解析完了get_project_quotas方法,现在我们回到方法def _get_quotas(self, context, resources, keys, has_sync, project_id=None):
def _get_quotas(self, context, resources, keys, has_sync, project_id=None):
"""
这是一个辅助的方法,从数据库获取特定的配额资源信息;
"""
# 筛选资源;
if has_sync:
sync_filt = lambda x: hasattr(x, 'sync')#判断对象x是否包含sync的特性;
else:
sync_filt = lambda x: not hasattr(x, 'sync')#判断对象x是否不包含sync的特性;
desired = set(keys)
sub_resources = dict((k, v) for k, v in resources.items()
if k in desired and sync_filt(v))
# Make sure we accounted for all of them...
# 确保所有磁盘配额资源都是已知的,否则引发异常,提示某些磁盘配额资源是未知的;
if len(keys) != len(sub_resources):
unknown = desired - set(sub_resources.keys())
raise exception.QuotaResourceUnknown(unknown=sorted(unknown))
# Grab and return the quotas (without usages)
# 获取并返回配额信息;
quotas = self.get_project_quotas(context, sub_resources,project_id,context.quota_class, usages=False)
return dict((k, v['limit']) for k, v in quotas.items())
可见获取了配额信息之后,以字典的方式返回各种资源的配额信息limit值(应该是三种资源:instances、ram、cores):
return dict((k, v['limit']) for k, v in quotas.items())
我们再回到方法def reserve(self, context, resources, deltas, expire=None, project_id=None):
def reserve(self, context, resources, deltas, expire=None, project_id=None):
"""
@@@@检测配额和储备资源;
"""
# 如果expire没有指定,则采用默认参数的值;
# reservation_expire:这个参数定义了预约(资源配额)的到期时间长度;
# 参数的默认值为86400;
if expire is None:
expire = CONF.reservation_expire
if isinstance(expire, (int, long)):
expire = datetime.timedelta(seconds=expire)
if isinstance(expire, datetime.timedelta):
expire = timeutils.utcnow() + expire
if not isinstance(expire, datetime.datetime):
raise exception.InvalidReservationExpiration(expire=expire)
# If project_id is None, then we use the project_id in context
if project_id is None:
project_id = context.project_id
# 获取给定对象id值,即project_id确定的对象的配额信息;
quotas = self._get_quotas(context, resources, deltas.keys(), has_sync=True, project_id=project_id)
return db.quota_reserve(context, resources, quotas, deltas, expire,
CONF.until_refresh, CONF.max_age,
project_id=project_id)
执行完语句quotas = self._get_quotas(context, resources, deltas.keys(), has_sync=True, project_id=project_id)之后,调试运行得到的返回结果为:
quotas = {instances:10, ram:51200, cores:20}
至此,方法_get_quotas解析完成,方法主要是完成了为project_id指定对象获取资源配额信息的功能;
b.2.2 解析语句return db.quota_reserve(context, resources, quotas, deltas, expire, CONF.until_refresh, CONF.max_age, project_id=project_id)
我们来看方法quota_reserve:
def quota_reserve(context, resources, quotas, deltas, expire, until_refresh, max_age, project_id=None):
elevated = context.elevated()
# 获取db_session的session;
# get_session:返回一个SQLAlchemy session,若没有定义,则新建一个SQLAlchemy session;
session = get_session()
with session.begin():
# 获取context中的project_id;
if project_id is None:
project_id = context.project_id
# 从quota_usages表中获得当前工程的各种资源的使用情况;
usages = _get_quota_usages(context, session, project_id)
# Handle usage refresh
# 注:deltas.keys() = ['instances', 'ram', 'cores']
work = set(deltas.keys())
while work:
resource = work.pop()
# Do we need to refresh the usage?
refresh = False
if resource not in usages:
usages[resource] = _quota_usage_create(elevated,project_id,resource,0, 0,until_refresh or None,session=session)
refresh = True
elif usages[resource].in_use < 0:
# Negative in_use count indicates a desync, so try to
# heal from that...
refresh = True
elif usages[resource].until_refresh is not None:
usages[resource].until_refresh -= 1
if usages[resource].until_refresh <= 0:
refresh = True
elif max_age and (usages[resource].updated_at - timeutils.utcnow()).seconds >= max_age:
refresh = True
# OK, refresh the usage
if refresh:
# Grab the sync routine
sync = resources[resource].sync
updates = sync(elevated, project_id, session)
for res, in_use in updates.items():
# Make sure we have a destination for the usage!
if res not in usages:
usages[res] = _quota_usage_create(elevated,project_id,res,0, 0,until_refresh or None,session=session)
# Update the usage
usages[res].in_use = in_use
usages[res].until_refresh = until_refresh or None
work.discard(res)
# Check for deltas that would go negative
unders = [resource for resource, delta in deltas.items()
if delta < 0 and
delta + usages[resource].in_use < 0]
overs = [resource for resource, delta in deltas.items()
if quotas[resource] >= 0 and delta >= 0 and
quotas[resource] < delta + usages[resource].total]
# Create the reservations
if not overs:
reservations = []
for resource, delta in deltas.items():
reservation = reservation_create(elevated,str(uuid.uuid4()),usages[resource],project_id,resource, delta, expire,session=session)
reservations.append(reservation.uuid)
if delta > 0:
usages[resource].reserved += delta
# Apply updates to the usages table
for usage_ref in usages.values():
usage_ref.save(session=session)
if unders:
LOG.warning(_("Change will make usage less than 0 for the following resources: %(unders)s") % locals())
if overs:
usages = dict((k, dict(in_use=v['in_use'], reserved=v['reserved'])) for k, v in usages.items())
raise exception.OverQuota(overs=sorted(overs), quotas=quotas,usages=usages)
return reservations
这个方法中包含的内容比较多,主要完成的就是对资源进行配额检测;
我们先来看一下传进来的参数值:
# 程序运行上下文信息;
context = <nova.context.RequestContext object at 0x4656d10>
# 资源信息;
resources = {'metadata_items': <nova.quota.AbsoluteResource object at 0x276e790>, 'injected_file_content_bytes': <nova.quota.AbsoluteResource object at 0x276e810>, 'ram': <nova.quota.ReservableResource object at 0x276e6d0>, 'floating_ips': <nova.quota.ReservableResource object at 0x276e710>, 'security_group_rules': <nova.quota.CountableResource object at 0x276e8d0>, 'instances': <nova.quota.ReservableResource object at 0x276e650>, 'key_pairs': <nova.quota.CountableResource object at 0x276e910>, 'injected_files': <nova.quota.AbsoluteResource object at 0x276e7d0>, 'cores': <nova.quota.ReservableResource object at 0x276e690>, 'fixed_ips': <nova.quota.ReservableResource object at 0x276e750>, 'injected_file_path_bytes': <nova.quota.AbsoluteResource object at 0x276e850>, 'security_groups': <nova.quota.ReservableResource object at 0x276e890>}
# 已获取的规定的限制的配额信息;
quotas = {'instances': 10, 'ram': 51200, 'cores': 20}
# 建立一个实例要求的资源信息,也就是每建立一个实例或者删除一个实例,资源配额的变化量;
deltas = {'instances': 1, 'ram': 2048L, 'cores': 1L}
# reservations的有效期;
expire = 2013-06-26 15:25:45.288831
until_refresh = 0
max_age = 0
#对象ID值;
project_id = 0e492e86f22e4d19bd523f1e7ca64566
这里解释一下:
until_refresh是从配置信息CONF.until_refresh赋值的,它的解释是直到usage刷新,reservations的数目,默认值为0;
max_age是从配置信息CONF.max_age赋值的,它的解释是刷新usage之间停留的秒数,默认值为0;
比较容易理解的语句直接就写在代码的注释中。
下面来看语句:
usages = _get_quota_usages(context, session, project_id)
这条语句完成了从quota_usages表中获得当前工程的各种资源的使用情况;
来看方法_get_quota_usages:
def _get_quota_usages(context, session, project_id):
# 获取资源配额使用信息,以字典的形式返回;
rows = model_query(context, models.QuotaUsage,
read_deleted="no",
session=session).\
filter_by(project_id=project_id).\
with_lockmode('update').\
all()
return dict((row.resource, row) for row in rows)
类QuotaUsage定义了当前资源的使用情况;
class QuotaUsage(BASE, NovaBase):
"""
Represents the current usage for a given resource.
表示一个给定资源当前的使用情况;
"""
__tablename__ = 'quota_usages'
id = Column(Integer, primary_key=True)
project_id = Column(String(255), index=True)
resource = Column(String(255))
in_use = Column(Integer)
reserved = Column(Integer)
@property
def total(self):
return self.in_use + self.reserved
until_refresh = Column(Integer, nullable=True)
来看下面一段代码:
if resource not in usages:
usages[resource] = _quota_usage_create(elevated,project_id,resource,0, 0,until_refresh or None,session=session)
refresh = True
如果当前的resource不在当前工程所使用的资源列表中,那么就把该资源添加进去,并且在数据库中增加一条相应的记录;为后续查询当前工程当前各种资源的使用情况做准备;
具体来看一下方法_quota_usage_create:
def _quota_usage_create(context, project_id, resource, in_use, reserved,
until_refresh, session=None):
quota_usage_ref = models.QuotaUsage()
quota_usage_ref.project_id = project_id
quota_usage_ref.resource = resource
quota_usage_ref.in_use = in_use
quota_usage_ref.reserved = reserved
quota_usage_ref.until_refresh = until_refresh
quota_usage_ref.save(session=session)
return quota_usage_ref
再看一下类QuotaUsage:
class QuotaUsage(BASE, NovaBase):
"""
Represents the current usage for a given resource.
表示一个给定资源当前的使用情况;
"""
__tablename__ = 'quota_usages'
id = Column(Integer, primary_key=True)
project_id = Column(String(255), index=True)
resource = Column(String(255))
in_use = Column(Integer)
reserved = Column(Integer)
@property
def total(self):
return self.in_use + self.reserved
until_refresh = Column(Integer, nullable=True)
应该比较好理解了;
看下一段代码:
elif usages[resource].in_use < 0:
# Negative in_use count indicates a desync, so try to
# heal from that...
refresh = True
elif usages[resource].until_refresh is not None:
usages[resource].until_refresh -= 1
if usages[resource].until_refresh <= 0:
refresh = True
elif max_age and (usages[resource].updated_at - timeutils.utcnow()).seconds >= max_age:
refresh = True
这段代码的含义是:
如果当前的resource在当前工程的使用列表中,并且该资源的in_use小于0,说明资源数据信息不同步,则执行refresh(刷新);
如果当前的until_refresh不为空,那么将其减1,如果减1之后小于等于0,则执行refresh(刷新);(目前还不是太明白)
如果max_age不为空,并且该资源更新的时间减去当前的时间大于max_age,说明需要执行refresh(刷新);
下一篇博文将会继续分析这个方法,接下来将会介绍如何执行refresh(刷新)同步操作的。