oVirt (Open Virtual) 之 VDSM 学习笔记 (二) 流程追踪

概述:

追踪 VDSM 启动后的代码大概流程,是继 vdsm/vdsm 文件学习后的继续。

Let‘s go!

从 “def serve_clients(log)” 开始

 1 def serve_clients(log):
 2     cif = None
 3     irs = None
 4     scheduler = None
 5     running = [True]
 6
 7     def sigtermHandler(signum, frame):
 8         log.debug("Received signal %s" % signum)
 9         running[0] = False
10
11     def sigusr1Handler(signum, frame):
12         if irs:
13             log.debug("Received signal %s" % signum)
14             irs.spmStop(
15                 irs.getConnectedStoragePoolsList()[‘poollist‘][0])
16
17     sigutils.register()
18     signal.signal(signal.SIGTERM, sigtermHandler)
19     signal.signal(signal.SIGUSR1, sigusr1Handler)
20     zombiereaper.registerSignalHandler()
21
22     profile.start()
23
24     libvirtconnection.start_event_loop()
25
26     try:
27         if config.getboolean(‘irs‘, ‘irs_enable‘):
28             try:
29                 irs = Dispatcher(HSM())
30             except:
31                 utils.panic("Error initializing IRS")
32
33         from clientIF import clientIF  # must import after config is read
34         cif = clientIF.getInstance(irs, log)
35
36         install_manhole({‘irs‘: irs, ‘cif‘: cif})
37
38         scheduler = schedule.Scheduler(name="vdsm.Scheduler",
39                                        clock=utils.monotonic_time)
40         scheduler.start()
41         cif.start()
42         periodic.start(cif, scheduler)
43         try:
44             while running[0]:
45                 sigutils.wait_for_signal()
46
47             profile.stop()
48         finally:
49             periodic.stop()
50             cif.prepareForShutdown()
51             scheduler.stop()
52     finally:
53         libvirtconnection.stop_event_loop(wait=False)

代码:

22     profile.start()

是调用 vdsm/lib/vdsm/profiling/profile.py 的 start() 方法,如下:

1 def start():
2     cpu.start()
3     memory.start()

再次调用同级目录的 cpu.py 和 memory.py 的 start() 方法,如下:

 1 def start():
 2     """ Starts application wide CPU profiling """
 3     if is_enabled():
 4         _start_profiling(_CLOCK, _BUILTINS, _THREADS)
 5
 6
 7
 8 def start():
 9     """ Starts application memory profiling """
10     if is_enabled():
11         _start_profiling()

其本质是两个线程,分别监测 CPU 和内存。

代码:

24     libvirtconnection.start_event_loop()

调用 libvirtconnection.start_event_loop() 注册与 libvirt 的连接事件处理。

其代码在 vdsm/lib/vdsm/libvirtconnection.py

 1 def start_event_loop():
 2     __event_loop.start()
 3
 4
 5 __event_loop = _EventLoop()
 6
 7
 8 class _EventLoop:
 9     def __init__(self):
10         self.run = False
11         self.__thread = None
12
13     def start(self):
14         assert not self.run
15         self.__thread = threading.Thread(target=self.__run,
16                                          name="libvirtEventLoop")
17         self.__thread.setDaemon(True)
18         self.run = True
19         self.__thread.start()
20
21     @utils.traceback(on=log.name)
22     def __run(self):
23         try:
24             libvirt.virEventRegisterDefaultImpl()
25             while self.run:
26                 libvirt.virEventRunDefaultImpl()
27         finally:
28             self.run = False

方法 start_event_loop() 通过 _EventLoop 对象的实例调用其 start() 方法,

从而调用到 __run 方法,在 __run() 方法中调用 libvirt 的默认实现方法:

virEventRegisterDefaultImpl()。

其实质也是一个线程,用于处理与 libvirt 的数据交互。

备注:

libvirt 项目代码不包含在 VDSM 项目代码里,如需查看其实现,请下载 libvirt 代码查看。

下载地址:http://libvirt.org/downloads.html。

代码:

29                 irs = Dispatcher(HSM())

涉及两个类的初始化。

HSM 类在 vdsm/vdsm/storage/hsm.py 中,查看其 __init__ 方法,代码如下:

 1     def __init__(self):
 2         """
 3         The HSM Constructor
 4
 5         :param defExcFunc: The function that will set the default exception
 6                            for this thread
 7         :type defExcFun: function
 8         """
 9         self._ready = False
