Изменение типа поля protobuf с double на float - PullRequest
0 голосов
/ 07 мая 2020

У меня есть прото-сообщение, которое я использую в службе для хранения данных в разных местах

Мое сообщение выглядит так:

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

Моя команда решила, что Matrix сообщение слишком велико, и изменение типа на float кажется простым способом добиться уменьшения размера полезной нагрузки. Но когда я изменяю определение прототипа, чтобы использовать здесь float вместо double, и пытаюсь прочитать старые данные (в считывающем устройстве Python), они выглядят поврежденными.

Один из вариантов, который я могу придумать состоит в том, чтобы добавить новую опцию с плавающей запятой для каждого поля:

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. Это работает, но выглядит как неуклюжий шаблон проектирования.

Есть ли другой способ обеспечить обратную совместимость со старыми данными в этом примере?

1 Ответ

0 голосов
/ 07 мая 2020

Думаю, вы правильно поняли. Вы захотите оставить старые поля вместе с их номерами без изменений, пока есть данные, хранящиеся в старом формате. Одна из замечательных особенностей буферов протокола заключается в том, что неустановленные поля по существу бесплатны, поэтому вы можете добавить столько новых полей, сколько хотите для облегчения миграции.

Я бы добавил новый набор 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;
}

Это гарантирует, что любые случайные сообщения в старом формате взорвутся при десериализации вместо того, чтобы вызывать повреждение данных.

Надеюсь, это поможет!

...