Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.7 KiB
140 lines
4.7 KiB
1 year ago
|
# Minimum Required Edition
|
||
|
|
||
|
**Author:** [@mcy](https://github.com/mcy)
|
||
|
|
||
|
**Approved:** 2022-11-15
|
||
|
|
||
|
A versioning mechanism for descriptors that ensures old runtimes do not load
|
||
|
descriptors that are "too new."
|
||
|
|
||
|
## Background
|
||
|
|
||
|
Suppose we decide to add a novel definition like
|
||
|
|
||
|
```
|
||
|
const int32 MY_CONSTANT = 42;
|
||
|
```
|
||
|
|
||
|
to the Protobuf language. This would entail a descriptor change to track the
|
||
|
values of constants, but they would not be loaded properly by older runtimes.
|
||
|
This document describes an addition to `descriptor.proto` that prevents this
|
||
|
version mismatch issue.
|
||
|
|
||
|
[Protobuf Editions](what-are-protobuf-editions.md) intends to add the concept of
|
||
|
an edition to Protobuf, which will be an approximately-annually incrementing
|
||
|
value. Because of their annual nature, and because runtimes need to be updated
|
||
|
to handle new features they implement regardless, we can use them as a poison
|
||
|
pill for old runtimes that try to load descriptors that are "too new."
|
||
|
|
||
|
## Overview
|
||
|
|
||
|
We propose adding a new field to `FileDescriptorProto`:
|
||
|
|
||
|
```
|
||
|
optional string minimum_required_edition = ...;
|
||
|
```
|
||
|
|
||
|
This field would exist alongside the `edition` field, and would have the
|
||
|
following semantics:
|
||
|
|
||
|
Every Protobuf runtime implementation must specify the newest edition whose
|
||
|
constructs it can handle (at a particular rev of that implementation). If that
|
||
|
edition is less than `minimum_required_edition`, loading the descriptor must
|
||
|
fail.
|
||
|
|
||
|
"Less than" is defined per the edition total order given in
|
||
|
[Life of an Edition](life-of-an-edition.md). To restate it, it is the following
|
||
|
algorithm:
|
||
|
|
||
|
```
|
||
|
def edition_less_than(a, b):
|
||
|
parts_a = a.split(".")
|
||
|
parts_b = b.split(".")
|
||
|
for i in range(0, min(len(parts_a), len(parts_b))):
|
||
|
if int(parts_a[i]) < int(parts_b[i]): return True
|
||
|
return len(a) < len(b)
|
||
|
```
|
||
|
|
||
|
`protoc` should keep track of which constructions require which minimum edition.
|
||
|
For example, if constants are introduced in edition 2025, but they are not
|
||
|
present in a file, `protoc` should not require that runtimes understand
|
||
|
constants by picking a lower edition, like 2023 (assuming no other construct
|
||
|
requires a higher edition).
|
||
|
|
||
|
In particular, the following changes should keep the minimum edition constant,
|
||
|
with all other things unchanged:
|
||
|
|
||
|
* An upgrade of the proto compiler.
|
||
|
* Upgrading the specified edition of a file via Prototiller.
|
||
|
|
||
|
### Bootstrapping Concerns
|
||
|
|
||
|
"Epochs for `descriptor.proto`" (not available externally) describes a potential
|
||
|
issue with bootstrapping. It is not the case here: minimum edition is only
|
||
|
incremented once a particular file uses a new feature. Since `descriptor.proto`
|
||
|
and other schemas used by `protoc` and the backends would not use new features
|
||
|
immediately, introducing a new feature does not immediately stop the compiler
|
||
|
from being able to compile itself.
|
||
|
|
||
|
### Concerns for Schema Producers
|
||
|
|
||
|
Schema producers should consider changes to their schemas that increase the
|
||
|
minimum required edition to be breaking changes, since it will stop compiled
|
||
|
descriptors from being loaded at runtime.
|
||
|
|
||
|
## Recommendation
|
||
|
|
||
|
We recommend adding the aforementioned minimum required edition field, along
|
||
|
with the semantics it entails. This logic should be implemented entirely in the
|
||
|
protoc frontend.
|
||
|
|
||
|
## Alternatives
|
||
|
|
||
|
### Use a Non-Editions Version Number
|
||
|
|
||
|
Rather than using the editions value, use some other version number. This number
|
||
|
would be incremented rarely (3-5 year horizon). This is the approach proposed
|
||
|
in "Epochs for `descriptor.proto`."
|
||
|
|
||
|
#### Pros
|
||
|
|
||
|
* Does not re-use the editions value for a semantically-different meaning; the
|
||
|
edition remains being "just" a key into a table of features defaults.
|
||
|
|
||
|
#### Cons
|
||
|
|
||
|
* Introduces another version number to Protobuf that increments at its own
|
||
|
cadence.
|
||
|
* Could potentially be confused with the edition value, even though they serve
|
||
|
distinct purposes.
|
||
|
|
||
|
### Minimum Required Edition Should Not Be Minimal
|
||
|
|
||
|
The proto compiler should not guarantee that the minimum required edition is as
|
||
|
small as it could possibly be.
|
||
|
|
||
|
#### Pros
|
||
|
|
||
|
* Reduces implementation burden.
|
||
|
|
||
|
#### Cons
|
||
|
|
||
|
* This introduces situations where an upgrade of the proto compiler, or an
|
||
|
innocuous change to a schema, can lead the the minimum required edition
|
||
|
being incremented. This is a problem for schema producers.
|
||
|
|
||
|
### Do Nothing
|
||
|
|
||
|
#### Pros
|
||
|
|
||
|
* Reduces churn in runtimes, since they do not need to implement new handling
|
||
|
for new *editions* (as contrasted to just *features)* regularly.
|
||
|
* Avoids a situation where old software cannot load new descriptors at
|
||
|
runtime.
|
||
|
|
||
|
#### Cons
|
||
|
|
||
|
* Commits us to never changing the descriptor wire format in
|
||
|
backwards-incompatible ways, which has far-reaching effects on evolution.
|
||
|
These consequences are discussed in "Epochs for `descriptor.proto`."
|