暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Yugabyte-Protobuf编程指南

原创 敏博科技 2021-03-29
1101

作者介绍:包子侠

原文链接:原文链接

1. 基本介绍

yugabyte使用google的protobuf实现rpc通信,因此大多数关于protobuf编程的细节可以参考官方文档。另外yugabyte基于protobuf构建rpc通信,其rpc客户端和服务器的实现是通用的,因此yugabyte实现了一个protobuf的plugin来负责对service相关的proto文件进行编译。

2. protobuf简单介绍

传送门:官方文档中文参考
下面是yugabyte的docdb.proto文件,以此作为protobuf编写的简单介绍:

syntax = "proto2";  // 指定protobuf协议,如果不指定,默认使用proto2

package yb.docdb; // 对应C++的名字空间,这里是两层名字空间yb和docdb

import "yb/common/common.proto";  // 引用其他proto文件中定义的类型
import "yb/util/opid.proto";

option java_package = "org.yb.docdb";

// 定义一个数据结构
// 成员变量除了类型之外,还需要提供一个标注,三选一:optional、repeated、required
// 分别表示可选、可重复[0-n]、必选
// 每个成员后面跟着一个数字,用来在二进制编码中标识该字段,因此必须唯一
message KeyValuePairPB {
  optional bytes key = 1;
  optional bytes value = 2;
  optional fixed64 external_hybrid_time = 3;
}

// A set of key/value pairs to be written into RocksDB.
message KeyValueWriteBatchPB {
  repeated KeyValuePairPB write_pairs = 1;
  optional TransactionMetadataPB transaction = 2;
  optional bool DEPRECATED_may_have_metadata = 3;
  // Used by serializable isolation transactions and row locking statements to store read intents.
  // In case of read-modify-write operation both read_pairs and write_pairs could present.
  repeated KeyValuePairPB read_pairs = 5;
  optional RowMarkType row_mark_type = 6;
}

message ConsensusFrontierPB {
  optional OpIdPB op_id = 1;
  optional fixed64 hybrid_time = 2;
  optional fixed64 history_cutoff = 3;
  optional fixed64 hybrid_time_filter = 4;
}

protoc会将proto文件中的message编译成C++的类,并生成成员变量的访问接口,每个成员变量会生成固定的一组形式相同的函数,以KeyValuePairPB的key为例:

bool has_key() const; void clear_key(); const ::std::string& key() const; void set_key(const ::std::string& value); #if LANG_CXX11 void set_key(::std::string&& value); #endif void set_key(const char* value); void set_key(const void* value, size_t size); ::std::string* mutable_key(); ::std::string* release_key(); void set_allocated_key(::std::string* key);

有些类型,比如int是不支持修改的,其接口要少一些

bool has_external_hybrid_time() const; void clear_external_hybrid_time(); ::google::protobuf::uint64 external_hybrid_time() const; void set_external_hybrid_time(::google::protobuf::uint64 value);

3. Yugabyte的protoc插件

3.1 protoc-gen-insertions

该插件主要两个功能:

  • 给编译后的源代码文件名添加.pb后缀,比如common.h会变成common.pb.h
  • 添加头文件:yb/gutil/dynamic_annotations.h

该插件在编译所有yugabyte的proto文件时都会用到,源码位置:
src\yb\util\protoc-gen-insertions.cc

3.2 protoc-gen-yrpc

该插件的主要功能是根据proto文件生成ServiceIf和RPC Proxy源代码,因此只有部分服务相关的proto文件会使用该插件进行编译。
我们在阅读yugabyte的源代码时,会发现一些核心的服务类,只有接口的实现,没有接口调用的地方,主要就是因为接口的调用处理是在ServiceIf文件中实现的,这些文件是通过proto在编译阶段生成的。同时客户端调用rpc请求时,最终的rpc调用函数也无法找到实现的地方,原因类似。

service类的proto以service关键字类定义,里面只有rpc接口声明,用关键字rpc标识,以TabletServerService为例:

syntax = "proto2";

package yb.tserver;

option java_package = "org.yb.tserver";

import "yb/common/common.proto";
import "yb/tserver/tserver.proto";
import "yb/tablet/metadata.proto";

