对导出的 DBus 对象进行引用计数?

对导出的 DBus 对象进行引用计数?

我正在开发 DBus 服务,需要在第三方应用程序请求时按需导出对象。这部分似乎相当简单。

但是当没有消费者时,我也需要“垃圾收集”这些对象。我可以使用 API 要求第三方应用程序明确释放对象,但缺点是如果消费者应用程序崩溃而没有释放引用,未使用的对象就会堆积起来。

不管怎样,我通过 python3-dbus 使用 Python 中的 DBus。所以我猜有两个问题:

  1. DBus 为导出对象的引用计数提供了什么样的机制,有没有办法知道零个进程当前正在“观察”一个对象?

  2. 什么被认为是设计这种 DBus API 的最佳实践,人们认为什么是值得效仿的好例子?(我能想到的唯一类似的东西是 Avahi 浏览器对象。)

如果我描述确切的问题,我的问题可能会更有意义:媒体是一个专门针对媒体文件的分布式文件系统。文件根据其内容哈希被赋予一个全局唯一的 ID。当应用程序需要使用文件(例如用于播放或显示)时,它将使用 Dmedia DBus API 将文件 ID 解析为常规文件路径。例如,此 ID:

5PULSAF3PFR4VPNJMLSAJ362HG475NDKKISDYXW7WUJCFUJN

例如可以解析到文件:

/media/MyDrive/.dmedia/files/5P/ULSAF3PFR4VPNJMLSAJ362HG475NDKKISDYXW7WUJCFUJN

但事情远比这复杂。文件可能不在本地可用,在这种情况下,Dmedia 可以从用户的其他设备或云端下载文件。因此,我们需要信号来表示下载进度,并在文件下载后发出信号来表示常规文件路径是什么。

当可移动驱动器连接或断开时,分辨率也可能随时间而变化。用户可能会移除驱动器,此时文件在本地不可用,Dmedia 会尝试下载它。或者用户可能会插入额外的驱动器,并且给定文件的分辨率可能会随着 Dmedia 在驱动器之间重新加载平衡而发生变化。

看起来,根据当前感兴趣的文件导出 DBus 对象是一种合理的方法,但也许这样会让事情变得太复杂。我认为这就是消费者和服务端需要更多过滤和智能之间的区别。单个对象上的信号和方法的平面集合将使服务的工作变得更容易,但会给消费者带来更多负担。

如果我们根据每个感兴趣的文件导出一个 DBus 对象,我确信我们需要垃圾收集,因为在 DBus 服务生命周期的某个时刻,可能会有大量文件引起我们的兴趣。

我将非常感激任何关于此事的建议!

答案1

首先,可能值得解释一下“观察”的含义:

DBus 为导出对象的引用计数提供了什么样的机制,有没有办法知道零个进程当前正在“观察”一个对象?

询问某物是否正在“观察” DBus 对象的唯一意义在于客户端是否会收到该对象发出的任何信号;否则就没有观察的概念,只有消息传递。客户端通过在总线上调用 AddMatch/RemoveMatch 来执行此操作,因此理论上您可以对匹配进行引用计数。不过,这似乎是一种容易出错的方法 - 您基本上需要重新实现守护进程的匹配处理程序,以确保您已经掌握了客户端可以监听信号的所有方式。

但是,如果您只想在客户端崩溃后进行清理,那么有一种方法 - 每个 DBus 客户端都会获得守护进程为其:1.693分配的唯一总线 ID(例如)。当客户端通过 DBus API 请求文件时,您可以记录他们的总线 ID,然后观察信号NameOwnerChangedorg.freedesktop.DBus此信号有 3 个部分 - 总线名称(在我们感兴趣的情况下,它将是唯一的总线 ID)、新所有者的总线 ID 和旧所有者的总线 ID。

因此,如果您收到NameOwnerChanged带有 的信号name=":1.693"new_owner=""并且old_owner=":1.693"您知道带有 bus-id 的客户端:1.693已与总线断开连接,并且可以删除该客户端正在使用的任何对象。

你会想这样做此外当然,当客户处理完文件后,他们会明确地告知您的服务。

编辑:

至于你的全球性问题 - 什么应该API 是 - 我认为这看起来足够复杂,你的 DBus 对象应该不是python-dmedia-client是主要的 API。用 a (也可能是 C )包装它libdmedia-client,并在那里处理引用计数和复杂性。

答案2

我遇到了类似的问题,并想出了一种跨 DBus 进行引用计数的机制。结果发现这相当棘手,所以我创建了DBus 错误 #38784提议将其纳入 DBus 规范作为标准接口/机制,以便其他人不必重复工作。

您可以以 docbook 格式阅读该提案这里

不过,我不相信它已经在 Python DBus 绑定或任何其他公开可用的 DBus 绑定中实现。

相关内容