protobuf 的 descriptor pool、option

protobuf 提供了下面两个有意思的功能。

descriptor pool

一个 protobuf 的 message 的 reflection API 是通过 descriptor 建立起来的,通常我们可以通过一个 message 的 static method:descriptor 拿到对应的 descriptor 继而进行一些工作。那么如果我们没有编译时候的类型信息,我们希望 runtime 通过一个 type erased 的类型获得相关的 descriptor 的话,可以依赖 descriptor pool,事实上 proto2::DescriptorPool 提供的 API 可以做非常多的事情,我们这里仅仅讨论一个对应的实现 DescriptorPool::generated_pool() 所返回的 pool 可以用来查询当前 binary 里面所链接的所有 message,这意味着我们可以通过一个 protobuf message 的 canonical name(字符串)获取对应的 Descriptor。

很显然如果我们需要将 message 类型本身通过 serialization/deserialization 的 boundary,字符串也要比 Descriptor* 容易很多。

options

protobuf 提供的一种 annotation 称为 option,它出现在 protobuf 的定义中,可以为几乎所有的东西提供 annotation:message 类型、field 甚至 enum value 等等。我们通过每个类型对应的 descriptor API 可以获得这些 annotation,这样我们就可以根据这些额外的 annotation 进行一些改变。

一个简单的例子:比如一个 query language 在处理某个 protobuf 的数据时,protobuf 本身其实作为一个 schema 可以将类型信息用在 query parsing 和 type verification 上,但是比如整数的 formatting 等问题并不能完全被 protobuf 本身涵盖,这更接近 query 这个 domain 希望如何 interpret 整数:uint64 是不是其实是一个 IP 地址,或者一个 timestamp 还是就是最好 hex 输出的 hash value

因此每个 domain 很可能希望有一套自己的 annotation,这样尽管生成数据的人尽管不关心 query,但是通过简单的 annotation 就可以在 query 自己数据的时候获得需要的格式了。

protobuf 的 option 也是通过 extension 来实现的。我们首先需要把 annotation 本身用一个 message type 来描述出来,然后在合适的 scope 中 extend protobuf 的 options,将自定义的 annotation type 以某种 extension 加入(如 message 是 proto2.MessageOptions)。这样我们就可以使用 option 关键字来 annotate 一些地方(field 和 value 的 annotation 语法稍微有点不同)。

除了以上这种用法,我们有时候还希望为某些类型关联一些 metadata,一种方法是通过 traits 在 C++ 代码里面提供,另一种就是当这些类型是 protobuf type 的时候我们也可以通过 options 来实现。很显然前者更为 generic,能够提供关联的方法,后者一般用相同的类型来存储 metadata,可以用 reflection/descriptor 的 API 来操作。

Advertisements
protobuf 的 descriptor pool、option

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s