10         rm.ResourceManager.getInstance().registerNamespace(
11             STORAGE, rm.SimpleResourceFactory())
12         self.storage_repository = config.get(‘irs‘, ‘repository‘)
13         self.taskMng = taskManager.TaskManager()
14
15         mountBasePath = os.path.join(self.storage_repository,
16                                      sd.DOMAIN_MNT_POINT)
17         fileUtils.createdir(mountBasePath)
18         storageServer.MountConnection.setLocalPathBase(mountBasePath)
19         storageServer.LocalDirectoryConnection.setLocalPathBase(mountBasePath)
20         self._connectionAliasRegistrar = 21             storageServer.ConnectionAliasRegistrar(STORAGE_CONNECTION_DIR)
22         self._connectionMonitor = 23             storageServer.ConnectionMonitor(self._connectionAliasRegistrar)
24         self._connectionMonitor.startMonitoring()
25
26         sp.StoragePool.cleanupMasterMount()
27         self.__releaseLocks()
28
29         self._preparedVolumes = defaultdict(list)
30
31         self.__validateLvmLockingType()
32
33         oop.setDefaultImpl(config.get(‘irs‘, ‘oop_impl‘))
34
35         # cleanStorageRepoitory uses tasksDir value, this must be assigned
36         # before calling it
37         self.tasksDir = config.get(‘irs‘, ‘hsm_tasks‘)
38
39         # This part should be in same thread to prevent race on mounted path,
40         # otherwise, storageRefresh can unlink path that is used by another
41         # thread that was initiated in the same time and tried to use the
42         # same link.
43         try:
44             # This call won‘t get stuck if mount is inaccessible thanks to
45             # misc.walk, this sync call won‘t delay hsm initialization.
46             self.__cleanStorageRepository()
47         except Exception:
48             self.log.warn("Failed to clean Storage Repository.", exc_info=True)
49
50         @utils.traceback(on=self.log.name)
51         def storageRefresh():
52             sdCache.refreshStorage()
53             lvm.bootstrap(refreshlvs=blockSD.SPECIAL_LVS)
54             self._ready = True
55             self.log.debug("HSM is ready")
56
57         storageRefreshThread = threading.Thread(target=storageRefresh,
58                                                 name="storageRefresh")
59         storageRefreshThread.daemon = True
60         storageRefreshThread.start()
61
62         monitorInterval = config.getint(‘irs‘, ‘sd_health_check_delay‘)
63         self.domainMonitor = monitor.DomainMonitor(monitorInterval)

在初始化函数要看这么多代码,刚开始,我是拒绝的,你不能说代码走到这里,我就

要马上看啊,后来,我试着看了一下,duang ...

代码:

10         rm.ResourceManager.getInstance().registerNamespace(
11             STORAGE, rm.SimpleResourceFactory())

这里的 rm 是模块 resourceManager 的别名 (import <模块> as <别名>),

该模块文件在 vdsm.vdsm.storage.resourceManager (. 替换为 / 即可找到位置,大家都懂的)

调用其模块内的类 ResourceManager.getInstance() 方法,用于获取

ResourceManager 的实例。那代码就转换为调用 ResourceManager 实例的注册名称空间

registerNamespace() 方法。

补充:

这个方法一般用在某一个类只能有一个实例的场景,使用 getInstance 方法来保证单实例,

C++、Java 也有类似的使用。

代码:

12         self.storage_repository = config.get(‘irs‘, ‘repository‘)
13         self.taskMng = taskManager.TaskManager()

从配置文件里读取存储路径

创建任务管理器,TaskManager 会创建线程池以及有关线程池操作、维护需要的锁等资源

代码:

15         mountBasePath = os.path.join(self.storage_repository,
16                                      sd.DOMAIN_MNT_POINT)
17         fileUtils.createdir(mountBasePath)
18         storageServer.MountConnection.setLocalPathBase(mountBasePath)
19         storageServer.LocalDirectoryConnection.setLocalPathBase(mountBasePath)
20         self._connectionAliasRegistrar = 21             storageServer.ConnectionAliasRegistrar(STORAGE_CONNECTION_DIR)
22         self._connectionMonitor = 23             storageServer.ConnectionMonitor(self._connectionAliasRegistrar)
24         self._connectionMonitor.startMonitoring()

根据从配置中获取的 [irs] 的 ‘repository‘ 的值来复制挂载的根路径

创建该目录

设置挂载目录连接的主目录

设置本地目录连接的主目录

连接的别名注册(打开 connnection 目录下的 ‘*.con‘ 文件,并保存文件信息, 使用了 pickle 模块 )

根据别名对象,生成连接管理对象

创建线程,定时检查连接、并根据连接情况进行处理

代码:

26         sp.StoragePool.cleanupMasterMount()
27         self.__releaseLocks()

清除目录 mnt/blockSD/ 目录下的挂载

释放所有的锁(在初始化 VDSM 需要释放所有的锁,例如:之前有 VDSM 在运行)

代码:

