RFC-0032:高效信封

RFC-0032:高效信封
状态已拒绝
领域
  • FIDL
说明

此 FTP 为信封提出了一种更紧凑的编码。

作者
提交日期(年-月-日)2019-02-06
审核日期(年-月-日)2019-02-21

“将信封变成明信片”

遭拒的理由

2019 年 2 月 21 日,我们最初接受了此 RFC。FIDL 团队努力在 2019 年的大部分时间里稳定了传输格式,最终在第三季度和第四季度全心全意投入工作。迁移已于 2019 年 12 月 1 日完成。

稳定工作涉及多项变更:

不过,随着工作的展开,并且 12 月 1 截止日期即将来临,FIDL 团队决定放弃实施高效信封变更,并希望将这项工作推到 2020 年。与稳定工作中的其他变更不同,高效的信封只是在内存中节省大小,而且体量非常小,尤其是与 FIDL 有线格式的其他方面(例如表的密集格式)相比。推迟是一种降低项目风险的计算方法,通过缩小范围,可以提高按时完成所有工作的几率。FIDL 小组的工作时间表也一样

现在,推迟实施已接近 18 个月,高效的信封早就被遗忘了。2020 年的大量性能工作表明,这一变更不会产生实质性影响。

是时候直面真相了,事情不会发生。已拒绝。

与其他 RFC 的关系

2021 年 6 月,我们再次访问了该主题,使用有针对性的基准来衡量性能。此结论已得出结论,并且 RFC-0113 提议重新引入相应更改,最终已被接受。

总结

此 FTP 为信封1 提出了一种更紧凑的编码方式。

设计初衷

信封是可扩展、可演进的数据结构(表和可扩展的联合)的基础。针对信封采用更紧凑高效的电线格式使得这些可扩展的结构能被用于更多对性能和电线尺寸至关重要的情境。

设计

建议的信封格式为:

图:64 位小端字节、MSB 32 位大小、16 位句柄_count,16 位预留

现有的信封格式相比:

  • 大小字段保持不变(32 位)。
    • 大小包括可能以递归方式编码的任何子对象的大小。
    • 例如,vector<string> 的大小包括外部矢量的内部字符串子对象的大小。
    • 这与当前信包实现的大小字段的现有行为一致。
  • 16 位已预留。
    • 解码器必须验证预留位是否为零。
    • 如果将来要使用预留位,则应改为修改有线格式。
      • 应更全面地考虑 FIDL 的预留位,以便在各种规范之间保持一致的行为。
      • 特别是,在 FIDL 中并没有让解码器忽略任何位的先例:线上的所有位都已定义和指定。
      • 这是最简单的决策(需要更改有线格式,而不是启用向前兼容性),这在确定关于保留位的政策之前可以保持简单。
  • handle_count 是 16 位,而不是 32 位。
    • 目前无法通过 Zircon 通道发送超过 64 个句柄;我们认为 16 位可以提供足够的提升空间来满足未来的需求。
    • process_count 包括所有递归子对象的句柄计数。
  • 在线/缺失字段会被丢弃。
    • 存在状态由 size 或 handle_count 字段中的非零值表示。
    • 缺失表示大小和句柄计数字段都为零。
  • 大小为 UINT32_MAX 且句柄计数为 0 是特殊情况:它表示存在但大小为零的信封内容。
    • 如果零大小的空结构体成为现实,则预留给将来使用2,并且目前不会对解码器的性能或复杂性造成任何负面影响。我们现在希望提一下,这样在未来可能的实现中,不会破坏传输格式。
    • 我们可以改为窃取其中一个保留位。我们对此问题没有明确意见;只要能通过某种方法将“当前大小为零”的信封与 FIDL_ALLOC_ABSENT 区分开来,也没有关系。 我们非常乐意达成共识。