service TabletServerService {
  rpc Write(WriteRequestPB) returns (WriteResponsePB);
  rpc Read(ReadRequestPB) returns (ReadResponsePB);
  rpc NoOp(NoOpRequestPB) returns (NoOpResponsePB);
  rpc ListTablets(ListTabletsRequestPB) returns (ListTabletsResponsePB);
  rpc GetLogLocation(GetLogLocationRequestPB) returns (GetLogLocationResponsePB);

  // Run full-scan data checksum on a tablet to verify data integrity.
  //
  // TODO: Consider refactoring this as a scan that runs a checksum aggregation
  // function.
  rpc Checksum(ChecksumRequestPB) returns (ChecksumResponsePB);

  rpc ListTabletsForTabletServer(ListTabletsForTabletServerRequestPB)
      returns (ListTabletsForTabletServerResponsePB);

  rpc ImportData(ImportDataRequestPB) returns (ImportDataResponsePB);
  rpc UpdateTransaction(UpdateTransactionRequestPB) returns (UpdateTransactionResponsePB);
  // Returns transaction status at coordinator, i.e. PENDING, ABORTED, COMMITTED etc.
  rpc GetTransactionStatus(GetTransactionStatusRequestPB) returns (GetTransactionStatusResponsePB);
  // Returns transaction status at participant, i.e. number of replicated batches or whether it was
  // aborted.
  rpc GetTransactionStatusAtParticipant(GetTransactionStatusAtParticipantRequestPB)
      returns (GetTransactionStatusAtParticipantResponsePB);
  rpc AbortTransaction(AbortTransactionRequestPB) returns (AbortTransactionResponsePB);
  rpc Truncate(TruncateRequestPB) returns (TruncateResponsePB);
  rpc GetTabletStatus(GetTabletStatusRequestPB) returns (GetTabletStatusResponsePB);
  rpc GetMasterAddresses(GetMasterAddressesRequestPB) returns (GetMasterAddressesResponsePB);

  rpc Publish(PublishRequestPB) returns (PublishResponsePB);

  rpc IsTabletServerReady(IsTabletServerReadyRequestPB) returns (IsTabletServerReadyResponsePB);

  // Takes precreated transaction from this tserver.
  rpc TakeTransaction(TakeTransactionRequestPB) returns (TakeTransactionResponsePB);
}

该插件的源码位置:
src\yb\rpc\protoc-gen-yrpc.cc

4. Yugabyte构建过程中如何使用proto文件

4.1 普通proto构建

对于非service类的proto定义,通过PROTOBUF_GENERATE_CPP指令来添加到CMakeList中,以docdb.proto为例

# docdb_proto

PROTOBUF_GENERATE_CPP(
        DOCDB_PROTO_SRCS DOCDB_PROTO_HDRS DOCDB_PROTO_TGTS
        SOURCE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..
        BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR}/../..
        PROTO_FILES docdb.proto)

ADD_YB_LIBRARY(docdb_proto
        SRCS ${DOCDB_PROTO_SRCS}
        DEPS protobuf yb_common_proto opid_proto
        NONLINK_DEPS ${DOCDB_PROTO_TGTS})

set(DOCDB_ENCODING_SRCS
        doc_key.cc
        doc_kv_util.cc
        key_bytes.cc
        primitive_value.cc
        primitive_value_util.cc
        intent.cc
        doc_scanspec_util.cc
        )

set(DOCDB_ENCODING_DEPS
        docdb_proto
        server_common
        yb_common
        yb_rocksutil
        yb_util
        )

ADD_YB_LIBRARY(yb_docdb_encoding
        SRCS ${DOCDB_ENCODING_SRCS}
        DEPS ${DOCDB_ENCODING_DEPS}
        )

4.2 service类proto构建

对于service类,需要使用额外的插件来生成代码,在CMakeLists文件中通过YRPC_GENERATE指令进行构建,以tserver_service.proto为例:

#########################################
# tserver_service_proto
#########################################

YRPC_GENERATE(
  TSERVER_YRPC_SRCS TSERVER_YRPC_HDRS TSERVER_YRPC_TGTS
  SOURCE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..
  BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR}/../..
  PROTO_FILES tserver_service.proto)
set(TSERVER_YRPC_LIBS
  yrpc
  yb_common_proto
  protobuf
  remote_bootstrap_proto
  rpc_header_proto
  tserver_proto
  wire_protocol_proto)
ADD_YB_LIBRARY(tserver_service_proto
  SRCS ${TSERVER_YRPC_SRCS}
  DEPS ${TSERVER_YRPC_LIBS}
  NONLINK_DEPS ${TSERVER_YRPC_TGTS})

MemFireDB,带你体验不一样的云端飞翔。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论