This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git


The following commit(s) were added to refs/heads/main by this push:
     new dfa4121  Check schema equality while updating (#71)
dfa4121 is described below

commit dfa4121234e75c74214eb6b4d29a7f8d5fdd98a9
Author: Jiajing LU <[email protected]>
AuthorDate: Wed Jan 26 09:21:52 2022 +0800

    Check schema equality while updating (#71)
    
    * support entity check
---
 api/proto/banyandb/common/v1/common.pb.go    |   2 +-
 api/proto/banyandb/common/v1/common.proto    |   2 +-
 api/proto/banyandb/database/v1/schema.pb.go  | 396 +++++++++++++--------------
 api/proto/banyandb/database/v1/schema.proto  |  20 +-
 banyand/metadata/metadata.go                 |  13 +
 banyand/metadata/schema/checker.go           |  65 +++++
 banyand/metadata/schema/checker_test.go      | 209 ++++++++++++++
 banyand/metadata/schema/etcd.go              |  46 +++-
 banyand/metadata/schema/etcd_test.go         |  40 ++-
 banyand/metadata/schema/schema.go            |  51 +++-
 banyand/metadata/schema/schema_suite_test.go |  30 ++
 banyand/metadata/schema/testdata/stream.json |   2 +-
 banyand/query/processor.go                   |   6 +-
 go.mod                                       |   3 +-
 go.sum                                       |   4 +-
 pkg/test/measure/testdata/measure.json       |   2 +-
 pkg/test/stream/testdata/stream.json         |   2 +-
 17 files changed, 662 insertions(+), 231 deletions(-)

diff --git a/api/proto/banyandb/common/v1/common.pb.go 
b/api/proto/banyandb/common/v1/common.pb.go
index bed7c73..0f8ac5d 100644
--- a/api/proto/banyandb/common/v1/common.pb.go
+++ b/api/proto/banyandb/common/v1/common.pb.go
@@ -180,7 +180,7 @@ type Group struct {
 
        // name of the group
        Name string `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
-       // updated_at_nanoseconds indicates when resources of the group are 
updated
+       // updated_at indicates when resources of the group are updated
        UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
diff --git a/api/proto/banyandb/common/v1/common.proto 
b/api/proto/banyandb/common/v1/common.proto
index d09e264..5a8ced0 100644
--- a/api/proto/banyandb/common/v1/common.proto
+++ b/api/proto/banyandb/common/v1/common.proto
@@ -47,6 +47,6 @@ message Metadata {
 message Group {
     // name of the group
     string name = 1;
-    // updated_at_nanoseconds indicates when resources of the group are updated
+    // updated_at indicates when resources of the group are updated
     google.protobuf.Timestamp updated_at = 2;
 }
diff --git a/api/proto/banyandb/database/v1/schema.pb.go 
b/api/proto/banyandb/database/v1/schema.pb.go
index 5f69192..588796e 100644
--- a/api/proto/banyandb/database/v1/schema.pb.go
+++ b/api/proto/banyandb/database/v1/schema.pb.go
@@ -578,8 +578,8 @@ type Stream struct {
        // entity indicates how to generate a series and shard a stream
        Entity *Entity       `protobuf:"bytes,3,opt,name=entity,proto3" 
json:"entity,omitempty"`
        Opts   *ResourceOpts `protobuf:"bytes,4,opt,name=opts,proto3" 
json:"opts,omitempty"`
-       // updated_at_nanoseconds indicates when the stream is updated
-       UpdatedAtNanoseconds *timestamppb.Timestamp 
`protobuf:"bytes,5,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3"
 json:"updated_at_nanoseconds,omitempty"`
+       // updated_at indicates when the stream is updated
+       UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
 func (x *Stream) Reset() {
@@ -642,9 +642,9 @@ func (x *Stream) GetOpts() *ResourceOpts {
        return nil
 }
 
-func (x *Stream) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
+func (x *Stream) GetUpdatedAt() *timestamppb.Timestamp {
        if x != nil {
-               return x.UpdatedAtNanoseconds
+               return x.UpdatedAt
        }
        return nil
 }
@@ -948,8 +948,8 @@ type Measure struct {
        IntervalRules []*IntervalRule 
`protobuf:"bytes,5,rep,name=interval_rules,json=intervalRules,proto3" 
json:"interval_rules,omitempty"`
        // opts is basic resource management options
        Opts *ResourceOpts `protobuf:"bytes,6,opt,name=opts,proto3" 
json:"opts,omitempty"`
-       // updated_at_nanoseconds indicates when the measure is updated
-       UpdatedAtNanoseconds *timestamppb.Timestamp 
`protobuf:"bytes,7,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3"
 json:"updated_at_nanoseconds,omitempty"`
+       // updated_at indicates when the measure is updated
+       UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,7,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
 func (x *Measure) Reset() {
@@ -1026,9 +1026,9 @@ func (x *Measure) GetOpts() *ResourceOpts {
        return nil
 }
 
-func (x *Measure) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
+func (x *Measure) GetUpdatedAt() *timestamppb.Timestamp {
        if x != nil {
-               return x.UpdatedAtNanoseconds
+               return x.UpdatedAt
        }
        return nil
 }
@@ -1058,8 +1058,8 @@ type TopNAggregation struct {
        CountersNumber int32 
`protobuf:"varint,7,opt,name=counters_number,json=countersNumber,proto3" 
json:"counters_number,omitempty"`
        // opts is basic resource management options
        Opts *ResourceOpts `protobuf:"bytes,8,opt,name=opts,proto3" 
json:"opts,omitempty"`
-       // updated_at_nanoseconds indicates when the measure is updated
-       UpdatedAtNanoseconds *timestamppb.Timestamp 
`protobuf:"bytes,9,opt,name=updated_at_nanoseconds,json=updatedAtNanoseconds,proto3"
 json:"updated_at_nanoseconds,omitempty"`
+       // updated_at indicates when the measure is updated
+       UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
 func (x *TopNAggregation) Reset() {
@@ -1150,9 +1150,9 @@ func (x *TopNAggregation) GetOpts() *ResourceOpts {
        return nil
 }
 
-func (x *TopNAggregation) GetUpdatedAtNanoseconds() *timestamppb.Timestamp {
+func (x *TopNAggregation) GetUpdatedAt() *timestamppb.Timestamp {
        if x != nil {
-               return x.UpdatedAtNanoseconds
+               return x.UpdatedAt
        }
        return nil
 }
@@ -1174,7 +1174,7 @@ type IndexRule struct {
        Type IndexRule_Type 
`protobuf:"varint,3,opt,name=type,proto3,enum=banyandb.database.v1.IndexRule_Type"
 json:"type,omitempty"`
        // location indicates where to store index.
        Location IndexRule_Location 
`protobuf:"varint,4,opt,name=location,proto3,enum=banyandb.database.v1.IndexRule_Location"
 json:"location,omitempty"`
-       // updated_at_nanoseconds indicates when the IndexRule is updated
+       // updated_at indicates when the IndexRule is updated
        UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
@@ -1322,7 +1322,7 @@ type IndexRuleBinding struct {
        // expire_at_nanoseconds it the timestamp, after which the binding will 
be inactive
        // expire_at_nanoseconds must be larger than begin_at_nanoseconds
        ExpireAt *timestamppb.Timestamp 
`protobuf:"bytes,5,opt,name=expire_at,json=expireAt,proto3" 
json:"expire_at,omitempty"`
-       // updated_at_nanoseconds indicates when the IndexRuleBinding is updated
+       // updated_at indicates when the IndexRuleBinding is updated
        UpdatedAt *timestamppb.Timestamp 
`protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" 
json:"updated_at,omitempty"`
 }
 
@@ -1438,7 +1438,7 @@ var file_banyandb_database_v1_schema_proto_rawDesc = 
[]byte{
        0x65, 0x12, 0x31, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 
0x01, 0x28, 0x0e, 0x32,
        0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 
0x61, 0x74, 0x61, 0x62,
        0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x54, 0x79, 
0x70, 0x65, 0x52, 0x04,
-       0x74, 0x79, 0x70, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x72, 
0x65, 0x61, 0x6d, 0x12,
+       0x74, 0x79, 0x70, 0x65, 0x22, 0xb3, 0x02, 0x0a, 0x06, 0x53, 0x74, 0x72, 
0x65, 0x61, 0x6d, 0x12,
        0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 
0x01, 0x20, 0x01, 0x28,
        0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 
0x2e, 0x63, 0x6f, 0x6d,
        0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 
0x61, 0x74, 0x61, 0x52,
@@ -1454,193 +1454,189 @@ var file_banyandb_database_v1_schema_proto_rawDesc = 
[]byte{
        0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 
0x61, 0x6e, 0x64, 0x62,
        0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 
0x2e, 0x52, 0x65, 0x73,
        0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 
0x70, 0x74, 0x73, 0x12,
-       0x50, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 
0x74, 0x5f, 0x6e, 0x61,
-       0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x05, 0x20, 
0x01, 0x28, 0x0b, 0x32,
-       0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 
0x74, 0x6f, 0x62, 0x75,
-       0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 
0x14, 0x75, 0x70, 0x64,
-       0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 
0x63, 0x6f, 0x6e, 0x64,
-       0x73, 0x22, 0x25, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 
0x1b, 0x0a, 0x09, 0x74,
-       0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 
0x28, 0x09, 0x52, 0x08,
-       0x74, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x5d, 0x0a, 0x0c, 
0x52, 0x65, 0x73, 0x6f,
-       0x75, 0x72, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 
0x73, 0x68, 0x61, 0x72,
-       0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 
0x08, 0x73, 0x68, 0x61,
-       0x72, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x30, 0x0a, 0x03, 0x74, 0x74, 0x6c, 
0x18, 0x02, 0x20, 0x01,
-       0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 
0x62, 0x2e, 0x64, 0x61,
-       0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x75, 
0x72, 0x61, 0x74, 0x69,
-       0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x86, 0x02, 0x0a, 0x09, 
0x46, 0x69, 0x65, 0x6c,
-       0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 
0x65, 0x18, 0x01, 0x20,
-       0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 
0x0a, 0x66, 0x69, 0x65,
-       0x6c, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 
0x0e, 0x32, 0x1f, 0x2e,
+       0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 
0x74, 0x18, 0x05, 0x20,
+       0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 
0x2e, 0x70, 0x72, 0x6f,
+       0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 
0x61, 0x6d, 0x70, 0x52,
+       0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x25, 
0x0a, 0x06, 0x45, 0x6e,
+       0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x67, 0x5f, 
0x6e, 0x61, 0x6d, 0x65,
+       0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x67, 
0x4e, 0x61, 0x6d, 0x65,
+       0x73, 0x22, 0x5d, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 
0x65, 0x4f, 0x70, 0x74,
+       0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x6e, 
0x75, 0x6d, 0x18, 0x01,
+       0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x4e, 
0x75, 0x6d, 0x12, 0x30,
+       0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x1e, 0x2e, 0x62, 0x61,
+       0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 
0x61, 0x73, 0x65, 0x2e,
+       0x76, 0x31, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 
0x03, 0x74, 0x74, 0x6c,
+       0x22, 0x86, 0x02, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x70, 
0x65, 0x63, 0x12, 0x12,
+       0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x04, 0x6e, 0x61,
+       0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 
0x74, 0x79, 0x70, 0x65,
+       0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x62, 0x61, 0x6e, 
0x79, 0x61, 0x6e, 0x64,
+       0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 
0x31, 0x2e, 0x46, 0x69,
+       0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x66, 0x69, 0x65, 
0x6c, 0x64, 0x54, 0x79,
+       0x70, 0x65, 0x12, 0x4d, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 
0x6e, 0x67, 0x5f, 0x6d,
+       0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 
0x24, 0x2e, 0x62, 0x61,
+       0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 
0x61, 0x73, 0x65, 0x2e,
+       0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 
0x65, 0x74, 0x68, 0x6f,
+       0x64, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 
0x65, 0x74, 0x68, 0x6f,
+       0x64, 0x12, 0x56, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 
0x73, 0x69, 0x6f, 0x6e,
+       0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 
0x0e, 0x32, 0x27, 0x2e,
        0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 
0x61, 0x62, 0x61, 0x73,
-       0x65, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 
0x70, 0x65, 0x52, 0x09,
-       0x66, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4d, 0x0a, 
0x0f, 0x65, 0x6e, 0x63,
-       0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 
0x18, 0x03, 0x20, 0x01,
-       0x28, 0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 
0x62, 0x2e, 0x64, 0x61,
-       0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 
0x63, 0x6f, 0x64, 0x69,
-       0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0e, 0x65, 0x6e, 
0x63, 0x6f, 0x64, 0x69,
-       0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x56, 0x0a, 0x12, 
0x63, 0x6f, 0x6d, 0x70,
-       0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 
0x6f, 0x64, 0x18, 0x04,
-       0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
-       0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 
0x43, 0x6f, 0x6d, 0x70,
-       0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 
0x64, 0x52, 0x11, 0x63,
-       0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 
0x74, 0x68, 0x6f, 0x64,
-       0x22, 0x7a, 0x0a, 0x0c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 
0x52, 0x75, 0x6c, 0x65,
-       0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 
0x18, 0x01, 0x20, 0x01,
-       0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 
0x12, 0x0a, 0x03, 0x73,
-       0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 
0x73, 0x74, 0x72, 0x12,
-       0x12, 0x0a, 0x03, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 
0x48, 0x00, 0x52, 0x03,
-       0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 
0x76, 0x61, 0x6c, 0x18,
-       0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 
0x76, 0x61, 0x6c, 0x42,
-       0x0b, 0x0a, 0x09, 0x74, 0x61, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 
0x22, 0xcf, 0x03, 0x0a,
-       0x07, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x38, 0x0a, 0x08, 
0x6d, 0x65, 0x74, 0x61,
-       0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 
0x2e, 0x62, 0x61, 0x6e,
-       0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 
0x2e, 0x76, 0x31, 0x2e,
-       0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 
0x74, 0x61, 0x64, 0x61,
-       0x74, 0x61, 0x12, 0x46, 0x0a, 0x0c, 0x74, 0x61, 0x67, 0x5f, 0x66, 0x61, 
0x6d, 0x69, 0x6c, 0x69,
-       0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 
0x61, 0x6e, 0x79, 0x61,
-       0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 
0x2e, 0x76, 0x31, 0x2e,
-       0x54, 0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x53, 0x70, 0x65, 
0x63, 0x52, 0x0b, 0x74,
-       0x61, 0x67, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x37, 
0x0a, 0x06, 0x66, 0x69,
-       0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 
0x2e, 0x62, 0x61, 0x6e,
+       0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 
0x73, 0x69, 0x6f, 0x6e,
+       0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 
0x72, 0x65, 0x73, 0x73,
+       0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x7a, 0x0a, 
0x0c, 0x49, 0x6e, 0x74,
+       0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x19, 0x0a, 
0x08, 0x74, 0x61, 0x67,
+       0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x07, 0x74, 0x61, 0x67,
+       0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 
0x02, 0x20, 0x01, 0x28,
+       0x09, 0x48, 0x00, 0x52, 0x03, 0x73, 0x74, 0x72, 0x12, 0x12, 0x0a, 0x03, 
0x69, 0x6e, 0x74, 0x18,
+       0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x03, 0x69, 0x6e, 0x74, 
0x12, 0x1a, 0x0a, 0x08,
+       0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x08,
+       0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42, 0x0b, 0x0a, 0x09, 
0x74, 0x61, 0x67, 0x5f,
+       0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb8, 0x03, 0x0a, 0x07, 0x4d, 0x65, 
0x61, 0x73, 0x75, 0x72,
+       0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 
0x61, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 
0x64, 0x62, 0x2e, 0x63,
+       0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 
0x61, 0x64, 0x61, 0x74,
+       0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 
0x46, 0x0a, 0x0c, 0x74,
+       0x61, 0x67, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x69, 0x65, 0x73, 0x18, 
0x02, 0x20, 0x03, 0x28,
+       0x0b, 0x32, 0x23, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 
0x2e, 0x64, 0x61, 0x74,
+       0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 
0x46, 0x61, 0x6d, 0x69,
+       0x6c, 0x79, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0b, 0x74, 0x61, 0x67, 0x46, 
0x61, 0x6d, 0x69, 0x6c,
+       0x69, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 
0x73, 0x18, 0x03, 0x20,
+       0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 
0x64, 0x62, 0x2e, 0x64,
+       0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x46, 
0x69, 0x65, 0x6c, 0x64,
+       0x53, 0x70, 0x65, 0x63, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 
0x12, 0x34, 0x0a, 0x06,
+       0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 
0x32, 0x1c, 0x2e, 0x62,
+       0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 
0x62, 0x61, 0x73, 0x65,
+       0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 
0x65, 0x6e, 0x74, 0x69,
+       0x74, 0x79, 0x12, 0x49, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 
0x61, 0x6c, 0x5f, 0x72,
+       0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 
0x2e, 0x62, 0x61, 0x6e,
        0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 
0x73, 0x65, 0x2e, 0x76,
-       0x31, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x70, 0x65, 0x63, 0x52, 
0x06, 0x66, 0x69, 0x65,
-       0x6c, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 
0x79, 0x18, 0x04, 0x20,
-       0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 
0x64, 0x62, 0x2e, 0x64,
-       0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 
0x6e, 0x74, 0x69, 0x74,
-       0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x49, 0x0a, 
0x0e, 0x69, 0x6e, 0x74,
-       0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 
0x05, 0x20, 0x03, 0x28,
-       0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 
0x2e, 0x64, 0x61, 0x74,
-       0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 
0x65, 0x72, 0x76, 0x61,
-       0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 
0x76, 0x61, 0x6c, 0x52,
-       0x75, 0x6c, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 
0x18, 0x06, 0x20, 0x01,
+       0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x75, 
0x6c, 0x65, 0x52, 0x0d,
+       0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 
0x73, 0x12, 0x36, 0x0a,
+       0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x22, 0x2e, 0x62, 0x61,
+       0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 
0x61, 0x73, 0x65, 0x2e,
+       0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 
0x70, 0x74, 0x73, 0x52,
+       0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 
0x61, 0x74, 0x65, 0x64,
+       0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 
0x67, 0x6f, 0x6f, 0x67,
+       0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 
0x54, 0x69, 0x6d, 0x65,
+       0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 
0x65, 0x64, 0x41, 0x74,
+       0x22, 0xf4, 0x03, 0x0a, 0x0f, 0x54, 0x6f, 0x70, 0x4e, 0x41, 0x67, 0x67, 
0x72, 0x65, 0x67, 0x61,
+       0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 
0x64, 0x61, 0x74, 0x61,
+       0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 
0x79, 0x61, 0x6e, 0x64,
+       0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 
0x4d, 0x65, 0x74, 0x61,
+       0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 
0x74, 0x61, 0x12, 0x43,
+       0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x61, 
0x73, 0x75, 0x72, 0x65,
+       0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 
0x79, 0x61, 0x6e, 0x64,
+       0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 
0x4d, 0x65, 0x74, 0x61,
+       0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 
0x4d, 0x65, 0x61, 0x73,
+       0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 
0x5f, 0x6e, 0x61, 0x6d,
+       0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 
0x6c, 0x64, 0x4e, 0x61,
+       0x6d, 0x65, 0x12, 0x41, 0x0a, 0x10, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 
0x76, 0x61, 0x6c, 0x75,
+       0x65, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 
0x32, 0x17, 0x2e, 0x62,
+       0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 
0x6c, 0x2e, 0x76, 0x31,
+       0x2e, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x0e, 0x66, 0x69, 0x65, 0x6c, 0x64, 
0x56, 0x61, 0x6c, 0x75,
+       0x65, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x67, 0x72, 0x6f, 
0x75, 0x70, 0x5f, 0x62,
+       0x79, 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 
0x05, 0x20, 0x03, 0x28,
+       0x09, 0x52, 0x0f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x54, 0x61, 
0x67, 0x4e, 0x61, 0x6d,
+       0x65, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 
0x69, 0x61, 0x18, 0x06,
+       0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
+       0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x69, 
0x74, 0x65, 0x72, 0x69,
+       0x61, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 
0x27, 0x0a, 0x0f, 0x63,
+       0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 
0x65, 0x72, 0x18, 0x07,
+       0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 
0x72, 0x73, 0x4e, 0x75,
+       0x6d, 0x62, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 
0x18, 0x08, 0x20, 0x01,
        0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 
0x62, 0x2e, 0x64, 0x61,
        0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 
0x73, 0x6f, 0x75, 0x72,
-       0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 
0x12, 0x50, 0x0a, 0x16,
-       0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 
0x61, 0x6e, 0x6f, 0x73,
-       0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 
0x32, 0x1a, 0x2e, 0x67,
-       0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 
0x75, 0x66, 0x2e, 0x54,
-       0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 
0x64, 0x61, 0x74, 0x65,
-       0x64, 0x41, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 
0x64, 0x73, 0x22, 0x8b,
-       0x04, 0x0a, 0x0f, 0x54, 0x6f, 0x70, 0x4e, 0x41, 0x67, 0x67, 0x72, 0x65, 
0x67, 0x61, 0x74, 0x69,
-       0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 
0x74, 0x61, 0x18, 0x01,
-       0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
-       0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 
0x74, 0x61, 0x64, 0x61,
-       0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 
0x12, 0x43, 0x0a, 0x0e,
-       0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x61, 0x73, 0x75, 
0x72, 0x65, 0x18, 0x02,
-       0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
-       0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 
0x74, 0x61, 0x64, 0x61,
-       0x74, 0x61, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 
0x61, 0x73, 0x75, 0x72,
-       0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, 
0x61, 0x6d, 0x65, 0x18,
-       0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 
0x4e, 0x61, 0x6d, 0x65,
-       0x12, 0x41, 0x0a, 0x10, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 
0x6c, 0x75, 0x65, 0x5f,
-       0x73, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 
0x2e, 0x62, 0x61, 0x6e,
-       0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 
0x76, 0x31, 0x2e, 0x53,
-       0x6f, 0x72, 0x74, 0x52, 0x0e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 
0x6c, 0x75, 0x65, 0x53,
-       0x6f, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x67, 0x72, 0x6f, 0x75, 0x70, 
0x5f, 0x62, 0x79, 0x5f,
-       0x74, 0x61, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 
0x03, 0x28, 0x09, 0x52,
-       0x0f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x54, 0x61, 0x67, 0x4e, 
0x61, 0x6d, 0x65, 0x73,
-       0x12, 0x37, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 
0x18, 0x06, 0x20, 0x03,
-       0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 
0x62, 0x2e, 0x6d, 0x6f,
-       0x64, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x65, 
0x72, 0x69, 0x61, 0x52,
-       0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x27, 0x0a, 
0x0f, 0x63, 0x6f, 0x75,
-       0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 
0x18, 0x07, 0x20, 0x01,
-       0x28, 0x05, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 
0x4e, 0x75, 0x6d, 0x62,
-       0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x08, 
0x20, 0x01, 0x28, 0x0b,
-       0x32, 0x22, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 
0x64, 0x61, 0x74, 0x61,
-       0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 
0x75, 0x72, 0x63, 0x65,
-       0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x50, 
0x0a, 0x16, 0x75, 0x70,
-       0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 
0x6f, 0x73, 0x65, 0x63,
-       0x6f, 0x6e, 0x64, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 
0x2e, 0x67, 0x6f, 0x6f,
-       0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 
0x2e, 0x54, 0x69, 0x6d,
-       0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 
0x74, 0x65, 0x64, 0x41,
-       0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 
0x22, 0xa4, 0x03, 0x0a,
-       0x09, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x38, 
0x0a, 0x08, 0x6d, 0x65,
-       0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 
0x32, 0x1c, 0x2e, 0x62,
-       0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 
0x6f, 0x6e, 0x2e, 0x76,
-       0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 
0x6d, 0x65, 0x74, 0x61,
-       0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 
0x18, 0x02, 0x20, 0x03,
-       0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x04, 
0x74, 0x79, 0x70, 0x65,
-       0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 
0x79, 0x61, 0x6e, 0x64,
-       0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 
0x31, 0x2e, 0x49, 0x6e,
-       0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 
0x52, 0x04, 0x74, 0x79,
-       0x70, 0x65, 0x12, 0x44, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x18, 0x04,
-       0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
-       0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 
0x49, 0x6e, 0x64, 0x65,
-       0x78, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x52, 0x08,
-       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 
0x75, 0x70, 0x64, 0x61,
-       0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 
0x32, 0x1a, 0x2e, 0x67,
+       0x63, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 
0x12, 0x39, 0x0a, 0x0a,
+       0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 
0x20, 0x01, 0x28, 0x0b,
+       0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 
0x6f, 0x74, 0x6f, 0x62,
+       0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 
0x52, 0x09, 0x75, 0x70,
+       0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xa4, 0x03, 0x0a, 0x09, 
0x49, 0x6e, 0x64, 0x65,
+       0x78, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 
0x61, 0x64, 0x61, 0x74,
+       0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x61, 
0x6e, 0x79, 0x61, 0x6e,
+       0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 
0x2e, 0x4d, 0x65, 0x74,
+       0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 
0x61, 0x74, 0x61, 0x12,
+       0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 
0x09, 0x52, 0x04, 0x74,
+       0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 
0x03, 0x20, 0x01, 0x28,
+       0x0e, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 
0x2e, 0x64, 0x61, 0x74,
+       0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x64, 
0x65, 0x78, 0x52, 0x75,
+       0x6c, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 
0x65, 0x12, 0x44, 0x0a,
+       0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 
0x01, 0x28, 0x0e, 0x32,
+       0x28, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 
0x61, 0x74, 0x61, 0x62,
+       0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 
0x52, 0x75, 0x6c, 0x65,
+       0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 
0x6f, 0x63, 0x61, 0x74,
+       0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 
0x65, 0x64, 0x5f, 0x61,
+       0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 
0x6f, 0x67, 0x6c, 0x65,
+       0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 
0x6d, 0x65, 0x73, 0x74,
+       0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 
0x41, 0x74, 0x22, 0x3e,
+       0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 
0x50, 0x45, 0x5f, 0x55,
+       0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 
0x12, 0x0d, 0x0a, 0x09,
+       0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x01, 0x12, 
0x11, 0x0a, 0x0d, 0x54,
+       0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x44, 
0x10, 0x02, 0x22, 0x4e,
+       0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 
0x0a, 0x14, 0x4c, 0x4f,
+       0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 
0x43, 0x49, 0x46, 0x49,
+       0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 
0x54, 0x49, 0x4f, 0x4e,
+       0x5f, 0x53, 0x45, 0x52, 0x49, 0x45, 0x53, 0x10, 0x01, 0x12, 0x13, 0x0a, 
0x0f, 0x4c, 0x4f, 0x43,
+       0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 
0x10, 0x02, 0x22, 0x54,
+       0x0a, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35, 0x0a, 
0x07, 0x63, 0x61, 0x74,
+       0x61, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 
0x2e, 0x62, 0x61, 0x6e,
+       0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 
0x2e, 0x76, 0x31, 0x2e,
+       0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x07, 0x63, 0x61, 0x74, 
0x61, 0x6c, 0x6f, 0x67,
+       0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x04,
+       0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc6, 0x02, 0x0a, 0x10, 0x49, 0x6e, 0x64, 
0x65, 0x78, 0x52, 0x75,
+       0x6c, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 
0x08, 0x6d, 0x65, 0x74,
+       0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x1c, 0x2e, 0x62, 0x61,
+       0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 
0x6e, 0x2e, 0x76, 0x31,
+       0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 
0x65, 0x74, 0x61, 0x64,
+       0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 
0x18, 0x02, 0x20, 0x03,
+       0x28, 0x09, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x37, 0x0a, 
0x07, 0x73, 0x75, 0x62,
+       0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 
0x2e, 0x62, 0x61, 0x6e,
+       0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 
0x73, 0x65, 0x2e, 0x76,
+       0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x73, 
0x75, 0x62, 0x6a, 0x65,
+       0x63, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 
0x61, 0x74, 0x18, 0x04,
+       0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 
0x65, 0x2e, 0x70, 0x72,
+       0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 
0x74, 0x61, 0x6d, 0x70,
+       0x52, 0x07, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x12, 0x37, 0x0a, 
0x09, 0x65, 0x78, 0x70,
+       0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 
0x32, 0x1a, 0x2e, 0x67,
        0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 
0x75, 0x66, 0x2e, 0x54,
-       0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 
0x64, 0x61, 0x74, 0x65,
-       0x64, 0x41, 0x74, 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 
0x14, 0x0a, 0x10, 0x54,
-       0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 
0x49, 0x45, 0x44, 0x10,
-       0x00, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 
0x45, 0x45, 0x10, 0x01,
-       0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 
0x45, 0x52, 0x54, 0x45,
-       0x44, 0x10, 0x02, 0x22, 0x4e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 
0x69, 0x6f, 0x6e, 0x12,
-       0x18, 0x0a, 0x14, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 
0x55, 0x4e, 0x53, 0x50,
-       0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 
0x0f, 0x4c, 0x4f, 0x43,
-       0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x52, 0x49, 0x45, 0x53, 
0x10, 0x01, 0x12, 0x13,
-       0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 
0x4c, 0x4f, 0x42, 0x41,
-       0x4c, 0x10, 0x02, 0x22, 0x54, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 
0x63, 0x74, 0x12, 0x35,
-       0x0a, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 
0x01, 0x28, 0x0e, 0x32,
-       0x1b, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x63, 
0x6f, 0x6d, 0x6d, 0x6f,
-       0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 
0x52, 0x07, 0x63, 0x61,
-       0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 
0x65, 0x18, 0x02, 0x20,
-       0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc6, 0x02, 
0x0a, 0x10, 0x49, 0x6e,
-       0x64, 0x65, 0x78, 0x52, 0x75, 0x6c, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 
0x6e, 0x67, 0x12, 0x38,
-       0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 
0x20, 0x01, 0x28, 0x0b,
-       0x32, 0x1c, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 
0x63, 0x6f, 0x6d, 0x6d,
-       0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 
0x74, 0x61, 0x52, 0x08,
-       0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 
0x72, 0x75, 0x6c, 0x65,
-       0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x75, 0x6c, 
0x65, 0x73, 0x12, 0x37,
-       0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 
0x01, 0x28, 0x0b, 0x32,
-       0x1d, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 
0x61, 0x74, 0x61, 0x62,
-       0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 
0x63, 0x74, 0x52, 0x07,
-       0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x62, 
0x65, 0x67, 0x69, 0x6e,
-       0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 
0x67, 0x6f, 0x6f, 0x67,
-       0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 
0x54, 0x69, 0x6d, 0x65,
-       0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x62, 0x65, 0x67, 0x69, 0x6e, 
0x41, 0x74, 0x12, 0x37,
-       0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 
0x05, 0x20, 0x01, 0x28,
-       0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 
0x72, 0x6f, 0x74, 0x6f,
-       0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 
0x70, 0x52, 0x08, 0x65,
-       0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 
0x70, 0x64, 0x61, 0x74,
-       0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x1a, 0x2e, 0x67, 0x6f,
-       0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 
0x66, 0x2e, 0x54, 0x69,
-       0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 
0x61, 0x74, 0x65, 0x64,
-       0x41, 0x74, 0x2a, 0x97, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x54, 0x79, 
0x70, 0x65, 0x12, 0x18,
-       0x0a, 0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 
0x4e, 0x53, 0x50, 0x45,
-       0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 
0x54, 0x41, 0x47, 0x5f,
-       0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 
0x01, 0x12, 0x10, 0x0a,
-       0x0c, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 
0x54, 0x10, 0x02, 0x12,
-       0x19, 0x0a, 0x15, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 
0x53, 0x54, 0x52, 0x49,
-       0x4e, 0x47, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x03, 0x12, 0x16, 
0x0a, 0x12, 0x54, 0x41,
-       0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x5f, 0x41, 
0x52, 0x52, 0x41, 0x59,
-       0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 
0x50, 0x45, 0x5f, 0x44,
-       0x41, 0x54, 0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x05, 
0x2a, 0x6e, 0x0a, 0x09,
-       0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 
0x16, 0x46, 0x49, 0x45,
-       0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 
0x45, 0x43, 0x49, 0x46,
-       0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x49, 0x45, 
0x4c, 0x44, 0x5f, 0x54,
-       0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 
0x12, 0x12, 0x0a, 0x0e,
-       0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 
0x4e, 0x54, 0x10, 0x02,
-       0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 
0x50, 0x45, 0x5f, 0x44,
-       0x41, 0x54, 0x41, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x03, 
0x2a, 0x4e, 0x0a, 0x0e,
-       0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 
0x6f, 0x64, 0x12, 0x1f,
-       0x0a, 0x1b, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 
0x45, 0x54, 0x48, 0x4f,
-       0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 
0x44, 0x10, 0x00, 0x12,
-       0x1b, 0x0a, 0x17, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 
0x4d, 0x45, 0x54, 0x48,
-       0x4f, 0x44, 0x5f, 0x47, 0x4f, 0x52, 0x49, 0x4c, 0x4c, 0x41, 0x10, 0x01, 
0x2a, 0x54, 0x0a, 0x11,
-       0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 
0x65, 0x74, 0x68, 0x6f,
-       0x64, 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 
0x53, 0x49, 0x4f, 0x4e,
-       0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 
0x45, 0x43, 0x49, 0x46,
-       0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4d, 
0x50, 0x52, 0x45, 0x53,
-       0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 
0x5a, 0x53, 0x54, 0x44,
-       0x10, 0x01, 0x42, 0x72, 0x0a, 0x2a, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 
0x61, 0x63, 0x68, 0x65,
-       0x2e, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 
0x62, 0x61, 0x6e, 0x79,
-       0x61, 0x6e, 0x64, 0x62, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 
0x65, 0x2e, 0x76, 0x31,
-       0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 
0x2f, 0x61, 0x70, 0x61,
-       0x63, 0x68, 0x65, 0x2f, 0x73, 0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 
0x6e, 0x67, 0x2d, 0x62,
-       0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 
0x70, 0x72, 0x6f, 0x74,
-       0x6f, 0x2f, 0x62, 0x61, 0x6e, 0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x64, 
0x61, 0x74, 0x61, 0x62,
-       0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 
0x6f, 0x33,
+       0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 
0x70, 0x69, 0x72, 0x65,
+       0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 
0x64, 0x5f, 0x61, 0x74,
+       0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 
0x67, 0x6c, 0x65, 0x2e,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 
0x65, 0x73, 0x74, 0x61,
+       0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 
0x74, 0x2a, 0x97, 0x01,
+       0x0a, 0x07, 0x54, 0x61, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 
0x14, 0x54, 0x41, 0x47,
+       0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 
0x49, 0x46, 0x49, 0x45,
+       0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x41, 0x47, 0x5f, 0x54, 
0x59, 0x50, 0x45, 0x5f,
+       0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 
0x54, 0x41, 0x47, 0x5f,
+       0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x19, 
0x0a, 0x15, 0x54, 0x41,
+       0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 
0x47, 0x5f, 0x41, 0x52,
+       0x52, 0x41, 0x59, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x41, 0x47, 
0x5f, 0x54, 0x59, 0x50,
+       0x45, 0x5f, 0x49, 0x4e, 0x54, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 
0x04, 0x12, 0x18, 0x0a,
+       0x14, 0x54, 0x41, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 
0x54, 0x41, 0x5f, 0x42,
+       0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x05, 0x2a, 0x6e, 0x0a, 0x09, 0x46, 
0x69, 0x65, 0x6c, 0x64,
+       0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x45, 0x4c, 
0x44, 0x5f, 0x54, 0x59,
+       0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 
0x45, 0x44, 0x10, 0x00,
+       0x12, 0x15, 0x0a, 0x11, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 
0x50, 0x45, 0x5f, 0x53,
+       0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x46, 
0x49, 0x45, 0x4c, 0x44,
+       0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x10, 0x02, 0x12, 
0x1a, 0x0a, 0x16, 0x46,
+       0x49, 0x45, 0x4c, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 
0x54, 0x41, 0x5f, 0x42,
+       0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x03, 0x2a, 0x4e, 0x0a, 0x0e, 0x45, 
0x6e, 0x63, 0x6f, 0x64,
+       0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 
0x1b, 0x45, 0x4e, 0x43,
+       0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 
0x5f, 0x55, 0x4e, 0x53,
+       0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 
0x0a, 0x17, 0x45, 0x4e,
+       0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 
0x44, 0x5f, 0x47, 0x4f,
+       0x52, 0x49, 0x4c, 0x4c, 0x41, 0x10, 0x01, 0x2a, 0x54, 0x0a, 0x11, 0x43, 
0x6f, 0x6d, 0x70, 0x72,
+       0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 
0x12, 0x22, 0x0a, 0x1e,
+       0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 
0x4d, 0x45, 0x54, 0x48,
+       0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 
0x45, 0x44, 0x10, 0x00,
+       0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 
0x49, 0x4f, 0x4e, 0x5f,
+       0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x5a, 0x53, 0x54, 0x44, 0x10, 
0x01, 0x42, 0x72, 0x0a,
+       0x2a, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 
0x73, 0x6b, 0x79, 0x77,
+       0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x61, 0x6e, 0x79, 0x61, 
0x6e, 0x64, 0x62, 0x2e,
+       0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x5a, 
0x44, 0x67, 0x69, 0x74,
+       0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2f, 0x73,
+       0x6b, 0x79, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x61, 
0x6e, 0x79, 0x61, 0x6e,
+       0x64, 0x62, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 
0x2f, 0x62, 0x61, 0x6e,
+       0x79, 0x61, 0x6e, 0x64, 0x62, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 
0x73, 0x65, 0x2f, 0x76,
+       0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1692,7 +1688,7 @@ var file_banyandb_database_v1_schema_proto_depIdxs = 
[]int32{
        8,  // 4: banyandb.database.v1.Stream.tag_families:type_name -> 
banyandb.database.v1.TagFamilySpec
        11, // 5: banyandb.database.v1.Stream.entity:type_name -> 
banyandb.database.v1.Entity
        12, // 6: banyandb.database.v1.Stream.opts:type_name -> 
banyandb.database.v1.ResourceOpts
-       21, // 7: banyandb.database.v1.Stream.updated_at_nanoseconds:type_name 
-> google.protobuf.Timestamp
+       21, // 7: banyandb.database.v1.Stream.updated_at:type_name -> 
google.protobuf.Timestamp
        7,  // 8: banyandb.database.v1.ResourceOpts.ttl:type_name -> 
banyandb.database.v1.Duration
        1,  // 9: banyandb.database.v1.FieldSpec.field_type:type_name -> 
banyandb.database.v1.FieldType
        2,  // 10: banyandb.database.v1.FieldSpec.encoding_method:type_name -> 
banyandb.database.v1.EncodingMethod
@@ -1703,13 +1699,13 @@ var file_banyandb_database_v1_schema_proto_depIdxs = 
[]int32{
        11, // 15: banyandb.database.v1.Measure.entity:type_name -> 
banyandb.database.v1.Entity
        14, // 16: banyandb.database.v1.Measure.interval_rules:type_name -> 
banyandb.database.v1.IntervalRule
        12, // 17: banyandb.database.v1.Measure.opts:type_name -> 
banyandb.database.v1.ResourceOpts
-       21, // 18: 
banyandb.database.v1.Measure.updated_at_nanoseconds:type_name -> 
google.protobuf.Timestamp
+       21, // 18: banyandb.database.v1.Measure.updated_at:type_name -> 
google.protobuf.Timestamp
        20, // 19: banyandb.database.v1.TopNAggregation.metadata:type_name -> 
banyandb.common.v1.Metadata
        20, // 20: 
banyandb.database.v1.TopNAggregation.source_measure:type_name -> 
banyandb.common.v1.Metadata
        22, // 21: 
banyandb.database.v1.TopNAggregation.field_value_sort:type_name -> 
banyandb.model.v1.Sort
        23, // 22: banyandb.database.v1.TopNAggregation.criteria:type_name -> 
banyandb.model.v1.Criteria
        12, // 23: banyandb.database.v1.TopNAggregation.opts:type_name -> 
banyandb.database.v1.ResourceOpts
-       21, // 24: 
banyandb.database.v1.TopNAggregation.updated_at_nanoseconds:type_name -> 
google.protobuf.Timestamp
+       21, // 24: banyandb.database.v1.TopNAggregation.updated_at:type_name -> 
google.protobuf.Timestamp
        20, // 25: banyandb.database.v1.IndexRule.metadata:type_name -> 
banyandb.common.v1.Metadata
        5,  // 26: banyandb.database.v1.IndexRule.type:type_name -> 
banyandb.database.v1.IndexRule.Type
        6,  // 27: banyandb.database.v1.IndexRule.location:type_name -> 
banyandb.database.v1.IndexRule.Location
diff --git a/api/proto/banyandb/database/v1/schema.proto 
b/api/proto/banyandb/database/v1/schema.proto
index 624766c..e759ed3 100644
--- a/api/proto/banyandb/database/v1/schema.proto
+++ b/api/proto/banyandb/database/v1/schema.proto
@@ -51,7 +51,7 @@ enum TagType {
 message TagFamilySpec {
     string name = 1;
     // tags defines accepted tags
-    repeated TagSpec tags = 2; 
+    repeated TagSpec tags = 2;
 }
 
 message TagSpec {
@@ -63,13 +63,13 @@ message TagSpec {
 message Stream {
     // metadata is the identity of a trace series
     common.v1.Metadata metadata = 1;
-    // tag_families 
+    // tag_families
     repeated TagFamilySpec tag_families = 2;
     // entity indicates how to generate a series and shard a stream
     Entity entity = 3;
     ResourceOpts opts = 4;
-    // updated_at_nanoseconds indicates when the stream is updated
-    google.protobuf.Timestamp updated_at_nanoseconds = 5;
+    // updated_at indicates when the stream is updated
+    google.protobuf.Timestamp updated_at = 5;
 }
 
 message Entity {
@@ -139,8 +139,8 @@ message Measure {
     repeated IntervalRule interval_rules = 5;
     // opts is basic resource management options
     ResourceOpts opts = 6;
-    // updated_at_nanoseconds indicates when the measure is updated
-    google.protobuf.Timestamp updated_at_nanoseconds = 7;
+    // updated_at indicates when the measure is updated
+    google.protobuf.Timestamp updated_at = 7;
 }
 
 // TopNAggregation generates offline TopN statistics for a measure's TopN 
approximation
@@ -164,8 +164,8 @@ message TopNAggregation {
     int32 counters_number = 7;
     // opts is basic resource management options
     ResourceOpts opts = 8;
-    // updated_at_nanoseconds indicates when the measure is updated
-    google.protobuf.Timestamp updated_at_nanoseconds = 9;
+    // updated_at indicates when the measure is updated
+    google.protobuf.Timestamp updated_at = 9;
 }
 
 // IndexRule defines how to generate indices based on tags and the index type
@@ -192,7 +192,7 @@ message IndexRule {
     }
     // location indicates where to store index.
     Location location = 4;
-    // updated_at_nanoseconds indicates when the IndexRule is updated
+    // updated_at indicates when the IndexRule is updated
     google.protobuf.Timestamp updated_at = 5;
 }
 
@@ -219,6 +219,6 @@ message IndexRuleBinding {
     // expire_at_nanoseconds it the timestamp, after which the binding will be 
inactive
     // expire_at_nanoseconds must be larger than begin_at_nanoseconds
     google.protobuf.Timestamp expire_at = 5;
-    // updated_at_nanoseconds indicates when the IndexRuleBinding is updated
+    // updated_at indicates when the IndexRuleBinding is updated
     google.protobuf.Timestamp updated_at = 6;
 }
diff --git a/banyand/metadata/metadata.go b/banyand/metadata/metadata.go
index a85faf5..40ae923 100644
--- a/banyand/metadata/metadata.go
+++ b/banyand/metadata/metadata.go
@@ -185,6 +185,10 @@ func (s *service) Subjects(ctx context.Context, indexRule 
*databasev1.IndexRule,
                        continue
                }
 
+               if !contains(binding.GetRules(), 
indexRule.GetMetadata().GetName()) {
+                       continue
+               }
+
                switch catalog {
                case commonv1.Catalog_CATALOG_STREAM:
                        stream, getErr := 
s.schemaRegistry.GetStream(context.TODO(), &commonv1.Metadata{
@@ -209,3 +213,12 @@ func (s *service) Subjects(ctx context.Context, indexRule 
*databasev1.IndexRule,
 
        return foundSubjects, subjectErr
 }
+
+func contains(s []string, e string) bool {
+       for _, a := range s {
+               if a == e {
+                       return true
+               }
+       }
+       return false
+}
diff --git a/banyand/metadata/schema/checker.go 
b/banyand/metadata/schema/checker.go
new file mode 100644
index 0000000..2298e6f
--- /dev/null
+++ b/banyand/metadata/schema/checker.go
@@ -0,0 +1,65 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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 schema
+
+import (
+       "github.com/google/go-cmp/cmp"
+       "google.golang.org/protobuf/proto"
+       "google.golang.org/protobuf/testing/protocmp"
+
+       commonv1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
+       databasev1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1"
+)
+
+type equalityChecker func(a, b proto.Message) bool
+
+var (
+       checkerMap = map[Kind]equalityChecker{
+               KindIndexRuleBinding: func(a, b proto.Message) bool {
+                       return cmp.Equal(a, b,
+                               protocmp.IgnoreUnknown(),
+                               
protocmp.IgnoreFields(&databasev1.IndexRuleBinding{}, "updated_at"),
+                               protocmp.IgnoreFields(&commonv1.Metadata{}, 
"id", "create_revision", "mod_revision"),
+                               protocmp.Transform(),
+                       )
+               },
+               KindIndexRule: func(a, b proto.Message) bool {
+                       return cmp.Equal(a, b,
+                               protocmp.IgnoreUnknown(),
+                               protocmp.IgnoreFields(&databasev1.IndexRule{}, 
"updated_at"),
+                               protocmp.IgnoreFields(&commonv1.Metadata{}, 
"id", "create_revision", "mod_revision"),
+                               protocmp.Transform(),
+                       )
+               },
+               KindMeasure: func(a, b proto.Message) bool {
+                       return cmp.Equal(a, b,
+                               protocmp.IgnoreUnknown(),
+                               protocmp.IgnoreFields(&databasev1.Measure{}, 
"updated_at"),
+                               protocmp.IgnoreFields(&commonv1.Metadata{}, 
"id", "create_revision", "mod_revision"),
+                               protocmp.Transform(),
+                       )
+               },
+               KindStream: func(a, b proto.Message) bool {
+                       return cmp.Equal(a, b,
+                               protocmp.IgnoreUnknown(),
+                               protocmp.IgnoreFields(&databasev1.Stream{}, 
"updated_at"),
+                               protocmp.IgnoreFields(&commonv1.Metadata{}, 
"id", "create_revision", "mod_revision"),
+                               protocmp.Transform())
+               },
+       }
+)
diff --git a/banyand/metadata/schema/checker_test.go 
b/banyand/metadata/schema/checker_test.go
new file mode 100644
index 0000000..cebb64f
--- /dev/null
+++ b/banyand/metadata/schema/checker_test.go
@@ -0,0 +1,209 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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 schema
+
+import (
+       "time"
+
+       "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+       "google.golang.org/protobuf/encoding/protojson"
+       "google.golang.org/protobuf/types/known/timestamppb"
+
+       databasev1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1"
+)
+
+func loadStream() *databasev1.Stream {
+       s := &databasev1.Stream{}
+       // preload stream
+       Expect(protojson.Unmarshal([]byte(streamJSON), s)).To(Succeed())
+       return s
+}
+
+func loadIndexRuleBinding() *databasev1.IndexRuleBinding {
+       irb := &databasev1.IndexRuleBinding{}
+       // preload index rule binding
+       Expect(protojson.Unmarshal([]byte(indexRuleBindingJSON), 
irb)).To(Succeed())
+       return irb
+}
+
+func loadIndexRule() *databasev1.IndexRule {
+       ir := &databasev1.IndexRule{}
+       data, err := indexRuleStore.ReadFile(indexRuleDir + "/db.instance.json")
+       Expect(err).NotTo(HaveOccurred())
+       Expect(protojson.Unmarshal(data, ir)).To(Succeed())
+       return ir
+}
+
+var _ = ginkgo.Describe("Utils", func() {
+       ginkgo.Context("Check equality for Stream", func() {
+               var s *databasev1.Stream
+               var checker equalityChecker
+
+               ginkgo.BeforeEach(func() {
+                       s = loadStream()
+                       checker = checkerMap[KindStream]
+               })
+
+               ginkgo.It("should be equal if nothing changed", func() {
+                       Expect(checker(s, s)).Should(BeTrue())
+               })
+
+               ginkgo.It("should not be equal if metadata.name changed", 
func() {
+                       newS := loadStream()
+                       newS.Metadata.Name = "new-name"
+                       Expect(checker(s, newS)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if metadata.group changed", 
func() {
+                       newS := loadStream()
+                       newS.GetMetadata().Group = "new-group"
+                       Expect(checker(s, newS)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if entity changed", func() {
+                       newS := loadStream()
+                       newS.GetEntity().TagNames = []string{"new-entity-tag"}
+                       Expect(checker(s, newS)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if tag name changed", func() {
+                       newS := loadStream()
+                       newS.GetTagFamilies()[0].Tags[0].Name = "binary-tag"
+                       Expect(checker(s, newS)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if tag type changed", func() {
+                       newS := loadStream()
+                       newS.GetTagFamilies()[0].Tags[0].Type = 
databasev1.TagType_TAG_TYPE_STRING
+                       Expect(checker(s, newS)).Should(BeFalse())
+               })
+
+               ginkgo.It("should be equal if UpdatedAt changed", func() {
+                       newS := loadStream()
+                       newS.UpdatedAt = timestamppb.Now()
+                       Expect(checker(s, newS)).Should(BeTrue())
+               })
+
+               ginkgo.It("should be equal if metadata.mod_revision changed", 
func() {
+                       newS := loadStream()
+                       newS.Metadata.ModRevision = 10000
+                       Expect(checker(s, newS)).Should(BeTrue())
+               })
+
+               ginkgo.It("should be equal if metadata.create_revision 
changed", func() {
+                       newS := loadStream()
+                       newS.Metadata.CreateRevision = 10000
+                       Expect(checker(s, newS)).Should(BeTrue())
+               })
+       })
+
+       ginkgo.Context("Check equality for IndexRuleBinding", func() {
+               var irb *databasev1.IndexRuleBinding
+               var checker equalityChecker
+
+               ginkgo.BeforeEach(func() {
+                       irb = loadIndexRuleBinding()
+                       checker = checkerMap[KindIndexRuleBinding]
+               })
+
+               ginkgo.It("should be equal if nothing changed", func() {
+                       Expect(checker(irb, irb)).Should(BeTrue())
+               })
+
+               ginkgo.It("should not be equal if metadata.name changed", 
func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.Metadata.Name = "new-name"
+                       Expect(checker(irb, newIrb)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if metadata.group changed", 
func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.GetMetadata().Group = "new-group"
+                       Expect(checker(irb, newIrb)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if rules changed", func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.Rules = []string{}
+                       Expect(checker(irb, newIrb)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if beginAt changed", func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.BeginAt = timestamppb.New(time.Now())
+                       Expect(checker(irb, newIrb)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if expireAt changed", func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.ExpireAt = timestamppb.New(time.Now())
+                       Expect(checker(irb, newIrb)).Should(BeFalse())
+               })
+
+               ginkgo.It("should be equal if UpdatedAtNanoseconds changed", 
func() {
+                       newIrb := loadIndexRuleBinding()
+                       newIrb.UpdatedAt = timestamppb.Now()
+                       Expect(checker(irb, newIrb)).Should(BeTrue())
+               })
+       })
+
+       ginkgo.Context("Check equality for IndexRule", func() {
+               var ir *databasev1.IndexRule
+               var checker equalityChecker
+
+               ginkgo.BeforeEach(func() {
+                       ir = loadIndexRule()
+                       checker = checkerMap[KindIndexRule]
+               })
+
+               ginkgo.It("should be equal if nothing changed", func() {
+                       Expect(checker(ir, ir)).Should(BeTrue())
+               })
+
+               ginkgo.It("should not be equal if metadata.name changed", 
func() {
+                       newIr := loadIndexRule()
+                       newIr.Metadata.Name = "new-name"
+                       Expect(checker(ir, newIr)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if metadata.id changed", func() {
+                       newIr := loadIndexRule()
+                       newIr.Metadata.Id = 1000
+                       Expect(checker(ir, newIr)).Should(BeTrue())
+               })
+
+               ginkgo.It("should not be equal if metadata.group changed", 
func() {
+                       newIr := loadIndexRule()
+                       newIr.GetMetadata().Group = "new-group"
+                       Expect(checker(ir, newIr)).Should(BeFalse())
+               })
+
+               ginkgo.It("should not be equal if rules changed", func() {
+                       newIr := loadIndexRule()
+                       newIr.Tags = []string{"new-tag"}
+                       Expect(checker(ir, newIr)).Should(BeFalse())
+               })
+
+               ginkgo.It("should be equal if UpdatedAtNanoseconds changed", 
func() {
+                       newIr := loadIndexRule()
+                       newIr.UpdatedAt = timestamppb.Now()
+                       Expect(checker(ir, newIr)).Should(BeTrue())
+               })
+       })
+})
diff --git a/banyand/metadata/schema/etcd.go b/banyand/metadata/schema/etcd.go
index 8e3685c..7836ca2 100644
--- a/banyand/metadata/schema/etcd.go
+++ b/banyand/metadata/schema/etcd.go
@@ -45,6 +45,7 @@ var (
 
        ErrEntityNotFound             = errors.New("entity is not found")
        ErrUnexpectedNumberOfEntities = errors.New("unexpected number of 
entities")
+       ErrConcurrentModification     = errors.New("concurrent modification of 
entities")
 
        unixDomainSockScheme = "unix"
 
@@ -498,14 +499,49 @@ func (e *etcdSchemaRegistry) get(ctx context.Context, key 
string, message proto.
 }
 
 func (e *etcdSchemaRegistry) update(ctx context.Context, group 
*commonv1.Group, metadata Metadata) error {
-       val, err := proto.Marshal(metadata.Spec.(proto.Message))
+       key, err := metadata.Key()
        if err != nil {
                return err
        }
-       _, err = e.kv.Put(ctx, metadata.Key(), string(val))
+       getResp, err := e.kv.Get(ctx, key)
+       if err != nil {
+               return err
+       }
+       if getResp.Count > 1 {
+               return ErrUnexpectedNumberOfEntities
+       }
+       val, err := proto.Marshal(metadata.Spec.(proto.Message))
        if err != nil {
                return err
        }
+       replace := getResp.Count > 0
+       if replace {
+               existingVal, innerErr := 
metadata.Unmarshal(getResp.Kvs[0].Value)
+               if innerErr != nil {
+                       return innerErr
+               }
+               // directly return if we have the same entity
+               if metadata.Equal(existingVal) {
+                       return nil
+               }
+
+               modRevision := getResp.Kvs[0].ModRevision
+               txnResp, txnErr := e.kv.Txn(context.Background()).
+                       If(clientv3.Compare(clientv3.ModRevision(key), "=", 
modRevision)).
+                       Then(clientv3.OpPut(key, string(val))).
+                       Commit()
+               if txnErr != nil {
+                       return txnErr
+               }
+               if !txnResp.Succeeded {
+                       return ErrConcurrentModification
+               }
+       } else {
+               _, err = e.kv.Put(ctx, key, string(val))
+               if err != nil {
+                       return err
+               }
+       }
        e.notifyUpdate(metadata)
        return e.touchGroup(ctx, group)
 }
@@ -550,7 +586,11 @@ func (e *etcdSchemaRegistry) listPrefixesForEntity(ctx 
context.Context, opt List
 }
 
 func (e *etcdSchemaRegistry) delete(ctx context.Context, g *commonv1.Group, 
metadata Metadata) (bool, error) {
-       resp, err := e.kv.Delete(ctx, metadata.Key(), clientv3.WithPrevKV())
+       key, err := metadata.Key()
+       if err != nil {
+               return false, err
+       }
+       resp, err := e.kv.Delete(ctx, key, clientv3.WithPrevKV())
        if err != nil {
                return false, err
        }
diff --git a/banyand/metadata/schema/etcd_test.go 
b/banyand/metadata/schema/etcd_test.go
index 16a2867..e7f58d1 100644
--- a/banyand/metadata/schema/etcd_test.go
+++ b/banyand/metadata/schema/etcd_test.go
@@ -418,6 +418,24 @@ func Test_Notify(t *testing.T) {
                                return r.UpdateIndexRule(ctx, ir)
                        },
                        validationFunc: func(mocked *mockedEventHandler) bool {
+                               return mocked.AssertNumberOfCalls(t, 
"OnAddOrUpdate", 1) &&
+                                       mocked.AssertNumberOfCalls(t, 
"OnDelete", 0)
+                       },
+               },
+               {
+                       name: "modify indexRule without modification",
+                       testFunc: func(ctx context.Context, r Registry) error {
+                               ir, err := r.GetIndexRule(ctx, 
&commonv1.Metadata{
+                                       Name:  "db.instance",
+                                       Group: "default",
+                               })
+                               if err != nil {
+                                       return err
+                               }
+
+                               return r.UpdateIndexRule(ctx, ir)
+                       },
+                       validationFunc: func(mocked *mockedEventHandler) bool {
                                return mocked.AssertNumberOfCalls(t, 
"OnAddOrUpdate", 0) &&
                                        mocked.AssertNumberOfCalls(t, 
"OnDelete", 0)
                        },
@@ -438,7 +456,7 @@ func Test_Notify(t *testing.T) {
                        },
                        validationFunc: func(mocked *mockedEventHandler) bool {
                                return mocked.AssertNumberOfCalls(t, 
"OnAddOrUpdate", 0) &&
-                                       mocked.AssertNumberOfCalls(t, 
"OnDelete", 0)
+                                       mocked.AssertNumberOfCalls(t, 
"OnDelete", 1)
                        },
                },
                {
@@ -461,6 +479,24 @@ func Test_Notify(t *testing.T) {
                        },
                },
                {
+                       name: "update indexRuleBinding without modification",
+                       testFunc: func(ctx context.Context, r Registry) error {
+                               irb, err := r.GetIndexRuleBinding(ctx, 
&commonv1.Metadata{
+                                       Name:  "sw-index-rule-binding",
+                                       Group: "default",
+                               })
+                               if err != nil {
+                                       return err
+                               }
+
+                               return r.UpdateIndexRuleBinding(ctx, irb)
+                       },
+                       validationFunc: func(mocked *mockedEventHandler) bool {
+                               return mocked.AssertNumberOfCalls(t, 
"OnAddOrUpdate", 0) &&
+                                       mocked.AssertNumberOfCalls(t, 
"OnDelete", 0)
+                       },
+               },
+               {
                        name: "delete indexRuleBinding",
                        testFunc: func(ctx context.Context, r Registry) error {
                                _, err := r.DeleteIndexRuleBinding(ctx, 
&commonv1.Metadata{
@@ -487,7 +523,7 @@ func Test_Notify(t *testing.T) {
                        mockedObj := new(mockedEventHandler)
                        mockedObj.On("OnAddOrUpdate", mock.Anything).Return()
                        mockedObj.On("OnDelete", mock.Anything).Return()
-                       
registry.RegisterHandler(KindStream|KindIndexRuleBinding, mockedObj)
+                       
registry.RegisterHandler(KindStream|KindIndexRuleBinding|KindIndexRule, 
mockedObj)
 
                        err := tt.testFunc(context.TODO(), registry)
                        req.NoError(err)
diff --git a/banyand/metadata/schema/schema.go 
b/banyand/metadata/schema/schema.go
index ab0f260..093bc65 100644
--- a/banyand/metadata/schema/schema.go
+++ b/banyand/metadata/schema/schema.go
@@ -21,10 +21,17 @@ import (
        "context"
        "io"
 
+       "github.com/pkg/errors"
+       "google.golang.org/protobuf/proto"
+
        commonv1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/common/v1"
        databasev1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1"
 )
 
+var (
+       ErrUnsupportedEntityType = errors.New("unsupported entity type")
+)
+
 type Kind int
 
 type EventHandler interface {
@@ -74,31 +81,63 @@ type Metadata struct {
 type Spec interface {
 }
 
-func (m Metadata) Key() string {
+func (tm TypeMeta) Unmarshal(data []byte) (m proto.Message, err error) {
+       switch tm.Kind {
+       case KindStream:
+               m = &databasev1.Stream{}
+               err = proto.Unmarshal(data, m)
+       case KindMeasure:
+               m = &databasev1.Measure{}
+               err = proto.Unmarshal(data, m)
+       case KindIndexRuleBinding:
+               m = &databasev1.IndexRuleBinding{}
+               err = proto.Unmarshal(data, m)
+       case KindIndexRule:
+               m = &databasev1.IndexRule{}
+               err = proto.Unmarshal(data, m)
+       default:
+               return nil, ErrUnsupportedEntityType
+       }
+       return
+}
+
+func (m Metadata) Key() (string, error) {
        switch m.Kind {
        case KindMeasure:
                return formatMeasureKey(&commonv1.Metadata{
                        Group: m.Group,
                        Name:  m.Name,
-               })
+               }), nil
        case KindStream:
                return formatStreamKey(&commonv1.Metadata{
                        Group: m.Group,
                        Name:  m.Name,
-               })
+               }), nil
        case KindIndexRule:
                return formatIndexRuleKey(&commonv1.Metadata{
                        Group: m.Group,
                        Name:  m.Name,
-               })
+               }), nil
        case KindIndexRuleBinding:
                return formatIndexRuleBindingKey(&commonv1.Metadata{
                        Group: m.Group,
                        Name:  m.Name,
-               })
+               }), nil
        default:
-               panic("unsupported Kind")
+               return "", ErrUnsupportedEntityType
+       }
+}
+
+func (m Metadata) Equal(other proto.Message) bool {
+       if other == nil {
+               return false
+       }
+
+       if checker, ok := checkerMap[m.Kind]; ok {
+               return checker(m.Spec.(proto.Message), other)
        }
+
+       return false
 }
 
 type Stream interface {
diff --git a/banyand/metadata/schema/schema_suite_test.go 
b/banyand/metadata/schema/schema_suite_test.go
new file mode 100644
index 0000000..34372bc
--- /dev/null
+++ b/banyand/metadata/schema/schema_suite_test.go
@@ -0,0 +1,30 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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 schema
+
+import (
+       "testing"
+
+       "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+)
+
+func TestSchema(t *testing.T) {
+       RegisterFailHandler(ginkgo.Fail)
+       ginkgo.RunSpecs(t, "Schema Suite")
+}
diff --git a/banyand/metadata/schema/testdata/stream.json 
b/banyand/metadata/schema/testdata/stream.json
index d4f9df9..767cc15 100644
--- a/banyand/metadata/schema/testdata/stream.json
+++ b/banyand/metadata/schema/testdata/stream.json
@@ -89,5 +89,5 @@
       "unit": "DURATION_UNIT_DAY"
     }
   },
-  "updated_at_nanoseconds": "2021-04-15T01:30:15.01Z"
+  "updated_at": "2021-04-15T01:30:15.01Z"
 }
\ No newline at end of file
diff --git a/banyand/query/processor.go b/banyand/query/processor.go
index 507fb5f..ba1d544 100644
--- a/banyand/query/processor.go
+++ b/banyand/query/processor.go
@@ -61,7 +61,9 @@ func (q *queryProcessor) Rev(message bus.Message) (resp 
bus.Message) {
        meta := queryCriteria.GetMetadata()
        ec, err := q.streamService.Stream(meta)
        if err != nil {
-               q.log.Error().Err(err).Msg("fail to get measure execution 
context")
+               q.log.Error().Err(err).
+                       Str("stream", meta.GetName()).
+                       Msg("fail to get execution context for stream")
                return
        }
 
@@ -73,7 +75,7 @@ func (q *queryProcessor) Rev(message bus.Message) (resp 
bus.Message) {
 
        s, err := analyzer.BuildStreamSchema(context.TODO(), meta)
        if err != nil {
-               q.log.Error().Err(err).Msg("fail to build trace schema")
+               q.log.Error().Err(err).Msg("fail to build stream schema")
                return
        }
 
diff --git a/go.mod b/go.mod
index b307f42..22513ff 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
        github.com/dgraph-io/ristretto v0.1.0
        github.com/golang/mock v1.5.0
        github.com/golang/protobuf v1.5.2
-       github.com/google/go-cmp v0.5.6
+       github.com/google/go-cmp v0.5.7
        github.com/google/uuid v1.3.0
        github.com/klauspost/compress v1.13.1
        github.com/oklog/run v1.1.0
@@ -98,6 +98,7 @@ require (
        golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
        golang.org/x/text v0.3.6 // indirect
        golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
+       golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
        gopkg.in/ini.v1 v1.62.0 // indirect
        gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
        gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index b409e5e..d0e069f 100644
--- a/go.sum
+++ b/go.sum
@@ -207,8 +207,8 @@ github.com/google/go-cmp v0.5.2/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.3/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
-github.com/google/go-cmp v0.5.6/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
+github.com/google/go-cmp v0.5.7/go.mod 
h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/gofuzz v1.0.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod 
h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod 
h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
diff --git a/pkg/test/measure/testdata/measure.json 
b/pkg/test/measure/testdata/measure.json
index 125a44b..a0ab240 100644
--- a/pkg/test/measure/testdata/measure.json
+++ b/pkg/test/measure/testdata/measure.json
@@ -67,5 +67,5 @@
       "unit": "DURATION_UNIT_DAY"
     }
   },
-  "updated_at_nanoseconds": "2021-04-15T01:30:15.01Z"
+  "updated_at": "2021-04-15T01:30:15.01Z"
 }
\ No newline at end of file
diff --git a/pkg/test/stream/testdata/stream.json 
b/pkg/test/stream/testdata/stream.json
index d4f9df9..767cc15 100644
--- a/pkg/test/stream/testdata/stream.json
+++ b/pkg/test/stream/testdata/stream.json
@@ -89,5 +89,5 @@
       "unit": "DURATION_UNIT_DAY"
     }
   },
-  "updated_at_nanoseconds": "2021-04-15T01:30:15.01Z"
+  "updated_at": "2021-04-15T01:30:15.01Z"
 }
\ No newline at end of file

Reply via email to