feat: metasrv (#300)

* meta: meta api&client

* meta: heartbeat server init

* feat: kv store

* chore: grpc server

* chore: meta server bootstrap

* feat: heartbeat client

* feat: route for create table

* chore: a channel pool manager

* feat: route client

* feat: store client

* chore: meta_client example

* chore: change schema

* chore: unit test & by cr

* chore: refactor meta client

* chore: add unit test
This commit is contained in:
Jiachun Feng
2022-10-19 11:02:58 +08:00
committed by GitHub
parent 4d08ee6fbb
commit d5b34f8917
43 changed files with 3846 additions and 12 deletions

View File

@@ -6,6 +6,10 @@ fn main() {
"greptime/v1/select.proto",
"greptime/v1/physical_plan.proto",
"greptime/v1/greptime.proto",
"greptime/v1/meta/common.proto",
"greptime/v1/meta/heartbeat.proto",
"greptime/v1/meta/route.proto",
"greptime/v1/meta/store.proto",
],
&["."],
)

View File

@@ -0,0 +1,46 @@
syntax = "proto3";
package greptime.v1.meta;
message RequestHeader {
uint64 protocol_version = 1;
// cluster_id is the ID of the cluster which be sent to.
uint64 cluster_id = 2;
// member_id is the ID of the sender server.
uint64 member_id = 3;
}
message ResponseHeader {
uint64 protocol_version = 1;
// cluster_id is the ID of the cluster which sent the response.
uint64 cluster_id = 2;
Error error = 3;
}
message Error {
int32 code = 1;
string err_msg = 2;
}
message Peer {
uint64 id = 1;
Endpoint endpoint = 2;
}
message Endpoint {
string addr = 1;
}
message TimeInterval {
// The unix timestamp in millis of the start of this period.
uint64 start_timestamp_millis = 1;
// The unix timestamp in millis of the end of this period.
uint64 end_timestamp_millis = 2;
}
message KeyValue {
// key is the key in bytes. An empty key is not allowed.
bytes key = 1;
// value is the value held by the key, in bytes.
bytes value = 2;
}

View File

@@ -0,0 +1,82 @@
syntax = "proto3";
package greptime.v1.meta;
import "greptime/v1/meta/common.proto";
service Heartbeat {
// Heartbeat, there may be many contents of the heartbeat, such as:
// 1. Metadata to be registered to meta server and discoverable by other nodes.
// 2. Some performance metrics, such as Load, CPU usage, etc.
// 3. The number of computing tasks being executed.
rpc Heartbeat(stream HeartbeatRequest) returns (stream HeartbeatResponse) {}
// Ask leader's endpoint.
rpc AskLeader(AskLeaderRequest) returns (AskLeaderResponse) {}
}
message HeartbeatRequest {
RequestHeader header = 1;
// Leader node
bool is_leader = 2;
// Leader Peer
Endpoint leader_endpoint = 3;
// Actually reported time interval
TimeInterval report_interval = 4;
// Node stat
NodeStat node_stat = 5;
// Region stats in this node
repeated RegionStat region_stats = 6;
// Follower nodes and stats, empty on follower nodes
repeated ReplicaStat replica_stats = 7;
}
message NodeStat {
// The read capacity units during this period
uint64 rcus = 1;
// The write capacity units during this period
uint64 wcus = 2;
// Table number in this node
uint64 table_num = 3;
// Regon number in this node
uint64 region_num = 4;
double cpu_usage = 5;
double load = 6;
// Read disk I/O in the node
double read_io_rate = 7;
// Write disk I/O in the node
double write_io_rate = 8;
}
message RegionStat {
string table_name = 1;
uint64 region_id = 2;
// The read capacity units during this period
uint64 rcus = 3;
// The write capacity units during this period
uint64 wcus = 4;
}
message ReplicaStat {
Peer peer = 1;
bool in_sync = 2;
bool is_learner = 3;
}
message HeartbeatResponse {
ResponseHeader header = 1;
repeated bytes payload = 2;
}
message AskLeaderRequest {
RequestHeader header = 1;
}
message AskLeaderResponse {
ResponseHeader header = 1;
Endpoint leader = 2;
}

View File

@@ -0,0 +1,93 @@
syntax = "proto3";
package greptime.v1.meta;
import "greptime/v1/meta/common.proto";
service Router {
// Fetch routing information for tables. The smallest unit is the complete
// routing information(all regions) of a table.
//
// table_1
// table_name
// table_schema
// regions
// region_1
// mutate_endpoint
// select_endpoint_1, select_endpoint_2
// region_2
// mutate_endpoint
// select_endpoint_1, select_endpoint_2, select_endpoint_3
// region_xxx
// table_2
// ...
//
rpc Route(RouteRequest) returns (RouteResponse) {}
rpc Create(CreateRequest) returns (CreateResponse) {}
}
message RouteRequest {
RequestHeader header = 1;
repeated TableName table_names = 2;
}
message RouteResponse {
ResponseHeader header = 1;
repeated Peer peers = 2;
repeated TableRoute table_routes = 3;
}
message CreateRequest {
RequestHeader header = 1;
TableName table_name = 2;
repeated Region regions = 3;
}
message CreateResponse {
ResponseHeader header = 1;
repeated Region regions = 2;
}
message TableRoute {
Table table = 1;
repeated RegionRoute region_routes = 2;
}
message RegionRoute {
Region region = 1;
// single leader node for write task
uint64 leader_peer_index = 2;
// multiple follower nodes for read task
repeated uint64 follower_peer_indexes = 3;
}
message TableName {
string catalog_name = 1;
string schema_name = 2;
string table_name = 3;
}
message Table {
TableName table_name = 1;
bytes table_schema = 2;
}
message Region {
uint64 id = 1;
string name = 2;
Peer peer = 3;
// PARTITION `region_name` VALUES LESS THAN (value_list)
message Partition {
repeated bytes column_list = 1;
repeated bytes value_list = 2;
}
Partition partition = 4;
map<string, string> attrs = 5;
}

