From b07ec74f356ce7e853bc18664e0bdb42b6b64404 Mon Sep 17 00:00:00 2001 From: liyang Date: Tue, 24 Sep 2024 01:29:26 +0800 Subject: [PATCH] feat: Supports gRPC write hints --- config.go | 4 +- examples/README.md | 1 + examples/hint/README.md | 58 +++++++++++++++++++ examples/hint/main.go | 121 ++++++++++++++++++++++++++++++++++++++++ pkg/hint/hint.go | 39 +++++++++++++ request/request.go | 8 ++- 6 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 examples/hint/README.md create mode 100644 examples/hint/main.go create mode 100644 pkg/hint/hint.go diff --git a/config.go b/config.go index 099e3cd..8aa6020 100644 --- a/config.go +++ b/config.go @@ -107,7 +107,7 @@ func (c *Config) WithMetricsEnabled(b bool) *Config { // WithMeterProvider provides a MeterProvider for SDK. // If metrics colleciton is not enabled, then this option has no effect. -// If metrics colleciton is enabled and this option is not provide +// If metrics colleciton is enabled and this option is not provide. // the global MeterProvider will be used. func (c *Config) WithMeterProvider(p metric.MeterProvider) *Config { c.telemetry.Metrics.MeterProvider = p @@ -122,7 +122,7 @@ func (c *Config) WithTracesEnabled(b bool) *Config { // WithTraceProvider provides a TracerProvider for SDK. // If traces colleciton is not enabled, then this option has no effect. -// If traces colleciton is enabled and this option is not provide +// If traces colleciton is enabled and this option is not provide. // the global MeterProvider will be used. func (c *Config) WithTraceProvider(p trace.TracerProvider) *Config { c.telemetry.Traces.TracerProvider = p diff --git a/examples/README.md b/examples/README.md index 3a450de..6634847 100644 --- a/examples/README.md +++ b/examples/README.md @@ -16,6 +16,7 @@ docker run --rm -p 4000-4003:4000-4003 \ - [table](table/README.md) - [object](object/README.md) - [healthcheck](healthcheck/README.md) +- [hint](hint/README.md) ## Query diff --git a/examples/hint/README.md b/examples/hint/README.md new file mode 100644 index 0000000..46a2b46 --- /dev/null +++ b/examples/hint/README.md @@ -0,0 +1,58 @@ +# Write Hints + +## Insert + +```go +go run main.go +``` + +Output: + +```log +2024/09/24 01:16:03 create table, name: 'monitor_table_with_hint' +2024/09/24 01:16:03 affected rows: 3 +``` + +## Query + +Your can using [MySQL Client](https://docs.greptime.com/user-guide/protocols/mysql) to query the data from GreptimeDB. + +```shell +$ mysql -h 127.0.0.1 -P 4002 public + +mysql> select * from monitor_table_with_hint; ++------+-------+-------------+----------------------------+ +| id | host | temperature | timestamp | ++------+-------+-------------+----------------------------+ +| 1 | hello | 1.1 | 2024-09-23 17:16:03.476898 | +| 2 | hello | 2.2 | 2024-09-23 17:16:03.476898 | +| 3 | hello | 3.3 | 2024-09-23 17:16:03.476898 | ++------+-------+-------------+----------------------------+ +3 rows in set (0.03 sec) +``` + +You can view hints using `show create table` command: + +```mysql +mysql> show create table monitor_table_with_hint; ++------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Table | Create Table | ++------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| monitor_table_with_hint | CREATE TABLE IF NOT EXISTS `monitor_table_with_hint` ( + `id` BIGINT NULL, + `host` STRING NULL, + `temperature` DOUBLE NULL, + `timestamp` TIMESTAMP(6) NOT NULL, + TIME INDEX (`timestamp`), + PRIMARY KEY (`id`) +) + +ENGINE=mito +WITH( + append_mode = 'false', + merge_mode = 'last_non_null', + ttl = '3day' +) | ++------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +1 row in set (0.02 sec) +``` diff --git a/examples/hint/main.go b/examples/hint/main.go new file mode 100644 index 0000000..19247bd --- /dev/null +++ b/examples/hint/main.go @@ -0,0 +1,121 @@ +// Copyright 2024 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "log" + "time" + + greptime "github.com/GreptimeTeam/greptimedb-ingester-go" + + "github.com/GreptimeTeam/greptimedb-ingester-go/pkg/hint" + "github.com/GreptimeTeam/greptimedb-ingester-go/table" + "github.com/GreptimeTeam/greptimedb-ingester-go/table/types" +) + +const ( + INSERT = 0 +) + +var ( + client *greptime.Client +) + +func init() { + cfg := greptime.NewConfig("127.0.0.1").WithDatabase("public") + + cli_, err := greptime.NewClient(cfg) + if err != nil { + log.Panic(err) + } + client = cli_ +} + +func initData() []*table.Table { + time1 := time.Now() + time2 := time.Now() + time3 := time.Now() + + itbl, err := table.New("monitor_table_with_hint") + if err != nil { + log.Println(err) + return nil + } + // add column at first. This is to define the schema of the table. + if err := itbl.AddTagColumn("id", types.INT64); err != nil { + log.Println(err) + return nil + } + if err := itbl.AddFieldColumn("host", types.STRING); err != nil { + log.Println(err) + return nil + } + if err := itbl.AddFieldColumn("temperature", types.FLOAT); err != nil { + log.Println(err) + return nil + } + if err := itbl.AddTimestampColumn("timestamp", types.TIMESTAMP_MICROSECOND); err != nil { + log.Println(err) + return nil + } + + if err := itbl.AddRow(1, "hello", 1.1, time1); err != nil { + log.Println(err) + return nil + } + if err := itbl.AddRow(2, "hello", 2.2, time2); err != nil { + log.Println(err) + return nil + } + if err := itbl.AddRow(3, "hello", 3.3, time3); err != nil { + log.Println(err) + return nil + } + + return []*table.Table{itbl} +} + +func write(data *table.Table) { + var hints []hint.Hint + hints = append(hints, + hint.Hint{Key: "ttl", Value: "3d"}, + hint.Hint{Key: "merge_mode", Value: "last_non_null"}, + hint.Hint{Key: "append_mode", Value: "false"}, + ) + + ctx := hint.CreateContextWithHints(hints) + ctx, cancel := context.WithTimeout(ctx, time.Second*3) + defer cancel() + + resp, err := client.Write(ctx, data) + if err != nil { + log.Println(err) + return + } + tableName, err := data.GetName() + if err != nil { + log.Println(err) + return + } + log.Printf("create table, name: '%s'", tableName) + log.Printf("affected rows: %d\n", resp.GetAffectedRows().GetValue()) +} + +func main() { + data := initData() + + write(data[INSERT]) +} diff --git a/pkg/hint/hint.go b/pkg/hint/hint.go new file mode 100644 index 0000000..bf0e19d --- /dev/null +++ b/pkg/hint/hint.go @@ -0,0 +1,39 @@ +// Copyright 2024 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hint + +import ( + "context" + + "google.golang.org/grpc/metadata" +) + +const ( + hintPrefix = "x-greptime-hint-" +) + +type Hint struct { + Key string + Value string +} + +func CreateContextWithHints(hints []Hint) context.Context { + md := metadata.New(nil) + for _, hint := range hints { + md.Append(hintPrefix+hint.Key, hint.Value) + } + ctx := metadata.NewOutgoingContext(context.Background(), md) + return ctx +} diff --git a/request/request.go b/request/request.go index 686b676..1d5e239 100644 --- a/request/request.go +++ b/request/request.go @@ -76,7 +76,9 @@ func (r *Request) Build() (*gpb.GreptimeRequest, error) { insertReqs = append(insertReqs, req) } req := &gpb.GreptimeRequest_RowInserts{ - RowInserts: &gpb.RowInsertRequests{Inserts: insertReqs}, + RowInserts: &gpb.RowInsertRequests{ + Inserts: insertReqs, + }, } return &gpb.GreptimeRequest{ Header: header, @@ -93,7 +95,9 @@ func (r *Request) Build() (*gpb.GreptimeRequest, error) { } req := &gpb.GreptimeRequest_RowDeletes{ - RowDeletes: &gpb.RowDeleteRequests{Deletes: deleteReqs}, + RowDeletes: &gpb.RowDeleteRequests{ + Deletes: deleteReqs, + }, } return &gpb.GreptimeRequest{ Header: header,