将 protobuf 字段类型从 double 更改为 float

Changing protobuf field type from double to float

我有一个原始消息,我在服务中使用它来在不同的地方存储数据

我的留言是这样的:

message Matrix {
  double width = 1;
  double height = 2;
  repeated double entries = 3;
}

我的团队认为 Matrix 消息太大,将类型更改为 float 似乎是减少负载大小的简单方法。 但是当我在这里更改原型定义以使用 float 而不是 double,并尝试读取旧数据(在 Python reader 中)时,它看起来已损坏。

我能想到的一个选项是为每个字段添加一个新的浮动选项:

message Matrix {
  oneof r_oneof {
    double width_d = 1;
    float width_f = 4;
  }
  oneof c_oneof {
    double height_d = 2;
    float height_f = 5;
  }
  oneof e_oneof {
    repeated double entries_d = 3;
    repeated float entries_f = 6;
  }
}

然后我的反序列化代码可以检查每个oneof字段是double还是float字段。这可行,但感觉像是一个笨拙的设计模式。

在此示例中,是否有另一种方法可以向后兼容旧数据?

我认为你的想法是正确的。只要有以旧格式存储的数据,您就会希望保持旧字段及其字段编号不变。 protocol buffers 的一大优点是未设置的字段基本上是免费的,因此您可以根据需要添加任意数量的新字段以促进迁移。

我要做的是添加一组新的 float 字段并重命名 double 字段,同时保留它们的字段编号:

message Matrix {
  // Values in these fields should be transitioned to floats
  double deprecated_width = 1;
  double deprecated_height = 2;
  repeated double deprecated_entries = 3;

  float width = 4;
  float height = 5;
  repeated float entries = 6;
}

每当您从持久存储中读取 Matrix 时,将任何值从已弃用的字段移动到未弃用的字段并写回结果。这应该有助于增量迁移到浮动。

我再提一件事你可能已经知道:协议缓冲区不关心字段名称。只有字段编号对序列化和反序列化很重要。这意味着只要操作它们的代码同样更新,字段就可以自由重命名。

在将来某个时候迁移完成后删除迁移代码并删除已弃用的字段但保留它们的字段编号:

message Matrix {
  reserved 1, 2, 3;
  float width = 4;
  float height = 5;
  repeated float entries = 6;
}

这可确保旧格式的任何杂散消息在反序列化时爆炸,而不是导致数据损坏。

希望对您有所帮助!