解码器可以使用指向信包数据的指针覆盖信封数据(假设它们知道信封内容的静态类型(架构)。 请参阅未知数据部分,了解在内容类型未知的情况下如何处理信封的建议。

编码/解码形式的 C/C++ 结构体

信封的编码形式可以由编码或解码形式的并集表示。

typedef union {
  struct {
    uint32_t size;
    uint16_t handle_count;
    uint16_t reserved;
  } encoded;
  void* data;
} fidl_envelope_t;

static_assert(sizeof(fidl_envelope_t) == sizeof(void*));

未知数据

在可演进的数据结构中使用时,接收器(验证器和解码器)可能不知道信封的类型。如果接收者不知道类型,则可以最低限度地解析和跳过信封。

  • 信封的大小决定了要跳过的外行数据量。
  • 如果信包的句柄计数为非零,验证器必须处理指定数量的句柄。
    • 默认处理行为必须是关闭所有句柄。
  • 如果解码器希望就地解码,可以使用指向信包内容的指针覆盖未知信包。
    • 如果解码器使用指针覆盖信包,则会丢失信包中的大小和句柄计数信息。绑定可以提供一种机制,以供解码器在覆盖信封之前保存大小和处理计数信息;此 FTP 不就此类机制如何运作发表意见。

实施策略

此 FTP 是一项重大的传输格式变更。

两个 FIDL 对等方都需要了解新信封格式,并将其传达给对等方,以便双方使用新格式。 因此,这通常会被视为硬性转换。由于此 FTP 没有添加任何新功能,因此如果我们决定进行硬转换,作者建议将此更改与其他传输格式更改(例如,提议的序数大小更改)组合在一起。

也就是说,可以进行软转换。两种方法为:

  1. 事务性邮件标头中有一个 uint32 预留/标志字段。我们可以为发起对等端预留 1 位,以表明它了解新的传输格式以及分阶段的软转换:
    1. 确保所有客户端和服务器都能理解新旧传输格式。 我们会继续使用旧的传输格式。
    2. 让对等方设置事务消息标头中的位,以启用新的传输格式。如果双方都设置了位,则双方都可以切换到新的线路格式。
    3. 软过渡通过所有层后,所有紫红色均可使用新的有线格式。我们可以移除交易邮件标头中的位设置。
    4. 删除旧传输格式的代码,并取消预留事务性消息标头位。
  2. 我们可以使用“[WireFormat=EnvelopeV2]”属性(或类似属性)来修饰特定的 FIDL 消息类型和/或接口,指示消息/接口应使用新的传输格式。
    1. 虽然使用 WireFormat 属性来修饰接口似乎更适合于传输格式更改,但对结构体实现 WireFormat 更改应该更容易,因为结构体可以在不同的接口中使用,并且绑定需要额外的逻辑来确定用于结构体的上下文。
    2. 我们建议接口 [WireFormat] 属性仅影响接口的方法参数的线路格式,而不会递归影响参数的结构。
    3. 这实现了部分迁移并选择启用新的传输格式,并让团队可以按照自己的节奏推进工作。
    4. 一旦所有结构体和接口都具有 [WireFormat] 属性,我们就可以丢弃旧的传输格式,假设所有结构体和接口都使用新的传输格式,并忽略该属性。

这两种软转换方法都涉及大量的开发时间、测试时间和出错空间。实现代码以正确执行任一方法、执行计划并成功跟进以移除旧代码,这都是一项庞大的工作。

我们很可能会有同时处理新旧有线格式的代码;否则,由于我们实现了对新有线格式的支持,将无法逐步推出 CL。鉴于处理这两种传输格式的代码都存在,我们建议使用上述软转换方法之一对软转换是否可行进行原型设计。此类原型设计工作还可能会带来一些关于未来重大线路格式变更的一般策略,这些策略可能很有价值。 否则,c'est la vie;硬转换。

对于软转换或硬转换,在 Fuchsia 中手动滚动 FIDL 消息的任何实例也需要升级到新的线上格式。

向后兼容性

提议的传输格式更改应与 API(源代码)兼容。所有手动 FIDL 代码都需要进行更新才能处理新的传输格式。

传输格式更改与 ABI 不兼容。 通过实现策略部分中所述的策略实现 ABI 兼容性。

性能

此 FTP 显著缩小了信封所需的大小,这似乎是一项总体可观的净收益。然而,如果可扩展数据结构因效率更高而变得越来越普遍,那么与使用不可扩展数据结构相比,其使用量增加可能会弥补这一优势,这可能会导致整体消息更加紧凑和动态分配性更高。

工效学设计

  • 更高效的可扩展数据结构使其能够用在效率至关重要的更多情境中,因此用户无需担心性能问题,并且在他们之前需要使用不可可扩展的结构时,还能获享可扩展性的优势。
  • 我们甚至可能建议将表默认用于 FIDL 数据结构,并为高性能上下文预留结构体。
    • 可扩展联合 (RFC-0061) 已尝试移除静态联合。

文档

  • 线上格式文档需要更新。
  • 更新文档时,应将信封解释为头等概念:当读者遇到用于可选性和可扩展的数据结构的有线格式时,这可以实现更好的认知分块
  • 我们应更新 FIDL 样式指南,针对何时应使用可扩展类型提出建议。

安全性

此 FTP 应该不会造成严重的安全隐患。

一个小的安全优势是,此 FTP 会移除旧格式大小和指针中重复的信息。以前,接收信包时可能会附带非零大小/句柄和 FIDL_ALLOC_ABSENT,也可能会用零大小/句柄和 FIDL_ALLOC_PRESENT 来接收。这就需要进行额外的验证检查,而不再需要这些检查。

测试

  • 由于此 FTP 正在更改信封的传输格式,因此我们认为现有的 FIDL 测试套件(尤其是兼容性测试)将对使用信封的所有场景进行充分测试。
  • 如果我们同意以软转换的形式提交有线格式更改(请参阅实现策略部分),我们将添加相关测试,供对等设备进行协商并可能切换到新的有线格式。

缺点、替代方案和未知情况

如果我们认为此方案的效率提升不值得投入实现成本,则可以保留现有的传输格式。

设计决策

在 FTP 提出建议的同时,我们也在积极征求意见并就以下决策达成共识:

  • 我们想要考虑软转换还是硬转换?如需了解优缺点,请参阅实现策略部分。
  • 我们建议在大小中使用 32 位,为句柄使用 16 位,并预留 16 位。
    • 32 位的大小是否合理?
    • 16 位的句柄是否合理?
  • 此方案衍生自 rfc-0026,建议将小于等于 32 位的类型将数据直接内嵌到信封中。
    • 我们决定撤消此提案的内嵌操作,因为这样做会大大增加实现复杂性。而且,除非有大量字段可以内嵌,否则它会带来边际好处。
    • 我们正在研究如何更全面地考虑可选性,例如,将可选字段分组为一个可选结构体。这种工作可能会废弃内嵌功能可能带来的任何好处。

早期技术和参考资料

此 FTP 是 rfc-0026 的精简版本,由于整个 FTP 无法获得足够的共识,遭到拒绝。

提案。 内嵌、在任何位置都进行封装以及将字符串/矢量计数移出外线都已移除。


  1. 此 FTP 基于 rfc-0026,但只有外行信封

  2. 请注意,目前空(零字段)结构体会在线占用一个字节。