让名称和 UUID 指向同一虚拟机对象
libvirt 为 Domain 对象维护 UUID 与名称两个哈希索引,两个入口指向同一个对象。
相关概念
工程问题#
API 调用者可能拿名称,也可能拿 UUID 查询虚拟机;创建、重命名和删除还必须保持各入口一致。
实际实现#
virDomainObjList 的 objs 与 objsName 分别索引 UUID 字符串和名称。加入第二张表失败时回滚第一张,并由锁与引用计数管理生命周期。
处理流程#
- 格式化 UUID 并建立第一索引
- 建立名称索引并增加引用
- 按调用者提供的键查询
- 更新或删除时协调两张索引
源码片段#
固定版本 · 原文摘录src/conf/virdomainobjlist.cv10.10.0 · L226–L244
226static int227virDomainObjListAddObjLocked(virDomainObjList *doms,228 virDomainObj *vm)229{230 char uuidstr[VIR_UUID_STRING_BUFLEN];231232 virUUIDFormat(vm->def->uuid, uuidstr);233 if (virHashAddEntry(doms->objs, uuidstr, vm) < 0)234 return -1;235 virObjectRef(vm);236237 if (virHashAddEntry(doms->objsName, vm->def->name, vm) < 0) {238 virHashRemoveEntry(doms->objs, uuidstr);239 return -1;240 }241 virObjectRef(vm);242243 return 0;244}virDomainObjListAddObjLocked
同一个 vm 先按 UUID 放入 objs,再按名称放入 objsName;第二次插入失败就删除第一项。两次 virObjectRef 对应两个索引持有的对象引用。函数名中的 Locked 表示调用者负责满足锁定约束。
收益与取舍#
工程分析带来的收益
- 常见点查找无需遍历全部虚拟机
- 避免复制完整 Domain 对象
付出的代价
- 工程分析:双索引多消耗键和表项内存
- 跨索引更新需要一致性与回滚逻辑
可比较的选择
单索引加遍历维护简单,但第二种查询方式需要线性扫描。
版本与适用范围#
对应 libvirt v10.10.0 的 UUID 与名称查询;数字运行 ID 查询在此实现中不等同于第三张哈希索引。
参考来源#
源码、官方文档与原始论文01
libvirt · virDomainObjListAddObjLocked / virDomainObjListFindByName
源码v10.10.0src/conf/virdomainobjlist.c · virDomainObjListAddObjLocked / virDomainObjListFindByName
相关实现与比较#
4 个相关案例QEMU TCG 用 QHT 保存 TranslationBlock 索引,帮助复用与当前客体执行状态一致的翻译结果。
附源码片段 · 缓存与复用
把上下文身份编码进块哈希,让重复请求共享已经计算的 KV cache。
附源码片段 · 缓存与复用
Redis 有序集合既要按成员查分数,也要按分数和名次遍历;较大集合通过两种索引服务这些访问方式。
附源码片段 · 索引与查找
Redis 7.2.0 的字典扩缩容保留新旧两张哈希表,逐桶迁移,降低一次性搬迁全部条目的停顿。
附源码片段 · 索引与查找