注意

本文档适用于 Ceph 的开发版本。

Watch Notify

请参阅 librados 中的 watch/notify 接口。

概述

object_info(参阅 osd/osd_types.h)在 object_info_t::watchers map 中持久地跟踪特定对象的观察者集。为了跟踪通知进度,我们还维护一些与 ObjectContext 相关的临时结构。

每个 Watch 都有一个关联的 Watch 对象(参阅 osd/Watch.h)。被观察对象的 ObjectContext 将为每个 watch 持有一个对 Watch 对象的(强)引用,并且每个 Watch 对象都持有一个对相应 ObjectContext 的引用。这种循环引用是故意的,当在新的对等间隔(peering interval)期间丢弃 Watch 状态或在超时过期或 unwatch 操作时移除 Watch 时,它会被打破。

watch 通过一个强 ConnectionRef Watch::conn 跟踪关联的连接。关联的连接在 OSD::Session 中存储了一个 WatchConState,用于跟踪关联的 Watches,以便能够在 ms_handle_reset() 时通知它们(通过 WatchConState::reset())。

每个 Watch 对象跟踪当前未确认的通知集。在 Watch 对象上调用 start_notify() 会向 Watch 添加对一个新的进行中的 Notify 的引用,并执行以下操作之一:

  • 如果 Watch 处于 connected 状态,则向客户端发送 Notify 消息

  • 如果 Watch 处于 unconnected 状态,则不执行任何操作。

当 Watch 变为 connected 状态时(在 PrimaryLogPG::do_osd_op_effects 中),通知会被重新发送给所有剩余的被跟踪的 Notify 对象。

每个 Notify 对象通过调用 complete_watcher() 跟踪未通知的观察者集。一旦剩余集为空或超时过期(在 init() 中注册的回调 cb),就会向客户端发送通知完成消息。

Watch 生命周期

一个 watch 可以处于以下 5 种状态之一:

  1. 不存在。

  2. 在磁盘上,但未注册到对象上下文。

  3. 已连接(Connected)

  4. 已断开连接(Disconnected),回调已注册到计时器

  5. 已断开连接(Disconnected),回调在 scrub 或 is_degraded 队列中

情况 2 发生在 OSD 变为 active 之后到由于访问而将带有观察者的对象的 ObjectContext 加载到内存之前。在情况 2 期间,没有为 watch 注册任何状态。情况 2 在 PrimaryLogPG::find_object_context 期间通过 PrimaryLogPG::populate_obc_watchers() 转换为情况 4。情况 1 通过 OSD::do_osd_op_effects 由于 watch 操作而变为情况 3。情况 4、5 以相同方式变为情况 3。当观察者会话上的连接重置时,情况 3 变为情况 4。

情况 4 和 5 需要一些解释。通常,当 Watch 进入情况 4 时,会向 OSDService::watch_timer 注册一个回调,以便在超时过期时调用。然而,在调用回调时,PG 可能处于无法写入对象以移除 watch 的状态(即,在 scrub 期间或对象处于 degraded 状态时)。在这种情况下,我们使用 Watch::get_delayed_cb() 生成另一个 Context,用于 callbacks_for_degraded_object 和 Scrubber::callbacks 列表。在任何一种情况下,Watch::unregister_cb() 都会执行正确的操作(对于未注册到计时器的上下文,SafeTimer::cancel_event() 无害)。

Notify 生命周期

通知超时更简单:在 notify init() 时注册超时回调。如果在超时发生之前所有观察者都确认通知,则取消超时并通知客户端通知完成。否则,超时触发,Notify 对象通过 cancel_notify ping 每个 Watch 以移除自身,并提前将通知完成发送给客户端。

由 Ceph 基金会为您呈现

Ceph 文档是由非营利性 Ceph 基金会 资助和托管的社区资源。如果您希望支持这项工作和我们的其他努力,请考虑 立即加入