View File

@@ -0,0 +1,94 @@
syntax = "proto3";
package greptime.v1.meta;
import "greptime/v1/meta/common.proto";
service Store {
// Range gets the keys in the range from the key-value store.
rpc Range(RangeRequest) returns (RangeResponse);
// Put puts the given key into the key-value store.
rpc Put(PutRequest) returns (PutResponse);
// DeleteRange deletes the given range from the key-value store.
rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse);
}
message RangeRequest {
RequestHeader header = 1;
// key is the first key for the range, If range_end is not given, the
// request only looks up key.
bytes key = 2;
// range_end is the upper bound on the requested range [key, range_end).
// If range_end is '\0', the range is all keys >= key.
// If range_end is key plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"),
// then the range request gets all keys prefixed with key.
// If both key and range_end are '\0', then the range request returns all
// keys.
bytes range_end = 3;
// limit is a limit on the number of keys returned for the request. When
// limit is set to 0, it is treated as no limit.
int64 limit = 4;
// keys_only when set returns only the keys and not the values.
bool keys_only = 5;
}
message RangeResponse {
ResponseHeader header = 1;
// kvs is the list of key-value pairs matched by the range request.
repeated KeyValue kvs = 2;
bool more = 3;
}
message PutRequest {
RequestHeader header = 1;
// key is the key, in bytes, to put into the key-value store.
bytes key = 2;
// value is the value, in bytes, to associate with the key in the
// key-value store.
bytes value = 3;
// If prev_kv is set, gets the previous key-value pair before changing it.
// The previous key-value pair will be returned in the put response.
bool prev_kv = 4;
}
message PutResponse {
ResponseHeader header = 1;
// If prev_kv is set in the request, the previous key-value pair will be
// returned.
KeyValue prev_kv = 2;
}
message DeleteRangeRequest {
RequestHeader header = 1;
// key is the first key to delete in the range.
bytes key = 2;
// range_end is the key following the last key to delete for the range
// [key, range_end).
// If range_end is not given, the range is defined to contain only the key
// argument.
// If range_end is one bit larger than the given key, then the range is all
// the keys with the prefix (the given key).
// If range_end is '\0', the range is all keys greater than or equal to the
// key argument.
bytes range_end = 3;
// If prev_kv is set, gets the previous key-value pairs before deleting it.
// The previous key-value pairs will be returned in the delete response.
bool prev_kv = 4;
}
message DeleteRangeResponse {
ResponseHeader header = 1;
// deleted is the number of keys deleted by the delete range request.
int64 deleted = 2;
// If prev_kv is set in the request, the previous key-value pairs will be
// returned.
repeated KeyValue prev_kvs = 3;
}

View File

@@ -4,3 +4,5 @@ tonic::include_proto!("greptime.v1");
pub mod codec {
tonic::include_proto!("greptime.v1.codec");
}
pub mod meta;

139
src/api/src/v1/meta.rs Normal file
View File

@@ -0,0 +1,139 @@
tonic::include_proto!("greptime.v1.meta");
pub const PROTOCOL_VERSION: u64 = 1;
impl Peer {
pub fn new(id: u64, addr: impl AsRef<str>) -> Self {
Self {
id,
endpoint: Some(addr.as_ref().into()),
}
}
}
impl From<&str> for Endpoint {
fn from(s: &str) -> Self {
Self {
addr: s.to_string(),
}
}
}
impl RequestHeader {
pub fn new(cluster_id: u64, member_id: u64) -> RequestHeader {
RequestHeader {
protocol_version: PROTOCOL_VERSION,
cluster_id,
member_id,
}
}
}
impl HeartbeatRequest {
pub fn new(header: RequestHeader) -> Self {
Self {
header: Some(header),
..Default::default()
}
}
}
impl AskLeaderRequest {
pub fn new(header: RequestHeader) -> Self {
Self {
header: Some(header),
}
}
}
impl TableName {
pub fn new(
catalog: impl Into<String>,
schema: impl Into<String>,
table: impl Into<String>,
) -> Self {
Self {
catalog_name: catalog.into(),
schema_name: schema.into(),
table_name: table.into(),
}
}
}
impl RouteRequest {
pub fn new(header: RequestHeader) -> Self {
Self {
header: Some(header),
..Default::default()
}
}
pub fn add_table(mut self, table_name: TableName) -> Self {
self.table_names.push(table_name);
self
}
}
impl CreateRequest {
pub fn new(header: RequestHeader, table_name: TableName) -> Self {
Self {
header: Some(header),
table_name: Some(table_name),
..Default::default()
}
}
pub fn add_region(mut self, region: Region) -> Self {
self.regions.push(region);
self
}
}
impl Region {
pub fn new(id: u64, name: impl Into<String>, partition: region::Partition) -> Self {
Self {
id,
name: name.into(),
partition: Some(partition),
..Default::default()
}
}
pub fn attr(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
self.attrs.insert(key.into(), val.into());
self
}
}
impl region::Partition {
pub fn new() -> Self {
Default::default()
}
pub fn column_list(mut self, column_list: Vec<Vec<u8>>) -> Self {
self.column_list = column_list;
self
}
pub fn value_list(mut self, value_list: Vec<Vec<u8>>) -> Self {
self.value_list = value_list;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_peer() {
let peer = Peer::new(1, "test_addr");
assert_eq!(1, peer.id);
assert_eq!(
Endpoint {
addr: "test_addr".to_string()
},
peer.endpoint.unwrap()
);
}
}