29         self._preparedVolumes = defaultdict(list)
30
31         self.__validateLvmLockingType()
32
33         oop.setDefaultImpl(config.get(‘irs‘, ‘oop_impl‘))

创建一个 defaultdict 类型(参见: Python defaultdict

检查 lvm 的 LockingType(执行 lvm 命令检查 lvm 的配置项:global/locking_type)

根据配置:irs/oop_impl 设置 oop 的默认实现

代码:

35         # cleanStorageRepoitory uses tasksDir value, this must be assigned
36         # before calling it
37         self.tasksDir = config.get(‘irs‘, ‘hsm_tasks‘)

设置 tasks 目录

代码:

39         # This part should be in same thread to prevent race on mounted path,
40         # otherwise, storageRefresh can unlink path that is used by another
41         # thread that was initiated in the same time and tried to use the
42         # same link.
43         try:
44             # This call won‘t get stuck if mount is inaccessible thanks to
45             # misc.walk, this sync call won‘t delay hsm initialization.
46             self.__cleanStorageRepository()
47         except Exception:
48             self.log.warn("Failed to clean Storage Repository.", exc_info=True)

调用清除存储目录

代码:

50         @utils.traceback(on=self.log.name)
51         def storageRefresh():
52             sdCache.refreshStorage()
53             lvm.bootstrap(refreshlvs=blockSD.SPECIAL_LVS)
54             self._ready = True
55             self.log.debug("HSM is ready")
56
57         storageRefreshThread = threading.Thread(target=storageRefresh,
58                                                 name="storageRefresh")
59         storageRefreshThread.daemon = True
60         storageRefreshThread.start()

创建线程,线程执行的函数为 storageRefresh(),而该函数调用 sdCache 模块的 refreshStorage

来进行实际的刷新存储相关的,

代码:

62         monitorInterval = config.getint(‘irs‘, ‘sd_health_check_delay‘)
63         self.domainMonitor = monitor.DomainMonitor(monitorInterval)

存储域管理

[欲知后事如何,请听下回分解...]

基于:

1. 文章代码流程分析篇幅较长,太长会冗长、乏味;

2. 没有一个实际的 oVirt 系统运行,像纸上谈兵、凭空捏造;

3. 后续流程涉及部分相关的业务。

VDSM 流程追踪将在后续文章中继续进行分析,而最近的将是 oVirt 系统搭建的简介。

时间: 2025-01-02 13:24:15

oVirt (Open Virtual) 之 VDSM 学习笔记 (二) 流程追踪的相关文章

spidering hacks 学习笔记(二)

看过去很乱,学习的记录东西而已,等我读完这本书,就把笔记给整理下!嘿嘿 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

Linux System Programming 学习笔记(二) 文件I/O

1.每个Linux进程都有一个最大打开文件数,默认情况下,最大值是1024 文件描述符不仅可以引用普通文件,也可以引用套接字socket,目录,管道(everything is a file) 默认情况下,子进程会获得其父进程文件表的完整拷贝 2.打开文件 open系统调用必须包含 O_RDONLY,O_WRONLY,O_RDWR 三种存取模式之一 注意 O_NONBLOCK模式 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己

JavaScript--基于对象的脚本语言学习笔记(二)

第二部分:DOM编程 1.文档象模型(DOM)提供了访问结构化文档的一种方式,很多语言自己的DOM解析器. DOM解析器就是完成结构化文档和DOM树之间的转换关系. DOM解析器解析结构化文档:将磁盘上的结构化文档转换成内存中的DOM树 从DOM树输出结构化文档:将内存中的DOM树转换成磁盘上的结构化文档 2.DOM模型扩展了HTML元素,为几乎所有的HTML元素都新增了innerHTML属性,该属性代表该元素的"内容",即返回的某个元素的开始标签.结束标签之间的字符串内容(不包含其它

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意

【Unity 3D】学习笔记二十八:unity工具类

unity为开发者提供了很多方便开发的工具,他们都是由系统封装的一些功能和方法.比如说:实现时间的time类,获取随机数的Random.Range( )方法等等. 时间类 time类,主要用来获取当前的系统时间. using UnityEngine; using System.Collections; public class Script_04_13 : MonoBehaviour { void OnGUI() { GUILayout.Label("当前游戏时间:" + Time.t

Spring Batch学习笔记二

此系列博客皆为学习Spring Batch时的一些笔记: Spring Batch的架构 一个Batch Job是指一系列有序的Step的集合,它们作为预定义流程的一部分而被执行: Step代表一个自定义的工作单元,它是Job的主要构件块:每一个Step由三部分组成:ItemReader.ItemProcessor.ItemWriter:这三个部分将执行在每一条被处理的记录上,ItemReader读取每一条记录,然后传递给ItemProcessor处理,最后交给ItemWriter做持久化:It